Ver Fonte

Added support for camera bloom
Added support for virtual files

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

Alexis Maiquez há 3 anos atrás
pai
commit
cdaebbe893

+ 2 - 0
CMakeLists.txt

@@ -42,6 +42,8 @@ add_executable(
         src/WallpaperEngine/Assets/CAssetLoadException.h
         src/WallpaperEngine/Assets/CContainer.h
         src/WallpaperEngine/Assets/CContainer.cpp
+        src/WallpaperEngine/Assets/CVirtualContainer.h
+        src/WallpaperEngine/Assets/CVirtualContainer.cpp
         src/WallpaperEngine/Assets/CCombinedContainer.h
         src/WallpaperEngine/Assets/CCombinedContainer.cpp
         src/WallpaperEngine/Assets/CDirectory.h

+ 113 - 0
main.cpp

@@ -18,6 +18,7 @@
 
 #include "WallpaperEngine/Assets/CPackage.h"
 #include "WallpaperEngine/Assets/CDirectory.h"
+#include "WallpaperEngine/Assets/CVirtualContainer.h"
 #include "WallpaperEngine/Assets/CCombinedContainer.h"
 #include "WallpaperEngine/Assets/CPackageLoadException.h"
 
@@ -160,6 +161,116 @@ void addPkg (CCombinedContainer* containers, const std::string& path, std::strin
     }
 }
 
+CVirtualContainer* buildVirtualContainer ()
+{
+    CVirtualContainer* container = new WallpaperEngine::Assets::CVirtualContainer ();
+
+    //
+    // Had to get a little creative with the effects to achieve the same bloom effect without any custom code
+    // these virtual files are loaded by an image in the scene that takes current _rt_FullFrameBuffer and
+    // applies the bloom effect to render it out to the screen
+    //
+
+    // add the effect file for screen bloom
+    container->add (
+        "effects/wpenginelinux/bloomeffect.json",
+        "{"
+        "\t\"name\":\"camerabloom_wpengine_linux\","
+        "\t\"group\":\"wpengine_linux_camera\","
+        "\t\"dependencies\":[],"
+        "\t\"passes\":"
+        "\t["
+        "\t\t{"
+        "\t\t\t\"material\": \"materials/util/downsample_quarter_bloom.json\","
+        "\t\t\t\"target\": \"_rt_4FrameBuffer\","
+        "\t\t\t\"bind\":"
+        "\t\t\t["
+        "\t\t\t\t{"
+        "\t\t\t\t\t\"name\": \"_rt_FullFrameBuffer\","
+        "\t\t\t\t\t\"index\": 0"
+        "\t\t\t\t}"
+        "\t\t\t]"
+        "\t\t},"
+        "\t\t{"
+        "\t\t\t\"material\": \"materials/util/downsample_eighth_blur_v.json\","
+        "\t\t\t\"target\": \"_rt_8FrameBuffer\","
+        "\t\t\t\"bind\":"
+        "\t\t\t["
+        "\t\t\t\t{"
+        "\t\t\t\t\t\"name\": \"_rt_4FrameBuffer\","
+        "\t\t\t\t\t\"index\": 0"
+        "\t\t\t\t}"
+        "\t\t\t]"
+        "\t\t},"
+        "\t\t{"
+        "\t\t\t\"material\": \"materials/util/blur_h_bloom.json\","
+        "\t\t\t\"target\": \"_rt_Bloom\","
+        "\t\t\t\"bind\":"
+        "\t\t\t["
+        "\t\t\t\t{"
+        "\t\t\t\t\t\"name\": \"_rt_8FrameBuffer\","
+        "\t\t\t\t\t\"index\": 0"
+        "\t\t\t\t}"
+        "\t\t\t]"
+        "\t\t},"
+        "\t\t{"
+        "\t\t\t\"material\": \"materials/util/combine.json\","
+        "\t\t\t\"target\": \"_rt_imageLayerComposite_-1_b\","
+        "\t\t\t\"bind\":"
+        "\t\t\t["
+        "\t\t\t\t{"
+        "\t\t\t\t\t\"name\": \"_rt_FullFrameBuffer\","
+        "\t\t\t\t\t\"index\": 0"
+        "\t\t\t\t},"
+        "\t\t\t\t{"
+        "\t\t\t\t\t\"name\": \"_rt_Bloom\","
+        "\t\t\t\t\t\"index\": 1"
+        "\t\t\t\t}"
+        "\t\t\t]"
+        "\t\t},"
+        "\t\t{"
+        "\t\t\t\"material\": \"materials/wpenginelinux.json\","
+        "\t\t\t\"bind\":"
+        "\t\t\t["
+        "\t\t\t\t{"
+        "\t\t\t\t\t\"name\": \"_rt_imageLayerComposite_-1_b\","
+        "\t\t\t\t\t\"index\": 0"
+        "\t\t\t\t}"
+        "\t\t\t]"
+        "\t\t}"
+        "\t]"
+        "}"
+    );
+
+    // add some model for the image element even if it's going to waste rendering cycles
+    container->add (
+        "models/wpenginelinux.json",
+        "{"
+        "\t\"material\":\"materials/wpenginelinux.json\""
+        "}"
+    );
+
+    // models require materials, so add that too
+    container->add (
+        "materials/wpenginelinux.json",
+        "{"
+        "\t\"passes\":"
+        "\t\t["
+        "\t\t\t{"
+        "\t\t\t\t\"blending\": \"normal\","
+        "\t\t\t\t\"cullmode\": \"nocull\","
+        "\t\t\t\t\"depthtest\": \"disabled\","
+        "\t\t\t\t\"depthwrite\": \"disabled\","
+        "\t\t\t\t\"shader\": \"genericimage2\","
+        "\t\t\t\t\"textures\": [\"_rt_FullFrameBuffer\"]"
+        "\t\t\t}"
+        "\t\t]"
+        "}"
+    );
+
+    return container;
+}
+
 int main (int argc, char* argv[])
 {
     std::vector <std::string> screens;
@@ -275,6 +386,8 @@ int main (int argc, char* argv[])
 
     // the background's path is required to load project.json regardless of the type of background we're using
     containers->add (new WallpaperEngine::Assets::CDirectory (path));
+    // add the virtual container for mocked up files
+    containers->add (buildVirtualContainer ());
     // try to add the common packages
     addPkg (containers, path, "scene.pkg");
     addPkg (containers, path, "gifscene.pkg");

+ 0 - 3
src/WallpaperEngine/Assets/CDirectory.h

@@ -1,6 +1,3 @@
-//
-// Created by almamu on 8/8/21.
-//
 #pragma once
 
 #include <string>

+ 36 - 0
src/WallpaperEngine/Assets/CVirtualContainer.cpp

@@ -0,0 +1,36 @@
+#include <memory.h>
+
+#include "CVirtualContainer.h"
+#include "CAssetLoadException.h"
+
+using namespace WallpaperEngine::Assets;
+
+void CVirtualContainer::add (const std::string& filename, void* contents, uint32_t length)
+{
+    this->m_virtualFiles.insert (
+        std::make_pair (filename, CFileEntry (contents, length))
+    );
+}
+
+void CVirtualContainer::add (const std::string& filename, const std::string& contents)
+{
+    char* copy = new char [contents.length () + 1];
+
+    // copy the text AND the \0
+    memcpy (copy, contents.c_str (), contents.length () + 1);
+
+    // finally add to the container
+    this->add (filename, copy, contents.length () + 1);
+}
+
+const void* CVirtualContainer::readFile (std::string filename, uint32_t* length) const
+{
+    auto cur = this->m_virtualFiles.find (filename);
+
+    if (cur == this->m_virtualFiles.end ())
+        throw CAssetLoadException (filename, "Cannot find file in the virtual container");
+
+    *length = (*cur).second.length;
+
+    return (*cur).second.address;
+}

+ 39 - 0
src/WallpaperEngine/Assets/CVirtualContainer.h

@@ -0,0 +1,39 @@
+#pragma once
+
+#include <string>
+#include <map>
+
+#include "CFileEntry.h"
+#include "CContainer.h"
+
+namespace WallpaperEngine::Assets
+{
+    class CVirtualContainer : public CContainer
+    {
+    public:
+        CVirtualContainer () {}
+        ~CVirtualContainer () {}
+
+        /**
+         * Adds a new file to the virtual container
+         *
+         * @param filename
+         * @param contents
+         * @param length
+         */
+        void add (const std::string& filename, void* contents, uint32_t length);
+
+        /**
+         * Adds a new file to the virtual container
+         *
+         * @param filename
+         * @param contents
+         */
+        void add (const std::string& filename, const std::string& contents);
+
+        const void* readFile (std::string filename, uint32_t* length) const override;
+
+    private:
+        std::map <std::string, CFileEntry> m_virtualFiles;
+    };
+}

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

@@ -28,7 +28,7 @@ CObject::CObject (
 {
 }
 
-CObject* CObject::fromJSON (json data, CContainer* container)
+CObject* CObject::fromJSON (json data, const CContainer* container)
 {
     std::string json = data.dump ();
 

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

@@ -18,7 +18,7 @@ namespace WallpaperEngine::Core
     class CObject
     {
     public:
-        static CObject* fromJSON (json data, CContainer* container);
+        static CObject* fromJSON (json data, const CContainer* container);
 
         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; }

+ 38 - 4
src/WallpaperEngine/Core/CScene.cpp

@@ -62,8 +62,8 @@ CScene* CScene::fromFile (const std::string& filename, CContainer* container)
     // TODO: FIND IF THESE DEFAULTS ARE SENSIBLE OR NOT AND PERFORM PROPER VALIDATION WHEN CAMERA PREVIEW AND CAMERA PARALLAX ARE PRESENT
     auto ambientcolor = jsonFindDefault <std::string> (*general_it, "ambientcolor", "0 0 0");
     auto bloom = jsonFindDefault <bool> (*general_it, "bloom", false);
-    auto bloomstrength = jsonFindDefault <double> (*general_it, "bloomstrength", 0.0f);
-    auto bloomthreshold = jsonFindDefault <double> (*general_it, "bloomthreshold", 0.0f);
+    auto bloomstrength = (*general_it).find ("bloomstrength");
+    auto bloomthreshold = (*general_it).find ("bloomthreshold");
     auto camerafade = jsonFindDefault <bool> (*general_it, "camerafade", false);
     auto cameraparallax = jsonFindDefault <bool> (*general_it, "cameraparallax", true);
     auto cameraparallaxamount = jsonFindDefault <double> (*general_it, "cameraparallaxamount", 1.0f);
@@ -77,14 +77,48 @@ CScene* CScene::fromFile (const std::string& filename, CContainer* container)
     auto clearcolor_it = jsonFindRequired (*general_it, "clearcolor", "General section must have clear color");
     auto orthogonalprojection_it = jsonFindRequired (*general_it, "orthogonalprojection", "General section must have orthogonal projection info");
     auto skylightcolor = jsonFindDefault <std::string> (*general_it, "skylightcolor", "0 0 0");
+    double bloomstrength_val = 0.0f;
+    double bloomthreshold_val = 0.0f;
+
+    if (bloomstrength != (*general_it).end ())
+    {
+        if ((*bloomstrength).is_object ())
+        {
+            auto value = (*bloomstrength).find ("value");
+
+            if (value != (*bloomstrength).end ())
+            {
+                bloomstrength = value;
+            }
+        }
+
+        if ((*bloomstrength).is_number ())
+            bloomstrength_val = (*bloomstrength);
+    }
+
+    if (bloomthreshold != (*general_it).end ())
+    {
+        if ((*bloomthreshold).is_object ())
+        {
+            auto value = (*bloomthreshold).find ("value");
+
+            if (value != (*bloomthreshold).end ())
+            {
+                bloomthreshold = value;
+            }
+        }
+
+        if ((*bloomthreshold).is_number ())
+            bloomthreshold_val = (*bloomthreshold);
+    }
 
     CScene* scene = new CScene (
             container,
             Scenes::CCamera::fromJSON (*camera_it),
             WallpaperEngine::Core::aToColorf(ambientcolor),
             bloom,
-            bloomstrength,
-            bloomthreshold,
+            bloomstrength_val,
+            bloomthreshold_val,
             camerafade,
             cameraparallax,
             cameraparallaxamount,

+ 2 - 2
src/WallpaperEngine/Core/Objects/CEffect.cpp

@@ -28,7 +28,7 @@ CEffect::CEffect (
 {
 }
 
-CEffect* CEffect::fromJSON (json data, Core::CObject* object, CContainer* container)
+CEffect* CEffect::fromJSON (json data, Core::CObject* object, const CContainer* container)
 {
     auto file_it = jsonFindRequired (data, "file", "Object effect must have a file");
     auto effectpasses_it = data.find ("passes");
@@ -216,7 +216,7 @@ void CEffect::dependencyFromJSON (json::const_iterator dependencies_it, CEffect*
     }
 }
 
-void CEffect::materialsFromJSON (json::const_iterator passes_it, CEffect* effect, CContainer* container)
+void CEffect::materialsFromJSON (json::const_iterator passes_it, CEffect* effect, const CContainer* container)
 {
     auto cur = (*passes_it).begin ();
     auto end = (*passes_it).end ();

+ 2 - 2
src/WallpaperEngine/Core/Objects/CEffect.h

@@ -28,7 +28,7 @@ namespace WallpaperEngine::Core::Objects
             Core::CObject* object
         );
 
-        static CEffect* fromJSON (json data, Core::CObject* object, CContainer* container);
+        static CEffect* fromJSON (json data, Core::CObject* object, const CContainer* container);
 
         const std::vector<std::string>& getDependencies () const;
         const std::vector<Images::CMaterial*>& getMaterials () const;
@@ -40,7 +40,7 @@ namespace WallpaperEngine::Core::Objects
         static void combosFromJSON (json::const_iterator combos_it, Core::Objects::Images::Materials::CPass* pass);
         static void fbosFromJSON (json::const_iterator fbos_it, CEffect* effect);
         static void dependencyFromJSON (json::const_iterator dependencies_it, CEffect* effect);
-        static void materialsFromJSON (json::const_iterator passes_it, CEffect* effect, CContainer* container);
+        static void materialsFromJSON (json::const_iterator passes_it, CEffect* effect, const CContainer* container);
 
         void insertDependency (const std::string& dep);
         void insertMaterial (Images::CMaterial* material);

+ 1 - 1
src/WallpaperEngine/Core/Objects/CImage.cpp

@@ -37,7 +37,7 @@ CImage::CImage (
 
 WallpaperEngine::Core::CObject* CImage::fromJSON (
     json data,
-    CContainer* container,
+    const CContainer* container,
     bool visible,
     uint32_t id,
     std::string name,

+ 1 - 1
src/WallpaperEngine/Core/Objects/CImage.h

@@ -19,7 +19,7 @@ namespace WallpaperEngine::Core::Objects
     public:
         static CObject* fromJSON (
             json data,
-            CContainer* container,
+            const CContainer* container,
             bool visible,
             uint32_t id,
             std::string name,

+ 1 - 1
src/WallpaperEngine/Core/Objects/CParticle.cpp

@@ -5,7 +5,7 @@ using namespace WallpaperEngine::Core::Objects;
 
 CParticle* CParticle::fromFile (
     const std::string& filename,
-    CContainer* container,
+    const CContainer* container,
     uint32_t id,
     std::string name,
     const glm::vec3& origin,

+ 1 - 1
src/WallpaperEngine/Core/Objects/CParticle.h

@@ -18,7 +18,7 @@ namespace WallpaperEngine::Core::Objects
     public:
         static CParticle* fromFile (
                 const std::string& filename,
-                CContainer* container,
+                const CContainer* container,
                 uint32_t id,
                 std::string name,
                 const glm::vec3& origin,

+ 2 - 2
src/WallpaperEngine/Core/Objects/Images/Materials/CPass.cpp

@@ -16,7 +16,7 @@ CPass* CPass::fromJSON (json data)
 {
     // TODO: FIGURE OUT DEFAULT BLENDING MODE
     auto blending = jsonFindDefault <std::string> (data, "blending", "normal");
-    auto cullmode_it = jsonFindRequired (data, "cullmode", "Material pass must have cullmode specified");
+    auto cullmode = jsonFindDefault <std::string> (data, "cullmode", "nocull");
     auto depthtest_it = jsonFindRequired (data, "depthtest", "Material pass must have depthtest specified");
     auto depthwrite_it = jsonFindRequired (data, "depthwrite", "Material pass must have depthwrite specified");
     auto shader_it = jsonFindRequired (data, "shader", "Material pass must have shader specified");
@@ -34,7 +34,7 @@ CPass* CPass::fromJSON (json data)
 
     CPass* pass = new CPass (
         blending,
-        *cullmode_it,
+        cullmode,
         *depthtest_it,
         *depthwrite_it,
         *shader_it

+ 100 - 0
src/WallpaperEngine/Render/CScene.cpp

@@ -72,6 +72,106 @@ CScene::CScene (Core::CScene* scene, CContext* context) :
 
         this->m_objectsByRenderOrder.emplace_back ((*obj).second);
     }
+
+    uint32_t sceneWidth = scene->getOrthogonalProjection ()->getWidth ();
+    uint32_t sceneHeight = scene->getOrthogonalProjection ()->getHeight ();
+
+    // create extra framebuffers for the bloom effect
+    this->_rt_4FrameBuffer = this->createFBO (
+        "_rt_4FrameBuffer",
+        ITexture::TextureFormat::ARGB8888,
+        ITexture::TextureFlags::NoInterpolation,
+        1.0,
+        sceneWidth / 4, sceneHeight / 4,
+        sceneWidth / 4, sceneHeight / 4
+    );
+    this->_rt_8FrameBuffer = this->createFBO (
+        "_rt_8FrameBuffer",
+        ITexture::TextureFormat::ARGB8888,
+        ITexture::TextureFlags::NoInterpolation,
+        1.0,
+        sceneWidth / 8, sceneHeight / 8,
+        sceneWidth / 8, sceneHeight / 8
+    );
+    this->_rt_Bloom = this->createFBO (
+        "_rt_Bloom",
+        ITexture::TextureFormat::ARGB8888,
+        ITexture::TextureFlags::NoInterpolation,
+        1.0,
+        sceneWidth / 8, sceneHeight / 8,
+        sceneWidth / 8, sceneHeight / 8
+    );
+
+    this->_rt_FullFrameBuffer_b = this->createFBO (
+        "_rt_FullFrameBuffer_b",
+        ITexture::TextureFormat::ARGB8888,
+        ITexture::TextureFlags::NoInterpolation,
+        1.0,
+        sceneWidth, sceneHeight,
+        sceneWidth, sceneHeight
+    );
+
+    //
+    // Had to get a little creative with the effects to achieve the same bloom effect without any custom code
+    // this custom image loads some effect files from the virtual container to achieve the same bloom effect
+    // this approach requires of two extra draw calls due to the way the effect works in official WPE
+    // (it renders directly to the screen, whereas here we never do that from a scene)
+    //
+
+    std::string imagejson =
+        "{"
+        "\t\"image\": \"models/wpenginelinux.json\","
+        "\t\"name\": \"bloomimagewpenginelinux\","
+        "\t\"visible\": true,"
+        "\t\"scale\": \"1.0 1.0 1.0\","
+        "\t\"angles\": \"0.0 0.0 0.0\","
+        "\t\"origin\": \"" + std::to_string (sceneWidth / 2) + " " + std::to_string (sceneHeight / 2) + " 0.0\","
+        "\t\"id\": " + std::to_string (0xFFFFFFFF) + ","
+        "\t\"effects\":"
+        "\t["
+        "\t\t{"
+        "\t\t\t\"file\": \"effects/wpenginelinux/bloomeffect.json\","
+        "\t\t\t\"id\": 15242000,"
+        "\t\t\t\"name\": \"\","
+        "\t\t\t\"passes\":"
+        "\t\t\t["
+        "\t\t\t\t{"
+        "\t\t\t\t\t\"constantshadervalues\":"
+        "\t\t\t\t\t{"
+        "\t\t\t\t\t\t\"bloomstrength\": " + std::to_string (this->getScene ()->getBloomStrength ()) + ","
+        "\t\t\t\t\t\t\"bloomthreshold\": " + std::to_string (this->getScene ()->getBloomThreshold ()) +
+        "\t\t\t\t\t}"
+        "\t\t\t\t},"
+        "\t\t\t\t{"
+        "\t\t\t\t\t\"constantshadervalues\":"
+        "\t\t\t\t\t{"
+        "\t\t\t\t\t\t\"bloomstrength\": " + std::to_string (this->getScene ()->getBloomStrength ()) + ","
+        "\t\t\t\t\t\t\"bloomthreshold\": " + std::to_string (this->getScene ()->getBloomThreshold ()) +
+        "\t\t\t\t\t}"
+        "\t\t\t\t},"
+        "\t\t\t\t{"
+        "\t\t\t\t\t\"constantshadervalues\":"
+        "\t\t\t\t\t{"
+        "\t\t\t\t\t\t\"bloomstrength\": " + std::to_string (this->getScene ()->getBloomStrength ()) + ","
+        "\t\t\t\t\t\t\"bloomthreshold\": " + std::to_string (this->getScene ()->getBloomThreshold ()) +
+        "\t\t\t\t\t}"
+        "\t\t\t\t}"
+        "\t\t\t]"
+        "\t\t}"
+        "\t],"
+        "\t\"size\": \"" + std::to_string (sceneWidth) + " " + std::to_string (sceneHeight) + "\""
+        "}";
+    auto json = nlohmann::json::parse (imagejson);
+
+    // create image for bloom passes
+    auto bloomPass = this->createObject (
+        WallpaperEngine::Core::CObject::fromJSON (
+            json, this->getContainer ()
+        )
+    );
+
+    if (this->getScene ()->isBloom () == true)
+        this->m_objectsByRenderOrder.emplace_back (bloomPass);
 }
 
 Render::CObject* CScene::createObject (Core::CObject* object)

+ 4 - 0
src/WallpaperEngine/Render/CScene.h

@@ -40,5 +40,9 @@ namespace WallpaperEngine::Render
         std::vector<CObject*> m_objectsByRenderOrder;
         glm::vec2 m_mousePosition;
         glm::vec2 m_parallaxDisplacement;
+        CFBO* _rt_4FrameBuffer;
+        CFBO* _rt_8FrameBuffer;
+        CFBO* _rt_Bloom;
+        CFBO* _rt_FullFrameBuffer_b; // this one doesn't exist on the official wallpaper engine, but our approach requires it
     };
 }

+ 8 - 0
src/WallpaperEngine/Render/Objects/CImage.cpp

@@ -92,6 +92,14 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
     GLfloat realWidth = this->m_texture->getRealWidth () / 2.0f;
     GLfloat realHeight = this->m_texture->getRealHeight () / 2.0f;
 
+    // TODO: XXXHACK: QUICK HACK TO MAKE BLOOM LAYER BEHAVE IN A SPECIAL WAY, PREVENTS VERTICAL FLIP
+    if (this->getId () == 0xFFFFFFFF)
+    {
+        float tmpy = this->m_pos.y;
+        this->m_pos.y = this->m_pos.w;
+        this->m_pos.w = tmpy;
+    }
+
     // build a list of vertices, these might need some change later (or maybe invert the camera)
     GLfloat sceneSpacePosition [] = {
         this->m_pos.x, this->m_pos.y, 0.0f,

+ 6 - 1
src/WallpaperEngine/Render/Objects/Effects/CPass.cpp

@@ -56,8 +56,9 @@ const ITexture* CPass::resolveTexture (const ITexture* expected, int index, cons
     // 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 ());
 
+    // try scene FBOs, these are our last resort, i guess the exception is better than a nullpo
     if (fbo == nullptr)
-        return nullptr;
+        return this->m_material->getImage ()->getScene ()->findFBO ((*it).second->getName ());
 
     return fbo;
 }
@@ -556,6 +557,8 @@ void CPass::setupUniforms ()
         }
     }
 
+    auto projection = this->getMaterial ()->getImage ()->getScene ()->getScene ()->getOrthogonalProjection ();
+
     // register variables like brightness and alpha with some default value
     this->addUniform ("g_Brightness", this->m_material->getImage ()->getImage ()->getBrightness ());
     this->addUniform ("g_UserAlpha", this->m_material->getImage ()->getImage ()->getAlpha ());
@@ -570,6 +573,8 @@ void CPass::setupUniforms ()
     this->addUniform ("g_PointerPosition", this->m_material->getImage ()->getScene ()->getMousePosition ());
     this->addUniform ("g_EffectTextureProjectionMatrix", glm::mat4(1.0));
     this->addUniform ("g_EffectTextureProjectionMatrixInverse", glm::mat4(1.0));
+    this->addUniform ("g_TexelSize", glm::vec2 (1.0 / projection->getWidth (), 1.0 / projection->getHeight ()));
+    this->addUniform ("g_TexelSize", glm::vec2 (0.5 / projection->getWidth (), 0.5 / projection->getHeight ()));
 }
 
 void CPass::addAttribute (const std::string& name, GLint type, GLint elements, const GLuint* value)