aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--example/hyprland.conf2
-rw-r--r--src/config/ConfigManager.cpp58
-rw-r--r--src/render/OpenGL.cpp77
-rw-r--r--src/render/OpenGL.hpp1
-rw-r--r--src/render/Shader.hpp18
-rw-r--r--src/render/shaders/Textures.hpp190
6 files changed, 266 insertions, 80 deletions
diff --git a/example/hyprland.conf b/example/hyprland.conf
index 698335ea..0f830ec3 100644
--- a/example/hyprland.conf
+++ b/example/hyprland.conf
@@ -63,6 +63,8 @@ decoration {
enabled = true
size = 3
passes = 1
+
+ vibrancy = 0.1696
}
drop_shadow = true
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 760e9e87..d07e6a6a 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -153,34 +153,36 @@ void CConfigManager::setDefaultVars() {
configValues["debug:suppress_errors"].intValue = 0;
configValues["debug:watchdog_timeout"].intValue = 5;
- configValues["decoration:rounding"].intValue = 0;
- configValues["decoration:blur:enabled"].intValue = 1;
- configValues["decoration:blur:size"].intValue = 8;
- configValues["decoration:blur:passes"].intValue = 1;
- configValues["decoration:blur:ignore_opacity"].intValue = 0;
- configValues["decoration:blur:new_optimizations"].intValue = 1;
- configValues["decoration:blur:xray"].intValue = 0;
- configValues["decoration:blur:noise"].floatValue = 0.0117;
- configValues["decoration:blur:contrast"].floatValue = 0.8916;
- configValues["decoration:blur:brightness"].floatValue = 0.8172;
- configValues["decoration:blur:special"].intValue = 0;
- configValues["decoration:active_opacity"].floatValue = 1;
- configValues["decoration:inactive_opacity"].floatValue = 1;
- configValues["decoration:fullscreen_opacity"].floatValue = 1;
- configValues["decoration:no_blur_on_oversized"].intValue = 0;
- configValues["decoration:drop_shadow"].intValue = 1;
- configValues["decoration:shadow_range"].intValue = 4;
- configValues["decoration:shadow_render_power"].intValue = 3;
- configValues["decoration:shadow_ignore_window"].intValue = 1;
- configValues["decoration:shadow_offset"].vecValue = Vector2D();
- configValues["decoration:shadow_scale"].floatValue = 1.f;
- configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
- configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
- configValues["decoration:dim_inactive"].intValue = 0;
- configValues["decoration:dim_strength"].floatValue = 0.5f;
- configValues["decoration:dim_special"].floatValue = 0.2f;
- configValues["decoration:dim_around"].floatValue = 0.4f;
- configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
+ configValues["decoration:rounding"].intValue = 0;
+ configValues["decoration:blur:enabled"].intValue = 1;
+ configValues["decoration:blur:size"].intValue = 8;
+ configValues["decoration:blur:passes"].intValue = 1;
+ configValues["decoration:blur:ignore_opacity"].intValue = 0;
+ configValues["decoration:blur:new_optimizations"].intValue = 1;
+ configValues["decoration:blur:xray"].intValue = 0;
+ configValues["decoration:blur:contrast"].floatValue = 0.8916;
+ configValues["decoration:blur:brightness"].floatValue = 1.0;
+ configValues["decoration:blur:vibrancy"].floatValue = 0.1696;
+ configValues["decoration:blur:vibrancy_darkness"].floatValue = 0.0;
+ configValues["decoration:blur:noise"].floatValue = 0.0117;
+ configValues["decoration:blur:special"].intValue = 0;
+ configValues["decoration:active_opacity"].floatValue = 1;
+ configValues["decoration:inactive_opacity"].floatValue = 1;
+ configValues["decoration:fullscreen_opacity"].floatValue = 1;
+ configValues["decoration:no_blur_on_oversized"].intValue = 0;
+ configValues["decoration:drop_shadow"].intValue = 1;
+ configValues["decoration:shadow_range"].intValue = 4;
+ configValues["decoration:shadow_render_power"].intValue = 3;
+ configValues["decoration:shadow_ignore_window"].intValue = 1;
+ configValues["decoration:shadow_offset"].vecValue = Vector2D();
+ configValues["decoration:shadow_scale"].floatValue = 1.f;
+ configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
+ configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
+ configValues["decoration:dim_inactive"].intValue = 0;
+ configValues["decoration:dim_strength"].floatValue = 0.5f;
+ configValues["decoration:dim_special"].floatValue = 0.2f;
+ configValues["decoration:dim_around"].floatValue = 0.4f;
+ configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:force_split"].intValue = 0;
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 690b0ede..e047f287 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -307,15 +307,18 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shEXT.applyTint = glGetUniformLocation(prog, "applyTint");
m_RenderData.pCurrentMonData->m_shEXT.tint = glGetUniformLocation(prog, "tint");
- prog = createProgram(TEXVERTSRC, FRAGBLUR1);
- m_RenderData.pCurrentMonData->m_shBLUR1.program = prog;
- m_RenderData.pCurrentMonData->m_shBLUR1.tex = glGetUniformLocation(prog, "tex");
- m_RenderData.pCurrentMonData->m_shBLUR1.alpha = glGetUniformLocation(prog, "alpha");
- m_RenderData.pCurrentMonData->m_shBLUR1.proj = glGetUniformLocation(prog, "proj");
- m_RenderData.pCurrentMonData->m_shBLUR1.posAttrib = glGetAttribLocation(prog, "pos");
- m_RenderData.pCurrentMonData->m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord");
- m_RenderData.pCurrentMonData->m_shBLUR1.radius = glGetUniformLocation(prog, "radius");
- m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel = glGetUniformLocation(prog, "halfpixel");
+ prog = createProgram(TEXVERTSRC, FRAGBLUR1);
+ m_RenderData.pCurrentMonData->m_shBLUR1.program = prog;
+ m_RenderData.pCurrentMonData->m_shBLUR1.tex = glGetUniformLocation(prog, "tex");
+ m_RenderData.pCurrentMonData->m_shBLUR1.alpha = glGetUniformLocation(prog, "alpha");
+ m_RenderData.pCurrentMonData->m_shBLUR1.proj = glGetUniformLocation(prog, "proj");
+ m_RenderData.pCurrentMonData->m_shBLUR1.posAttrib = glGetAttribLocation(prog, "pos");
+ m_RenderData.pCurrentMonData->m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord");
+ m_RenderData.pCurrentMonData->m_shBLUR1.radius = glGetUniformLocation(prog, "radius");
+ m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel = glGetUniformLocation(prog, "halfpixel");
+ m_RenderData.pCurrentMonData->m_shBLUR1.passes = glGetUniformLocation(prog, "passes");
+ m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy = glGetUniformLocation(prog, "vibrancy");
+ m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy_darkness = glGetUniformLocation(prog, "vibrancy_darkness");
prog = createProgram(TEXVERTSRC, FRAGBLUR2);
m_RenderData.pCurrentMonData->m_shBLUR2.program = prog;
@@ -327,15 +330,23 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shBLUR2.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel");
+ prog = createProgram(TEXVERTSRC, FRAGBLURPREPARE);
+ m_RenderData.pCurrentMonData->m_shBLURPREPARE.program = prog;
+ m_RenderData.pCurrentMonData->m_shBLURPREPARE.tex = glGetUniformLocation(prog, "tex");
+ m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj = glGetUniformLocation(prog, "proj");
+ m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib = glGetAttribLocation(prog, "pos");
+ m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib = glGetAttribLocation(prog, "texcoord");
+ m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast = glGetUniformLocation(prog, "contrast");
+ m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness = glGetUniformLocation(prog, "brightness");
+
prog = createProgram(TEXVERTSRC, FRAGBLURFINISH);
m_RenderData.pCurrentMonData->m_shBLURFINISH.program = prog;
m_RenderData.pCurrentMonData->m_shBLURFINISH.tex = glGetUniformLocation(prog, "tex");
m_RenderData.pCurrentMonData->m_shBLURFINISH.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib = glGetAttribLocation(prog, "texcoord");
- m_RenderData.pCurrentMonData->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise");
- m_RenderData.pCurrentMonData->m_shBLURFINISH.contrast = glGetUniformLocation(prog, "contrast");
m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness = glGetUniformLocation(prog, "brightness");
+ m_RenderData.pCurrentMonData->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise");
prog = createProgram(QUADVERTSRC, FRAGSHADOW);
m_RenderData.pCurrentMonData->m_shSHADOW.program = prog;
@@ -912,8 +923,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
// get the config settings
- static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur:size")->intValue;
- static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur:passes")->intValue;
+ static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur:size")->intValue;
+ static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur:passes")->intValue;
+ static auto* const PBLURVIBRANCY = &g_pConfigManager->getConfigValuePtr("decoration:blur:vibrancy")->floatValue;
+ static auto* const PBLURVIBRANCYDARKNESS = &g_pConfigManager->getConfigValuePtr("decoration:blur:vibrancy_darkness")->floatValue;
// prep damage
CRegion damage{*originalDamage};
@@ -927,7 +940,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
CFramebuffer* currentRenderToFB = PMIRRORFB;
- // begin with color adjustments
+ // Begin with base color adjustments - global brightness and contrast
// TODO: make this a part of the first pass maybe to save on a drawcall?
{
static auto* const PBLURCONTRAST = &g_pConfigManager->getConfigValuePtr("decoration:blur:contrast")->floatValue;
@@ -941,24 +954,23 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glTexParameteri(m_RenderData.pCurrentMonData->primaryFB.m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program);
+ glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program);
#ifndef GLES2
- glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix);
+ glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix);
#else
wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix);
#endif
- glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.contrast, *PBLURCONTRAST);
- glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS);
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST);
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS);
+ glUniform1i(m_RenderData.pCurrentMonData->m_shBLURPREPARE.tex, 0);
- glUniform1i(m_RenderData.pCurrentMonData->m_shBLURFINISH.tex, 0);
+ glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
+ glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
- glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
- glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
-
- glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib);
- glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib);
+ glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib);
+ glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib);
if (!damage.empty()) {
for (auto& RECT : damage.getRects()) {
@@ -967,8 +979,8 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
}
}
- glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib);
- glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib);
+ glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib);
+ glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib);
currentRenderToFB = PMIRRORSWAPFB;
}
@@ -996,10 +1008,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a
- if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1)
+ if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) {
glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f),
0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f));
- else
+ glUniform1i(m_RenderData.pCurrentMonData->m_shBLUR1.passes, *PBLURPASSES);
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy, *PBLURVIBRANCY);
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy_darkness, *PBLURVIBRANCYDARKNESS);
+ } else
glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f),
0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f));
glUniform1i(pShader->tex, 0);
@@ -1045,9 +1060,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up
}
- // finalize with noise
+ // finalize the image
{
- static auto* const PBLURNOISE = &g_pConfigManager->getConfigValuePtr("decoration:blur:noise")->floatValue;
+ static auto* const PBLURNOISE = &g_pConfigManager->getConfigValuePtr("decoration:blur:noise")->floatValue;
+ static auto* const PBLURBRIGHTNESS = &g_pConfigManager->getConfigValuePtr("decoration:blur:brightness")->floatValue;
if (currentRenderToFB == PMIRRORFB)
PMIRRORSWAPFB->bind();
@@ -1069,6 +1085,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE);
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS);
glUniform1i(m_RenderData.pCurrentMonData->m_shBLURFINISH.tex, 0);
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 7e3e4e7c..0c6ef13c 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -64,6 +64,7 @@ struct SMonitorRenderData {
CShader m_shEXT;
CShader m_shBLUR1;
CShader m_shBLUR2;
+ CShader m_shBLURPREPARE;
CShader m_shBLURFINISH;
CShader m_shSHADOW;
CShader m_shBORDER1;
diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp
index b67f61ef..70fe468c 100644
--- a/src/render/Shader.hpp
+++ b/src/render/Shader.hpp
@@ -46,13 +46,21 @@ class CShader {
GLint distort = -1;
GLint output = -1;
- GLint noise = -1;
- GLint contrast = -1;
- GLint brightness = -1;
+ // Blur prepare
+ GLint contrast = -1;
- GLint getUniformLocation(const std::string&);
+ // Blur
+ GLint passes = -1; // Used by `vibrancy`
+ GLint vibrancy = -1;
+ GLint vibrancy_darkness = -1;
- void destroy();
+ // Blur finish
+ GLint brightness = -1;
+ GLint noise = -1;
+
+ GLint getUniformLocation(const std::string&);
+
+ void destroy();
private:
std::unordered_map<std::string, GLint> m_muUniforms;
diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp
index cf753bb4..15e80410 100644
--- a/src/render/shaders/Textures.hpp
+++ b/src/render/shaders/Textures.hpp
@@ -180,12 +180,116 @@ void main() {
inline const std::string FRAGBLUR1 = R"#(
#version 100
-precision mediump float;
+precision mediump float;
varying mediump vec2 v_texcoord; // is in 0-1
-uniform sampler2D tex;
+uniform sampler2D tex;
+
+uniform float radius;
+uniform vec2 halfpixel;
+uniform int passes;
+uniform float vibrancy;
+uniform float vibrancy_darkness;
+
+// see http://alienryderflex.com/hsp.html
+const float Pr = 0.299;
+const float Pg = 0.587;
+const float Pb = 0.114;
+
+// Y is "v" ( brightness ). X is "s" ( saturation )
+// see https://www.desmos.com/3d/a88652b9a4
+// Determines if high brightness or high saturation is more important
+const float a = 0.93;
+const float b = 0.11;
+const float c = 0.66; // Determines the smoothness of the transition of unboosted to boosted colors
+//
+
+// http://www.flong.com/archive/texts/code/shapers_circ/
+float doubleCircleSigmoid(float x, float a) {
+ float min_param_a = 0.0;
+ float max_param_a = 1.0;
+ a = max(min_param_a, min(max_param_a, a));
+
+ float y = .0;
+ if (x <= a) {
+ y = a - sqrt(a * a - x * x);
+ } else {
+ y = a + sqrt(pow(1. - a, 2.) - pow(x - 1., 2.));
+ }
+ return y;
+}
-uniform float radius;
-uniform vec2 halfpixel;
+vec3 rgb2hsl(vec3 col) {
+ float red = col.r;
+ float green = col.g;
+ float blue = col.b;
+
+ float minc = min(col.r, min(col.g, col.b));
+ float maxc = max(col.r, max(col.g, col.b));
+ float delta = maxc - minc;
+
+ float lum = (minc + maxc) * 0.5;
+ float sat = 0.0;
+ float hue = 0.0;
+
+ if (lum > 0.0 && lum < 1.0) {
+ float mul = (lum < 0.5) ? (lum) : (1.0 - lum);
+ sat = delta / (mul * 2.0);
+ }
+
+ vec3 masks = vec3((maxc == red && maxc != green) ? 1.0 : 0.0, (maxc == green && maxc != blue) ? 1.0 : 0.0, (maxc == blue && maxc != red) ? 1.0 : 0.0);
+
+ vec3 adds = vec3(((green - blue) / delta), 2.0 + ((blue - red) / delta), 4.0 + ((red - green) / delta));
+
+ float deltaGtz = (delta > 0.0) ? 1.0 : 0.0;
+
+ hue += dot(adds, masks);
+ hue *= deltaGtz;
+ hue /= 6.0;
+
+ if (hue < 0.0)
+ hue += 1.0;
+
+ return vec3(hue, sat, lum);
+}
+vec3 hsl2rgb(vec3 col) {
+ const float onethird = 1.0 / 3.0;
+ const float twothird = 2.0 / 3.0;
+ const float rcpsixth = 6.0;
+
+ float hue = col.x;
+ float sat = col.y;
+ float lum = col.z;
+
+ vec3 xt = vec3(rcpsixth * (hue - twothird), 0.0, rcpsixth * (1.0 - hue));
+
+ if (hue < twothird) {
+ xt.r = 0.0;
+ xt.g = rcpsixth * (twothird - hue);
+ xt.b = rcpsixth * (hue - onethird);
+ }
+
+ if (hue < onethird) {
+ xt.r = rcpsixth * (onethird - hue);
+ xt.g = rcpsixth * hue;
+ xt.b = 0.0;
+ }
+
+ xt = min(xt, 1.0);
+
+ float sat2 = 2.0 * sat;
+ float satinv = 1.0 - sat;
+ float luminv = 1.0 - lum;
+ float lum2m1 = (2.0 * lum) - 1.0;
+ vec3 ct = (sat2 * xt) + satinv;
+
+ vec3 rgb;
+ if (lum >= 0.5)
+ rgb = (luminv * ct) + lum2m1;
+ else
+ rgb = lum * ct;
+
+ return rgb;
+}
void main() {
vec2 uv = v_texcoord * 2.0;
@@ -196,7 +300,28 @@ void main() {
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
- gl_FragColor = sum / 8.0;
+ vec4 color = sum / 8.0;
+
+ if (vibrancy == 0.0) {
+ gl_FragColor = color;
+ } else {
+ // Invert it so that it correctly maps to the config setting
+ float vibrancy_darkness1 = 1.0 - vibrancy_darkness;
+
+ // Decrease the RGB components based on their perceived brightness, to prevent visually dark colors from overblowing the rest.
+ vec3 hsl = rgb2hsl(color.rgb);
+ // Calculate perceived brightness, as not boost visually dark colors like deep blue as much as equally saturated yellow
+ float perceivedBrightness = doubleCircleSigmoid(sqrt(color.r * color.r * Pr + color.g * color.g * Pg + color.b * color.b * Pb), 0.8 * vibrancy_darkness1);
+
+ float b1 = b * vibrancy_darkness1;
+ float boostBase = hsl[1] > 0.0 ? smoothstep(b1 - c * 0.5, b1 + c * 0.5, 1.0 - (pow(1.0 - hsl[1] * cos(a), 2.0) + pow(1.0 - perceivedBrightness * sin(a), 2.0))) : 0.0;
+
+ float saturation = clamp(hsl[1] + (boostBase * vibrancy) / float(passes), 0.0, 1.0);
+
+ vec3 newColor = hsl2rgb(vec3(hsl[0], saturation, hsl[2]));
+
+ gl_FragColor = vec4(newColor, color[3]);
+ }
}
)#";
@@ -226,35 +351,66 @@ void main() {
}
)#";
-inline const std::string FRAGBLURFINISH = R"#(
-precision mediump float;
-varying vec2 v_texcoord; // is in 0-1
+inline const std::string FRAGBLURPREPARE = R"#(
+precision mediump float;
+varying vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
-uniform float contrast;
-uniform float noise;
-uniform float brightness;
+uniform float contrast;
+uniform float brightness;
-float hash(vec2 p) {
- return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
+float gain(float x, float k) {
+ float a = 0.5 * pow(2.0 * ((x < 0.5) ? x : 1.0 - x), k);
+ return (x < 0.5) ? a : 1.0 - a;
}
void main() {
vec4 pixColor = texture2D(tex, v_texcoord);
// contrast
- pixColor.rgb = (pixColor.rgb - 0.5) * contrast + 0.5;
+ if (contrast != 1.0) {
+ pixColor.r = gain(pixColor.r, contrast);
+ pixColor.g = gain(pixColor.g, contrast);
+ pixColor.b = gain(pixColor.b, contrast);
+ }
// brightness
- pixColor.rgb *= brightness;
+ if (brightness > 1.0) {
+ pixColor.rgb *= brightness;
+ }
+
+ gl_FragColor = pixColor;
+}
+)#";
+
+inline const std::string FRAGBLURFINISH = R"#(
+precision mediump float;
+varying vec2 v_texcoord; // is in 0-1
+uniform sampler2D tex;
+
+uniform float noise;
+uniform float brightness;
+
+float hash(vec2 p) {
+ return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
+}
+
+void main() {
+ vec4 pixColor = texture2D(tex, v_texcoord);
// noise
- float noiseHash = hash(v_texcoord);
+ float noiseHash = hash(v_texcoord);
float noiseAmount = (mod(noiseHash, 1.0) - 0.5);
pixColor.rgb += noiseAmount * noise;
+ // brightness
+ if (brightness < 1.0) {
+ pixColor.rgb *= brightness;
+ }
+
gl_FragColor = pixColor;
-})#";
+}
+)#";
inline const std::string TEXFRAGSRCEXT = R"#(
#extension GL_OES_EGL_image_external : require