mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-11-16 23:05:58 +01:00
background: add blurring
This commit is contained in:
parent
2836f02ded
commit
1b57d52179
8 changed files with 645 additions and 13 deletions
|
@ -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
|
||||
|
|
112
src/renderer/Framebuffer.cpp
Normal file
112
src/renderer/Framebuffer.cpp
Normal 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;
|
||||
}
|
24
src/renderer/Framebuffer.hpp
Normal file
24
src/renderer/Framebuffer.hpp
Normal 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;
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -119,4 +119,235 @@ 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;
|
||||
}
|
||||
)#";
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue