diff --git a/es-core/src/GuiComponent.cpp b/es-core/src/GuiComponent.cpp index 0e4f21c36..60840fa91 100644 --- a/es-core/src/GuiComponent.cpp +++ b/es-core/src/GuiComponent.cpp @@ -33,6 +33,7 @@ GuiComponent::GuiComponent() , mSaturation {1.0f} , mDimming {1.0f} , mThemeOpacity {1.0f} + , mThemeSaturation {1.0f} , mRotation {0.0f} , mScale {1.0f} , mDefaultZIndex {0.0f} @@ -376,6 +377,9 @@ void GuiComponent::applyTheme(const std::shared_ptr& theme, else setVisible(true); + if (properties & ThemeFlags::SATURATION && elem->has("saturation")) + mThemeSaturation = glm::clamp(elem->get("saturation"), 0.0f, 1.0f); + if (properties && elem->has("gameselector")) mThemeGameSelector = elem->get("gameselector"); } diff --git a/es-core/src/GuiComponent.h b/es-core/src/GuiComponent.h index 51264766a..29f6da440 100644 --- a/es-core/src/GuiComponent.h +++ b/es-core/src/GuiComponent.h @@ -113,10 +113,10 @@ public: void setVisible(bool visible) { mVisible = visible; } // clang-format off - enum ComponentThemeFlags : unsigned int { - SCROLL_HIDE = 0x00000001, - SCROLL_FADE_IN = 0x00000002 - }; + enum ComponentThemeFlags : unsigned int { + SCROLL_HIDE = 0x00000001, + SCROLL_FADE_IN = 0x00000002 + }; // clang-format on const bool getScrollHide() { return mComponentThemeFlags & ComponentThemeFlags::SCROLL_HIDE; } @@ -303,6 +303,7 @@ protected: float mSaturation; float mDimming; float mThemeOpacity; + float mThemeSaturation; float mRotation; float mScale; float mDefaultZIndex; diff --git a/es-core/src/ThemeData.cpp b/es-core/src/ThemeData.cpp index 1eadcf2d6..f3ff24111 100644 --- a/es-core/src/ThemeData.cpp +++ b/es-core/src/ThemeData.cpp @@ -96,6 +96,7 @@ std::map> {"gradientType", STRING}, {"scrollFadeIn", BOOLEAN}, {"opacity", FLOAT}, + {"saturation", FLOAT}, {"visible", BOOLEAN}, {"zIndex", FLOAT}}}, {"video", @@ -116,6 +117,7 @@ std::map> {"fadeInTime", FLOAT}, {"scrollFadeIn", BOOLEAN}, {"opacity", FLOAT}, + {"saturation", FLOAT}, {"visible", BOOLEAN}, {"zIndex", FLOAT}, {"showSnapshotNoVideo", BOOLEAN}, // For backward compatibility with legacy themes. @@ -132,6 +134,7 @@ std::map> {"keepAspectRatio", BOOLEAN}, {"interpolation", STRING}, {"opacity", FLOAT}, + {"saturation", FLOAT}, {"visible", BOOLEAN}, {"zIndex", FLOAT}}}, {"badges", diff --git a/es-core/src/ThemeData.h b/es-core/src/ThemeData.h index f8509b2d6..118233cba 100644 --- a/es-core/src/ThemeData.h +++ b/es-core/src/ThemeData.h @@ -62,7 +62,8 @@ namespace ThemeFlags Z_INDEX = 0x00004000, ROTATION = 0x00008000, OPACITY = 0x00010000, - VISIBLE = 0x00020000, + SATURATION = 0x00020000, + VISIBLE = 0x00040000, ALL = 0xFFFFFFFF }; // clang-format on diff --git a/es-core/src/components/GIFAnimComponent.cpp b/es-core/src/components/GIFAnimComponent.cpp index bc859f428..1f6a882dc 100644 --- a/es-core/src/components/GIFAnimComponent.cpp +++ b/es-core/src/components/GIFAnimComponent.cpp @@ -488,7 +488,7 @@ void GIFAnimComponent::render(const glm::mat4& parentTrans) for (int i = 0; i < 4; ++i) vertices[i].position = glm::round(vertices[i].position); - vertices->saturation = mSaturation; + vertices->saturation = mSaturation * mThemeSaturation; vertices->opacity = mOpacity * mThemeOpacity; vertices->dimming = mDimming; vertices->shaderFlags = Renderer::ShaderFlags::BGRA_TO_RGBA; diff --git a/es-core/src/components/ImageComponent.cpp b/es-core/src/components/ImageComponent.cpp index c1e7bee9f..c9fe5f5d6 100644 --- a/es-core/src/components/ImageComponent.cpp +++ b/es-core/src/components/ImageComponent.cpp @@ -419,7 +419,7 @@ void ImageComponent::render(const glm::mat4& parentTrans) else fadeIn(mTexture->bind()); - mVertices->saturation = mSaturation; + mVertices->saturation = mSaturation * mThemeSaturation; mVertices->opacity = mThemeOpacity; mVertices->dimming = mDimming; diff --git a/es-core/src/components/LottieAnimComponent.cpp b/es-core/src/components/LottieAnimComponent.cpp index 32d160ac7..0ec026af9 100644 --- a/es-core/src/components/LottieAnimComponent.cpp +++ b/es-core/src/components/LottieAnimComponent.cpp @@ -477,7 +477,7 @@ void LottieAnimComponent::render(const glm::mat4& parentTrans) for (int i = 0; i < 4; ++i) vertices[i].position = glm::round(vertices[i].position); - vertices->saturation = mSaturation; + vertices->saturation = mSaturation * mThemeSaturation; vertices->opacity = mOpacity * mThemeOpacity; vertices->dimming = mDimming; vertices->shaderFlags = Renderer::ShaderFlags::BGRA_TO_RGBA; diff --git a/es-core/src/components/VideoComponent.cpp b/es-core/src/components/VideoComponent.cpp index 7fdd63c88..64a1c3fc9 100644 --- a/es-core/src/components/VideoComponent.cpp +++ b/es-core/src/components/VideoComponent.cpp @@ -277,6 +277,7 @@ void VideoComponent::renderSnapshot(const glm::mat4& parentTrans) if (mStaticImagePath != "") { mStaticImage.setOpacity(mOpacity * mThemeOpacity); + mStaticImage.setSaturation(mSaturation * mThemeSaturation); mStaticImage.setDimming(mDimming); mStaticImage.render(parentTrans); } diff --git a/es-core/src/components/VideoFFmpegComponent.cpp b/es-core/src/components/VideoFFmpegComponent.cpp index 2768d36f7..b8975b4f4 100644 --- a/es-core/src/components/VideoFFmpegComponent.cpp +++ b/es-core/src/components/VideoFFmpegComponent.cpp @@ -165,10 +165,10 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans) for (int i = 0; i < 4; ++i) vertices[i].position = glm::round(vertices[i].position); - if (mDecodedFrame && (mFadeIn < 1.0f || mThemeOpacity < 1.0f)) + if (mFadeIn < 1.0f || mThemeOpacity < 1.0f) vertices->opacity = mFadeIn * mThemeOpacity; - vertices->saturation = mSaturation; + vertices->saturation = mSaturation * mThemeSaturation; vertices->dimming = mDimming; std::unique_lock pictureLock(mPictureMutex); diff --git a/es-core/src/renderers/RendererOpenGL.cpp b/es-core/src/renderers/RendererOpenGL.cpp index b3b53b1c1..97c3845f9 100644 --- a/es-core/src/renderers/RendererOpenGL.cpp +++ b/es-core/src/renderers/RendererOpenGL.cpp @@ -446,6 +446,7 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices, GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_DYNAMIC_DRAW)); mScanlinelShader->setOpacity(vertices->opacity); + mScanlinelShader->setSaturation(vertices->saturation); mScanlinelShader->setTextureSize({shaderWidth, shaderHeight}); GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); mLastShader = mScanlinelShader; diff --git a/resources/shaders/glsl/scanlines.glsl b/resources/shaders/glsl/scanlines.glsl index 69f1633ba..960a0065e 100644 --- a/resources/shaders/glsl/scanlines.glsl +++ b/resources/shaders/glsl/scanlines.glsl @@ -54,6 +54,7 @@ precision mediump float; uniform vec2 textureSize; uniform float opacity; +uniform float saturation; uniform sampler2D textureSampler; in vec2 texCoord; in vec2 onex; @@ -100,6 +101,13 @@ void main() float h_weight_00 = dx / SPOT_WIDTH; WEIGHT(h_weight_00); + // Saturation. + if (saturation != 1.0) { + vec3 grayscale = vec3(dot(color.rgb, vec3(0.34, 0.55, 0.11))); + vec3 blendedColor = mix(grayscale, color.rgb, saturation); + color = vec4(blendedColor, color.a); + } + color *= vec4(h_weight_00, h_weight_00, h_weight_00, h_weight_00); // Get closest horizontal neighbour to blend. @@ -114,6 +122,13 @@ void main() } vec4 colorNB = TEX2D(texture_coords + coords01); + // Saturation. + if (saturation != 1.0) { + vec3 grayscale = vec3(dot(colorNB.rgb, vec3(0.34, 0.55, 0.11))); + vec3 blendedColor = mix(grayscale, colorNB.rgb, saturation); + colorNB = vec4(blendedColor, colorNB.a); + } + float h_weight_01 = dx / SPOT_WIDTH; WEIGHT(h_weight_01); @@ -137,6 +152,13 @@ void main() } colorNB = TEX2D(texture_coords + coords10); + // Saturation. + if (saturation != 1.0) { + vec3 grayscale = vec3(dot(colorNB.rgb, vec3(0.34, 0.55, 0.11))); + vec3 blendedColor = mix(grayscale, colorNB.rgb, saturation); + colorNB = vec4(blendedColor, colorNB.a); + } + float v_weight_10 = dy / SPOT_HEIGHT; WEIGHT(v_weight_10);