소스 검색

+ added ansiotropic filtering
~ material's binds are now a map by index so it's easier to use
- removed depth buffer for FBOs as they're not really useful (at least for now)
~ separated image setup in two stages so FBO creation happens before actually requiring them
- removed ping-pong FBOs where they didn't make sense
~ image's should now render to scene buffer directly whenever possible
~ better support for FBO scaling
~ rendering should now take into account targets and binds in a much better way

Signed-off-by: Alexis Maiquez <almamu@almamu.com>

Alexis Maiquez 5 년 전
부모
커밋
f5e943b0fc

+ 4 - 2
src/WallpaperEngine/Assets/CTexture.cpp

@@ -85,14 +85,16 @@ CTexture::CTexture (void* fileData)
     if (this->m_header->flags & TextureFlags::NoInterpolation)
     {
         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
     }
     else
     {
         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
     }
 
+    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 8.0f);
+
     // TODO: USE THIS ONE
     // uint32_t blockSize = (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
 

+ 1 - 1
src/WallpaperEngine/Core/CObject.cpp

@@ -133,7 +133,7 @@ CObject* CObject::fromJSON (json data, CContainer* container)
         for (; cur != end; cur ++)
         {
             object->insertEffect (
-                    Objects::CEffect::fromJSON (*cur, object, container)
+                Objects::CEffect::fromJSON (*cur, object, container)
             );
         }
     }

+ 2 - 2
src/WallpaperEngine/Core/Objects/Images/CMaterial.cpp

@@ -62,7 +62,7 @@ void CMaterial::insertPass (Materials::CPass* mass)
 
 void CMaterial::insertTextureBind (Effects::CBind* bind)
 {
-    this->m_textureBindings.push_back (bind);
+    this->m_textureBindings.insert (std::make_pair (bind->getIndex (), bind));
 }
 
 void CMaterial::setTarget (const std::string& target)
@@ -74,7 +74,7 @@ const std::vector <Materials::CPass*>& CMaterial::getPasses () const
 {
     return this->m_passes;
 }
-const std::vector <Effects::CBind*>& CMaterial::getTextureBinds () const
+const std::map <int, Effects::CBind*>& CMaterial::getTextureBinds () const
 {
     return this->m_textureBindings;
 }

+ 2 - 2
src/WallpaperEngine/Core/Objects/Images/CMaterial.h

@@ -23,7 +23,7 @@ namespace WallpaperEngine::Core::Objects::Images
         void insertTextureBind (Effects::CBind* bind);
 
         const std::vector <Materials::CPass*>& getPasses () const;
-        const std::vector <Effects::CBind*>& getTextureBinds () const;
+        const std::map <int, Effects::CBind*>& getTextureBinds () const;
         const std::string& getTarget () const;
         const bool hasTarget () const;
     protected:
@@ -32,7 +32,7 @@ namespace WallpaperEngine::Core::Objects::Images
         void setTarget (const std::string& target);
     private:
         std::vector <Materials::CPass*> m_passes;
-        std::vector <Effects::CBind*> m_textureBindings;
+        std::map <int, Effects::CBind*> m_textureBindings;
         std::string m_target;
     };
 };

+ 6 - 10
src/WallpaperEngine/Render/CFBO.cpp

@@ -19,16 +19,12 @@ CFBO::CFBO (std::string name, ITexture::TextureFormat format, float scale, uint3
     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
 
     // set filtering parameters, otherwise the texture is not rendered
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-    // create the depth render buffer for the main framebuffer
-    glGenRenderbuffers (1, &this->m_depthbuffer);
-    glBindRenderbuffer (GL_RENDERBUFFER, this->m_depthbuffer);
-    glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, textureWidth, textureHeight);
-    glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->m_depthbuffer);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 8.0f);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
     // set the texture as the colour attachmend #0
     glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->m_texture, 0);
     // finally set the list of draw buffers

+ 3 - 3
src/WallpaperEngine/Render/CObject.h

@@ -13,10 +13,10 @@ namespace WallpaperEngine::Render
     class CObject
     {
     public:
-        template<class T> const T* As () const { assert (Is<T> ()); return (const T*) this; }
-        template<class T> T* As () { assert (Is<T> ()); return (T*) this; }
+        template<class T> const T* as () const { assert (is<T>()); return (const T*) this; }
+        template<class T> T* as () { assert (is<T>()); return (T*) this; }
 
-        template<class T> bool Is () { return this->m_type == T::Type; }
+        template<class T> bool is () { return this->m_type == T::Type; }
 
         virtual void render () = 0;
 

+ 10 - 1
src/WallpaperEngine/Render/CScene.cpp

@@ -40,6 +40,15 @@ CScene::CScene (Core::CScene* scene, CContainer* container) :
         if (object != nullptr)
             this->m_objects.emplace_back (object);
     }
+
+    auto objectsCur = this->m_objects.begin ();
+    auto objectsEnd = this->m_objects.end ();
+
+    for (; objectsCur != objectsEnd; objectsCur ++)
+    {
+        if ((*objectsCur)->is <Objects::CImage> () == true)
+            (*objectsCur)->as <Objects::CImage> ()->setup ();
+    }
 }
 
 CCamera* CScene::getCamera () const
@@ -56,7 +65,7 @@ void CScene::renderFrame ()
     // clear screen
     FloatColor clearColor = this->getScene ()->getClearColor ();
 
-    glClearColor (clearColor.r, clearColor.g, clearColor.b, clearColor.a);
+    glClearColor (clearColor.r, clearColor.g, clearColor.b, 0.0f);
 
     // use the scene's framebuffer by default
     glBindFramebuffer (GL_FRAMEBUFFER, this->getWallpaperFramebuffer());

+ 6 - 19
src/WallpaperEngine/Render/CWallpaper.cpp

@@ -285,22 +285,6 @@ void CWallpaper::render (glm::vec4 viewport, bool newFrame)
     glDrawArrays (GL_TRIANGLES, 0, 6);
 }
 
-void CWallpaper::pinpongFramebuffer (GLuint* drawTo, GLuint* inputTexture)
-{
-    // temporarily store FBOs used
-    CFBO* currentMainFBO = this->m_mainFBO;
-    CFBO* currentSubFBO = this->m_subFBO;
-
-    if (drawTo != nullptr)
-        *drawTo = currentSubFBO->getFramebuffer ();
-    if (inputTexture != nullptr)
-        *inputTexture = currentMainFBO->getTextureID();
-
-    // swap the FBOs
-    this->m_mainFBO = currentSubFBO;
-    this->m_subFBO = currentMainFBO;
-}
-
 void CWallpaper::setupFramebuffers ()
 {
     int windowWidth = 1920;
@@ -321,8 +305,6 @@ void CWallpaper::setupFramebuffers ()
         windowHeight = video->getHeight ();
     }
 
-    this->m_mainFBO = this->createFBO ("_rt_FullFrameBuffera", ITexture::TextureFormat::ARGB8888, 1.0, windowWidth, windowHeight, windowWidth, windowHeight);
-    this->m_subFBO = this->createFBO ("_rt_FullFrameBuffera", ITexture::TextureFormat::ARGB8888, 1.0, windowWidth, windowHeight, windowWidth, windowHeight);
     // create framebuffer for the scene
     this->m_sceneFBO = this->createFBO ("_rt_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, 1.0, windowWidth, windowHeight, windowWidth, windowHeight);
 }
@@ -342,7 +324,7 @@ const std::map<std::string, CFBO*>& CWallpaper::getFBOs () const
 }
 
 
-const CFBO* CWallpaper::findFBO (const std::string& name) const
+CFBO* CWallpaper::findFBO (const std::string& name) const
 {
     auto it = this->m_fbos.find (name);
 
@@ -350,4 +332,9 @@ const CFBO* CWallpaper::findFBO (const std::string& name) const
         throw std::runtime_error ("Cannot find given FBO");
 
     return it->second;
+}
+
+CFBO* CWallpaper::getFBO () const
+{
+    return this->m_sceneFBO;
 }

+ 6 - 18
src/WallpaperEngine/Render/CWallpaper.h

@@ -35,14 +35,6 @@ namespace WallpaperEngine::Render
          */
         CContainer* getContainer () const;
 
-        /**
-         * Performs a ping-pong on the available framebuffers to be able to continue rendering things to them
-         *
-         * @param drawTo The framebuffer to use
-         * @param asInput The last texture used as output (if needed)
-         */
-        void pinpongFramebuffer (GLuint* drawTo, GLuint* inputTexture);
-
         /**
          * @return The scene's framebuffer
          */
@@ -69,7 +61,12 @@ namespace WallpaperEngine::Render
          * @param name
          * @return
          */
-        const CFBO* findFBO (const std::string& name) const;
+        CFBO* findFBO (const std::string& name) const;
+
+        /**
+         * @return The main FBO of this wallpaper
+         */
+        CFBO* getFBO () const;
 
     protected:
         /**
@@ -87,15 +84,6 @@ namespace WallpaperEngine::Render
 
         Core::CWallpaper* getWallpaperData ();
 
-        /**
-         * The main FBO used for ping pong
-         */
-        CFBO* m_mainFBO;
-        /**
-         * The sub FBO used for ping pong
-         */
-        CFBO* m_subFBO;
-
         /**
          * The FBO used for scene output
          */

+ 5 - 5
src/WallpaperEngine/Render/Objects/CEffect.cpp

@@ -21,7 +21,7 @@ const std::vector<Effects::CMaterial*>& CEffect::getMaterials () const
     return this->m_materials;
 }
 
-const CFBO* CEffect::findFBO (const std::string& name) const
+CFBO* CEffect::findFBO (const std::string& name) const
 {
     auto cur = this->m_fbos.begin ();
     auto end = this->m_fbos.end ();
@@ -58,10 +58,10 @@ void CEffect::generateFBOs ()
                 (*cur)->getName (),
                 ITexture::TextureFormat::ARGB8888, // TODO: CHANGE
                 (*cur)->getScale (),
-                this->m_image->getImage ()->getSize ().x,
-                this->m_image->getImage ()->getSize ().y,
-                this->m_image->getImage ()->getSize ().x,
-                this->m_image->getImage ()->getSize ().y
+                this->m_image->getImage ()->getSize ().x / (*cur)->getScale (),
+                this->m_image->getImage ()->getSize ().y / (*cur)->getScale (),
+                this->m_image->getImage ()->getSize ().x / (*cur)->getScale (),
+                this->m_image->getImage ()->getSize ().y / (*cur)->getScale ()
             )
         );
     }

+ 1 - 1
src/WallpaperEngine/Render/Objects/CEffect.h

@@ -23,7 +23,7 @@ namespace WallpaperEngine::Render::Objects
 
         const std::vector<Effects::CMaterial*>& getMaterials () const;
 
-        const CFBO* findFBO (const std::string& name) const;
+        CFBO* findFBO (const std::string& name) const;
 
     private:
         void generatePasses ();

+ 81 - 34
src/WallpaperEngine/Render/Objects/CImage.cpp

@@ -54,10 +54,10 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
     std::ostringstream nameA, nameB;
 
     nameA << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_a";
-    nameA << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_b";
+    nameB << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_b";
 
-    this->m_mainFBO = scene->createFBO (nameA.str (), ITexture::TextureFormat::ARGB8888, 1, this->m_texture->getRealWidth (), this->m_texture->getRealHeight (), this->m_texture->getTextureWidth (), this->m_texture->getTextureHeight ());
-    this->m_subFBO = scene->createFBO (nameB.str (), ITexture::TextureFormat::ARGB8888, 1, this->m_texture->getRealWidth (), this->m_texture->getRealHeight (), this->m_texture->getTextureWidth (), this->m_texture->getTextureHeight ());
+    this->m_currentMainFBO = this->m_mainFBO = scene->createFBO (nameA.str (), ITexture::TextureFormat::ARGB8888, 1, this->m_texture->getRealWidth (), this->m_texture->getRealHeight (), this->m_texture->getTextureWidth (), this->m_texture->getTextureHeight ());
+    this->m_currentSubFBO = this->m_subFBO = scene->createFBO (nameB.str (), ITexture::TextureFormat::ARGB8888, 1, this->m_texture->getRealWidth (), this->m_texture->getRealHeight (), this->m_texture->getTextureWidth (), this->m_texture->getTextureHeight ());
 
     // build a list of vertices, these might need some change later (or maybe invert the camera)
     GLfloat data [] = {
@@ -142,7 +142,10 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
     glGenBuffers (1, &this->m_passTexCoordBuffer);
     glBindBuffer (GL_ARRAY_BUFFER, this->m_passTexCoordBuffer);
     glBufferData (GL_ARRAY_BUFFER, sizeof (this->m_passTexCoordList), this->m_passTexCoordList, GL_STATIC_DRAW);
+}
 
+void CImage::setup ()
+{
     // generate the main material used to render the image
     this->m_material = new Effects::CMaterial (
         new CEffect (this, new Core::Objects::CEffect ("", "", "", "", this->m_image)),
@@ -157,53 +160,79 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
         this->m_effects.emplace_back (new CEffect (this, *cur));
 }
 
-void CImage::pinpongFramebuffer (GLuint* drawTo, GLuint* inputTexture)
+void CImage::pinpongFramebuffer (CFBO** drawTo, ITexture** asInput)
 {
     // temporarily store FBOs used
-    CFBO* currentMainFBO = this->m_mainFBO;
-    CFBO* currentSubFBO = this->m_subFBO;
+    CFBO* currentMainFBO = this->m_currentMainFBO;
+    CFBO* currentSubFBO = this->m_currentSubFBO;
 
     if (drawTo != nullptr)
-        *drawTo = currentSubFBO->getFramebuffer ();
-    if (inputTexture != nullptr)
-        *inputTexture = currentMainFBO->getTextureID ();
+        *drawTo = currentSubFBO;
+    if (asInput != nullptr)
+        *asInput = currentMainFBO;
 
     // swap the FBOs
-    this->m_mainFBO = currentSubFBO;
-    this->m_subFBO = currentMainFBO;
+    this->m_currentMainFBO = currentSubFBO;
+    this->m_currentSubFBO = currentMainFBO;
 }
 
-void CImage::render ()
+void CImage::simpleRender ()
 {
-    // start drawing to the main framebuffer
-    GLuint drawTo = this->m_mainFBO->getFramebuffer ();
-    GLuint inputTexture = this->getTexture ()->getTextureID ();
+    // a simple material renders directly to the screen
+    auto cur = this->m_material->getPasses ().begin ();
+    auto end = this->m_material->getPasses ().end ();
 
-    // render all the other materials
-    auto cur = this->getEffects ().begin ();
-    auto end = this->getEffects ().end ();
+    for (; cur != end; cur ++)
+        (*cur)->render (this->getScene ()->getFBO (), this->getTexture ());
+}
 
-    inputTexture = this->getTexture ()->getTextureID ();
+void CImage::complexRender ()
+{
+    // start drawing to the main framebuffer
+    CFBO* drawTo = this->m_mainFBO;
+    ITexture* asInput = this->getTexture ();
 
-    // set the correct viewport
-    glViewport (0, 0, this->getTexture ()->getRealWidth (), this->getTexture ()->getRealHeight ());
+    // do the first pass render into the main framebuffer
+    auto cur = this->m_material->getPasses ().begin ();
+    auto end = this->m_material->getPasses ().end ();
 
-    // render all the passes first
     for (; cur != end; cur ++)
+        (*cur)->render (drawTo, asInput);
+
+    // render all the other materials
+    auto effectCur = this->getEffects ().begin ();
+    auto effectEnd = this->getEffects ().end ();
+
+    for (; effectCur != effectEnd; effectCur ++)
     {
-        auto materialCur = (*cur)->getMaterials ().begin ();
-        auto materialEnd = (*cur)->getMaterials ().end ();
+        auto materialCur = (*effectCur)->getMaterials ().begin ();
+        auto materialEnd = (*effectCur)->getMaterials ().end ();
 
         for (; materialCur != materialEnd; materialCur ++)
         {
+            // set viewport and target texture if needed
+            if ((*materialCur)->getMaterial ()->hasTarget () == true)
+            {
+                // setup target texture
+                std::string target = (*materialCur)->getMaterial ()->getTarget ();
+                drawTo = (*effectCur)->findFBO (target);
+
+                // not a local FBO, so try that one now
+                if (drawTo == nullptr)
+                    // this one throws if no fbo was found
+                    drawTo = this->getScene ()->findFBO (target);
+            }
+
             auto passCur = (*materialCur)->getPasses ().begin ();
             auto passEnd = (*materialCur)->getPasses ().end ();
 
             for (; passCur != passEnd; passCur ++)
             {
-                (*passCur)->render (drawTo, inputTexture);
+                // ping-pong only if there's a target
+                if ((*materialCur)->getMaterial ()->hasTarget () == false)
+                    this->pinpongFramebuffer (&drawTo, &asInput);
 
-                this->pinpongFramebuffer (&drawTo, &inputTexture);
+                (*passCur)->render (drawTo, asInput);
             }
         }
     }
@@ -211,18 +240,36 @@ void CImage::render ()
     if (this->getImage ()->isVisible () == false)
         return;
 
-    // this material only has one pass that we know of
-    // so just take that and render it to the screen's framebuffer
-    auto pass = this->m_material->getPasses ().begin ();
-    auto projection = this->getScene ()->getScene ()->getOrthogonalProjection ();
+    // pinpong the framebuffer so we know exactly what we're drawing to the scene
+    this->pinpongFramebuffer (&drawTo, &asInput);
+
+    // final step, this one might need more changes, should passes render directly to the output instead of an intermediate framebuffer?
+    // do the first pass render into the main framebuffer
+    cur = this->m_material->getPasses ().begin ();
+    end = this->m_material->getPasses ().end ();
+
+    glColorMask (true, true, true, false);
+
+    for (; cur != end; cur ++)
+        (*cur)->render (this->getScene ()->getFBO (), asInput);
+}
+
+void CImage::render ()
+{
+    // first and foremost reset the framebuffer switching
+    this->m_currentMainFBO = this->m_mainFBO;
+    this->m_currentSubFBO = this->m_subFBO;
 
-    // set the viewport properly
-    glViewport (0, 0, projection->getWidth (), projection->getHeight ());
+    glColorMask (true, true, true, true);
 
-    (*pass)->render (this->getScene ()->getWallpaperFramebuffer (), inputTexture);
+    // check if there's more than one pass and do different things based on that
+    if (this->m_effects.empty () == true)
+        this->simpleRender ();
+    else
+        this->complexRender ();
 }
 
-const ITexture* CImage::getTexture () const
+ITexture* CImage::getTexture () const
 {
     return this->m_texture;
 }

+ 9 - 3
src/WallpaperEngine/Render/Objects/CImage.h

@@ -27,9 +27,11 @@ namespace WallpaperEngine::Render::Objects
 
     class CImage : public CObject
     {
+        friend CObject;
     public:
         CImage (CScene* scene, Core::Objects::CImage* image);
 
+        void setup ();
         void render () override;
 
         const Core::Objects::CImage* getImage () const;
@@ -40,7 +42,7 @@ namespace WallpaperEngine::Render::Objects
         const GLuint* getPassVertexBuffer () const;
         const GLuint* getTexCoordBuffer () const;
         const GLuint* getPassTexCoordBuffer () const;
-        const ITexture* getTexture () const;
+        ITexture* getTexture () const;
 
         /**
          * Performs a ping-pong on the available framebuffers to be able to continue rendering things to them
@@ -48,13 +50,15 @@ namespace WallpaperEngine::Render::Objects
          * @param drawTo The framebuffer to use
          * @param asInput The last texture used as output (if needed)
          */
-        void pinpongFramebuffer (GLuint* drawTo, GLuint* inputTexture);
+        void pinpongFramebuffer (CFBO** drawTo, ITexture** asInput);
 
     protected:
         static const std::string Type;
 
+        void simpleRender ();
+        void complexRender ();
     private:
-        const ITexture* m_texture;
+        ITexture* m_texture;
         GLfloat m_vertexList [6 * 3];
         GLfloat m_passesVertexList [6 * 3];
         GLfloat m_texCoordList [6 * 2];
@@ -67,6 +71,8 @@ namespace WallpaperEngine::Render::Objects
 
         CFBO* m_mainFBO;
         CFBO* m_subFBO;
+        CFBO* m_currentMainFBO;
+        CFBO* m_currentSubFBO;
 
         Core::Objects::CImage* m_image;
 

+ 5 - 0
src/WallpaperEngine/Render/Objects/Effects/CMaterial.cpp

@@ -29,4 +29,9 @@ void CMaterial::generatePasses ()
     // these are simple now, just create the entries and done
     for (; cur != end; cur ++)
         this->m_passes.emplace_back (new CPass (this, *cur));
+}
+
+const Core::Objects::Images::CMaterial* CMaterial::getMaterial () const
+{
+    return this->m_material;
 }

+ 1 - 0
src/WallpaperEngine/Render/Objects/Effects/CMaterial.h

@@ -28,6 +28,7 @@ namespace WallpaperEngine::Render::Objects::Effects
 
         const std::vector<CPass*>& getPasses () const;
         CImage* getImage () const;
+        const Core::Objects::Images::CMaterial* getMaterial () const;
 
     private:
         void generatePasses ();

+ 79 - 60
src/WallpaperEngine/Render/Objects/Effects/CPass.cpp

@@ -30,14 +30,47 @@ CPass::CPass (CMaterial* material, Core::Objects::Images::Materials::CPass* pass
     this->setupShaderVariables ();
 }
 
-void CPass::render (GLuint drawTo, GLuint input)
+
+ITexture* CPass::resolveTexture (ITexture* expected, int index, ITexture* previous)
+{
+    if (expected == nullptr)
+    {
+        auto it = this->m_fbos.find (index);
+
+        if (it == this->m_fbos.end ())
+            return nullptr;
+
+        return (*it).second;
+    }
+
+    // first check in the binds and replace it if necessary
+    auto it = this->m_material->getMaterial ()->getTextureBinds ().find (index);
+
+    if (it == this->m_material->getMaterial ()->getTextureBinds ().end ())
+        return expected;
+
+    // a bind named "previous" is just another way of telling it to use whatever texture there was already
+    if ((*it).second->getName () == "previous")
+        if (previous == nullptr)
+            return expected;
+        else
+            return previous;
+    // the bind actually has a name, search the FBO in the effect and return it
+    auto fbo = this->m_material->m_effect->findFBO ((*it).second->getName ());
+
+    if (fbo == nullptr)
+        return nullptr;
+
+    return fbo;
+}
+
+void CPass::render (CFBO* drawTo, ITexture* input)
 {
     // set the framebuffer we're drawing to
-    glBindFramebuffer (GL_FRAMEBUFFER, drawTo);
+    glBindFramebuffer (GL_FRAMEBUFFER, drawTo->getFramebuffer ());
 
-    // clear whatever buffer we're drawing to if we're not drawing to screen
-    if (drawTo != this->m_material->getImage()->getScene()->getWallpaperFramebuffer())
-        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    // set proper viewport based on what we're drawing to
+    glViewport (0, 0, drawTo->getRealWidth (), drawTo->getRealHeight ());
 
     // set texture blending
     if (this->m_pass->getBlendingMode () == "translucent")
@@ -70,7 +103,23 @@ void CPass::render (GLuint drawTo, GLuint input)
         glEnable (GL_DEPTH_TEST);
     }
 
-    // TODO: SUPPORT TARGET TO DRAW TEXTURE TO
+    if (this->m_pass->getCullingMode () == "nocull")
+    {
+        glDisable (GL_CULL_FACE);
+    }
+    else
+    {
+        glEnable (GL_CULL_FACE);
+    }
+
+    if (this->m_pass->getDepthWrite () == "disabled")
+    {
+        glDepthMask (false);
+    }
+    else
+    {
+        glDepthMask (true);
+    }
 
     // update variables used in the render process (like g_ModelViewProjectionMatrix)
     this->m_modelViewProjectionMatrix =
@@ -87,16 +136,10 @@ void CPass::render (GLuint drawTo, GLuint input)
     // use the shader we have registered
     glUseProgram (this->m_programID);
 
-    // bind the input texture (take into account input fbos)
-    auto it = this->m_fbos.find (0);
-
-    if (it != this->m_fbos.end ())
-    {
-        input = (*it).second->getTextureID();
-    }
+    ITexture* texture = this->resolveTexture (input, 0, input);
 
     glActiveTexture (GL_TEXTURE0);
-    glBindTexture (GL_TEXTURE_2D, input);
+    glBindTexture (GL_TEXTURE_2D, texture->getTextureID ());
     int lastTextureIndex = 0;
 
     // first bind the textures to their sampler place
@@ -107,25 +150,10 @@ void CPass::render (GLuint drawTo, GLuint input)
 
         for (int index = 1; cur != end; cur ++, index ++)
         {
-            if ((*cur) == nullptr)
-            {
-                auto it = this->m_fbos.find (index);
-
-                if (it == this->m_fbos.end ())
-                    continue;
+            texture = this->resolveTexture ((*cur), index, input);
 
-                // set the active texture index
-                glActiveTexture (GL_TEXTURE0 + index);
-                // bind the correct texture there
-                glBindTexture (GL_TEXTURE_2D, (*it).second->getTextureID());
-            }
-            else
-            {
-                // set the active texture index
-                glActiveTexture (GL_TEXTURE0 + index);
-                // bind the correct texture there
-                glBindTexture (GL_TEXTURE_2D, (*cur)->getTextureID ());
-            }
+            glActiveTexture (GL_TEXTURE0 + index);
+            glBindTexture (GL_TEXTURE_2D, texture->getTextureID ());
             // increase the number of textures counter
             lastTextureIndex ++;
         }
@@ -141,10 +169,11 @@ void CPass::render (GLuint drawTo, GLuint input)
             if ((*cur).first <= lastTextureIndex)
                 continue;
 
+            texture = this->resolveTexture ((*cur).second, (*cur).first);
             // set the active texture index
             glActiveTexture (GL_TEXTURE0 + (*cur).first);
             // bind the correct texture here
-            glBindTexture(GL_TEXTURE_2D, (*cur).second->getTextureID ());
+            glBindTexture(GL_TEXTURE_2D, texture->getTextureID ());
         }
     }
 
@@ -158,10 +187,11 @@ void CPass::render (GLuint drawTo, GLuint input)
             if ((*cur).first <= lastTextureIndex)
                 continue;
 
+            texture = this->resolveTexture ((*cur).second, (*cur).first);
             // set the active texture index
             glActiveTexture (GL_TEXTURE0 + (*cur).first);
             // bind the correct texture here
-            glBindTexture(GL_TEXTURE_2D, (*cur).second->getTextureID ());
+            glBindTexture(GL_TEXTURE_2D, texture->getTextureID ());
         }
     }
 
@@ -222,7 +252,7 @@ void CPass::render (GLuint drawTo, GLuint input)
     }
 
     // start actual rendering now
-    glBindBuffer (GL_ARRAY_BUFFER, (drawTo != this->m_material->getImage()->getScene()->getWallpaperFramebuffer()) ? *this->m_material->getImage ()->getPassVertexBuffer () : *this->m_material->getImage ()->getVertexBuffer ());
+    glBindBuffer (GL_ARRAY_BUFFER, (drawTo != this->m_material->getImage()->getScene()->getFBO ()) ? *this->m_material->getImage ()->getPassVertexBuffer () : *this->m_material->getImage ()->getVertexBuffer ());
     glDrawArrays (GL_TRIANGLES, 0, 6);
 
     // disable vertex attribs array
@@ -365,6 +395,8 @@ void CPass::setupAttributes ()
 
 void CPass::setupUniforms ()
 {
+    // resolve the main texture
+    ITexture* texture = this->resolveTexture (this->m_material->getImage ()->getTexture (), 0);
     // register all the texture uniforms with correct values
     this->addUniform ("g_Texture0", 0);
     this->addUniform ("g_Texture1", 1);
@@ -374,13 +406,7 @@ void CPass::setupUniforms ()
     this->addUniform ("g_Texture5", 5);
     this->addUniform ("g_Texture6", 6);
     this->addUniform ("g_Texture7", 7);
-    // check if the input is an fbo
-    auto it = this->m_fbos.find (0);
-
-    if (it == this->m_fbos.end ())
-        this->addUniform ("g_Texture0Resolution", this->m_material->getImage ()->getTexture ()->getResolution ());
-    else
-        this->addUniform ("g_Texture0Resolution", (*it).second->getResolution ());
+    this->addUniform ("g_Texture0Resolution", texture->getResolution ());
 
     int lastTextureIndex = 0;
     // register the extra texture resolutions
@@ -394,20 +420,8 @@ void CPass::setupUniforms ()
 
             namestream << "g_Texture" << index << "Resolution";
 
-            if ((*cur) == nullptr)
-            {
-                // fbo used
-                auto it = this->m_fbos.find (index);
-
-                if (it == this->m_fbos.end ())
-                    continue;
-
-                this->addUniform (namestream.str (), (*it).second->getResolution ());
-            }
-            else
-            {
-                this->addUniform (namestream.str (), (*cur)->getResolution ());
-            }
+            texture = this->resolveTexture ((*cur), index);
+            this->addUniform (namestream.str (), texture->getResolution ());
             lastTextureIndex ++;
         }
     }
@@ -426,7 +440,8 @@ void CPass::setupUniforms ()
 
             namestream << "g_Texture" << (*cur).first << "Resolution";
 
-            this->addUniform (namestream.str (), (*cur).second->getResolution ());
+            texture = this->resolveTexture ((*cur).second, (*cur).first);
+            this->addUniform (namestream.str (), texture->getResolution ());
         }
     }
 
@@ -444,7 +459,8 @@ void CPass::setupUniforms ()
 
             namestream << "g_Texture" << (*cur).first << "Resolution";
 
-            this->addUniform (namestream.str (), (*cur).second->getResolution ());
+            texture = this->resolveTexture ((*cur).second, (*cur).first);
+            this->addUniform (namestream.str (), texture->getResolution ());
         }
     }
 
@@ -516,11 +532,14 @@ void CPass::setupTextures ()
 
         if ((*cur).find ("_rt_") == 0)
         {
-            const CFBO* fbo = this->m_material->m_effect->findFBO ((*cur));
+            CFBO* fbo = this->m_material->m_effect->findFBO ((*cur));
+
+            if (fbo == nullptr)
+                fbo = this->m_material->getImage ()->getScene ()->findFBO ((*cur));
 
             if (fbo != nullptr)
             {
-                this->m_fbos.insert (std::make_pair (index, const_cast <CFBO*> (fbo)));
+                this->m_fbos.insert (std::make_pair (index, fbo));
                 this->m_textures.emplace_back (
                     nullptr
                 );

+ 3 - 1
src/WallpaperEngine/Render/Objects/Effects/CPass.h

@@ -21,7 +21,7 @@ namespace WallpaperEngine::Render::Objects::Effects
     public:
         CPass (CMaterial* material, Core::Objects::Images::Materials::CPass* pass);
 
-        void render (GLuint drawTo, GLuint input);
+        void render (CFBO* drawTo, ITexture* input);
 
     private:
         enum UniformType
@@ -84,6 +84,8 @@ namespace WallpaperEngine::Render::Objects::Effects
         template <typename T> void addUniform (const std::string& name, UniformType type, T value);
         template <typename T> void addUniform (const std::string& name, UniformType type, T* value);
 
+        ITexture* resolveTexture (ITexture* expected, int index, ITexture* previous = nullptr);
+
         CMaterial* m_material;
         Core::Objects::Images::Materials::CPass* m_pass;
         std::vector<ITexture*> m_textures;