background: add blurring

This commit is contained in:
Vaxry 2024-02-21 22:19:01 +00:00
parent 2836f02ded
commit 1b57d52179
8 changed files with 645 additions and 13 deletions

View file

@ -27,6 +27,13 @@ void CConfigManager::init() {
m_config.addSpecialConfigValue("background", "monitor", Hyprlang::STRING{""});
m_config.addSpecialConfigValue("background", "path", Hyprlang::STRING{""});
m_config.addSpecialConfigValue("background", "color", Hyprlang::INT{0xFF111111});
m_config.addSpecialConfigValue("background", "blur_size", Hyprlang::INT{8});
m_config.addSpecialConfigValue("background", "blur_passes", Hyprlang::INT{0});
m_config.addSpecialConfigValue("background", "noise", Hyprlang::FLOAT{0.0117});
m_config.addSpecialConfigValue("background", "contrast", Hyprlang::FLOAT{0.8917});
m_config.addSpecialConfigValue("background", "brightness", Hyprlang::FLOAT{0.8172});
m_config.addSpecialConfigValue("background", "vibrancy", Hyprlang::FLOAT{0.1686});
m_config.addSpecialConfigValue("background", "vibrancy_darkness", Hyprlang::FLOAT{0.05});
m_config.addSpecialCategory("input-field", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
m_config.addSpecialConfigValue("input-field", "monitor", Hyprlang::STRING{""});
@ -83,6 +90,13 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
{
{"path", m_config.getSpecialConfigValue("background", "path", k.c_str())},
{"color", m_config.getSpecialConfigValue("background", "color", k.c_str())},
{"blur_size", m_config.getSpecialConfigValue("background", "blur_size", k.c_str())},
{"blur_passes", m_config.getSpecialConfigValue("background", "blur_passes", k.c_str())},
{"noise", m_config.getSpecialConfigValue("background", "noise", k.c_str())},
{"contrast", m_config.getSpecialConfigValue("background", "contrast", k.c_str())},
{"vibrancy", m_config.getSpecialConfigValue("background", "vibrancy", k.c_str())},
{"brightness", m_config.getSpecialConfigValue("background", "brightness", k.c_str())},
{"vibrancy_darkness", m_config.getSpecialConfigValue("background", "vibrancy_darkness", k.c_str())},
}
});
// clang-format on

View file

@ -0,0 +1,112 @@
#include "Framebuffer.hpp"
#include "../helpers/Log.hpp"
#include <libdrm/drm_fourcc.h>
static uint32_t drmFormatToGL(uint32_t drm) {
switch (drm) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010: return GL_RGB10_A2;
default: return GL_RGBA;
}
return GL_RGBA;
}
static uint32_t glFormatToType(uint32_t gl) {
return gl != GL_RGBA ? GL_UNSIGNED_INT_2_10_10_10_REV : GL_UNSIGNED_BYTE;
}
bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) {
bool firstAlloc = false;
uint32_t glFormat = drmFormatToGL(drmFormat);
uint32_t glType = glFormatToType(glFormat);
if (m_iFb == (uint32_t)-1) {
firstAlloc = true;
glGenFramebuffers(1, &m_iFb);
}
if (m_cTex.m_iTexID == 0) {
firstAlloc = true;
glGenTextures(1, &m_cTex.m_iTexID);
glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
if (firstAlloc || m_vSize != Vector2D(w, h)) {
glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID);
glTexImage2D(GL_TEXTURE_2D, 0, glFormat, w, h, 0, GL_RGBA, glType, 0);
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0);
if (m_pStencilTex) {
glBindTexture(GL_TEXTURE_2D, m_pStencilTex->m_iTexID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_pStencilTex->m_iTexID, 0);
}
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
Debug::log(ERR, "Framebuffer incomplete, couldn't create! (FB status: {})", status);
abort();
}
Debug::log(LOG, "Framebuffer created, status {}", status);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
m_vSize = Vector2D(w, h);
return true;
}
void CFramebuffer::addStencil() {
glBindTexture(GL_TEXTURE_2D, m_pStencilTex->m_iTexID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_vSize.x, m_vSize.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_pStencilTex->m_iTexID, 0);
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Failed adding a stencil to fbo!", status);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void CFramebuffer::bind() const {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iFb);
glViewport(0, 0, m_vSize.x, m_vSize.y);
}
void CFramebuffer::release() {
if (m_iFb != (uint32_t)-1 && m_iFb)
glDeleteFramebuffers(1, &m_iFb);
if (m_cTex.m_iTexID)
glDeleteTextures(1, &m_cTex.m_iTexID);
m_cTex.m_iTexID = 0;
m_iFb = -1;
m_vSize = Vector2D();
}
CFramebuffer::~CFramebuffer() {
release();
}
bool CFramebuffer::isAllocated() {
return m_iFb != (GLuint)-1;
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "../helpers/Vector2D.hpp"
#include <GLES3/gl32.h>
#include "Texture.hpp"
class CFramebuffer {
public:
~CFramebuffer();
bool alloc(int w, int h, uint32_t format = GL_RGBA);
void addStencil();
void bind() const;
void release();
void reset();
bool isAllocated();
Vector2D m_vSize;
CTexture m_cTex;
GLuint m_iFb = -1;
CTexture* m_pStencilTex = nullptr;
};

View file

@ -106,6 +106,47 @@ CRenderer::CRenderer() {
texShader.tint = glGetUniformLocation(prog, "tint");
texShader.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte");
prog = createProgram(TEXVERTSRC, FRAGBLUR1);
blurShader1.program = prog;
blurShader1.tex = glGetUniformLocation(prog, "tex");
blurShader1.alpha = glGetUniformLocation(prog, "alpha");
blurShader1.proj = glGetUniformLocation(prog, "proj");
blurShader1.posAttrib = glGetAttribLocation(prog, "pos");
blurShader1.texAttrib = glGetAttribLocation(prog, "texcoord");
blurShader1.radius = glGetUniformLocation(prog, "radius");
blurShader1.halfpixel = glGetUniformLocation(prog, "halfpixel");
blurShader1.passes = glGetUniformLocation(prog, "passes");
blurShader1.vibrancy = glGetUniformLocation(prog, "vibrancy");
blurShader1.vibrancy_darkness = glGetUniformLocation(prog, "vibrancy_darkness");
prog = createProgram(TEXVERTSRC, FRAGBLUR2);
blurShader2.program = prog;
blurShader2.tex = glGetUniformLocation(prog, "tex");
blurShader2.alpha = glGetUniformLocation(prog, "alpha");
blurShader2.proj = glGetUniformLocation(prog, "proj");
blurShader2.posAttrib = glGetAttribLocation(prog, "pos");
blurShader2.texAttrib = glGetAttribLocation(prog, "texcoord");
blurShader2.radius = glGetUniformLocation(prog, "radius");
blurShader2.halfpixel = glGetUniformLocation(prog, "halfpixel");
prog = createProgram(TEXVERTSRC, FRAGBLURPREPARE);
blurPrepareShader.program = prog;
blurPrepareShader.tex = glGetUniformLocation(prog, "tex");
blurPrepareShader.proj = glGetUniformLocation(prog, "proj");
blurPrepareShader.posAttrib = glGetAttribLocation(prog, "pos");
blurPrepareShader.texAttrib = glGetAttribLocation(prog, "texcoord");
blurPrepareShader.contrast = glGetUniformLocation(prog, "contrast");
blurPrepareShader.brightness = glGetUniformLocation(prog, "brightness");
prog = createProgram(TEXVERTSRC, FRAGBLURFINISH);
blurFinishShader.program = prog;
blurFinishShader.tex = glGetUniformLocation(prog, "tex");
blurFinishShader.proj = glGetUniformLocation(prog, "proj");
blurFinishShader.posAttrib = glGetAttribLocation(prog, "pos");
blurFinishShader.texAttrib = glGetAttribLocation(prog, "texcoord");
blurFinishShader.brightness = glGetUniformLocation(prog, "brightness");
blurFinishShader.noise = glGetUniformLocation(prog, "noise");
wlr_matrix_identity(projMatrix.data());
asyncResourceGatherer = std::make_unique<CAsyncResourceGatherer>();
@ -199,9 +240,9 @@ void CRenderer::renderRect(const CBox& box, const CColor& col, int rounding) {
glDisableVertexAttribArray(rectShader.posAttrib);
}
void CRenderer::renderTexture(const CBox& box, const CTexture& tex, float a, int rounding) {
void CRenderer::renderTexture(const CBox& box, const CTexture& tex, float a, int rounding, bool noTransform) {
float matrix[9];
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_FLIPPED_180 /* ugh coordinate spaces */, 0,
wlr_matrix_project_box(matrix, &box, noTransform ? WL_OUTPUT_TRANSFORM_NORMAL : WL_OUTPUT_TRANSFORM_FLIPPED_180 /* ugh coordinate spaces */, 0,
projMatrix.data()); // TODO: write own, don't use WLR here
float glMatrix[9];
@ -262,7 +303,7 @@ std::vector<std::unique_ptr<IWidget>>* CRenderer::getOrCreateWidgetsFor(const CS
else if (!PATH.empty())
resourceID = "background:" + PATH;
widgets[surf].emplace_back(std::make_unique<CBackground>(surf->size, resourceID, std::any_cast<Hyprlang::INT>(c.values.at("color"))));
widgets[surf].emplace_back(std::make_unique<CBackground>(surf->size, resourceID, c.values));
} else if (c.type == "input-field") {
widgets[surf].emplace_back(std::make_unique<CPasswordInputField>(surf->size, c.values));
} else if (c.type == "label") {
@ -273,3 +314,170 @@ std::vector<std::unique_ptr<IWidget>>* CRenderer::getOrCreateWidgetsFor(const CS
return &widgets[surf];
}
void CRenderer::blurTexture(const CFramebuffer& outfb, const CTexture& tex, SBlurParams params) {
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
float matrix[9];
CBox box{0, 0, tex.m_vSize.x, tex.m_vSize.y};
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
projMatrix.data()); // TODO: write own, don't use WLR here
float glMatrix[9];
wlr_matrix_multiply(glMatrix, projection.data(), matrix);
CFramebuffer mirrors[2];
mirrors[0].alloc(tex.m_vSize.x, tex.m_vSize.y);
mirrors[1].alloc(tex.m_vSize.x, tex.m_vSize.y);
CFramebuffer* currentRenderToFB = &mirrors[0];
// Begin with base color adjustments - global brightness and contrast
// TODO: make this a part of the first pass maybe to save on a drawcall?
{
mirrors[1].bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex.m_iTarget, tex.m_iTexID);
glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(blurPrepareShader.program);
#ifndef GLES2
glUniformMatrix3fv(blurPrepareShader.proj, 1, GL_TRUE, glMatrix);
#else
wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(blurPrepareShader.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(blurPrepareShader.contrast, params.contrast);
glUniform1f(blurPrepareShader.brightness, params.brightness);
glUniform1i(blurPrepareShader.tex, 0);
glVertexAttribPointer(blurPrepareShader.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(blurPrepareShader.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(blurPrepareShader.posAttrib);
glEnableVertexAttribArray(blurPrepareShader.texAttrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(blurPrepareShader.posAttrib);
glDisableVertexAttribArray(blurPrepareShader.texAttrib);
currentRenderToFB = &mirrors[1];
}
// declare the draw func
auto drawPass = [&](CShader* pShader) {
if (currentRenderToFB == &mirrors[0])
mirrors[1].bind();
else
mirrors[0].bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID);
glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(pShader->program);
// prep two shaders
#ifndef GLES2
glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix);
#else
wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(pShader->radius, params.size);
if (pShader == &blurShader1) {
glUniform2f(blurShader1.halfpixel, 0.5f / (tex.m_vSize.x / 2.f), 0.5f / (tex.m_vSize.y / 2.f));
glUniform1i(blurShader1.passes, params.passes);
glUniform1f(blurShader1.vibrancy, params.vibrancy);
glUniform1f(blurShader1.vibrancy_darkness, params.vibrancy_darkness);
} else
glUniform2f(blurShader2.halfpixel, 0.5f / (tex.m_vSize.x * 2.f), 0.5f / (tex.m_vSize.y * 2.f));
glUniform1i(pShader->tex, 0);
glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(pShader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(pShader->posAttrib);
glEnableVertexAttribArray(pShader->texAttrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(pShader->posAttrib);
glDisableVertexAttribArray(pShader->texAttrib);
if (currentRenderToFB != &mirrors[0])
currentRenderToFB = &mirrors[0];
else
currentRenderToFB = &mirrors[1];
};
// draw the things.
// first draw is swap -> mirr
mirrors[0].bind();
glBindTexture(mirrors[1].m_cTex.m_iTarget, mirrors[1].m_cTex.m_iTexID);
for (int i = 1; i <= params.passes; ++i) {
drawPass(&blurShader1); // down
}
for (int i = params.passes - 1; i >= 0; --i) {
drawPass(&blurShader2); // up
}
// finalize the image
{
if (currentRenderToFB == &mirrors[0])
mirrors[1].bind();
else
mirrors[0].bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID);
glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(blurFinishShader.program);
#ifndef GLES2
glUniformMatrix3fv(blurFinishShader.proj, 1, GL_TRUE, glMatrix);
#else
wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(blurFinishShader.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(blurFinishShader.noise, params.noise);
glUniform1f(blurFinishShader.brightness, params.brightness);
glUniform1i(blurFinishShader.tex, 0);
glVertexAttribPointer(blurFinishShader.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(blurFinishShader.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(blurFinishShader.posAttrib);
glEnableVertexAttribArray(blurFinishShader.texAttrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(blurFinishShader.posAttrib);
glDisableVertexAttribArray(blurFinishShader.texAttrib);
if (currentRenderToFB != &mirrors[0])
currentRenderToFB = &mirrors[0];
else
currentRenderToFB = &mirrors[1];
}
// finish
outfb.bind();
renderTexture(box, currentRenderToFB->m_cTex, 1.0, 0, true);
glEnable(GL_BLEND);
}

View file

@ -9,6 +9,7 @@
#include "../helpers/Color.hpp"
#include "AsyncResourceGatherer.hpp"
#include "widgets/IWidget.hpp"
#include "Framebuffer.hpp"
typedef std::unordered_map<const CSessionLockSurface*, std::vector<std::unique_ptr<IWidget>>> widgetMap_t;
@ -20,10 +21,16 @@ class CRenderer {
bool needsFrame = false;
};
struct SBlurParams {
int size = 0, passes = 0;
float noise = 0, contrast = 0, brightness = 0, vibrancy = 0, vibrancy_darkness = 0;
};
SRenderFeedback renderLock(const CSessionLockSurface& surface);
void renderRect(const CBox& box, const CColor& col, int rounding = 0);
void renderTexture(const CBox& box, const CTexture& tex, float a = 1.0, int rounding = 0);
void renderTexture(const CBox& box, const CTexture& tex, float a = 1.0, int rounding = 0, bool noTransform = false);
void blurTexture(const CFramebuffer& outfb, const CTexture& tex, SBlurParams params);
std::unique_ptr<CAsyncResourceGatherer> asyncResourceGatherer;
std::chrono::system_clock::time_point gatheredAt;
@ -35,6 +42,10 @@ class CRenderer {
CShader rectShader;
CShader texShader;
CShader blurShader1;
CShader blurShader2;
CShader blurPrepareShader;
CShader blurFinishShader;
std::array<float, 9> projMatrix;
std::array<float, 9> projection;

View file

@ -120,3 +120,234 @@ void main() {
gl_FragColor = pixColor * alpha;
})#";
inline const std::string FRAGBLUR1 = R"#(
#version 100
precision highp float;
varying highp vec2 v_texcoord; // is in 0-1
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) {
a = clamp(a, 0.0, 1.0);
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;
}
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);
}
if (delta > 0.0) {
vec3 maxcVec = vec3(maxc);
vec3 masks = vec3(equal(maxcVec, col)) * vec3(notEqual(maxcVec, vec3(green, blue, red)));
vec3 adds = vec3(0.0, 2.0, 4.0) + vec3(green - blue, blue - red, red - green) / delta;
hue += dot(adds, masks);
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(0.0);
if (hue < onethird) {
xt.r = rcpsixth * (onethird - hue);
xt.g = rcpsixth * hue;
xt.b = 0.0;
} else if (hue < twothird) {
xt.r = 0.0;
xt.g = rcpsixth * (twothird - hue);
xt.b = rcpsixth * (hue - onethird);
} else
xt = vec3(rcpsixth * (hue - twothird), 0.0, rcpsixth * (1.0 - hue));
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;
vec4 sum = texture2D(tex, uv) * 4.0;
sum += texture2D(tex, uv - halfpixel.xy * radius);
sum += texture2D(tex, uv + halfpixel.xy * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
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]);
}
}
)#";
inline const std::string FRAGBLUR2 = R"#(
#version 100
precision highp float;
varying highp vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float radius;
uniform vec2 halfpixel;
void main() {
vec2 uv = v_texcoord / 2.0;
vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius);
sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius);
sum += texture2D(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0;
gl_FragColor = sum / 12.0;
}
)#";
inline const std::string FRAGBLURPREPARE = R"#(
precision highp float;
varying vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float contrast;
uniform float brightness;
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
if (contrast != 1.0) {
pixColor.r = gain(pixColor.r, contrast);
pixColor.g = gain(pixColor.g, contrast);
pixColor.b = gain(pixColor.b, contrast);
}
// brightness
if (brightness > 1.0) {
pixColor.rgb *= brightness;
}
gl_FragColor = pixColor;
}
)#";
inline const std::string FRAGBLURFINISH = R"#(
precision highp 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 noiseAmount = (mod(noiseHash, 1.0) - 0.5);
pixColor.rgb += noiseAmount * noise;
// brightness
if (brightness < 1.0) {
pixColor.rgb *= brightness;
}
gl_FragColor = pixColor;
}
)#";

View file

@ -1,8 +1,17 @@
#include "Background.hpp"
#include "../Renderer.hpp"
CBackground::CBackground(const Vector2D& viewport_, const std::string& resourceID_, const CColor& color_) : viewport(viewport_), resourceID(resourceID_), color(color_) {
;
CBackground::CBackground(const Vector2D& viewport_, const std::string& resourceID_, const std::unordered_map<std::string, std::any>& props) :
viewport(viewport_), resourceID(resourceID_) {
color = std::any_cast<Hyprlang::INT>(props.at("color"));
blurPasses = std::any_cast<Hyprlang::INT>(props.at("blur_passes"));
blurSize = std::any_cast<Hyprlang::INT>(props.at("blur_size"));
vibrancy = std::any_cast<Hyprlang::FLOAT>(props.at("vibrancy"));
vibrancy_darkness = std::any_cast<Hyprlang::FLOAT>(props.at("vibrancy_darkness"));
noise = std::any_cast<Hyprlang::FLOAT>(props.at("noise"));
brightness = std::any_cast<Hyprlang::FLOAT>(props.at("brightness"));
contrast = std::any_cast<Hyprlang::FLOAT>(props.at("contrast"));
}
bool CBackground::draw(const SRenderData& data) {
@ -21,11 +30,21 @@ bool CBackground::draw(const SRenderData& data) {
if (!asset)
return false;
CBox texbox = {{}, asset->texture.m_vSize};
if (blurPasses > 0 && !blurredFB.isAllocated()) {
// make it brah
blurredFB.alloc(viewport.x, viewport.y); // TODO 10 bit
blurredFB.bind();
g_pRenderer->blurTexture(blurredFB, asset->texture, CRenderer::SBlurParams{blurSize, blurPasses, noise, contrast, brightness, vibrancy, vibrancy_darkness});
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
Vector2D size = asset->texture.m_vSize;
float scaleX = viewport.x / asset->texture.m_vSize.x;
float scaleY = viewport.y / asset->texture.m_vSize.y;
CTexture* tex = blurredFB.isAllocated() ? &blurredFB.m_cTex : &asset->texture;
CBox texbox = {{}, asset->texture.m_vSize};
Vector2D size = asset->texture.m_vSize;
float scaleX = viewport.x / asset->texture.m_vSize.x;
float scaleY = viewport.y / asset->texture.m_vSize.y;
texbox.w *= std::max(scaleX, scaleY);
texbox.h *= std::max(scaleX, scaleY);
@ -35,7 +54,7 @@ bool CBackground::draw(const SRenderData& data) {
else
texbox.x = -(texbox.w - viewport.x) / 2.f;
g_pRenderer->renderTexture(texbox, asset->texture, data.opacity);
g_pRenderer->renderTexture(texbox, *tex, data.opacity);
return data.opacity < 1.0;
}

View file

@ -3,17 +3,30 @@
#include "IWidget.hpp"
#include "../../helpers/Vector2D.hpp"
#include "../../helpers/Color.hpp"
#include "../Framebuffer.hpp"
#include <string>
#include <unordered_map>
#include <any>
struct SPreloadedAsset;
class CBackground : public IWidget {
public:
CBackground(const Vector2D& viewport, const std::string& resourceID, const CColor& color);
CBackground(const Vector2D& viewport, const std::string& resourceID, const std::unordered_map<std::string, std::any>& props);
virtual bool draw(const SRenderData& data);
private:
// if needed
CFramebuffer blurredFB;
int blurSize = 10;
int blurPasses = 3;
float noise = 0.0117;
float contrast = 0.8916;
float brightness = 0.8172;
float vibrancy = 0.1696;
float vibrancy_darkness = 0.0;
Vector2D viewport;
std::string resourceID;
CColor color;