Added scaling and clamp support

This commit is contained in:
Pasalc 2023-11-13 19:25:17 +03:00
parent 4212095335
commit 11666abf32
13 changed files with 371 additions and 109 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

@ -28,10 +28,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' },
{ "clamp-strategy", required_argument, nullptr, 't' }, { "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 +85,8 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
.mode = NORMAL_WINDOW, .mode = NORMAL_WINDOW,
.maximumFPS = 30, .maximumFPS = 30,
.pauseOnFullscreen = true, .pauseOnFullscreen = true,
.window = { .geometry = {}, .clamp = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVs, .scaleToFit=false }, .window = { .geometry = {}, .clamp = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVs,
.scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::DefaultUVs, },
}, },
.audio = .audio =
{ {
@ -105,6 +125,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 +154,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,25 +218,38 @@ CApplicationContext::CApplicationContext (int argc, char* argv[])
break; break;
case 't': case 't':
{ {
char opt = optarg[0]; size_t hash = customHash(optarg);
switch (opt) // Use a switch statement with the hash
{ switch (hash) {
case 's':/* stretch*/ // --scale options
this->settings.render.window.scaleToFit=true; case customHash("stretch"):
break; this->settings.render.window.scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::StretchUVs;
case 'b':/* clamp border (crop black)*/ break;
this->settings.render.window.clamp = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVsBorder;//clampStrategy(optarg); case customHash("fit"):
break; this->settings.render.window.scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::ZoomFitUVs;
case 'c':/* clamp*/ break;
this->settings.render.window.clamp = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVs; case customHash("fill"):
break; this->settings.render.window.scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::ZoomFillUVs;
case 'r': break;
this->settings.render.window.clamp = WallpaperEngine::Assets::ITexture::TextureFlags::NoFlags; case customHash("default"):
break; this->settings.render.window.scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::DefaultUVs;
default: break;
sLog.error("Wrong argument provided for clamp-strategy"); // --clamp options
break; 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; break;
@ -314,5 +349,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--clamp-strategy <strategy>\t Clamp strategy if wallpaper doesn't fit screen. Can be stretch, border, repeat, clamp. Can be shortend to s, b, r, c. Default is clamp"); 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

@ -12,6 +12,7 @@
#include "CApplicationState.h" #include "CApplicationState.h"
#include "WallpaperEngine/Assets/ITexture.h" #include "WallpaperEngine/Assets/ITexture.h"
#include "WallpaperEngine/Render/CWallpaperState.h"
namespace WallpaperEngine::Application namespace WallpaperEngine::Application
{ {
@ -52,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;
/** /**
@ -71,7 +74,7 @@ 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::Assets::ITexture::TextureFlags clamp;
bool scaleToFit; 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

@ -36,9 +36,9 @@ namespace WallpaperEngine::Render
// render the background // render the background
if (ref != this->m_wallpapers.end ()) if (ref != this->m_wallpapers.end ())
ref->second->render (viewport->viewport, this->getOutput ().renderVFlip (), this->getApp().getContext().settings.render.window.scaleToFit); ref->second->render (viewport->viewport, this->getOutput ().renderVFlip ());
else else
this->m_defaultWallpaper->render (viewport->viewport, this->getOutput ().renderVFlip (), this->getApp().getContext().settings.render.window.scaleToFit); this->m_defaultWallpaper->render (viewport->viewport, this->getOutput ().renderVFlip ());
#if !NDEBUG #if !NDEBUG
glPopDebugGroup (); glPopDebugGroup ();

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,78 +202,26 @@ 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::setTextureUVs(const glm::ivec4& viewport, const bool vflip, const bool scale, void CWallpaper::updateUVs(const glm::ivec4& viewport, const bool vflip){
float& ustart, float& uend, float& vstart, float& vend){ //update UVs if something has changed, otherwise use old values
if(this->m_state.hasChanged(viewport, vflip, this->getWidth(), this->getHeight())){
ustart = 0.0f; // Update wallpaper state
uend = 1.0f; this->m_state.updateState(viewport, vflip, this->getWidth(), this->getHeight());
vstart = 1.0f;
vend = 0.0f;
if (vflip){
vstart = 0.0f;
vend = 1.0f;
}
if(!scale){
uint32_t projectionWidth = this->getWidth ();
uint32_t projectionHeight = this->getHeight ();
const float m1 = float(viewport.z) / projectionWidth;
const float m2 = float(viewport.w) / projectionHeight;
const float m = std::max(m1,m2);
projectionWidth*=m;
projectionHeight*=m;
if (projectionWidth!=viewport.z)
{
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 (projectionHeight!=viewport.w)
{
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;
}
}
} }
} }
void CWallpaper::render (glm::ivec4 viewport, bool vflip, bool scale) void CWallpaper::render (glm::ivec4 viewport, bool vflip)
{ {
this->renderFrame (viewport); this->renderFrame (viewport);
//Update UVs coordinates according to scaling mode of this wallpaper
updateUVs(viewport,vflip);
auto [ ustart, uend, vstart, vend ] = this->m_state.getTextureUVs();
float ustart,uend,vstart,vend;
setTextureUVs(viewport, vflip, scale, ustart, uend, vstart, vend);
GLfloat texCoords [] = { GLfloat texCoords [] = {
ustart, vstart, ustart, vstart,
uend, vstart, uend, vstart,
@ -363,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;
@ -34,15 +36,10 @@ namespace WallpaperEngine::Render
~CWallpaper (); ~CWallpaper ();
/**
* Get texture UV coordinates for render
*/
void setTextureUVs(const glm::ivec4& viewport, const bool vflip, const bool scale,
float& ustart, float& uend, float& vstart, float& vend);
/** /**
* Performs a render pass of the wallpaper * Performs a render pass of the wallpaper
*/ */
void render (glm::ivec4 viewport, bool vflip, bool scale); void render (glm::ivec4 viewport, bool vflip);
/** /**
* @return The container to resolve files for this wallpaper * @return The container to resolve files for this wallpaper
@ -88,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
@ -116,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
@ -158,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;
};
}