Ver Fonte

Merge branch 'pr75-main'

# Conflicts:
#	src/WallpaperEngine/Render/CContext.cpp
#	src/WallpaperEngine/Render/CWallpaper.cpp
#	src/WallpaperEngine/Render/CWallpaper.h
Alexis Maiquez há 4 anos atrás
pai
commit
9ff5330a39

+ 8 - 6
main.cpp

@@ -231,8 +231,6 @@ int main (int argc, char* argv[])
     // parse the project.json file
     auto project = WallpaperEngine::Core::CProject::fromFile ("project.json", containers);
     WallpaperEngine::Render::CWallpaper* wallpaper;
-    // initialize custom context class
-    WallpaperEngine::Render::CContext* context = new WallpaperEngine::Render::CContext (screens);
 
     // auto projection = project->getWallpaper ()->as <WallpaperEngine::Core::CScene> ()->getOrthogonalProjection ();
     // create the window!
@@ -250,8 +248,6 @@ int main (int argc, char* argv[])
     // initialize inputs
     CMouseInput* mouseInput = new CMouseInput (window);
 
-    context->setMouse (mouseInput);
-
     glfwMakeContextCurrent (window);
 
     // TODO: FIGURE THESE OUT BASED ON THE SCREEN
@@ -260,9 +256,8 @@ int main (int argc, char* argv[])
 
     // get the real framebuffer size
     glfwGetFramebufferSize (window, &windowWidth, &windowHeight);
-    // set the default viewport
-    context->setDefaultViewport ({0, 0, windowWidth, windowHeight});
 
+    // initialize glew
     if (glewInit () != GLEW_OK)
     {
         fprintf (stderr, "Failed to initialize GLEW");
@@ -270,6 +265,13 @@ int main (int argc, char* argv[])
         return 3;
     }
 
+    // initialize custom context class
+    WallpaperEngine::Render::CContext* context = new WallpaperEngine::Render::CContext (screens);
+    // initialize mouse support
+    context->setMouse (mouseInput);
+    // set the default viewport
+    context->setDefaultViewport ({0, 0, windowWidth, windowHeight});
+
     if (project->getType () == "scene")
     {
         WallpaperEngine::Core::CScene* scene = project->getWallpaper ()->as <WallpaperEngine::Core::CScene> ();

+ 68 - 37
src/WallpaperEngine/Render/CContext.cpp

@@ -25,27 +25,34 @@ void CContext::initializeViewports ()
     if (this->m_isRootWindow == false || this->m_screens.empty () == true)
         return;
 
-    Display* display = XOpenDisplay (nullptr);
+    this->m_display = XOpenDisplay (nullptr);
 
     int xrandr_result, xrandr_error;
 
-    if (!XRRQueryExtension (display, &xrandr_result, &xrandr_error))
+    if (!XRRQueryExtension (this->m_display, &xrandr_result, &xrandr_error))
     {
         std::cerr << "XRandr is not present, cannot detect specified screens, running in window mode" << std::endl;
         return;
     }
 
-    int fullWidth = DisplayWidth (display, DefaultScreen (display));
-    int fullHeight = DisplayHeight (display, DefaultScreen (display));
-    XRRScreenResources* screenResources = XRRGetScreenResources (display, DefaultRootWindow (display));
+    Window root = DefaultRootWindow (this->m_display);
+    int fullWidth = DisplayWidth (this->m_display, DefaultScreen (this->m_display));
+    int fullHeight = DisplayHeight (this->m_display, DefaultScreen (this->m_display));
+    XRRScreenResources* screenResources = XRRGetScreenResources (this->m_display, DefaultRootWindow (this->m_display));
 
     // there are some situations where xrandr returns null (like screen not using the extension)
     if (screenResources == nullptr)
         return;
 
+    // create the pixmap and gc used for this display, most situations only have one "display"
+    this->m_pixmap = XCreatePixmap (this->m_display, DefaultRootWindow (this->m_display), fullWidth, fullHeight, 24);
+    this->m_gc = XCreateGC (this->m_display, this->m_pixmap, 0, nullptr);
+    // fill the whole pixmap with black for now
+    XFillRectangle (this->m_display, this->m_pixmap, this->m_gc, 0, 0, fullWidth, fullHeight);
+
     for (int i = 0; i < screenResources->noutput; i ++)
     {
-        XRROutputInfo* info = XRRGetOutputInfo (display, screenResources, screenResources->outputs [i]);
+        XRROutputInfo* info = XRRGetOutputInfo (this->m_display, screenResources, screenResources->outputs [i]);
 
         // there are some situations where xrandr returns null (like screen not using the extension)
         if (info == nullptr)
@@ -58,11 +65,11 @@ void CContext::initializeViewports ()
         {
             if (info->connection == RR_Connected && strcmp (info->name, (*cur).c_str ()) == 0)
             {
-                XRRCrtcInfo* crtc = XRRGetCrtcInfo (display, screenResources, info->crtc);
+                XRRCrtcInfo* crtc = XRRGetCrtcInfo (this->m_display, screenResources, info->crtc);
 
                 std::cout << "Found requested screen: " << info->name << " -> " << crtc->x << "x" << crtc->y << ":" << crtc->width << "x" << crtc->height << std::endl;
 
-                glm::vec4 viewport = {
+                glm::ivec4 viewport = {
                     crtc->x, fullHeight - (crtc->y + crtc->height), crtc->width, crtc->height
                 };
 
@@ -77,6 +84,17 @@ void CContext::initializeViewports ()
 
     XRRFreeScreenResources (screenResources);
 
+    // create the fbo that will handle the screen
+    this->m_fbo = new CFBO("_sc_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, 1.0, fullWidth, fullHeight, fullWidth, fullHeight);
+
+    // set the window background so the pixmap is drawn
+    XSetWindowBackgroundPixmap(this->m_display, root, this->m_pixmap);
+
+    this->m_imageData = new char [fullWidth * fullHeight * 4];
+
+    // create the image for X11 to be able to copy it over
+    this->m_image = XCreateImage (this->m_display, CopyFromParent, 24, ZPixmap, 0, this->m_imageData, fullWidth, fullHeight, 32, 0);
+
     // Cause of issue for issue #59 origial issue
     // glfwWindowHintPointer (GLFW_NATIVE_PARENT_HANDLE, reinterpret_cast <void*> (DefaultRootWindow (display)));
 }
@@ -88,43 +106,40 @@ void CContext::render ()
 
     if (this->m_viewports.empty () == false)
     {
-        static Display* display = XOpenDisplay (nullptr);
+        bool firstFrame = true;
+        bool renderFrame = true;
         auto cur = this->m_viewports.begin ();
         auto end = this->m_viewports.end ();
+        int fullWidth = DisplayWidth (this->m_display, DefaultScreen (this->m_display));
+        int fullHeight = DisplayHeight (this->m_display, DefaultScreen (this->m_display));
+        Window root = DefaultRootWindow (this->m_display);
 
-        Window root = DefaultRootWindow(display);
-        int windowWidth = 1920, windowHeight = 1080;
-        int fullWidth = DisplayWidth (display, DefaultScreen (display));
-        int fullHeight = DisplayHeight (display, DefaultScreen (display));
-
-        Pixmap pm = XCreatePixmap(display, root, fullWidth, fullHeight, 24);
-        GC gc = XCreateGC(display, pm, 0, NULL);
-        XFillRectangle(display, pm, gc, 0, 0, fullWidth, fullHeight);
-
-        char* image_data;
-        image_data = new char[windowWidth*windowHeight*4];
-
-        this->m_wallpaper->render (this->m_defaultViewport, true, image_data);
-        XImage* image = XCreateImage(display, CopyFromParent, 24, ZPixmap, 0, (char *)image_data, windowWidth, windowHeight, 32, 0);
         for (; cur != end; cur ++)
         {
-            XPutImage(display, pm, gc, image, 0, 0, (*cur).x, (*cur).y, windowWidth, windowHeight);
+            // render the background
+            this->m_wallpaper->render (*cur, renderFrame, firstFrame);
+            // scenes need to render a new frame for each viewport as they produce different results
+            // but videos should only be rendered once per group of viewports
+            firstFrame = false;
+            renderFrame = !this->m_wallpaper->is <CVideo> ();
         }
 
-        // _XROOTPMAP_ID & ESETROOT_PMAP_ID allow other programs (compositors) to 
+        // read the full texture into the image
+        glReadPixels (0, 0, fullWidth, fullHeight, GL_BGRA, GL_UNSIGNED_BYTE, (void*) this->m_imageData);
+
+        // put the image back into the screen
+        XPutImage (this->m_display, this->m_pixmap, this->m_gc, this->m_image, 0, 0, 0, 0, fullWidth, fullHeight);
+
+        // _XROOTPMAP_ID & ESETROOT_PMAP_ID allow other programs (compositors) to
         // edit the background. Without these, other programs will clear the screen.
-        Atom prop_root = XInternAtom(display, "_XROOTPMAP_ID", False);
-        Atom prop_esetroot = XInternAtom(display, "ESETROOT_PMAP_ID", False);
-        XChangeProperty(display, root, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pm, 1);
-        XChangeProperty(display, root, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pm, 1);
-
-        XSetWindowBackgroundPixmap(display, root, pm);
-        XClearWindow(display, root);
-        XFlush(display);
-
-        XDestroyImage(image);
-        XFreePixmap(display, pm);
-        XFreeGC(display, gc);
+        // it also forces the compositor to refresh the background (tested with picom)
+        Atom prop_root = XInternAtom(this->m_display, "_XROOTPMAP_ID", False);
+        Atom prop_esetroot = XInternAtom(this->m_display, "ESETROOT_PMAP_ID", False);
+        XChangeProperty(this->m_display, root, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
+        XChangeProperty(this->m_display, root, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
+
+        XClearWindow(this->m_display, root);
+        XFlush(this->m_display);
     }
     else
         this->m_wallpaper->render (this->m_defaultViewport);
@@ -133,6 +148,22 @@ void CContext::render ()
 void CContext::setWallpaper (CWallpaper* wallpaper)
 {
     this->m_wallpaper = wallpaper;
+
+    // update the wallpaper's texcoords based on the mode we're running
+    if (this->m_screens.empty () == false)
+    {
+        GLfloat texCoords [] = {
+                0.0f, 1.0f,
+                1.0f, 1.0f,
+                0.0f, 0.0f,
+                0.0f, 0.0f,
+                1.0f, 1.0f,
+                1.0f, 0.0f
+        };
+
+        this->m_wallpaper->updateTexCoord (texCoords, sizeof (texCoords));
+        this->m_wallpaper->setDestinationFramebuffer (this->m_fbo->getFramebuffer ());
+    }
 }
 
 void CContext::setDefaultViewport (glm::vec4 defaultViewport)

+ 9 - 1
src/WallpaperEngine/Render/CContext.h

@@ -5,6 +5,7 @@
 
 #include "WallpaperEngine/Input/CMouseInput.h"
 #include "CWallpaper.h"
+#include <X11/Xlib.h>
 
 using namespace WallpaperEngine::Input;
 
@@ -23,9 +24,16 @@ namespace WallpaperEngine::Render
         void setDefaultViewport (glm::vec4 defaultViewport);
         CMouseInput* getMouse () const;
         void setMouse (CMouseInput* mouse);
+
     private:
+        Display* m_display;
+        Pixmap m_pixmap;
+        GC m_gc;
+        XImage* m_image;
+        char* m_imageData;
+        CFBO* m_fbo;
         std::vector <std::string> m_screens;
-        std::vector <glm::vec4> m_viewports;
+        std::vector <glm::ivec4> m_viewports;
         glm::vec4 m_defaultViewport;
         CWallpaper* m_wallpaper;
         CMouseInput* m_mouse;

+ 2 - 2
src/WallpaperEngine/Render/CScene.cpp

@@ -56,7 +56,7 @@ CCamera* CScene::getCamera () const
     return this->m_camera;
 }
 
-void CScene::renderFrame (glm::vec4 viewport)
+void CScene::renderFrame (glm::ivec4 viewport)
 {
     auto projection = this->getScene ()->getOrthogonalProjection ();
     auto cur = this->m_objects.begin ();
@@ -82,7 +82,7 @@ void CScene::renderFrame (glm::vec4 viewport)
     glViewport (0, 0, projection->getWidth (), projection->getHeight ());
 }
 
-void CScene::updateMouse (glm::vec4 viewport)
+void CScene::updateMouse (glm::ivec4 viewport)
 {
     // projection also affects the mouse position
     auto projection = this->getScene ()->getOrthogonalProjection ();

+ 2 - 2
src/WallpaperEngine/Render/CScene.h

@@ -24,8 +24,8 @@ namespace WallpaperEngine::Render
         glm::vec2* getMousePosition ();
 
     protected:
-        void renderFrame (glm::vec4 viewport) override;
-        void updateMouse (glm::vec4 viewport);
+        void renderFrame (glm::ivec4 viewport) override;
+        void updateMouse (glm::ivec4 viewport);
 
         friend class CWallpaper;
 

+ 1 - 1
src/WallpaperEngine/Render/CVideo.cpp

@@ -115,7 +115,7 @@ void CVideo::setSize (int width, int height)
                     SWS_BILINEAR, NULL, NULL, NULL);
 }
 
-void CVideo::renderFrame (glm::vec4 viewport)
+void CVideo::renderFrame (glm::ivec4 viewport)
 {
     // do not render using the CWallpaper function, just use this one
     this->setSize (m_codecCtx->width, m_codecCtx->height);

+ 1 - 1
src/WallpaperEngine/Render/CVideo.h

@@ -25,7 +25,7 @@ namespace WallpaperEngine::Render
         int getHeight ();
 
     protected:
-        void renderFrame (glm::vec4 viewport) override;
+        void renderFrame (glm::ivec4 viewport) override;
 
         friend class CWallpaper;
 

+ 20 - 52
src/WallpaperEngine/Render/CWallpaper.cpp

@@ -12,7 +12,8 @@ CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CCont
     m_container (container),
     m_wallpaperData (wallpaperData),
     m_type (std::move(type)),
-    m_context (context)
+    m_context (context),
+    m_destFramebuffer (GL_NONE)
 {
     this->setupShaders ();
 
@@ -185,9 +186,20 @@ void CWallpaper::setupShaders ()
     this->a_TexCoord = glGetAttribLocation (this->m_shader, "a_TexCoord");
 }
 
-void CWallpaper::render (glm::vec4 viewport, bool drawToBackground, char* image_data)
+void CWallpaper::updateTexCoord (GLfloat* texCoords, GLsizeiptr size) const
 {
-    this->renderFrame (viewport);
+    glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
+    glBufferData (GL_ARRAY_BUFFER, size, texCoords, GL_STATIC_DRAW);
+}
+void CWallpaper::setDestinationFramebuffer (GLuint framebuffer)
+{
+    this->m_destFramebuffer = framebuffer;
+}
+
+void CWallpaper::render (glm::ivec4 viewport, bool renderFrame, bool newFrame)
+{
+    if (renderFrame == true)
+        this->renderFrame (viewport);
 
     int windowWidth = 1920;
     int windowHeight = 1080;
@@ -257,53 +269,13 @@ void CWallpaper::render (glm::vec4 viewport, bool drawToBackground, char* image_
     glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
     glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
 
-    // we only want texCoords to be set once
-    static bool setTexCoords = true;
-    if (setTexCoords)
-    {
-        setTexCoords = false;
-        if (drawToBackground)
-        {
-            // Need to flip the image (FB stores the image upside down)
-            GLfloat texCoords [] = {
-                0.0f, 1.0f,
-                1.0f, 1.0f,
-                0.0f, 0.0f,
-                0.0f, 0.0f,
-                1.0f, 1.0f,
-                1.0f, 0.0f
-            };
-            glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
-            glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW);
-        }
-        else 
-        {
-            GLfloat texCoords [] = {
-                0.0f, 0.0f,
-                1.0f, 0.0f,
-                0.0f, 1.0f,
-                0.0f, 1.0f,
-                1.0f, 0.0f,
-                1.0f, 1.0f
-            };
-            glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
-            glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW);
-        }
-    }
-
     glViewport (viewport.x, viewport.y, viewport.z, viewport.w);
 
-    static CFBO* screen_fbo = new CFBO("_sc_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, 1.0, windowWidth, windowHeight, windowWidth, windowHeight);
-    
-    if (drawToBackground)
-        // write to screen buffer
-        glBindFramebuffer (GL_FRAMEBUFFER, screen_fbo->getFramebuffer());
-    else
-        // write to default's framebuffer
-        glBindFramebuffer (GL_FRAMEBUFFER, GL_NONE);
-
-    
-    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    glBindFramebuffer (GL_FRAMEBUFFER, this->m_destFramebuffer);
+
+    if (newFrame)
+        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
     glDisable (GL_BLEND);
     glDisable (GL_DEPTH_TEST);
     // do not use any shader
@@ -324,10 +296,6 @@ void CWallpaper::render (glm::vec4 viewport, bool drawToBackground, char* image_
     // write the framebuffer as is to the screen
     glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
     glDrawArrays (GL_TRIANGLES, 0, 6);
-
-    // Get FB data from OpenGL, X11 will free this pointer when it is created into an XImage.
-    if (image_data)
-        glReadPixels(0, 0, 1920, 1080, GL_BGRA,  GL_UNSIGNED_BYTE, (void*)(image_data));
 }
 
 void CWallpaper::setupFramebuffers ()

+ 17 - 2
src/WallpaperEngine/Render/CWallpaper.h

@@ -31,7 +31,7 @@ namespace WallpaperEngine::Render
         /**
          * Performs a render pass of the wallpaper
          */
-        void render (glm::vec4 viewport, bool drawToBackground = false, char* image_data = nullptr);
+        void render (glm::ivec4 viewport, bool renderFrame = true, bool newFrame = true);
 
         /**
          * @return The container to resolve files for this wallpaper
@@ -71,11 +71,22 @@ namespace WallpaperEngine::Render
          */
         CFBO* getFBO () const;
 
+        /**
+         * Updates the texcoord used for drawing to the used framebuffer
+         */
+        void updateTexCoord (GLfloat* texCoords, GLsizeiptr size) const;
+        /**
+         * Updates the destination framebuffer for this wallpaper
+         *
+         * @param framebuffer
+         */
+        void setDestinationFramebuffer (GLuint framebuffer);
+
     protected:
         /**
          * Renders a frame of the wallpaper
          */
-        virtual void renderFrame (glm::vec4 viewport) = 0;
+        virtual void renderFrame (glm::ivec4 viewport) = 0;
 
         /**
          * Setups OpenGL's framebuffers for ping-pong and scene rendering
@@ -108,6 +119,10 @@ namespace WallpaperEngine::Render
         GLint g_Texture0;
         GLint a_Position;
         GLint a_TexCoord;
+        /**
+         * The framebuffer to draw the background to
+         */
+        GLuint m_destFramebuffer;
         /**
          * Setups OpenGL's shaders for this wallpaper backbuffer
          */