// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #pragma once // GL type definitions needed by class declarations. // If GLAD was already included, these types are already defined. #ifndef GLAD_GL_H_ typedef unsigned int GLuint; typedef int GLint; typedef unsigned int GLenum; typedef int GLsizei; #endif #include namespace dragonx { namespace ui { namespace effects { /** * @brief OpenGL Framebuffer Object manager for off-screen rendering * * Used for capturing screen content to use as blur source for acrylic effects. */ class Framebuffer { public: Framebuffer(); ~Framebuffer(); // Non-copyable Framebuffer(const Framebuffer&) = delete; Framebuffer& operator=(const Framebuffer&) = delete; // Move constructors Framebuffer(Framebuffer&& other) noexcept; Framebuffer& operator=(Framebuffer&& other) noexcept; /** * @brief Initialize framebuffer with given dimensions * @param width Width in pixels * @param height Height in pixels * @param useFloat16 Use RGBA16F format for higher precision (reduces banding) * @return true if successful */ bool init(int width, int height, bool useFloat16 = false); /** * @brief Resize framebuffer (recreates internal textures) * @param width New width * @param height New height * @return true if successful */ bool resize(int width, int height); /** * @brief Release all OpenGL resources */ void destroy(); /** * @brief Bind this framebuffer for rendering */ void bind(); /** * @brief Unbind (return to default framebuffer) */ void unbind(); /** * @brief Clear the framebuffer * @param r Red component (0-1) * @param g Green component (0-1) * @param b Blue component (0-1) * @param a Alpha component (0-1) */ void clear(float r = 0.0f, float g = 0.0f, float b = 0.0f, float a = 1.0f); /** * @brief Get the color texture attached to this framebuffer * @return OpenGL texture ID */ GLuint getColorTexture() const { return colorTexture_; } /** * @brief Get the underlying framebuffer object ID * @return OpenGL FBO ID */ GLuint getFbo() const { return fbo_; } /** * @brief Get framebuffer dimensions */ int getWidth() const { return width_; } int getHeight() const { return height_; } /** * @brief Check if framebuffer is valid and complete */ bool isValid() const { return fbo_ != 0 && isComplete_; } /** * @brief Copy a region from the current framebuffer to this one * @param srcX Source X position * @param srcY Source Y position * @param srcWidth Source width * @param srcHeight Source height * @param dstX Destination X position * @param dstY Destination Y position */ void blitFrom(GLuint srcFbo, int srcX, int srcY, int srcWidth, int srcHeight, int dstX = 0, int dstY = 0); /** * @brief Copy entire default framebuffer to this one * @param viewportWidth Current viewport width * @param viewportHeight Current viewport height */ void captureScreen(int viewportWidth, int viewportHeight); private: void cleanup(); bool checkComplete(); GLuint fbo_ = 0; GLuint colorTexture_ = 0; GLuint depthRbo_ = 0; // Renderbuffer for depth (optional) int width_ = 0; int height_ = 0; bool useFloat16_ = false; // RGBA16F for blur precision bool isComplete_ = false; }; /** * @brief Manages multiple framebuffers for ping-pong blur operations */ class FramebufferPingPong { public: FramebufferPingPong() = default; ~FramebufferPingPong() = default; /** * @brief Initialize both framebuffers */ bool init(int width, int height, bool useFloat16 = false); /** * @brief Resize both framebuffers */ bool resize(int width, int height); /** * @brief Destroy both framebuffers */ void destroy(); /** * @brief Swap which buffer is source/destination */ void swap(); /** * @brief Get current source framebuffer */ Framebuffer& getSource() { return buffers_[currentSource_]; } /** * @brief Get current destination framebuffer */ Framebuffer& getDest() { return buffers_[1 - currentSource_]; } /** * @brief Get source texture for reading */ GLuint getSourceTexture() const { return buffers_[currentSource_].getColorTexture(); } /** * @brief Get destination texture */ GLuint getDestTexture() const { return buffers_[1 - currentSource_].getColorTexture(); } bool isValid() const { return buffers_[0].isValid() && buffers_[1].isValid(); } private: Framebuffer buffers_[2]; int currentSource_ = 0; }; } // namespace effects } // namespace ui } // namespace dragonx