summaryrefslogtreecommitdiff
path: root/src/render
diff options
context:
space:
mode:
authorvaxerski <43317083+vaxerski@users.noreply.github.com>2022-04-09 16:51:08 +0200
committervaxerski <43317083+vaxerski@users.noreply.github.com>2022-04-09 16:51:08 +0200
commit969bebbd06d3f9ac20910b70bb3310ec91931e74 (patch)
tree4890e37f12c85fcc43c679d23567a29af7eabec8 /src/render
parentb7094200f6f4b24026cd1e0458ed0d75a34d50ef (diff)
Added blurring 🎉
Diffstat (limited to 'src/render')
-rw-r--r--src/render/OpenGL.cpp107
-rw-r--r--src/render/OpenGL.hpp3
-rw-r--r--src/render/Renderer.cpp5
-rw-r--r--src/render/Shaders.hpp103
4 files changed, 216 insertions, 2 deletions
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 5f5818fb..26e18970 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -50,6 +50,22 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
m_shEXT.posAttrib = glGetAttribLocation(prog, "pos");
m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord");
+ prog = createProgram(TEXVERTSRC, FRAGBLUR1);
+ m_shBLUR1.program = prog;
+ m_shBLUR1.tex = glGetUniformLocation(prog, "tex");
+ m_shBLUR1.alpha = glGetUniformLocation(prog, "alpha");
+ m_shBLUR1.proj = glGetUniformLocation(prog, "proj");
+ m_shBLUR1.posAttrib = glGetAttribLocation(prog, "pos");
+ m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord");
+
+ prog = createProgram(TEXVERTSRC, FRAGBLUR2);
+ m_shBLUR2.program = prog;
+ m_shBLUR2.tex = glGetUniformLocation(prog, "tex");
+ m_shBLUR2.alpha = glGetUniformLocation(prog, "alpha");
+ m_shBLUR2.proj = glGetUniformLocation(prog, "proj");
+ m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos");
+ m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord");
+
Debug::log(LOG, "Shaders initialized successfully.");
// End shaders
@@ -259,6 +275,97 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, float matrix[9], float
glBindTexture(tex.m_iTarget, 0);
}
+// This is probably not the quickest method possible,
+// feel free to contribute if you have a better method.
+// cheers.
+
+// 2-pass pseudo-gaussian blur
+void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9], float a, int round) {
+ RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
+ RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
+
+ // if blur disabled, just render the texture
+ if (g_pConfigManager->getInt("decoration:blur") == 0) {
+ renderTexture(tex, matrix, a, round);
+ return;
+ }
+
+ // create a stencil for our thang
+ glEnable(GL_STENCIL_TEST);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+ // we clear the stencil and then draw our texture with GL_ALWAYS to make a stencil mask.
+ glClear(GL_STENCIL_BUFFER_BIT);
+
+ glStencilMask(0xFF);
+
+ glStencilFunc(GL_ALWAYS, 1, 0xFF);
+
+ renderTexture(tex, matrix, 0, round); // 0 alpha because we dont want to draw to the FB
+
+ // then we disable writing to the mask and ONLY accept writing within the stencil
+ glStencilMask(0x00);
+ glStencilFunc(GL_EQUAL, 1, 0xFF);
+
+ glEnable(GL_BLEND);
+
+ // now we make the blur by blurring the main framebuffer (it will only affect the stencil)
+
+ // matrix
+ const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
+ float matrixFull[9];
+ wlr_box fullMonBox = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y};
+ wlr_matrix_project_box(matrixFull, &fullMonBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
+
+ float glMatrix[9];
+ wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrixFull);
+ wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
+
+ wlr_matrix_transpose(glMatrix, glMatrix);
+
+ const auto RADIUS = g_pConfigManager->getInt("decoration:blur_size") + 2;
+ const auto PFRAMEBUFFER = &m_mMonitorFramebuffers[m_RenderData.pMonitor];
+
+ auto drawWithShader = [=](CShader* pShader) {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(PFRAMEBUFFER->m_cTex.m_iTarget, PFRAMEBUFFER->m_cTex.m_iTexID);
+
+ glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ glUseProgram(pShader->program);
+
+ glUniform1f(glGetUniformLocation(pShader->program, "radius"), RADIUS);
+ glUniform2f(glGetUniformLocation(pShader->program, "resolution"), m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y);
+ glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
+ glUniform1i(pShader->tex, 0);
+ glUniform1f(pShader->alpha, a / 255.f);
+
+ 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);
+ };
+
+ drawWithShader(&m_shBLUR1); // horizontal pass
+ drawWithShader(&m_shBLUR2); // vertical pass
+
+ glBindTexture(tex.m_iTarget, 0);
+
+ // when the blur is done, let's render the window itself
+ renderTexture(tex, matrix, a, round);
+
+ // and disable the stencil
+ glStencilMask(0xFF);
+ glStencilFunc(GL_ALWAYS, 1, 0xFF);
+ glDisable(GL_STENCIL_TEST);
+}
+
void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) {
// 0-1 space god damnit
arr[counter * 2 + 0] = x / box->width;
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 7792a1fc..bc2c6d88 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -40,6 +40,7 @@ public:
void renderRect(wlr_box*, const CColor&);
void renderTexture(wlr_texture*, float matrix[9], float a, int round = 0);
void renderTexture(const CTexture&, float matrix[9], float a, int round = 0);
+ void renderTextureWithBlur(const CTexture&, float matrix[9], float a, int round = 0);
void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0);
void makeWindowSnapshot(CWindow*);
@@ -68,6 +69,8 @@ private:
CShader m_shRGBA;
CShader m_shRGBX;
CShader m_shEXT;
+ CShader m_shBLUR1;
+ CShader m_shBLUR2;
//
GLuint createProgram(const std::string&, const std::string&);
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 197b29b1..b47a74b9 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -31,7 +31,10 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
float matrix[9];
wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, RDATA->output->transform_matrix);
- g_pHyprOpenGL->renderTexture(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding")); // TODO: fadeinout
+ if (RDATA->surface && surface == RDATA->surface)
+ g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"));
+ else
+ g_pHyprOpenGL->renderTexture(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"));
wlr_surface_send_frame_done(surface, RDATA->when);
diff --git a/src/render/Shaders.hpp b/src/render/Shaders.hpp
index b8239c57..09d4d504 100644
--- a/src/render/Shaders.hpp
+++ b/src/render/Shaders.hpp
@@ -138,6 +138,107 @@ void main() {
gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;
})#";
+// thanks to Loadus
+// https://www.shadertoy.com/view/Mtl3Rj
+// for this pseudo-gaussian blur!
+inline const std::string FRAGBLUR1 = R"#(
+precision mediump float;
+varying vec2 v_texcoord; // is in 0-1
+uniform sampler2D tex;
+
+uniform float radius;
+uniform vec2 resolution;
+uniform float alpha;
+
+float SCurve (float x) {
+ x = x * 2.0 - 1.0;
+ return -x * abs(x) * 0.5 + x + 0.5;
+}
+
+vec4 BlurH (vec2 size, vec2 uv) {
+ if (radius >= 1.0) {
+ vec4 A = vec4(0.0);
+ vec4 C = vec4(0.0);
+
+ float width = 1.0 / size.x;
+
+ float divisor = 0.0;
+ float weight = 0.0;
+
+ float radiusMultiplier = 1.0 / radius;
+
+ for (float x = -radius; x <= radius; x++) {
+ A = texture2D(tex, uv + vec2(x * width, 0.0));
+
+ weight = SCurve(1.0 - (abs(x) * radiusMultiplier));
+
+ C += A * weight;
+
+ divisor += weight;
+ }
+
+ return vec4(C.r / divisor, C.g / divisor, C.b / divisor, 1.0);
+ }
+
+ return texture2D(tex, uv);
+}
+
+
+void main() {
+ gl_FragColor = BlurH(resolution, v_texcoord) * alpha;
+}
+
+)#";
+
+inline const std::string FRAGBLUR2 = R"#(
+precision mediump float;
+varying vec2 v_texcoord; // is in 0-1
+uniform sampler2D tex;
+
+uniform float radius;
+uniform vec2 resolution;
+uniform float alpha;
+
+float SCurve (float x) {
+ x = x * 2.0 - 1.0;
+ return -x * abs(x) * 0.5 + x + 0.5;
+}
+
+vec4 BlurV (vec2 size, vec2 uv) {
+ if (radius >= 1.0) {
+ vec4 A = vec4(0.0);
+ vec4 C = vec4(0.0);
+
+ float height = 1.0 / size.y;
+
+ float divisor = 0.0;
+ float weight = 0.0;
+
+ float radiusMultiplier = 1.0 / radius;
+
+ for (float y = -radius; y <= radius; y++) {
+ A = texture2D(tex, uv + vec2(0.0, y * height));
+
+ weight = SCurve(1.0 - (abs(y) * radiusMultiplier));
+
+ C += A * weight;
+
+ divisor += weight;
+ }
+
+ return vec4(C.r / divisor, C.g / divisor, C.b / divisor, 1.0);
+ }
+
+ return texture2D(tex, uv);
+}
+
+
+void main() {
+ gl_FragColor = BlurV(resolution, v_texcoord) * alpha;
+}
+
+)#";
+
inline const std::string TEXFRAGSRCEXT = R"#(
#extension GL_OES_EGL_image_external : require
@@ -189,4 +290,4 @@ void main() {
}
gl_FragColor = texture2D(texture0, v_texcoord) * alpha;
-})#"; \ No newline at end of file
+})#";