Merge pull request #188 from Pasalc/viewport-clamp

Fixed texture clamping caused by texture coordinates being outside of (0,1) interval
This commit is contained in:
Alexis Maiquez 2023-12-12 01:06:19 +01:00 committed by GitHub
commit 51db2962e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 388 additions and 88 deletions

View File

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

View File

@ -29,9 +29,29 @@ struct option long_options[] = {
{ "noautomute", no_argument, nullptr, 'm' }, { "noautomute", no_argument, nullptr, 'm' },
{ "no-fullscreen-pause", no_argument, nullptr, 'n' }, { "no-fullscreen-pause", no_argument, nullptr, 'n' },
{ "disable-mouse", no_argument, nullptr, 'e' }, { "disable-mouse", no_argument, nullptr, 'e' },
{ "scaling", required_argument, nullptr, 't' },
{ "clamping", required_argument, nullptr, 't' },
{ nullptr, 0, nullptr, 0 } { 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) std::string stringPathFixes (const std::string& s)
{ {
if (s.empty ()) if (s.empty ())
@ -66,7 +86,8 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
.mode = NORMAL_WINDOW, .mode = NORMAL_WINDOW,
.maximumFPS = 30, .maximumFPS = 30,
.pauseOnFullscreen = true, .pauseOnFullscreen = true,
.window = { .geometry = {}}, .window = { .geometry = {}, .clamp = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVs,
.scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::DefaultUVs, },
}, },
.audio = .audio =
{ {
@ -90,7 +111,7 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
std::string lastScreen; 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) 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 // no need to check for previous screen being in the list, as it's the only way for this variable
// to have any value // to have any value
this->settings.general.screenBackgrounds[lastScreen] = translateBackground (optarg); this->settings.general.screenBackgrounds[lastScreen] = translateBackground (optarg);
this->settings.general.screenScalings[lastScreen] = this->settings.render.window.scalingMode;
break; break;
case 'o': case 'o':
@ -133,6 +155,7 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
this->settings.render.mode = DESKTOP_BACKGROUND; this->settings.render.mode = DESKTOP_BACKGROUND;
lastScreen = optarg; lastScreen = optarg;
this->settings.general.screenBackgrounds[lastScreen] = ""; this->settings.general.screenBackgrounds[lastScreen] = "";
this->settings.general.screenScalings[lastScreen] = this->settings.render.window.scalingMode;
break; break;
case 'w': case 'w':
@ -196,6 +219,42 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
this->settings.mouse.enabled = false; this->settings.mouse.enabled = false;
break; 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: default:
sLog.out ("Default on path parsing: ", optarg); sLog.out ("Default on path parsing: ", optarg);
break; 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--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--no-fullscreen-pause\tPrevents the background pausing when an app is fullscreen");
sLog.out ("\t--disable-mouse\tDisables mouse interactions"); 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.");
} }

View File

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

View File

@ -322,13 +322,13 @@ namespace WallpaperEngine::Application
for (const auto& it : this->m_backgrounds) for (const auto& it : this->m_backgrounds)
context->setWallpaper ( context->setWallpaper (
it.first, 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 // set the default rendering wallpaper if available
if (this->m_defaultBackground != nullptr) if (this->m_defaultBackground != nullptr)
context->setDefaultWallpaper (WallpaperEngine::Render::CWallpaper::fromWallpaper ( 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; static time_t seconds;

View File

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

View File

@ -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_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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 else
{ {
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@
using namespace WallpaperEngine::Render; 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), CContextAware (context),
m_wallpaperData (wallpaperData), m_wallpaperData (wallpaperData),
m_type (std::move(type)), m_type (std::move(type)),
@ -22,7 +22,8 @@ CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRend
a_Position (GL_NONE), a_Position (GL_NONE),
a_TexCoord (GL_NONE), a_TexCoord (GL_NONE),
m_vaoBuffer (GL_NONE), m_vaoBuffer (GL_NONE),
m_audioContext (audioContext) m_audioContext (audioContext),
m_state(scalingMode)
{ {
// generate the VAO to stop opengl from complaining // generate the VAO to stop opengl from complaining
glGenVertexArrays (1, &this->m_vaoBuffer); glGenVertexArrays (1, &this->m_vaoBuffer);
@ -201,81 +202,25 @@ void CWallpaper::setupShaders ()
this->a_TexCoord = glGetAttribLocation (this->m_shader, "a_TexCoord"); 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) void CWallpaper::setDestinationFramebuffer (GLuint framebuffer)
{ {
this->m_destFramebuffer = 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) void CWallpaper::render (glm::ivec4 viewport, bool vflip)
{ {
this->renderFrame (viewport); this->renderFrame (viewport);
//Update UVs coordinates according to scaling mode of this wallpaper
uint32_t projectionWidth = this->getWidth (); updateUVs(viewport,vflip);
uint32_t projectionHeight = this->getHeight (); auto [ ustart, uend, vstart, vend ] = this->m_state.getTextureUVs();
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;
}
}
GLfloat texCoords [] = { GLfloat texCoords [] = {
ustart, vstart, ustart, vstart,
@ -319,12 +264,13 @@ void CWallpaper::setupFramebuffers ()
{ {
uint32_t width = this->getWidth (); uint32_t width = this->getWidth ();
uint32_t height = this->getHeight (); uint32_t height = this->getHeight ();
ITexture::TextureFlags clamp = this->getContext().getApp().getContext().settings.render.window.clamp;
// create framebuffer for the scene // create framebuffer for the scene
this->m_sceneFBO = this->createFBO ( this->m_sceneFBO = this->createFBO (
"_rt_FullFrameBuffer", "_rt_FullFrameBuffer",
ITexture::TextureFormat::ARGB8888, ITexture::TextureFormat::ARGB8888,
ITexture::TextureFlags::ClampUVs, clamp,
1.0, 1.0,
width, height, width, height,
width, height width, height
@ -366,12 +312,12 @@ CFBO* CWallpaper::getFBO () const
return this->m_sceneFBO; 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> ()) 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> ()) 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 else
sLog.exception ("Unsupported wallpaper type"); sLog.exception ("Unsupported wallpaper type");
} }

View File

@ -14,6 +14,8 @@
#include "WallpaperEngine/Render/CFBO.h" #include "WallpaperEngine/Render/CFBO.h"
#include "WallpaperEngine/Render/Helpers/CContextAware.h" #include "WallpaperEngine/Render/Helpers/CContextAware.h"
#include "CWallpaperState.h"
using namespace WallpaperEngine::Assets; using namespace WallpaperEngine::Assets;
using namespace WallpaperEngine::Audio; using namespace WallpaperEngine::Audio;
@ -83,9 +85,9 @@ namespace WallpaperEngine::Render
[[nodiscard]] CFBO* getFBO () const; [[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 * Updates the destination framebuffer for this wallpaper
@ -111,10 +113,10 @@ namespace WallpaperEngine::Render
* *
* @return * @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: 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 * Renders a frame of the wallpaper
@ -153,5 +155,7 @@ namespace WallpaperEngine::Render
std::map<std::string, CFBO*> m_fbos; std::map<std::string, CFBO*> m_fbos;
/** Audio context that is using this wallpaper */ /** Audio context that is using this wallpaper */
CAudioContext& m_audioContext; CAudioContext& m_audioContext;
/** Current Wallpaper state */
CWallpaperState m_state;
}; };
} }

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

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