Parcourir la source

Merge pull request #188 from Pasalc/viewport-clamp

Fixed texture clamping caused by texture coordinates being outside of (0,1) interval
Alexis Maiquez il y a 2 ans
Parent
commit
51db2962e7

+ 2 - 0
CMakeLists.txt

@@ -200,6 +200,8 @@ add_executable(
 
     src/WallpaperEngine/Render/CWallpaper.h
     src/WallpaperEngine/Render/CWallpaper.cpp
+    src/WallpaperEngine/Render/CWallpaperState.h
+    src/WallpaperEngine/Render/CWallpaperState.cpp
     src/WallpaperEngine/Render/CScene.h
     src/WallpaperEngine/Render/CScene.cpp
     src/WallpaperEngine/Render/CVideo.h

+ 65 - 2
src/WallpaperEngine/Application/CApplicationContext.cpp

@@ -29,9 +29,29 @@ struct option long_options[] = {
     { "noautomute", no_argument,            nullptr, 'm' },
     { "no-fullscreen-pause", no_argument,   nullptr, 'n' },
     { "disable-mouse", no_argument,         nullptr, 'e' },
+    { "scaling", required_argument,         nullptr, 't' },
+    { "clamping", required_argument,        nullptr, 't' },
     { nullptr, 0,                           nullptr, 0 }
 };
 
+/* std::hash::operator() isn't constexpr, so it can't be used to get hash values as compile-time constants
+ * So here is customHash. It skips all spaces, so hashes for " find " and "fi nd" are the same 
+ * Basicly got it from here: https://stackoverflow.com/questions/8317508/hash-function-for-a-string
+*/
+constexpr size_t customHash(const char* str) {
+    constexpr size_t A = 54059; /* a prime */
+    constexpr size_t B = 76963; /* another prime */
+    constexpr size_t C = 86969; /* yet another prime */
+    constexpr size_t FIRSTH = 37; /* also prime */
+    size_t hash = FIRSTH;
+    while (*str) {
+        if(*str != ' ') // Skip spaces
+            hash = (hash * A) ^ (*str * B);
+        ++str;
+    }
+    return hash % C;
+}
+
 std::string stringPathFixes (const std::string& s)
 {
     if (s.empty ())
@@ -66,7 +86,8 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
             .mode = NORMAL_WINDOW,
             .maximumFPS = 30,
             .pauseOnFullscreen = true,
-            .window = { .geometry = {}},
+            .window = { .geometry = {}, .clamp = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVs,
+            .scalingMode =  WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::DefaultUVs, },
         },
         .audio =
         {
@@ -90,7 +111,7 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
 
     std::string lastScreen;
 
-    while ((c = getopt_long (argc, argv, "b:r:p:d:shf:a:w:mn", long_options, nullptr)) != -1)
+    while ((c = getopt_long (argc, argv, "b:r:p:d:shf:a:w:mnt:", long_options, nullptr)) != -1)
     {
         switch (c)
         {
@@ -105,6 +126,7 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
                 // no need to check for previous screen being in the list, as it's the only way for this variable
                 // to have any value
                 this->settings.general.screenBackgrounds[lastScreen] = translateBackground (optarg);
+                this->settings.general.screenScalings[lastScreen] = this->settings.render.window.scalingMode;
                 break;
 
             case 'o':
@@ -133,6 +155,7 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
                 this->settings.render.mode = DESKTOP_BACKGROUND;
                 lastScreen = optarg;
                 this->settings.general.screenBackgrounds[lastScreen] = "";
+                this->settings.general.screenScalings[lastScreen] = this->settings.render.window.scalingMode;
                 break;
 
             case 'w':
@@ -196,6 +219,42 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
                 this->settings.mouse.enabled = false;
                 break;
 
+            case 't':
+            {   
+                size_t hash = customHash(optarg);
+                // Use a switch statement with the hash
+                switch (hash) {
+                    // --scale options
+                    case customHash("stretch"):
+                        this->settings.render.window.scalingMode =  WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::StretchUVs;
+                        break;
+                    case customHash("fit"):
+                        this->settings.render.window.scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::ZoomFitUVs;
+                        break;
+                    case customHash("fill"):
+                        this->settings.render.window.scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::ZoomFillUVs;
+                        break;
+                    case customHash("default"):
+                        this->settings.render.window.scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::DefaultUVs;
+                        break;
+                    // --clamp options
+                    case customHash("clamp"):
+                        this->settings.render.window.clamp = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVs;
+                        break;
+                    case customHash("border"):
+                        this->settings.render.window.clamp = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVsBorder;
+                        break;
+                    case customHash("repeat"):
+                        this->settings.render.window.clamp = WallpaperEngine::Assets::ITexture::TextureFlags::NoFlags;
+                        break;
+                    default:
+                        sLog.error("Wrong argument:");
+                        sLog.error(optarg);
+                        sLog.exception("Wrong argument provided for --scale or --clamp option.");
+                        break;
+                }
+            }
+            break;
             default:
                 sLog.out ("Default on path parsing: ", optarg);
                 break;
@@ -293,4 +352,8 @@ void CApplicationContext::printHelp (const char* route)
     sLog.out ("\t--set-property <name=value>\tOverrides the default value of the given property");
     sLog.out ("\t--no-fullscreen-pause\tPrevents the background pausing when an app is fullscreen");
     sLog.out ("\t--disable-mouse\tDisables mouse interactions");
+    sLog.out ("\t--scaling <mode>\t Scaling mode for wallpaper. Can be stretch, fit, fill, default. Must be used before wallpaper provided.\n\
+                    \t\t For default wallpaper last specified value will be used.\n\
+                    \t\t Example: ./wallengine --scaling stretch --screen-root eDP-1 --bg 2667198601 --scaling fill --screen-root eDP-2 2667198602");
+    sLog.out ("\t--clamping <mode>\t Clamping mode for all wallpapers. Can be clamp, border, repeat. Enables GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, GL_REPEAT accordingly. Default is clamp.");
 }

+ 7 - 0
src/WallpaperEngine/Application/CApplicationContext.h

@@ -11,6 +11,9 @@
 
 #include "CApplicationState.h"
 
+#include "WallpaperEngine/Assets/ITexture.h"
+#include "WallpaperEngine/Render/CWallpaperState.h"
+
 namespace WallpaperEngine::Application
 {
 	/**
@@ -50,6 +53,8 @@ namespace WallpaperEngine::Application
                 std::map <std::string, std::filesystem::path> screenBackgrounds;
                 /** Properties to change values for */
                 std::map <std::string, std::string> properties;
+                /** The scaling mode for different screens */
+                std::map <std::string, WallpaperEngine::Render::CWallpaperState::TextureUVsScaling> screenScalings;
             } general;
 
             /**
@@ -68,6 +73,8 @@ namespace WallpaperEngine::Application
                 {
                     /** The window size used in explicit window */
                     glm::ivec4 geometry;
+                    WallpaperEngine::Assets::ITexture::TextureFlags clamp;
+                    WallpaperEngine::Render::CWallpaperState::TextureUVsScaling scalingMode;
                 } window;
             } render;
 

+ 2 - 2
src/WallpaperEngine/Application/CWallpaperApplication.cpp

@@ -322,13 +322,13 @@ namespace WallpaperEngine::Application
         for (const auto& it : this->m_backgrounds)
             context->setWallpaper (
                 it.first,
-                WallpaperEngine::Render::CWallpaper::fromWallpaper (it.second->getWallpaper (), *context, *audioContext)
+                WallpaperEngine::Render::CWallpaper::fromWallpaper (it.second->getWallpaper (), *context, *audioContext, this->m_context.settings.general.screenScalings[it.first])
             );
 
         // set the default rendering wallpaper if available
         if (this->m_defaultBackground != nullptr)
             context->setDefaultWallpaper (WallpaperEngine::Render::CWallpaper::fromWallpaper (
-                this->m_defaultBackground->getWallpaper (), *context, *audioContext
+                this->m_defaultBackground->getWallpaper (), *context, *audioContext, this->m_context.settings.render.window.scalingMode
             ));
 
         static time_t seconds;

+ 1 - 0
src/WallpaperEngine/Assets/ITexture.h

@@ -69,6 +69,7 @@ namespace WallpaperEngine::Assets
             NoInterpolation = 1,
             ClampUVs = 2,
             IsGif = 4,
+            ClampUVsBorder = 8,
         };
 
         /**

+ 5 - 0
src/WallpaperEngine/Render/CFBO.cpp

@@ -41,6 +41,11 @@ CFBO::CFBO (
         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     }
+    else if (flags & TextureFlags::ClampUVsBorder)
+    {
+        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+    }
     else
     {
         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

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

@@ -6,6 +6,8 @@
 #include "WallpaperEngine/Render/Objects/CImage.h"
 #include "WallpaperEngine/Render/Objects/CSound.h"
 
+#include "WallpaperEngine/Render/CWallpaperState.h"
+
 #include "CScene.h"
 
 extern float g_Time;
@@ -14,8 +16,8 @@ extern float g_TimeLast;
 using namespace WallpaperEngine;
 using namespace WallpaperEngine::Render;
 
-CScene::CScene (Core::CScene* scene, CRenderContext& context, CAudioContext& audioContext) :
-    CWallpaper (scene, Type, context, audioContext),
+CScene::CScene (Core::CScene* scene, CRenderContext& context, CAudioContext& audioContext, const CWallpaperState::TextureUVsScaling& scalingMode) :
+    CWallpaper (scene, Type, context, audioContext, scalingMode),
     m_mousePosition (),
     m_mousePositionLast (),
     m_parallaxDisplacement ()

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

@@ -15,7 +15,7 @@ namespace WallpaperEngine::Render
     class CScene : public CWallpaper
     {
     public:
-        CScene (Core::CScene* scene, CRenderContext& context, CAudioContext& audioContext);
+        CScene (Core::CScene* scene, CRenderContext& context, CAudioContext& audioContext, const CWallpaperState::TextureUVsScaling& scalingMode);
 
         CCamera* getCamera () const;
 

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

@@ -11,8 +11,8 @@ void* get_proc_address (void* ctx, const char* name)
     return static_cast<CVideo*> (ctx)->getContext ().getDriver ().getProcAddress (name);
 }
 
-CVideo::CVideo (Core::CVideo* video, CRenderContext& context, CAudioContext& audioContext) :
-    CWallpaper (video, Type, context, audioContext),
+CVideo::CVideo (Core::CVideo* video, CRenderContext& context, CAudioContext& audioContext, const CWallpaperState::TextureUVsScaling& scalingMode) :
+    CWallpaper (video, Type, context, audioContext, scalingMode),
     m_width (16),
     m_height (16),
     m_mpvGl (nullptr)

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

@@ -12,7 +12,7 @@ namespace WallpaperEngine::Render
     class CVideo : public CWallpaper
     {
     public:
-        CVideo (Core::CVideo* video, CRenderContext& context, CAudioContext& audioContext);
+        CVideo (Core::CVideo* video, CRenderContext& context, CAudioContext& audioContext, const CWallpaperState::TextureUVsScaling& scalingMode);
 
         Core::CVideo* getVideo ();
 

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

@@ -9,7 +9,7 @@
 
 using namespace WallpaperEngine::Render;
 
-CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRenderContext& context, CAudioContext& audioContext) :
+CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRenderContext& context, CAudioContext& audioContext, const CWallpaperState::TextureUVsScaling& scalingMode) :
     CContextAware (context),
     m_wallpaperData (wallpaperData),
     m_type (std::move(type)),
@@ -22,7 +22,8 @@ CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRend
     a_Position (GL_NONE),
     a_TexCoord (GL_NONE),
     m_vaoBuffer (GL_NONE),
-    m_audioContext (audioContext)
+    m_audioContext (audioContext),
+    m_state(scalingMode)
 {
     // generate the VAO to stop opengl from complaining
     glGenVertexArrays (1, &this->m_vaoBuffer);
@@ -201,81 +202,25 @@ void CWallpaper::setupShaders ()
     this->a_TexCoord = glGetAttribLocation (this->m_shader, "a_TexCoord");
 }
 
-void CWallpaper::updateTexCoord (GLfloat* texCoords, GLsizeiptr size) const
-{
-    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::updateUVs(const glm::ivec4& viewport, const bool vflip){
+    //update UVs if something has changed, otherwise use old values
+    if(this->m_state.hasChanged(viewport, vflip, this->getWidth(), this->getHeight())){
+        // Update wallpaper state
+        this->m_state.updateState(viewport, vflip, this->getWidth(), this->getHeight());
+    }
+}
+
 void CWallpaper::render (glm::ivec4 viewport, bool vflip)
 {
     this->renderFrame (viewport);
-
-    uint32_t projectionWidth = this->getWidth ();
-    uint32_t projectionHeight = this->getHeight ();
-
-    float ustart = 0.0f;
-    float uend = 0.0f;
-    float vstart = 0.0f;
-    float vend = 0.0f;
-
-    if (
-        (viewport.w > viewport.z && projectionWidth >= projectionHeight) ||
-            (viewport.z > viewport.w && projectionHeight > projectionWidth)
-        )
-    {
-        if (vflip)
-        {
-            vstart = 0.0f;
-            vend = 1.0f;
-        }
-        else
-        {
-            vstart = 1.0f;
-            vend = 0.0f;
-        }
-
-        int newWidth = viewport.w / (float) projectionHeight * projectionWidth;
-        float newCenter = newWidth / 2.0f;
-        float viewportCenter = viewport.z / 2.0;
-
-        float left = newCenter - viewportCenter;
-        float right = newCenter + viewportCenter;
-
-        ustart = left / newWidth;
-        uend = right / newWidth;
-    }
-
-    if (
-        (viewport.z > viewport.w && projectionWidth >= projectionHeight) ||
-            (viewport.w > viewport.z && projectionHeight > projectionWidth)
-        )
-    {
-        ustart = 0.0f;
-        uend = 1.0f;
-
-        int newHeight = viewport.z / (float) projectionWidth * projectionHeight;
-        float newCenter = newHeight / 2.0f;
-        float viewportCenter = viewport.w / 2.0;
-
-        float down = newCenter - viewportCenter;
-        float up = newCenter + viewportCenter;
-
-        if (vflip)
-        {
-            vstart = down / newHeight;
-            vend = up / newHeight;
-        }
-        else
-        {
-            vstart = up / newHeight;
-            vend = down / newHeight;
-        }
-    }
+    //Update UVs coordinates according to scaling mode of this wallpaper
+    updateUVs(viewport,vflip);
+    auto [ ustart, uend, vstart, vend ] = this->m_state.getTextureUVs();
 
     GLfloat texCoords [] = {
         ustart, vstart,
@@ -319,12 +264,13 @@ void CWallpaper::setupFramebuffers ()
 {
     uint32_t width = this->getWidth ();
     uint32_t height = this->getHeight ();
-
+    ITexture::TextureFlags clamp = this->getContext().getApp().getContext().settings.render.window.clamp;
+    
     // create framebuffer for the scene
     this->m_sceneFBO = this->createFBO (
         "_rt_FullFrameBuffer",
         ITexture::TextureFormat::ARGB8888,
-        ITexture::TextureFlags::ClampUVs,
+        clamp,
         1.0,
         width, height,
         width, height
@@ -366,12 +312,12 @@ CFBO* CWallpaper::getFBO () const
     return this->m_sceneFBO;
 }
 
-CWallpaper* CWallpaper::fromWallpaper (Core::CWallpaper* wallpaper, CRenderContext& context, CAudioContext& audioContext)
+CWallpaper* CWallpaper::fromWallpaper (Core::CWallpaper* wallpaper, CRenderContext& context, CAudioContext& audioContext, const CWallpaperState::TextureUVsScaling& scalingMode)
 {
     if (wallpaper->is <Core::CScene> ())
-        return new WallpaperEngine::Render::CScene (wallpaper->as <Core::CScene> (), context, audioContext);
+        return new WallpaperEngine::Render::CScene (wallpaper->as <Core::CScene> (), context, audioContext, scalingMode);
     else if (wallpaper->is <Core::CVideo> ())
-        return new WallpaperEngine::Render::CVideo (wallpaper->as <Core::CVideo> (), context, audioContext);
+        return new WallpaperEngine::Render::CVideo (wallpaper->as <Core::CVideo> (), context, audioContext, scalingMode);
     else
         sLog.exception ("Unsupported wallpaper type");
 }

+ 8 - 4
src/WallpaperEngine/Render/CWallpaper.h

@@ -14,6 +14,8 @@
 #include "WallpaperEngine/Render/CFBO.h"
 #include "WallpaperEngine/Render/Helpers/CContextAware.h"
 
+#include "CWallpaperState.h"
+
 using namespace WallpaperEngine::Assets;
 using namespace WallpaperEngine::Audio;
 
@@ -83,9 +85,9 @@ namespace WallpaperEngine::Render
         [[nodiscard]] CFBO* getFBO () const;
 
         /**
-         * Updates the texcoord used for drawing to the used framebuffer
+         * Updates the UVs coordinates if window/screen/vflip/projection has changed 
          */
-        void updateTexCoord (GLfloat* texCoords, GLsizeiptr size) const;
+        void updateUVs (const glm::ivec4& viewport, const bool vflip);
 
         /**
          * Updates the destination framebuffer for this wallpaper
@@ -111,10 +113,10 @@ namespace WallpaperEngine::Render
          *
          * @return
          */
-        static CWallpaper* fromWallpaper (Core::CWallpaper* wallpaper, CRenderContext& context, CAudioContext& audioContext);
+        static CWallpaper* fromWallpaper (Core::CWallpaper* wallpaper, CRenderContext& context, CAudioContext& audioContext, const CWallpaperState::TextureUVsScaling& scalingMode);
 
     protected:
-        CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRenderContext& context, CAudioContext& audioContext);
+        CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRenderContext& context, CAudioContext& audioContext,  const CWallpaperState::TextureUVsScaling& scalingMode);
 
         /**
          * Renders a frame of the wallpaper
@@ -153,5 +155,7 @@ namespace WallpaperEngine::Render
         std::map<std::string, CFBO*> m_fbos;
         /** Audio context that is using this wallpaper */
         CAudioContext& m_audioContext;
+        /** Current Wallpaper state */
+        CWallpaperState m_state;
     };
 }

+ 170 - 0
src/WallpaperEngine/Render/CWallpaperState.cpp

@@ -0,0 +1,170 @@
+#include "CWallpaperState.h"
+#include <algorithm>
+#include "WallpaperEngine/Logging/CLog.h"
+
+using namespace WallpaperEngine::Render;
+
+// Reset UVs to 0/1 values
+void CWallpaperState::resetUVs(){
+    this->UVs.ustart=0;
+    this->UVs.uend=1;
+    if (vflip){
+        this->UVs.vstart = 0.0f;
+        this->UVs.vend = 1.0f;
+    }
+    else{
+        this->UVs.vstart=1.0f;
+        this->UVs.vend=0.0f;
+    }
+}
+
+// Update Us coordinates for current viewport and projection
+void CWallpaperState::updateUs(const int& projectionWidth, const int& projectionHeight){
+    const float viewportWidth  = this->getViewportWidth();
+    const float viewportHeight = this->getViewportHeight();
+    int newWidth = viewportHeight  / projectionHeight * projectionWidth;
+    float newCenter = newWidth / 2.0f;
+    float viewportCenter = viewportWidth / 2.0;
+
+    float left = newCenter - viewportCenter;
+    float right = newCenter + viewportCenter;
+
+    this->UVs.ustart = left / newWidth;
+    this->UVs.uend   = right / newWidth;
+}
+
+// Update Vs coordinates for current viewport and projection 
+void CWallpaperState::updateVs(const int& projectionWidth, const int& projectionHeight){
+    const float viewportWidth  = this->getViewportWidth();
+    const float viewportHeight =  this->getViewportHeight();
+    int newHeight = viewportWidth / projectionWidth * projectionHeight;
+    float newCenter = newHeight / 2.0f;
+    float viewportCenter = viewportHeight / 2.0;
+
+    float down = newCenter - viewportCenter;
+    float up = newCenter + viewportCenter;
+
+    if (vflip)
+    {
+        this->UVs.vstart = down / newHeight;
+        this->UVs.vend = up / newHeight;
+    }
+    else
+    {
+        this->UVs.vstart = up / newHeight;
+        this->UVs.vend = down / newHeight;
+    }
+}
+
+
+template<> void CWallpaperState::updateTextureUVs<CWallpaperState::TextureUVsScaling::StretchUVs>(){
+    this->resetUVs();
+}
+
+template<> void CWallpaperState::updateTextureUVs<CWallpaperState::TextureUVsScaling::ZoomFillUVs>(){
+    this->resetUVs();
+
+    const int viewportWidth  = this->getViewportWidth();
+    const int viewportHeight =  this->getViewportHeight();
+    uint32_t projectionWidth = this->getProjectionWidth();
+    uint32_t projectionHeight = this->getProjectionHeight();
+
+    const float m1 = static_cast<float>(viewportWidth) / projectionWidth;
+    const float m2 = static_cast<float>(viewportHeight) / projectionHeight;
+    const float m = std::max(m1,m2);
+    projectionWidth*=m;
+    projectionHeight*=m;
+
+    if (projectionWidth!=viewportWidth)
+    {
+        this->updateUs(projectionWidth,projectionHeight);
+    }
+    else if (projectionHeight!=viewportHeight)
+    {
+        this->updateVs(projectionWidth,projectionHeight);
+    }
+}
+
+template<> void CWallpaperState::updateTextureUVs<CWallpaperState::TextureUVsScaling::ZoomFitUVs>(){
+    this->resetUVs();
+    
+    const int viewportWidth  = this->getViewportWidth();
+    const int viewportHeight =  this->getViewportHeight();
+    uint32_t projectionWidth = this->getProjectionWidth();
+    uint32_t projectionHeight = this->getProjectionHeight();
+
+    const float m1 = static_cast<float>(viewportWidth) / projectionWidth;
+    const float m2 = static_cast<float>(viewportHeight) / projectionHeight;
+    const float m = std::min(m1,m2);
+    projectionWidth*=m;
+    projectionHeight*=m;
+
+    if (projectionWidth!=viewportWidth)
+    {
+        this->updateUs(projectionWidth,projectionHeight);
+    }
+    else if (projectionHeight!=viewportHeight)
+    {
+        this->updateVs(projectionWidth,projectionHeight);
+    }
+}
+
+template<> void CWallpaperState::updateTextureUVs<CWallpaperState::TextureUVsScaling::DefaultUVs>(){
+    this->resetUVs();
+
+    const int viewportWidth  = this->getViewportWidth();
+    const int viewportHeight =  this->getViewportHeight();
+    uint32_t projectionWidth = this->getProjectionWidth();
+    uint32_t projectionHeight = this->getProjectionHeight();
+
+    if (
+        (viewportHeight > viewportWidth && projectionWidth >= projectionHeight) ||
+            (viewportWidth > viewportHeight && projectionHeight > projectionWidth)
+        )
+    {
+        updateUs(projectionWidth,projectionHeight);
+    }
+
+    if (
+        (viewportWidth > viewportHeight && projectionWidth >= projectionHeight) ||
+            (viewportHeight > viewportWidth && projectionHeight > projectionWidth)
+        )
+    {
+        updateVs(projectionWidth,projectionHeight);
+    }
+}
+
+template<CWallpaperState::TextureUVsScaling T> void CWallpaperState::updateTextureUVs(){
+    sLog.exception("Using generic template for scaling is not allowed. Write specialization template for your scaling mode.\
+     This message is for developers, if you are just user it's a bug.");
+}
+
+
+void CWallpaperState::updateState(const glm::ivec4& viewport, const bool& vflip, const int& projectionWidth, const int& projectionHeight){
+    this->viewport.width = viewport.z;
+    this->viewport.height = viewport.w;
+    this->vflip = vflip;
+    this->projection.width = projectionWidth;
+    this->projection.height = projectionHeight;
+
+    //Set texture UVs according to choosen scaling mode for this wallpaper
+    switch (this->getTextureUVsScaling())
+    {
+        case CWallpaperState::TextureUVsScaling::StretchUVs :
+            this->updateTextureUVs<CWallpaperState::TextureUVsScaling::StretchUVs>();
+            break;
+        case CWallpaperState::TextureUVsScaling::ZoomFillUVs :
+            this->updateTextureUVs<CWallpaperState::TextureUVsScaling::ZoomFillUVs>();
+            break;
+        case CWallpaperState::TextureUVsScaling::ZoomFitUVs :
+            this->updateTextureUVs<CWallpaperState::TextureUVsScaling::ZoomFitUVs>();
+            break;
+        case CWallpaperState::TextureUVsScaling::DefaultUVs :
+            this->updateTextureUVs<CWallpaperState::TextureUVsScaling::DefaultUVs>();
+            break;
+        default:
+            sLog.exception("Switch case for specified scaling mode doesn't exist. Add your realisation in switch statement.\
+                This message is for developers, if you are just user it's a bug.");
+            break;
+    }
+}

+ 99 - 0
src/WallpaperEngine/Render/CWallpaperState.h

@@ -0,0 +1,99 @@
+#pragma once
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+#include <glm/vec4.hpp>
+
+namespace WallpaperEngine::Render
+{
+    /**
+     * Represents current wallpaper state
+     */
+    class CWallpaperState
+    {
+    public:
+        // Scaling modes. Defines how UVs coordinates are calculated.
+        enum class TextureUVsScaling : uint8_t
+        {
+            DefaultUVs,
+            ZoomFitUVs,
+            ZoomFillUVs,
+            StretchUVs,
+        };
+
+        CWallpaperState(const TextureUVsScaling& textureUVsMode) : m_textureUVsMode(textureUVsMode)
+        {};
+
+        // Compares saved state values with passed arguments
+        bool hasChanged(const glm::ivec4& viewport, const bool& vflip, const int& projectionWidth, const int& projectionHeight) const{
+            return this->viewport.width != viewport.z || this->viewport.height != viewport.w || 
+                this->projection.width != projectionWidth || this->projection.height != projectionHeight || this->vflip != vflip;
+        }
+
+        // Reset UVs to 0/1 values
+        void resetUVs();
+        
+        // Update Us coordinates for current viewport and projection
+        void updateUs(const int& projectionWidth, const int& projectionHeight);
+
+        // Update Vs coordinates for current viewport and projection 
+        void updateVs(const int& projectionWidth, const int& projectionHeight);
+
+        // Get texture UV coordinates
+        auto getTextureUVs() const {return UVs;};
+
+        // Set texture UV coordinates according to texture scaling mode
+        template<CWallpaperState::TextureUVsScaling> void updateTextureUVs();
+        
+        // Updates state with provided values
+        void updateState(const glm::ivec4& viewport, const bool& vflip, const int& projectionWidth, const int& projectionHeight);
+
+        // @return The texture scaling mode
+        TextureUVsScaling getTextureUVsScaling ()  const { return m_textureUVsMode; };
+
+        // Set texture scaling mode
+        void setTextureUVsStrategy(const TextureUVsScaling strategy) { m_textureUVsMode=strategy; } ;
+
+        // @return The width of viewport
+        int getViewportWidth () const { return viewport.width;};
+
+        // @return The height of viewport
+        int getViewportHeight () const { return viewport.height;};
+
+        // @return The width of viewport
+        uint32_t getProjectionWidth () const { return projection.width;};
+
+        // @return The height of viewport
+        uint32_t getProjectionHeight () const { return projection.height;};
+
+    private:
+        // Cached UVs value for texture coordinates. No need to recalculate if viewport and projection haven't changed.
+        struct
+        {
+            float ustart;
+            float uend;
+            float vstart;
+            float vend;
+        } UVs;
+
+        // Viewport for which UVs were calculated
+        struct
+        {
+            int width;
+            int height;
+        } viewport{};
+
+        // Wallpaper dimensions
+        struct
+        {
+            uint32_t width;
+            uint32_t height;
+        } projection{};
+
+        // Are Vs coordinates fliped
+        bool vflip = false;
+
+        // Texture scaling mode
+        TextureUVsScaling m_textureUVsMode = TextureUVsScaling::DefaultUVs;
+    };
+}

+ 1 - 0
src/WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.cpp

@@ -1,3 +1,4 @@
+#include <GL/glew.h>
 #include <GLFW/glfw3.h>
 #include "CGLFWWindowOutput.h"
 #include "WallpaperEngine/Logging/CLog.h"