From 39d34440d80492f2fb69c7ae83c32fa13223e008 Mon Sep 17 00:00:00 2001 From: Pasalc Date: Fri, 29 Dec 2023 17:44:35 +0300 Subject: [PATCH] Working CEF --- CMakeLists.txt | 49 +-- main.cpp | 79 ++++- src/WallpaperEngine/Core/CProject.cpp | 57 +-- src/WallpaperEngine/Core/CWeb.cpp | 71 ++++ src/WallpaperEngine/Core/CWeb.h | 37 ++ src/WallpaperEngine/Render/CWallpaper.cpp | 111 +++++- src/WallpaperEngine/Render/CWallpaper.h | 1 - src/WallpaperEngine/Render/CWeb.cpp | 403 ++++++++++------------ src/WallpaperEngine/Render/CWeb.h | 250 +++++--------- src/common.h | 5 + 10 files changed, 620 insertions(+), 443 deletions(-) create mode 100644 src/WallpaperEngine/Core/CWeb.cpp create mode 100644 src/WallpaperEngine/Core/CWeb.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d4d59c..680ad70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,12 +32,12 @@ find_package(FFMPEG REQUIRED) find_package(FreeImage REQUIRED) find_package(PulseAudio REQUIRED) -set(CEF_ROOT "/home/kermit/Projects/fun/linux-wallpaperengine/OffScreenCEF/thirdparty/cef_binary") +set(CEF_ROOT "/home/kermit/Projects/fun/linux-wallpaperengine/OffScreenCEF/thirdparty/cef_binary/") find_package(CEF REQUIRED) set( CMAKE_RUNTIME_OUTPUT_DIRECTORY - ${CMAKE_HOME_DIRECTORY}/bin + ${CMAKE_HOME_DIRECTORY}/build ) set( @@ -47,7 +47,7 @@ set( set( TARGET_OUTPUT_DIRECTORY - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$ + ${CMAKE_HOME_DIRECTORY}/build ) add_subdirectory(${CEF_LIBCEF_DLL_WRAPPER_PATH} libcef_dll_wrapper) @@ -63,8 +63,7 @@ include_directories( ${FREEIMAGE_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIR} src - # /home/kermit/Projects/fun/linux-wallpaperengine/src/WallpaperEngine/Render/cefsimple_opengl - /home/kermit/Projects/fun/linux-wallpaperengine/cef-project/third_party/cef/cef_binary_106.0.26+ge105400+chromium-106.0.5249.91_linux64 + /home/kermit/Projects/fun/linux-wallpaperengine/OffScreenCEF/thirdparty/cef_binary ${CMAKE_SOURCE_DIR} include) @@ -75,20 +74,19 @@ set_target_properties(ceflib # PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libcef.so) PROPERTIES IMPORTED_LOCATION ${TARGET_OUTPUT_DIRECTORY}/libcef.so) + + ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}") -SET_CEF_TARGET_OUT_DIR() +# SET_CEF_TARGET_OUT_DIR() include_directories(${_CEF_ROOT}) message(CEF_ROOT="${_CEF_ROOT}") -message(CEF_ROOT="${CMAKE_SOURCE_DIR}") # target_link_libraries(linux-wallpaperengine PUBLIC ceflib) # SET_LIBRARY_TARGET_PROPERTIES(linux-wallpaperengine) -message(PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}") target_include_directories(ceflib INTERFACE "/home/kermit/Projects/fun/linux-wallpaperengine/cef-project/third_party/cef/cef_binary_106.0.26+ge105400+chromium-106.0.5249.91_linux64/include") - # target_link_libraries(linux-wallpaperengine "libcef" ${CEF_STANDARD_LIBS}) @@ -246,15 +244,6 @@ add_executable( src/WallpaperEngine/Render/Helpers/CContextAware.cpp src/WallpaperEngine/Render/Helpers/CContextAware.h - # src/WallpaperEngine/Render/cefsimple_opengl/CEFGLWindow.hpp - # src/WallpaperEngine/Render/cefsimple_opengl/CEFGLWindow.cpp - # src/WallpaperEngine/Render/cefsimple_opengl/GLWindow.hpp - # src/WallpaperEngine/Render/cefsimple_opengl/GLWindow.cpp - # src/WallpaperEngine/Render/cefsimple_opengl/BrowserView.hpp - # src/WallpaperEngine/Render/cefsimple_opengl/BrowserView.cpp - # src/WallpaperEngine/Render/cefsimple_opengl/GLCore.hpp - # src/WallpaperEngine/Render/cefsimple_opengl/GLCore.cpp - src/WallpaperEngine/Render/CWallpaper.h src/WallpaperEngine/Render/CWallpaper.cpp src/WallpaperEngine/Render/CWallpaperState.h @@ -385,6 +374,12 @@ add_executable( ${WAYLAND_SOURCES} ) +COPY_FILES(linux-wallpaperengine "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${TARGET_OUTPUT_DIRECTORY}") +COPY_FILES(linux-wallpaperengine "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${TARGET_OUTPUT_DIRECTORY}") + +message("${CEF_RESOURCE_FILES}") +message("${TARGET_OUTPUT_DIRECTORY}") + SET_EXECUTABLE_TARGET_PROPERTIES(linux-wallpaperengine) add_dependencies(linux-wallpaperengine libcef_dll_wrapper) target_link_libraries (linux-wallpaperengine PUBLIC @@ -404,24 +399,6 @@ target_link_libraries (linux-wallpaperengine PUBLIC ${PULSEAUDIO_LIBRARY} glfw) -COPY_FILES(linux-wallpaperengine "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${TARGET_OUTPUT_DIRECTORY}") -COPY_FILES(linux-wallpaperengine "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${TARGET_OUTPUT_DIRECTORY}") - -# target_link_libraries(linux-wallpaperengine PUBLIC -# ${X11_LIBRARIES} -# ${Xrandr_LIBRARIES} -# ${X11_Xxf86vm_LIB} -# ${OPENGL_LIBRARIES} -# ${GLEW_LIBRARIES} -# ${GLUT_LIBRARIES} -# ${ZLIB_LIBRARIES} -# ${LZ4_LIBRARY} -# ${SDL2_LIBRARIES} -# ${FFMPEG_LIBRARIES} -# ${FREEIMAGE_LIBRARIES} -# ${MPV_LIBRARY} -# ${PULSEAUDIO_LIBRARY} -# glfw) if (WAYLAND_SUPPORT_FOUND) target_link_libraries(linux-wallpaperengine PUBLIC diff --git a/main.cpp b/main.cpp index b737943..3a789e5 100644 --- a/main.cpp +++ b/main.cpp @@ -3,12 +3,19 @@ #include "WallpaperEngine/Application/CApplicationContext.h" #include "WallpaperEngine/Application/CWallpaperApplication.h" +#include "WallpaperEngine/Core/CWeb.h" #include "common.h" WallpaperEngine::Application::CWallpaperApplication* appPointer; void signalhandler(int sig) { + sLog.debug("Hello"); + if(g_CEFused){ + sLog.debug("Shutting down CEF"); + CefShutdown(); + } + if (appPointer == nullptr) return; @@ -21,11 +28,69 @@ void initLogging () sLog.addError (new std::ostream (std::cerr.rdbuf ())); } +static void CEFsetUp(int argc, char** argv) +{ + // This function should be called from the application entry point function to + // execute a secondary process. It can be used to run secondary processes from + // the browser client executable (default behavior) or from a separate + // executable specified by the CefSettings.browser_subprocess_path value. If + // called for the browser process (identified by no "type" command-line value) + // it will return immediately with a value of -1. If called for a recognized + // secondary process it will block until the process should exit and then return + // the process exit code. The |application| parameter may be empty. The + // |windows_sandbox_info| parameter is only used on Windows and may be NULL (see + // cef_sandbox_win.h for details). + + CefMainArgs args(argc, argv); + + int exit_code = CefExecuteProcess(args, nullptr, nullptr);//Spawned processes will terminate here(see CefIninitilize below). Maybe implementing settings.browser_subprocess_path will allow it to work not in main function. + if (exit_code >= 0) + { + // Sub proccess has endend, so exit + exit(exit_code); + } + else if (exit_code == -1) + { + // If called for the browser process (identified by no "type" command-line value) + // it will return immediately with a value of -1 + } + + // Configurate Chromium + CefSettings settings; + //CefString(&settings.locales_dir_path) = "OffScreenCEF/godot/locales"; + //CefString(&settings.resources_dir_path) = "OffScreenCEF/godot/"; + //CefString(&settings.framework_dir_path) = "OffScreenCEF/godot/"; + //CefString(&settings.cache_path) = "OffScreenCEF/godot/"; + // CefString(&settings.browser_subprocess_path) = "path/to/client" + settings.windowless_rendering_enabled = true; +#if defined(CEF_NO_SANDBOX) + settings.no_sandbox = true; +#endif + + bool result = CefInitialize(args, settings, nullptr, nullptr); //Spawn 2 new processes; Can be moved to Core::CWeb + if (!result) + { + std::cerr << "CefInitialize: failed" << std::endl; + exit(-2); + } + +} + +bool g_CEFused=false;//Will be set to true if wallpaper has "web" type int main (int argc, char* argv[]) { - initLogging (); + //START of CEF init block(it will run 3 times) + char** argv2 = new char*[argc]; //Cef modify argv on CefInit, copy it before that - WallpaperEngine::Application::CApplicationContext appContext (argc, argv); + for(int i=0; i (content, "dependency", "No dependency"); + if(dependency=="No dependency"){ + std::string title = *jsonFindRequired (content, "title", "Project title missing"); + std::string type = *jsonFindRequired (content, "type", "Project type missing"); + std::string file = *jsonFindRequired (content, "file", "Project's main file missing"); + auto general = content.find ("general"); + CWallpaper* wallpaper; - std::transform (type.begin (), type.end (), type.begin (), tolower); + std::transform (type.begin (), type.end (), type.begin (), tolower); - CProject* project = new CProject (title, type, container); + CProject* project = new CProject (title, type, container); - if (type == "scene") - wallpaper = CScene::fromFile (file, *project, container); - else if (type == "video") - wallpaper = new CVideo (file, *project); - else if (type == "web") - sLog.exception ("Web wallpapers are not supported yet"); - else - sLog.exception ("Unsupported wallpaper type: ", type); + if (type == "scene") + wallpaper = CScene::fromFile (file, *project, container); + else if (type == "video") + wallpaper = new CVideo (file.c_str (), *project); + else if (type == "web") + wallpaper = new CWeb (file.c_str (), *project); + else + sLog.exception ("Unsupported wallpaper type: ", type); - project->setWallpaper (wallpaper); + project->setWallpaper (wallpaper); - if (general != content.end ()) { - const auto properties = general->find ("properties"); + if (general != content.end ()) { + const auto properties = general->find ("properties"); - if (properties != general->end ()) { - for (const auto& cur : properties->items ()) { - Projects::CProperty* property = Projects::CProperty::fromJSON (cur.value (), cur.key ()); - - if (property != nullptr) - project->insertProperty (property); + if (properties != general-> end ()) { + for (const auto& cur : properties->items ()) { + Projects::CProperty* property = Projects::CProperty::fromJSON (cur.value (), cur.key ()); + if (property != nullptr) + project->insertProperty (property); + } } } + return project; + } + else{ + sLog.exception("Project have dependency. They are not supported, quiting"); } - - return project; } void CProject::setWallpaper (CWallpaper* wallpaper) { diff --git a/src/WallpaperEngine/Core/CWeb.cpp b/src/WallpaperEngine/Core/CWeb.cpp new file mode 100644 index 0000000..f0271b1 --- /dev/null +++ b/src/WallpaperEngine/Core/CWeb.cpp @@ -0,0 +1,71 @@ +#include "CWeb.h" + +#include +#include "common.h" + +static void CEFsetUp(int argc, char** argv) +{ + // This function should be called from the application entry point function to + // execute a secondary process. It can be used to run secondary processes from + // the browser client executable (default behavior) or from a separate + // executable specified by the CefSettings.browser_subprocess_path value. If + // called for the browser process (identified by no "type" command-line value) + // it will return immediately with a value of -1. If called for a recognized + // secondary process it will block until the process should exit and then return + // the process exit code. The |application| parameter may be empty. The + // |windows_sandbox_info| parameter is only used on Windows and may be NULL (see + // cef_sandbox_win.h for details). + CefMainArgs args(argc,argv); + int exit_code = CefExecuteProcess(args, nullptr, nullptr); + if (exit_code >= 0) + { + sLog.debug("CEF sub proccess has endend"); + // Sub proccess has endend, so exit + exit(exit_code); + } + else if (exit_code == -1) + { + // If called for the browser process (identified by no "type" command-line value) + // it will return immediately with a value of -1 + } + + // Configurate Chromium + CefSettings settings; + //CefString(&settings.locales_dir_path) = "OffScreenCEF/godot/locales"; + //CefString(&settings.resources_dir_path) = "OffScreenCEF/godot/"; + //CefString(&settings.framework_dir_path) = "OffScreenCEF/godot/"; + //CefString(&settings.cache_path) = "OffScreenCEF/godot/"; + settings.windowless_rendering_enabled = true; +#if defined(CEF_NO_SANDBOX) + settings.no_sandbox = true; +#endif + + bool result = CefInitialize(args, settings, nullptr, nullptr); + if (!result) + { + sLog.error("CefInitialize: failed"); + exit(-2); + } +} + +using namespace WallpaperEngine::Core; + +const std::string& CWeb::getFilename () +{ + return this->m_filename; +} + +CWeb::CWeb (std::string filename, CProject& project) : + CWallpaper (Type, project), + m_filename (std::move(filename)) +{ + if(!g_CEFused) { + sLog.debug("Setting up CEF"); + // char** argv = new char*("linux-wallpaper\n"); + // CEFsetUp(1, argv); + // delete argv; + g_CEFused=true; + } +} + +const std::string CWeb::Type = "web"; diff --git a/src/WallpaperEngine/Core/CWeb.h b/src/WallpaperEngine/Core/CWeb.h new file mode 100644 index 0000000..ad8ab97 --- /dev/null +++ b/src/WallpaperEngine/Core/CWeb.h @@ -0,0 +1,37 @@ +#pragma once + +#include "Core.h" +#include "CWallpaper.h" + +// Chromium Embedded Framework +#include "include/cef_render_handler.h" +#include "include/cef_client.h" +#include "include/cef_app.h" + +extern "C" +{ +#include +#include +#include +#include +} + +namespace WallpaperEngine::Core +{ + class CWeb : public CWallpaper + { + public: + explicit CWeb (std::string filename, CProject& project); + + const std::string& getFilename (); + + protected: + friend class CWallpaper; + + const std::string m_filename; + + static const std::string Type; + + private: + }; +} \ No newline at end of file diff --git a/src/WallpaperEngine/Render/CWallpaper.cpp b/src/WallpaperEngine/Render/CWallpaper.cpp index b641059..34cde5e 100644 --- a/src/WallpaperEngine/Render/CWallpaper.cpp +++ b/src/WallpaperEngine/Render/CWallpaper.cpp @@ -2,11 +2,12 @@ #include "CScene.h" #include "CVideo.h" #include "common.h" +#include "CWeb.h" #include #include #include -#include "Drivers/CX11OpenGLDriver.h" + using namespace WallpaperEngine::Render; CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRenderContext& context, @@ -25,9 +26,7 @@ CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRend m_vaoBuffer (GL_NONE), m_audioContext (audioContext), m_state (scalingMode), - cef_window(1920,1080, "test title", reinterpret_cast(const_cast(&context.getDriver()))->getWindow()) { - cef_window.setup(); // generate the VAO to stop opengl from complaining glGenVertexArrays (1, &this->m_vaoBuffer); glBindVertexArray (this->m_vaoBuffer); @@ -197,7 +196,105 @@ void CWallpaper::updateUVs (const glm::ivec4& viewport, const bool vflip) { void CWallpaper::render (glm::ivec4 viewport, bool vflip) { this->renderFrame (viewport); - cef_window.update(); + + uint32_t projectionWidth = this->getWidth (); + uint32_t projectionHeight = this->getHeight (); + + float ustart = 0.0f; + float uend = 0.0f; + float vstart = 0.0f; + float vend = 0.0f; + + if ( + (viewport.w > viewport.z && projectionWidth >= projectionHeight) || + (viewport.z > viewport.w && projectionHeight > projectionWidth) + ) + { + if (vflip) + { + vstart = 0.0f; + vend = 1.0f; + } + else + { + vstart = 1.0f; + vend = 0.0f; + } + + int newWidth = viewport.w / (float) projectionHeight * projectionWidth; + float newCenter = newWidth / 2.0f; + float viewportCenter = viewport.z / 2.0; + + float left = newCenter - viewportCenter; + float right = newCenter + viewportCenter; + + ustart = left / newWidth; + uend = right / newWidth; + } + + if ( + (viewport.z > viewport.w && projectionWidth >= projectionHeight) || + (viewport.w > viewport.z && projectionHeight > projectionWidth) + ) + { + ustart = 0.0f; + uend = 1.0f; + + int newHeight = viewport.z / (float) projectionWidth * projectionHeight; + float newCenter = newHeight / 2.0f; + float viewportCenter = viewport.w / 2.0; + + float down = newCenter - viewportCenter; + float up = newCenter + viewportCenter; + + if (vflip) + { + vstart = down / newHeight; + vend = up / newHeight; + } + else + { + vstart = up / newHeight; + vend = down / newHeight; + } + } + + GLfloat texCoords [] = { + ustart, vstart, + uend, vstart, + ustart, vend, + ustart, vend, + uend, vstart, + uend, vend, + }; + + glViewport (viewport.x, viewport.y, viewport.z, viewport.w); + + glBindFramebuffer (GL_FRAMEBUFFER, this->m_destFramebuffer); + + glBindVertexArray (this->m_vaoBuffer); + + glDisable (GL_BLEND); + glDisable (GL_DEPTH_TEST); + // do not use any shader + glUseProgram (this->m_shader); + // activate scene texture + glActiveTexture (GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, this->getWallpaperTexture ()); + // set uniforms and attribs + glEnableVertexAttribArray (this->a_TexCoord); + glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer); + glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW); + glVertexAttribPointer (this->a_TexCoord, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + glEnableVertexAttribArray (this->a_Position); + glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer); + glVertexAttribPointer (this->a_Position, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glUniform1i (this->g_Texture0, 0); + // write the framebuffer as is to the screen + glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer); + glDrawArrays (GL_TRIANGLES, 0, 6); } void CWallpaper::setupFramebuffers () { @@ -254,6 +351,8 @@ CWallpaper* CWallpaper::fromWallpaper (Core::CWallpaper* wallpaper, CRenderConte return new WallpaperEngine::Render::CScene (wallpaper->as (), context, audioContext, scalingMode); if (wallpaper->is ()) return new WallpaperEngine::Render::CVideo (wallpaper->as (), context, audioContext, scalingMode); - - sLog.exception ("Unsupported wallpaper type"); + else if (wallpaper->is ()) + return new WallpaperEngine::Render::CWeb (wallpaper->as (), context, audioContext); + else + sLog.exception ("Unsupported wallpaper type"); } \ No newline at end of file diff --git a/src/WallpaperEngine/Render/CWallpaper.h b/src/WallpaperEngine/Render/CWallpaper.h index 817187f..e54891a 100644 --- a/src/WallpaperEngine/Render/CWallpaper.h +++ b/src/WallpaperEngine/Render/CWallpaper.h @@ -185,6 +185,5 @@ class CWallpaper : public Helpers::CContextAware { CAudioContext& m_audioContext; /** Current Wallpaper state */ CWallpaperState m_state; - CEFGLWindow cef_window; }; } // namespace WallpaperEngine::Render diff --git a/src/WallpaperEngine/Render/CWeb.cpp b/src/WallpaperEngine/Render/CWeb.cpp index e55156f..f853c9d 100644 --- a/src/WallpaperEngine/Render/CWeb.cpp +++ b/src/WallpaperEngine/Render/CWeb.cpp @@ -1,249 +1,228 @@ // This code is a modification of the original projects that can be found at // https://github.com/if1live/cef-gl-example // https://github.com/andmcgregor/cefgui +#include "CWeb.h" -#include "BrowserView.hpp" -#include "GLCore.hpp" +using namespace WallpaperEngine::Render; -//------------------------------------------------------------------------------ -BrowserView::RenderHandler::RenderHandler(glm::vec4 const& viewport) - : m_viewport(viewport) -{} - -//------------------------------------------------------------------------------ -BrowserView::RenderHandler::~RenderHandler() +CWeb::CWeb (Core::CWeb* web, CRenderContext& context, CAudioContext& audioContext) : + CWallpaper (web, Type, context, audioContext), + m_width (context.getOutput ().getFullWidth ()), + m_height (context.getOutput ().getFullHeight ()), + m_browser(), + m_client() { - // Free GPU memory - GLCore::deleteProgram(m_prog); - glDeleteBuffers(1, &m_vbo); - glDeleteVertexArrays(1, &m_vao); -} + // setup framebuffers + this->setupFramebuffers(); -//------------------------------------------------------------------------------ -bool BrowserView::RenderHandler::init() -{ - // Dummy texture data - const unsigned char data[] = { - 255, 0, 0, 255, - 0, 255, 0, 255, - 0, 0, 255, 255, - 255, 255, 255, 255, - }; - - // Compile vertex and fragment shaders - m_prog = GLCore::createShaderProgram("shaders/tex.vert", "shaders/tex.frag"); - if (m_prog == 0) - { - std::cerr << "shader compile failed" << std::endl; - return false; - } - - // Get locations of shader variables (attributes and uniforms) - m_pos_loc = GLCHECK(glGetAttribLocation(m_prog, "position")); - m_tex_loc = GLCHECK(glGetUniformLocation(m_prog, "tex")); - m_mvp_loc = GLCHECK(glGetUniformLocation(m_prog, "mvp")) - - // Square vertices (texture positions are computed directly inside the shader) - float coords[] = {-1.0,-1.0,-1.0,1.0,1.0,-1.0,1.0,-1.0,-1.0,1.0,1.0,1.0}; - - // See https://learnopengl.com/Getting-started/Textures - GLCHECK(glGenVertexArrays(1, &m_vao)); - GLCHECK(glBindVertexArray(m_vao)); - GLCHECK(glGenBuffers(1, &m_vbo)); - GLCHECK(glBindBuffer(GL_ARRAY_BUFFER, m_vbo)); - GLCHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(coords), coords, GL_STATIC_DRAW)); - GLCHECK(glEnableVertexAttribArray(m_pos_loc)); - GLCHECK(glVertexAttribPointer(m_pos_loc, 2, GL_FLOAT, GL_FALSE, 0, 0)); - - // GLCHECK(glGenTextures(1, &m_tex)); - // GLCHECK(glBindTexture(GL_TEXTURE_2D, m_tex)); - // GLCHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - // GLCHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - // GLCHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - // GLCHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - // GLCHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)); - // GLCHECK(glBindTexture(GL_TEXTURE_2D, 0)); - - GLCHECK(glBindBuffer(GL_ARRAY_BUFFER, 0)); - GLCHECK(glBindVertexArray(0)); - - return true; -} - -//------------------------------------------------------------------------------ -void BrowserView::RenderHandler::draw(glm::vec4 const& viewport, bool fixed) -{ - // Where to paint on the OpenGL window - GLCHECK(glViewport(viewport[0], - viewport[1], - GLsizei(viewport[2] * m_width), - GLsizei(viewport[3] * m_height))); - - // // Apply a rotation - glm::mat4 trans = glm::mat4(1.0f); // Identity matrix - // if (!fixed) - // { - // trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)); - // trans = glm::rotate(trans, (float)glfwGetTime() / 5.0f, glm::vec3(0.0f, 0.0f, 1.0f)); - // } - - // See https://learnopengl.com/Getting-started/Textures - GLCHECK(glUseProgram(m_prog)); - GLCHECK(glBindVertexArray(m_vao)); - - GLCHECK(glUniformMatrix4fv(m_mvp_loc, 1, GL_FALSE, glm::value_ptr(trans))); - GLCHECK(glBindBuffer(GL_ARRAY_BUFFER, m_vbo)); - GLCHECK(glActiveTexture(GL_TEXTURE0)); - GLCHECK(glBindTexture(GL_TEXTURE_2D, m_tex)); - GLCHECK(glDrawArrays(GL_TRIANGLES, 0, 6)); - GLCHECK(glBindTexture(GL_TEXTURE_2D, 0)); - GLCHECK(glBindBuffer(GL_ARRAY_BUFFER, 0)); - - GLCHECK(glBindVertexArray(0)); - GLCHECK(glUseProgram(0)); -} - -//------------------------------------------------------------------------------ -void BrowserView::RenderHandler::reshape(int w, int h) -{ - m_width = w; - m_height = h; -} - -bool BrowserView::viewport(float x, float y, float w, float h) -{ - if (!(x >= 0.0f) && (x < 1.0f)) - return false; - - if (!(x >= 0.0f) && (y < 1.0f)) - return false; - - if (!(w > 0.0f) && (w <= 1.0f)) - return false; - - if (!(h > 0.0f) && (h <= 1.0f)) - return false; - - if (x + w > 1.0f) - return false; - - if (y + h > 1.0f) - return false; - - m_viewport[0] = x; - m_viewport[1] = y; - m_viewport[2] = w; - m_viewport[3] = h; - - return true; -} - -//------------------------------------------------------------------------------ -void BrowserView::RenderHandler::GetViewRect(CefRefPtr browser, CefRect &rect) -{ - rect = CefRect(m_viewport[0], m_viewport[1], m_viewport[2] * m_width, m_viewport[3] * m_height); -} - -//------------------------------------------------------------------------------ -void BrowserView::RenderHandler::OnPaint(CefRefPtr browser, PaintElementType type, - const RectList &dirtyRects, const void *buffer, - int width, int height) -{ - //std::cout << "BrowserView::RenderHandler::OnPaint" << std::endl; - GLCHECK(glActiveTexture(GL_TEXTURE0)); - GLCHECK(glBindTexture(GL_TEXTURE_2D, m_tex)); - GLCHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA_EXT, - GL_UNSIGNED_BYTE, (unsigned char*)buffer)); - GLCHECK(glBindTexture(GL_TEXTURE_2D, 0)); -} - -//------------------------------------------------------------------------------ -BrowserView::BrowserView(const std::string &url) - : m_mouse_x(0), m_mouse_y(0), m_viewport(0.0f, 0.0f, 1.0f, 1.0f) -{ CefWindowInfo window_info; window_info.SetAsWindowless(0); - m_render_handler = new RenderHandler(m_viewport); - m_initialized = m_render_handler->init(); - m_render_handler->reshape(128, 128); // initial size + this->m_render_handler = new RenderHandler(this); CefBrowserSettings browserSettings; - browserSettings.windowless_frame_rate = 60; // 30 is default + //Documentaion says said that 60 fps is maximum value + browserSettings.windowless_frame_rate = std::max(60,context.getApp().getContext().settings.render.maximumFPS); m_client = new BrowserClient(m_render_handler); + std::filesystem::path htmlpath = this->getWeb ()->getProject ().getContainer ()->resolveRealFile (this->getWeb ()->getFilename ()); + //To open local file in browser URL must be "file:///path/to/file.html" + const std::string htmlURL = std::string("file:///") + htmlpath.c_str(); m_browser = CefBrowserHost::CreateBrowserSync(window_info, m_client.get(), - url, browserSettings, + htmlURL, browserSettings, nullptr, nullptr); } -//------------------------------------------------------------------------------ -BrowserView::~BrowserView() +void CWeb::setSize (int64_t width, int64_t height) { - CefDoMessageLoopWork(); - m_browser->GetHost()->CloseBrowser(true); + this->m_width = width > 0 ? width : this->m_width; + this->m_height = height > 0 ? height : this->m_height; - m_browser = nullptr; - m_client = nullptr; -} + // do not refresh the texture if any of the sizes are invalid + if (this->m_width <= 0 || this->m_height <= 0) + return; -//------------------------------------------------------------------------------ -void BrowserView::load(const std::string &url) -{ - assert(m_initialized); - m_browser->GetMainFrame()->LoadURL(url); -} + // reconfigure the texture + glBindTexture (GL_TEXTURE_2D, this->getWallpaperTexture()); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, this->getWidth(), this->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); -//------------------------------------------------------------------------------ -void BrowserView::draw() -{ - CefDoMessageLoopWork(); - m_render_handler->draw(m_viewport, m_fixed); -} - -//------------------------------------------------------------------------------ -void BrowserView::reshape(int w, int h) -{ - m_render_handler->reshape(w, h); - GLCHECK(glViewport(m_viewport[0], - m_viewport[1], - GLsizei(m_viewport[2] * w), - GLsizei(m_viewport[3] * h))); + // Notify cef that it was resized(maybe it's not even needed) m_browser->GetHost()->WasResized(); } -//------------------------------------------------------------------------------ -void BrowserView::mouseMove(int x, int y) +void CWeb::renderFrame (glm::ivec4 viewport) { - m_mouse_x = x; - m_mouse_y = y; + // ensure the virtual mouse position is up to date + this->updateMouse (viewport); + // use the scene's framebuffer by default + glBindFramebuffer (GL_FRAMEBUFFER, this->getWallpaperFramebuffer()); + // ensure we render over the whole framebuffer + glViewport (0, 0, this->getWidth (), this->getHeight ()); + + //Cef processes all messages, including OnPaint, which renders frame + //If there is no OnPaint in message loop, we will not update(render) frame + // This means some frames will not have OnPaint call in cef messageLoop + // Because of that glClear will result in flickering on higher fps + // Do not use glClear until some method to control rendering with cef is supported + //We might actually try to use cef to execute javascript, and not using off-screen rendering at all + //But for now let it be like this + // glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + CefDoMessageLoopWork(); +} +void CWeb::updateMouse (glm::ivec4 viewport) +{ + // update virtual mouse position first + glm::dvec2 position = this->getContext ().getInputContext ().getMouseInput ().position(); CefMouseEvent evt; - evt.x = x; - evt.y = y; - - bool mouse_leave = false; // TODO - m_browser->GetHost()->SendMouseMoveEvent(evt, mouse_leave); + // Set mouse current position. Maybe clamps are not needed + evt.x = std::clamp(int(position.x - viewport.x),0,viewport.z); + evt.y = std::clamp(int(position.y - viewport.y),0,viewport.w); + // Send mouse position to cef + m_browser->GetHost()->SendMouseMoveEvent(evt, false); } -//------------------------------------------------------------------------------ -void BrowserView::mouseClick(CefBrowserHost::MouseButtonType btn, bool mouse_up) +CWeb::~CWeb(){ + CefDoMessageLoopWork(); + m_browser->GetHost()->CloseBrowser(true); +} + +//TODO Remove +GLuint compileShaderFromCode(GLenum shader_type, const char *src) { - CefMouseEvent evt; - evt.x = m_mouse_x; - evt.y = m_mouse_y; + GLuint shader = glCreateShader(shader_type); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); - int click_count = 1; // TODO - m_browser->GetHost()->SendMouseClickEvent(evt, btn, mouse_up, click_count); + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status == GL_TRUE) { + return shader; + } + + // shader compile fail! + fprintf(stderr, "SHADER COMPILE ERROR\n"); + + GLint info_len = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len); + if (info_len > 1) { + char *info_log = (char*)malloc(sizeof(char) * info_len); + glGetShaderInfoLog(shader, info_len, NULL, info_log); + fprintf(stderr, "Error compiling shader: \n%s\n", info_log); + free(info_log); + } + glDeleteShader(shader); + return 0; } -//------------------------------------------------------------------------------ -void BrowserView::keyPress(int key, bool pressed) +GLuint createShaderProgram(GLuint vert, GLuint frag) { - CefKeyEvent evt; - evt.character = key; - evt.native_key_code = key; - evt.type = pressed ? KEYEVENT_CHAR : KEYEVENT_KEYUP; + GLuint program = glCreateProgram(); - m_browser->GetHost()->SendKeyEvent(evt); + glAttachShader(program, vert); + glAttachShader(program, frag); + glLinkProgram(program); + glDetachShader(program, vert); + glDetachShader(program, frag); + + GLint linked; + glGetProgramiv(program, GL_LINK_STATUS, &linked); + if (linked) { + return program; + } + + // fail... + GLint info_len = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_len); + if (info_len > 1) { + char *info_log = (char*)malloc(sizeof(char) * info_len); + glGetProgramInfoLog(program, info_len, NULL, info_log); + fprintf(stderr, "Error linking program: \n%s\n", info_log); + free(info_log); + } + + glDeleteProgram(program); + return 0; } + +CWeb::RenderHandler::RenderHandler(CWeb* webdata): + m_webdata(webdata) +{ + // m_prog = GLCore::createShaderProgram("shaders/tex.vert", "shaders/tex.frag"); + + //GLuint vertShader = compileShaderFromFile(GL_VERTEX_SHADER, vert); + + + // const char *vertCode = R"( + // #version 150 + + // uniform mat4 mvp; + // in vec2 position; + // out vec2 Texcoord; + + // void main() { + // Texcoord = (vec2(position.x + 1.0f, position.y - 1.0f) * 0.5); + // Texcoord.y *= -1.0f; + // gl_Position = mvp * vec4(position.x, position.y, 0.0f, 1.0f); + // })"; + // GLuint vertShader = compileShaderFromCode(GL_VERTEX_SHADER, vertCode); + + // const char *fragCode = R"( + // #version 150 + + // in vec2 Texcoord; + + // out vec4 outputColor; + + // uniform sampler2D tex; + + // void main() { + // outputColor = texture2D(tex, Texcoord); + // if (outputColor.a < 0.1) + // { + // discard; + // } + // } + // )"; + // GLuint fragShader = compileShaderFromCode(GL_FRAGMENT_SHADER, fragCode); + + // if (vertShader == 0 || fragShader == 0) { + // sLog.exception("Can't compile vert or frag shader in Web"); + // } + + // this->m_prog = createShaderProgram(vertShader, fragShader); + // if(this->m_prog==0){ + // sLog.exception("Can't create program from shaders in Web"); + // } + +} +CWeb::RenderHandler::~RenderHandler(){ + // glDeleteProgram(this->m_prog); + // glDeleteBuffers(1, &this->m_vbo); + // glDeleteVertexArrays(1, &this->m_vao); +} +//Required by CEF +void CWeb::RenderHandler::GetViewRect(CefRefPtr browser, CefRect &rect) +{ + rect = CefRect(0, 0, this->m_webdata->getWidth(), this->m_webdata->getHeight()); +} +//Will be executed in CEF message loop +void CWeb::RenderHandler::OnPaint(CefRefPtr browser, PaintElementType type, + const RectList &dirtyRects, const void *buffer, + int width, int height) +{ + //sLog.debug("BrowserView::RenderHandler::OnPaint"); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, this->texture()); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA_EXT, + GL_UNSIGNED_BYTE, (unsigned char*)buffer); + glBindTexture(GL_TEXTURE_2D, 0); + // GLCHECK(glActiveTexture(GL_TEXTURE0)); + // GLCHECK(glBindTexture(GL_TEXTURE_2D, this->texture())); + // GLCHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA_EXT, + // GL_UNSIGNED_BYTE, (unsigned char*)buffer)); + // GLCHECK(glBindTexture(GL_TEXTURE_2D, 0)); + +} + +const std::string CWeb::Type = "web"; \ No newline at end of file diff --git a/src/WallpaperEngine/Render/CWeb.h b/src/WallpaperEngine/Render/CWeb.h index c0602c7..1731e53 100644 --- a/src/WallpaperEngine/Render/CWeb.h +++ b/src/WallpaperEngine/Render/CWeb.h @@ -1,187 +1,119 @@ -// This code is a modification of the original "cefsimple" example that can be found at -// https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage - -#ifndef BROWSERVIEW_HPP -# define BROWSERVIEW_HPP - -# include - -// OpenGL -# include -# include +#pragma once // Matrices manipulation for OpenGL -# include -# include +#include +#include -// Chromium Embedded Framework -# include -# include -# include +#include +#include +#include +#include -# include -# include -# include -# include +#include "common.h" +#include "WallpaperEngine/Core/CWeb.h" +#include "WallpaperEngine/Render/CWallpaper.h" +#include "WallpaperEngine/Audio/CAudioStream.h" -// **************************************************************************** -//! \brief Interface class rendering a single web page. -// **************************************************************************** -class BrowserView +namespace WallpaperEngine::Render { -public: - - //! \brief Default Constructor using a given URL. - BrowserView(const std::string &url); - - //! \brief - ~BrowserView(); - - //! \brief Load the given web page. - void load(const std::string &url); - - //! \brief Render the web page. - void draw(); - - //! \brief Set the windows size. - void reshape(int w, int h); - - //! \brief Set the viewport: the rectangle on the window where to display - //! the web document. - //! \return false if arguments are incorrect. - bool viewport(float x, float y, float w, float h); - - //! \brief Get the viewport. - inline glm::vec4 const& viewport() const + class CWeb : public CWallpaper { - return m_viewport; - } + public: + CWeb (Core::CWeb* scene, CRenderContext& context, CAudioContext& audioContext); + ~CWeb(); + uint32_t getWidth () const override { return this->m_width; } - //! \brief TODO - // void executeJS(const std::string &cmd); + uint32_t getHeight () const override { return this->m_height; } - //! \brief Set the new mouse position - void mouseMove(int x, int y); + void setSize (int64_t width, int64_t height); - //! \brief Set the new mouse state (clicked ...) - void mouseClick(CefBrowserHost::MouseButtonType btn, bool mouse_up); + protected: + void renderFrame (glm::ivec4 viewport) override; + void updateMouse (glm::ivec4 viewport); + Core::CWeb* getWeb () + { + return this->getWallpaperData ()->as (); + } - //! \brief Set the new keyboard state (char typed ...) - void keyPress(int key, bool pressed); + friend class CWallpaper; -private: + static const std::string Type; - // ************************************************************************* - //! \brief Private implementation to handle CEF events to draw the web page. - // ************************************************************************* - class RenderHandler: public CefRenderHandler - { - public: + private: + // ************************************************************************* + //! \brief Private implementation to handle CEF events to draw the web page. + // ************************************************************************* + class RenderHandler: public CefRenderHandler + { + public: - RenderHandler(glm::vec4 const& viewport); + RenderHandler(CWeb* webdata); - //! \brief - ~RenderHandler(); + //! \brief + ~RenderHandler(); - //! \brief Compile OpenGL shaders and create OpenGL objects (VAO, - //! VBO, texture, locations ...) - bool init(); + //! \brief Compile OpenGL shaders and create OpenGL objects (VAO, + //! VBO, texture, locations ...) + bool init(); - //! \brief Render OpenGL VAO (rotating a textured square) - void draw(glm::vec4 const& viewport, bool fixed); + //! \brief CefRenderHandler interface + virtual void GetViewRect(CefRefPtr browser, CefRect &rect) override; - //! \brief Resize the view - void reshape(int w, int h); + //! \brief CefRenderHandler interface + //! Update the OpenGL texture. + virtual void OnPaint(CefRefPtr browser, PaintElementType type, + const RectList &dirtyRects, const void *buffer, + int width, int height) override; - //! \brief Return the OpenGL texture handle - GLuint texture() const - { - return m_tex; - } + //! \brief CefBase interface + IMPLEMENT_REFCOUNTING(RenderHandler); - //! \brief CefRenderHandler interface - virtual void GetViewRect(CefRefPtr browser, CefRect &rect) override; + private: + CWeb* m_webdata; - //! \brief CefRenderHandler interface - //! Update the OpenGL texture. - virtual void OnPaint(CefRefPtr browser, PaintElementType type, - const RectList &dirtyRects, const void *buffer, - int width, int height) override; + uint32_t getWidth () const { + return this->m_webdata->getWidth(); + }; + uint32_t getHeight () const { + return this->m_webdata->getHeight(); + }; + //! \brief Return the OpenGL texture handle + GLuint texture() const + { + return this->m_webdata->getWallpaperFramebuffer(); + } + }; - //! \brief CefBase interface - IMPLEMENT_REFCOUNTING(RenderHandler); + // ************************************************************************* + //! \brief Provide access to browser-instance-specific callbacks. A single + //! CefClient instance can be shared among any number of browsers. + // ************************************************************************* + class BrowserClient: public CefClient + { + public: - private: + BrowserClient(CefRefPtr ptr) + : m_renderHandler(ptr) + {} - //! \brief Dimension - int m_width; - int m_height; + virtual CefRefPtr GetRenderHandler() override + { + return m_renderHandler; + } - //! \brief Where to draw on the OpenGL window - glm::vec4 const& m_viewport; + CefRefPtr m_renderHandler; - //! \brief OpenGL shader program handle - GLuint m_prog = 0; - //! \brief OpenGL texture handle - GLuint m_tex = 0; - //! \brief OpenGL vertex array object handle - GLuint m_vao = 0; - //! \brief OpenGL vertex buffer obejct handle - GLuint m_vbo = 0; + IMPLEMENT_REFCOUNTING(BrowserClient); + }; + + CefRefPtr m_browser; + CefRefPtr m_client; + RenderHandler* m_render_handler = nullptr; - //! \brief OpenGL shader variable locations for vertices of the - //! rectangle - GLint m_pos_loc = -1; - //! \brief OpenGL shader variable locations for the texture - GLint m_tex_loc = -1; - //! \brief OpenGL shader variable locations for the Model View - //! Projection matrix. - GLint m_mvp_loc = -1; + int64_t m_width; + int64_t m_height; + + glm::vec2 m_mousePosition; + glm::vec2 m_mousePositionLast; }; - - // ************************************************************************* - //! \brief Provide access to browser-instance-specific callbacks. A single - //! CefClient instance can be shared among any number of browsers. - // ************************************************************************* - class BrowserClient: public CefClient - { - public: - - BrowserClient(CefRefPtr ptr) - : m_renderHandler(ptr) - {} - - virtual CefRefPtr GetRenderHandler() override - { - return m_renderHandler; - } - - CefRefPtr m_renderHandler; - - IMPLEMENT_REFCOUNTING(BrowserClient); - }; - -private: - - //! \brief Mouse cursor position on the OpenGL window - int m_mouse_x; - int m_mouse_y; - - //! \brief Where to draw on the OpenGL window - glm::vec4 m_viewport; - - //! \brief Chromium Embedded framework elements - CefRefPtr m_browser; - CefRefPtr m_client; - RenderHandler* m_render_handler = nullptr; - - //! \brief OpenGL has created GPU elements with success - bool m_initialized = false; - -public: - - //! \brief If set to false then the web page is turning. - bool m_fixed = true; -}; - -#endif // BROWSERVIEW_HPP +} diff --git a/src/common.h b/src/common.h index 77bc521..ef789dc 100644 --- a/src/common.h +++ b/src/common.h @@ -1,3 +1,8 @@ #pragma once #include "WallpaperEngine/Logging/CLog.h" +#include "WallpaperEngine/Core/CWeb.h" + +//global variables are bad +extern bool g_CEFused; +extern CefMainArgs g_args; \ No newline at end of file