diff --git a/main.cpp b/main.cpp index 2df67c5..30e9089 100644 --- a/main.cpp +++ b/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 ()->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 (); diff --git a/src/WallpaperEngine/Render/CContext.cpp b/src/WallpaperEngine/Render/CContext.cpp index be1062b..923d71b 100644 --- a/src/WallpaperEngine/Render/CContext.cpp +++ b/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 (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 (); } - // _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); + // 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); - XSetWindowBackgroundPixmap(display, root, pm); - XClearWindow(display, root); - XFlush(display); - - XDestroyImage(image); - XFreePixmap(display, pm); - XFreeGC(display, gc); + 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) diff --git a/src/WallpaperEngine/Render/CContext.h b/src/WallpaperEngine/Render/CContext.h index 8a568a7..440cd9d 100644 --- a/src/WallpaperEngine/Render/CContext.h +++ b/src/WallpaperEngine/Render/CContext.h @@ -5,6 +5,7 @@ #include "WallpaperEngine/Input/CMouseInput.h" #include "CWallpaper.h" +#include 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 m_screens; - std::vector m_viewports; + std::vector m_viewports; glm::vec4 m_defaultViewport; CWallpaper* m_wallpaper; CMouseInput* m_mouse; diff --git a/src/WallpaperEngine/Render/CScene.cpp b/src/WallpaperEngine/Render/CScene.cpp index fee694f..6089f27 100644 --- a/src/WallpaperEngine/Render/CScene.cpp +++ b/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 (); diff --git a/src/WallpaperEngine/Render/CScene.h b/src/WallpaperEngine/Render/CScene.h index 4ea2a62..1011aab 100644 --- a/src/WallpaperEngine/Render/CScene.h +++ b/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; diff --git a/src/WallpaperEngine/Render/CVideo.cpp b/src/WallpaperEngine/Render/CVideo.cpp index eb23140..3c8ec79 100644 --- a/src/WallpaperEngine/Render/CVideo.cpp +++ b/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); diff --git a/src/WallpaperEngine/Render/CVideo.h b/src/WallpaperEngine/Render/CVideo.h index 329d206..5b0f453 100644 --- a/src/WallpaperEngine/Render/CVideo.h +++ b/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; diff --git a/src/WallpaperEngine/Render/CWallpaper.cpp b/src/WallpaperEngine/Render/CWallpaper.cpp index b87bd9b..309795a 100644 --- a/src/WallpaperEngine/Render/CWallpaper.cpp +++ b/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); + glBindFramebuffer (GL_FRAMEBUFFER, this->m_destFramebuffer); + + if (newFrame) + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - 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 () diff --git a/src/WallpaperEngine/Render/CWallpaper.h b/src/WallpaperEngine/Render/CWallpaper.h index c4d1b39..6604f3d 100644 --- a/src/WallpaperEngine/Render/CWallpaper.h +++ b/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 */