Working CEF

This commit is contained in:
Pasalc 2023-12-29 17:44:35 +03:00
parent 0b72eebacc
commit 39d34440d8
10 changed files with 620 additions and 443 deletions

View File

@ -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}/$<CONFIGURATION>
${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

View File

@ -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<argc; ++i)
{
argv2[i] = new char[strlen(argv[i])+1];
strcpy(argv2[i],argv[i]);
}
CEFsetUp(argc,argv);//Cef will launch new process with main(argc,argv) twice. If we won't pass argc and argv from main, we will create fork bomb and system will freeze until reboot.
//END of CEF init block
initLogging ();
WallpaperEngine::Application::CApplicationContext appContext (argc, argv2);
WallpaperEngine::Application::CWallpaperApplication app (appContext);
// halt if the list-properties option was specified
@ -38,10 +103,18 @@ int main (int argc, char* argv[])
std::signal (SIGINT, signalhandler);
std::signal (SIGTERM, signalhandler);
if(!g_CEFused){
sLog.debug("No web wallpapers, shutting down CEF");
CefShutdown();
}
// show the wallpaper application
app.show ();
appPointer = nullptr;
if(g_CEFused){
sLog.debug("Shutting down CEF");
CefShutdown();
}
appPointer = nullptr;
return 0;
}

View File

@ -5,6 +5,7 @@
#include "CProject.h"
#include "CScene.h"
#include "CVideo.h"
#include "CWeb.h"
using namespace WallpaperEngine::Core;
using namespace WallpaperEngine::Assets;
@ -18,10 +19,12 @@ CProject::CProject (std::string title, std::string type, CContainer* container)
CProject* CProject::fromFile (const std::string& filename, CContainer* container) {
json content = json::parse (WallpaperEngine::FileSystem::loadFullFile (filename, container));
const std::string title = *jsonFindRequired (content, "title", "Project title missing");
std::string dependency = jsonFindDefault<std::string> (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");
const std::string file = *jsonFindRequired (content, "file", "Project's main file missing");
const auto general = content.find ("general");
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);
@ -31,9 +34,9 @@ CProject* CProject::fromFile (const std::string& filename, CContainer* container
if (type == "scene")
wallpaper = CScene::fromFile (file, *project, container);
else if (type == "video")
wallpaper = new CVideo (file, *project);
wallpaper = new CVideo (file.c_str (), *project);
else if (type == "web")
sLog.exception ("Web wallpapers are not supported yet");
wallpaper = new CWeb (file.c_str (), *project);
else
sLog.exception ("Unsupported wallpaper type: ", type);
@ -42,17 +45,19 @@ CProject* CProject::fromFile (const std::string& filename, CContainer* container
if (general != content.end ()) {
const auto properties = general->find ("properties");
if (properties != general->end ()) {
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");
}
}
void CProject::setWallpaper (CWallpaper* wallpaper) {

View File

@ -0,0 +1,71 @@
#include "CWeb.h"
#include <utility>
#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";

View File

@ -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 <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
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:
};
}

View File

@ -2,11 +2,12 @@
#include "CScene.h"
#include "CVideo.h"
#include "common.h"
#include "CWeb.h"
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <utility>
#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<Drivers::CX11OpenGLDriver*>(const_cast<Drivers::CVideoDriver*>(&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<Core::CScene> (), context, audioContext, scalingMode);
if (wallpaper->is<Core::CVideo> ())
return new WallpaperEngine::Render::CVideo (wallpaper->as<Core::CVideo> (), context, audioContext, scalingMode);
else if (wallpaper->is <Core::CWeb> ())
return new WallpaperEngine::Render::CWeb (wallpaper->as <Core::CWeb> (), context, audioContext);
else
sLog.exception ("Unsupported wallpaper type");
}

View File

@ -185,6 +185,5 @@ class CWallpaper : public Helpers::CContextAware {
CAudioContext& m_audioContext;
/** Current Wallpaper state */
CWallpaperState m_state;
CEFGLWindow cef_window;
};
} // namespace WallpaperEngine::Render

View File

@ -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<CefBrowser> 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<CefBrowser> 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<CefBrowser> 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<CefBrowser> 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";

View File

@ -1,76 +1,45 @@
// 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 <iostream>
// OpenGL
# include <GL/glew.h>
# include <GLFW/glfw3.h>
#pragma once
// Matrices manipulation for OpenGL
# include <glm/glm.hpp>
# include <glm/ext.hpp>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
// Chromium Embedded Framework
# include <cef_render_handler.h>
# include <cef_client.h>
# include <cef_app.h>
#include <string>
#include <vector>
#include <memory>
#include <algorithm>
# include <string>
# include <vector>
# include <memory>
# include <algorithm>
#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; }
uint32_t getHeight () const override { return this->m_height; }
void setSize (int64_t width, int64_t height);
protected:
void renderFrame (glm::ivec4 viewport) override;
void updateMouse (glm::ivec4 viewport);
Core::CWeb* getWeb ()
{
return this->getWallpaperData ()->as<Core::CWeb> ();
}
//! \brief TODO
// void executeJS(const std::string &cmd);
friend class CWallpaper;
//! \brief Set the new mouse position
void mouseMove(int x, int y);
//! \brief Set the new mouse state (clicked ...)
void mouseClick(CefBrowserHost::MouseButtonType btn, bool mouse_up);
//! \brief Set the new keyboard state (char typed ...)
void keyPress(int key, bool pressed);
private:
static const std::string Type;
private:
// *************************************************************************
//! \brief Private implementation to handle CEF events to draw the web page.
// *************************************************************************
@ -78,7 +47,7 @@ private:
{
public:
RenderHandler(glm::vec4 const& viewport);
RenderHandler(CWeb* webdata);
//! \brief
~RenderHandler();
@ -87,18 +56,6 @@ private:
//! VBO, texture, locations ...)
bool init();
//! \brief Render OpenGL VAO (rotating a textured square)
void draw(glm::vec4 const& viewport, bool fixed);
//! \brief Resize the view
void reshape(int w, int h);
//! \brief Return the OpenGL texture handle
GLuint texture() const
{
return m_tex;
}
//! \brief CefRenderHandler interface
virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect) override;
@ -112,31 +69,19 @@ private:
IMPLEMENT_REFCOUNTING(RenderHandler);
private:
CWeb* m_webdata;
//! \brief Dimension
int m_width;
int m_height;
//! \brief Where to draw on the OpenGL window
glm::vec4 const& m_viewport;
//! \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;
//! \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;
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();
}
};
// *************************************************************************
@ -161,27 +106,14 @@ private:
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<CefBrowser> m_browser;
CefRefPtr<BrowserClient> m_client;
RenderHandler* m_render_handler = nullptr;
//! \brief OpenGL has created GPU elements with success
bool m_initialized = false;
int64_t m_width;
int64_t m_height;
public:
//! \brief If set to false then the web page is turning.
bool m_fixed = true;
};
#endif // BROWSERVIEW_HPP
glm::vec2 m_mousePosition;
glm::vec2 m_mousePositionLast;
};
}

View File

@ -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;