From 747ff3369d6377628e3e27e3b108c8d61cbc5733 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Sat, 25 Jun 2022 20:28:40 +0200 Subject: [PATCH] added drop shadows --- src/Window.cpp | 6 +- src/config/ConfigManager.cpp | 5 + src/render/OpenGL.cpp | 68 ++++ src/render/OpenGL.hpp | 2 + src/render/Renderer.cpp | 5 +- src/render/Shaders.hpp | 341 +----------------- .../decorations/CHyprDropShadowDecoration.cpp | 66 ++++ .../decorations/CHyprDropShadowDecoration.hpp | 27 ++ .../decorations/IHyprWindowDecoration.hpp | 3 +- src/render/shaders/Shadow.hpp | 83 +++++ src/render/shaders/Textures.hpp | 341 ++++++++++++++++++ 11 files changed, 603 insertions(+), 344 deletions(-) create mode 100644 src/render/decorations/CHyprDropShadowDecoration.cpp create mode 100644 src/render/decorations/CHyprDropShadowDecoration.hpp create mode 100644 src/render/shaders/Shadow.hpp create mode 100644 src/render/shaders/Textures.hpp diff --git a/src/Window.cpp b/src/Window.cpp index 8476360a..fbd06417 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -1,11 +1,14 @@ #include "Window.hpp" #include "Compositor.hpp" +#include "render/decorations/CHyprDropShadowDecoration.hpp" CWindow::CWindow() { m_vRealPosition.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*) this, AVARDAMAGE_ENTIRE); m_vRealSize.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE); m_cRealBorderColor.create(AVARTYPE_COLOR, &g_pConfigManager->getConfigValuePtr("animations:borders_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:borders")->intValue, &g_pConfigManager->getConfigValuePtr("animations:borders_curve")->strValue, (void*)this, AVARDAMAGE_BORDER); m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE); + + m_dWindowDecorations.emplace_back(std::make_unique(this)); // put the shadow so it's the first deco (has to be rendered first) } CWindow::~CWindow() { @@ -16,8 +19,9 @@ CWindow::~CWindow() { } wlr_box CWindow::getFullWindowBoundingBox() { + static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; - SWindowDecorationExtents maxExtents; + SWindowDecorationExtents maxExtents = {{*PBORDERSIZE + 1, *PBORDERSIZE + 1}, {*PBORDERSIZE + 1, *PBORDERSIZE + 1}}; for (auto& wd : m_dWindowDecorations) { diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 966ef29d..bbcf2bc7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -49,6 +49,11 @@ void CConfigManager::setDefaultVars() { configValues["decoration:fullscreen_opacity"].floatValue = 1; configValues["decoration:multisample_edges"].intValue = 0; configValues["decoration:no_blur_on_oversized"].intValue = 1; + 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:col.shadow"].intValue = 0xee1a1a1a; configValues["dwindle:pseudotile"].intValue = 0; configValues["dwindle:col.group_border"].intValue = 0x66777700; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 92c9d9c9..9951939d 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -75,6 +75,12 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos"); m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord"); + prog = createProgram(QUADVERTSRC, FRAGSHADOW); + m_shSHADOW.program = prog; + m_shSHADOW.proj = glGetUniformLocation(prog, "proj"); + m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); + m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); + Debug::log(LOG, "Shaders initialized successfully."); // End shaders @@ -858,6 +864,68 @@ void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) { pixman_region32_fini(&fakeDamage); } +void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range) { + RASSERT(m_RenderData.pMonitor, "Tried to render shadow without begin()!"); + RASSERT((box->width > 0 && box->height > 0), "Tried to render shadow with width/height < 0!"); + + static auto *const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue; + static auto *const PSHADOWPOWER = &g_pConfigManager->getConfigValuePtr("decoration:shadow_render_power")->intValue; + static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue; + + const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4); + + const auto col = CColor(*PSHADOWCOL); + + float matrix[9]; + wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here + + float glMatrix[9]; + wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix); + + wlr_matrix_transpose(glMatrix, glMatrix); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glUseProgram(m_shSHADOW.program); + + glUniformMatrix3fv(m_shSHADOW.proj, 1, GL_FALSE, glMatrix); + glUniform4f(glGetUniformLocation(m_shSHADOW.program, "color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f); + + const auto TOPLEFT = Vector2D(range + round, range + round); + const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round)); + const auto FULLSIZE = Vector2D(box->width, box->height); + + // Rounded corners + glUniform2f(glGetUniformLocation(m_shSHADOW.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(glGetUniformLocation(m_shSHADOW.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(glGetUniformLocation(m_shSHADOW.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(glGetUniformLocation(m_shSHADOW.program, "radius"), range + round); + glUniform1f(glGetUniformLocation(m_shSHADOW.program, "range"), range); + glUniform1f(glGetUniformLocation(m_shSHADOW.program, "shadowPower"), SHADOWPOWER); + glUniform1i(glGetUniformLocation(m_shSHADOW.program, "ignoreWindow"), *PSHADOWIGNOREWINDOW); + + glVertexAttribPointer(m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + + glEnableVertexAttribArray(m_shSHADOW.posAttrib); + glEnableVertexAttribArray(m_shSHADOW.texAttrib); + + if (pixman_region32_not_empty(m_RenderData.pDamage)) { + PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { + const auto RECT = RECTSARR[i]; + scissor(&RECT); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + + glDisableVertexAttribArray(m_shSHADOW.posAttrib); + glDisableVertexAttribArray(m_shSHADOW.texAttrib); + + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +} + void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 0648e73a..5cae6486 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -61,6 +61,7 @@ public: void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0); void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool border = false, bool allowPrimary = false); void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool border = false); + void renderRoundedShadow(wlr_box*, int round, int range); void makeWindowSnapshot(CWindow*); void makeLayerSnapshot(SLayerSurface*); @@ -106,6 +107,7 @@ private: CShader m_shEXT; CShader m_shBLUR1; CShader m_shBLUR2; + CShader m_shSHADOW; // GLuint createProgram(const std::string&, const std::string&); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a917a1cc..5d99565b 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -569,7 +569,7 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) { // damage by size & pos // TODO TEMP: revise when added shadows/etc - wlr_box damageBox = {pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, pWindow->m_vRealSize.vec().x, pWindow->m_vRealSize.vec().y}; + wlr_box damageBox = pWindow->getFullWindowBoundingBox(); for (auto& m : g_pCompositor->m_lMonitors) { wlr_box fixedDamageBox = damageBox; fixedDamageBox.x -= m.vecPosition.x; @@ -584,8 +584,7 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) { Debug::log(LOG, "Damage: Window floated (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); } else { // damage by real size & pos + border size * 2 (JIC) - static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; - wlr_box damageBox = { pWindow->m_vRealPosition.vec().x - *PBORDERSIZE - 1, pWindow->m_vRealPosition.vec().y - *PBORDERSIZE - 1, pWindow->m_vRealSize.vec().x + 2 * *PBORDERSIZE + 2, pWindow->m_vRealSize.vec().y + 2 * *PBORDERSIZE + 2}; + wlr_box damageBox = pWindow->getFullWindowBoundingBox(); for (auto& m : g_pCompositor->m_lMonitors) { wlr_box fixedDamageBox = damageBox; fixedDamageBox.x -= m.vecPosition.x; diff --git a/src/render/Shaders.hpp b/src/render/Shaders.hpp index d01e7775..ac7f9424 100644 --- a/src/render/Shaders.hpp +++ b/src/render/Shaders.hpp @@ -1,341 +1,4 @@ #pragma once -#include - -inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string { - return R"#( - if (pixCoord[0] < topLeft[0]) { - // we're close left - if (pixCoord[1] < topLeft[1]) { - // top - - if (ignoreCorners == 1) { - discard; - return; - } - - float topLeftDistance = distance(topLeft, pixCoord); - - if (topLeftDistance > radius - 1.0) { - if (primitiveMultisample == 0 && topLeftDistance > radius) { - discard; - return; - } else if (primitiveMultisample == 1) { - float distances = 0.0; - if (distance(topLeft, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(topLeft, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(topLeft, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } - if (distance(topLeft, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } - - if (distances == 0.0) { - discard; - return; - } - - distances = distances / 4.0; - - gl_FragColor = )#" + colorVarName + R"#( * distances; - return; - } - } - } else if (pixCoord[1] > bottomRight[1]) { - // bottom - - if (ignoreCorners == 1) { - discard; - return; - } - - float topLeftDistance = distance(vec2(topLeft[0], bottomRight[1]), pixCoord); - - if (topLeftDistance > radius - 1.0) { - if (primitiveMultisample == 0 && topLeftDistance > radius) { - discard; - return; - } else if (primitiveMultisample == 1) { - float distances = 0.0; - if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } - if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } - - if (distances == 0.0) { - discard; - return; - } - - distances = distances / 4.0; - - gl_FragColor = )#" + colorVarName + R"#( * distances; - return; - } - } - } - } - else if (pixCoord[0] > bottomRight[0]) { - // we're close right - if (pixCoord[1] < topLeft[1]) { - // top - - if (ignoreCorners == 1) { - discard; - return; - } - - float topLeftDistance = distance(vec2(bottomRight[0], topLeft[1]), pixCoord); - - if (topLeftDistance > radius - 1.0) { - if (primitiveMultisample == 0 && topLeftDistance > radius) { - discard; - return; - } else if (primitiveMultisample == 1) { - float distances = 0.0; - if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } - if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } - - if (distances == 0.0) { - discard; - return; - } - - distances = distances / 4.0; - - gl_FragColor = )#" + colorVarName + R"#( * distances; - return; - } - } - } else if (pixCoord[1] > bottomRight[1]) { - // bottom - - if (ignoreCorners == 1) { - discard; - return; - } - - float topLeftDistance = distance(bottomRight, pixCoord); - - if (topLeftDistance > radius - 1.0) { - if (primitiveMultisample == 0 && topLeftDistance > radius) { - discard; - return; - } else if (primitiveMultisample == 1) { - float distances = 0.0; - if (distance(bottomRight, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(bottomRight, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(bottomRight, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } - if (distance(bottomRight, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } - - if (distances == 0.0) { - discard; - return; - } - - distances = distances / 4.0; - - gl_FragColor = )#" + colorVarName + R"#( * distances; - return; - } - } - } - } - )#"; -}; - -inline const std::string QUADVERTSRC = R"#( -uniform mat3 proj; -uniform vec4 color; -attribute vec2 pos; -attribute vec2 texcoord; -varying vec4 v_color; -varying vec2 v_texcoord; - -void main() { - gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); - v_color = color; - v_texcoord = texcoord; -})#"; - -inline const std::string QUADFRAGSRC = R"#( -precision mediump float; -varying vec4 v_color; -varying vec2 v_texcoord; - -uniform vec2 topLeft; -uniform vec2 bottomRight; -uniform vec2 fullSize; -uniform float radius; - -uniform int primitiveMultisample; -uniform int ignoreCorners; - -void main() { - if (radius == 0.0) { - gl_FragColor = v_color; - return; - } - - vec2 pixCoord = fullSize * v_texcoord; - - )#" + ROUNDED_SHADER_FUNC("v_color") + R"#( - - gl_FragColor = v_color; -})#"; - -inline const std::string TEXVERTSRC = R"#( -uniform mat3 proj; -attribute vec2 pos; -attribute vec2 texcoord; -varying vec2 v_texcoord; - -void main() { - gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); - v_texcoord = texcoord; -})#"; - -inline const std::string TEXFRAGSRCRGBA = R"#( -precision mediump float; -varying vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 bottomRight; -uniform vec2 fullSize; -uniform float radius; - -uniform int discardOpaque; - -uniform int primitiveMultisample; -uniform int ignoreCorners; - -void main() { - - vec4 pixColor = texture2D(tex, v_texcoord); - - if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { - discard; - return; - } - - vec2 pixCoord = fullSize * v_texcoord; - - )#" + ROUNDED_SHADER_FUNC("pixColor") + - R"#( - - gl_FragColor = pixColor * alpha; -})#"; - -inline const std::string TEXFRAGSRCRGBX = R"#( -precision mediump float; -varying vec2 v_texcoord; -uniform sampler2D tex; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 bottomRight; -uniform vec2 fullSize; -uniform float radius; - -uniform int discardOpaque; - -uniform int primitiveMultisample; -uniform int ignoreCorners; - -void main() { - - if (discardOpaque == 1 && alpha == 1.0) { - discard; - return; - } - - vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0); - - vec2 pixCoord = fullSize * v_texcoord; - - )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( - - gl_FragColor = pixColor * alpha; -})#"; - -inline const std::string FRAGBLUR1 = R"#( -#version 100 -precision mediump float; -varying mediump 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) * 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); - gl_FragColor = sum / 8.0; -} -)#"; - -inline const std::string FRAGBLUR2 = R"#( -#version 100 -precision mediump float; -varying mediump 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 TEXFRAGSRCEXT = R"#( -#extension GL_OES_EGL_image_external : require - -precision mediump float; -varying vec2 v_texcoord; -uniform samplerExternalOES texture0; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 bottomRight; -uniform vec2 fullSize; -uniform float radius; - -uniform int discardOpaque; - -uniform int primitiveMultisample; -uniform int ignoreCorners; - -void main() { - - vec4 pixColor = texture2D(texture0, v_texcoord); - - if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { - discard; - return; - } - - vec2 pixCoord = fullSize * v_texcoord; - - )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( - - gl_FragColor = pixColor * alpha; -})#"; +#include "shaders/Textures.hpp" +#include "shaders/Shadow.hpp" \ No newline at end of file diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp new file mode 100644 index 00000000..528e00cf --- /dev/null +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -0,0 +1,66 @@ +#include "CHyprDropShadowDecoration.hpp" + +#include "../../Compositor.hpp" + +CHyprDropShadowDecoration::CHyprDropShadowDecoration(CWindow* pWindow) { + m_pWindow = pWindow; +} + +CHyprDropShadowDecoration::~CHyprDropShadowDecoration() { + updateWindow(m_pWindow); +} + +SWindowDecorationExtents CHyprDropShadowDecoration::getWindowDecorationExtents() { + static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; + + if (*PSHADOWS != 1) + return {{}, {}}; + + return m_seExtents; +} + +eDecorationType CHyprDropShadowDecoration::getDecorationType() { + return DECORATION_SHADOW; +} + +void CHyprDropShadowDecoration::damageEntire() { + static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; + + if (*PSHADOWS != 1) + return; // disabled + + wlr_box dm = {m_vLastWindowPos.x - m_seExtents.topLeft.x, m_vLastWindowPos.y - m_seExtents.topLeft.y, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y}; + g_pHyprRenderer->damageBox(&dm); +} + +void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) { + damageEntire(); +} + +void CHyprDropShadowDecoration::draw(SMonitor* pMonitor) { + + if (!g_pCompositor->windowValidMapped(m_pWindow)) + return; + + static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; + static auto *const PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue; + static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; + + if (*PSHADOWS != 1) + return; // disabled + + // update the extents if needed + if (*PSHADOWSIZE != m_seExtents.topLeft.x) + m_seExtents = {{*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}, {*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}}; + + m_vLastWindowPos = m_pWindow->m_vRealPosition.vec(); + m_vLastWindowSize = m_pWindow->m_vRealSize.vec(); + + // draw the shadow + wlr_box fullBox = {m_vLastWindowPos.x - m_seExtents.topLeft.x + 2, m_vLastWindowPos.y - m_seExtents.topLeft.y + 2, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x - 4, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y - 4}; + + fullBox.x -= pMonitor->vecPosition.x; + fullBox.y -= pMonitor->vecPosition.y; + + g_pHyprOpenGL->renderRoundedShadow(&fullBox, *PROUNDING, *PSHADOWSIZE); +} diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp new file mode 100644 index 00000000..2a248a2f --- /dev/null +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "IHyprWindowDecoration.hpp" + +class CHyprDropShadowDecoration : public IHyprWindowDecoration { +public: + CHyprDropShadowDecoration(CWindow*); + virtual ~CHyprDropShadowDecoration(); + + virtual SWindowDecorationExtents getWindowDecorationExtents(); + + virtual void draw(SMonitor*); + + virtual eDecorationType getDecorationType(); + + virtual void updateWindow(CWindow*); + + virtual void damageEntire(); + +private: + SWindowDecorationExtents m_seExtents; + + CWindow* m_pWindow = nullptr; + + Vector2D m_vLastWindowPos; + Vector2D m_vLastWindowSize; +}; \ No newline at end of file diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index 0815273d..e9011a29 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -4,7 +4,8 @@ enum eDecorationType { DECORATION_NONE = -1, - DECORATION_GROUPBAR + DECORATION_GROUPBAR, + DECORATION_SHADOW }; struct SWindowDecorationExtents { diff --git a/src/render/shaders/Shadow.hpp b/src/render/shaders/Shadow.hpp new file mode 100644 index 00000000..f54124fa --- /dev/null +++ b/src/render/shaders/Shadow.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include + +inline const std::string FRAGSHADOW = R"#( +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; +uniform float range; +uniform float shadowPower; +uniform int ignoreWindow; + +float pixAlphaRoundedDistance(float distanceToCorner) { + if (distanceToCorner > radius) { + return 0.0; + } + + if (distanceToCorner > radius - range) { + return pow((range - (distanceToCorner - radius + range)) / range, shadowPower); // i think? + } + + return 1.0; +} + +void main() { + + vec4 pixColor = v_color; + float originalAlpha = pixColor[3]; + + bool done = false; + + vec2 pixCoord = fullSize * v_texcoord; + + // ok, now we check the distance to a border. + + if (pixCoord[0] < topLeft[0]) { + if (pixCoord[1] < topLeft[1]) { + // top left + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, topLeft)); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom left + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(topLeft[0], bottomRight[1]))); + done = true; + } + } else if (pixCoord[0] > bottomRight[0]) { + if (pixCoord[1] < topLeft[1]) { + // top right + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(bottomRight[0], topLeft[1]))); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom right + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, bottomRight)); + done = true; + } + } + + if (!done) { + // distance to all straight bb borders + float distanceT = pixCoord[1]; + float distanceB = fullSize[1] - pixCoord[1]; + float distanceL = pixCoord[0]; + float distanceR = fullSize[0] - pixCoord[0]; + + // get the smallest + float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR)); + + if (smallest < range) { + pixColor[3] = pixColor[3] * pow((smallest / range), shadowPower); + } + } + + if (pixColor[3] == 0.0 || (ignoreWindow == 1 && pixColor[3] == originalAlpha)) { + discard; return; + } + + gl_FragColor = pixColor; +})#"; \ No newline at end of file diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp new file mode 100644 index 00000000..d01e7775 --- /dev/null +++ b/src/render/shaders/Textures.hpp @@ -0,0 +1,341 @@ +#pragma once + +#include + +inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string { + return R"#( + if (pixCoord[0] < topLeft[0]) { + // we're close left + if (pixCoord[1] < topLeft[1]) { + // top + + if (ignoreCorners == 1) { + discard; + return; + } + + float topLeftDistance = distance(topLeft, pixCoord); + + if (topLeftDistance > radius - 1.0) { + if (primitiveMultisample == 0 && topLeftDistance > radius) { + discard; + return; + } else if (primitiveMultisample == 1) { + float distances = 0.0; + if (distance(topLeft, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(topLeft, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(topLeft, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } + if (distance(topLeft, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } + + if (distances == 0.0) { + discard; + return; + } + + distances = distances / 4.0; + + gl_FragColor = )#" + colorVarName + R"#( * distances; + return; + } + } + } else if (pixCoord[1] > bottomRight[1]) { + // bottom + + if (ignoreCorners == 1) { + discard; + return; + } + + float topLeftDistance = distance(vec2(topLeft[0], bottomRight[1]), pixCoord); + + if (topLeftDistance > radius - 1.0) { + if (primitiveMultisample == 0 && topLeftDistance > radius) { + discard; + return; + } else if (primitiveMultisample == 1) { + float distances = 0.0; + if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } + if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } + + if (distances == 0.0) { + discard; + return; + } + + distances = distances / 4.0; + + gl_FragColor = )#" + colorVarName + R"#( * distances; + return; + } + } + } + } + else if (pixCoord[0] > bottomRight[0]) { + // we're close right + if (pixCoord[1] < topLeft[1]) { + // top + + if (ignoreCorners == 1) { + discard; + return; + } + + float topLeftDistance = distance(vec2(bottomRight[0], topLeft[1]), pixCoord); + + if (topLeftDistance > radius - 1.0) { + if (primitiveMultisample == 0 && topLeftDistance > radius) { + discard; + return; + } else if (primitiveMultisample == 1) { + float distances = 0.0; + if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } + if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } + + if (distances == 0.0) { + discard; + return; + } + + distances = distances / 4.0; + + gl_FragColor = )#" + colorVarName + R"#( * distances; + return; + } + } + } else if (pixCoord[1] > bottomRight[1]) { + // bottom + + if (ignoreCorners == 1) { + discard; + return; + } + + float topLeftDistance = distance(bottomRight, pixCoord); + + if (topLeftDistance > radius - 1.0) { + if (primitiveMultisample == 0 && topLeftDistance > radius) { + discard; + return; + } else if (primitiveMultisample == 1) { + float distances = 0.0; + if (distance(bottomRight, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(bottomRight, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(bottomRight, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } + if (distance(bottomRight, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } + + if (distances == 0.0) { + discard; + return; + } + + distances = distances / 4.0; + + gl_FragColor = )#" + colorVarName + R"#( * distances; + return; + } + } + } + } + )#"; +}; + +inline const std::string QUADVERTSRC = R"#( +uniform mat3 proj; +uniform vec4 color; +attribute vec2 pos; +attribute vec2 texcoord; +varying vec4 v_color; +varying vec2 v_texcoord; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_color = color; + v_texcoord = texcoord; +})#"; + +inline const std::string QUADFRAGSRC = R"#( +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; + +uniform int primitiveMultisample; +uniform int ignoreCorners; + +void main() { + if (radius == 0.0) { + gl_FragColor = v_color; + return; + } + + vec2 pixCoord = fullSize * v_texcoord; + + )#" + ROUNDED_SHADER_FUNC("v_color") + R"#( + + gl_FragColor = v_color; +})#"; + +inline const std::string TEXVERTSRC = R"#( +uniform mat3 proj; +attribute vec2 pos; +attribute vec2 texcoord; +varying vec2 v_texcoord; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_texcoord = texcoord; +})#"; + +inline const std::string TEXFRAGSRCRGBA = R"#( +precision mediump float; +varying vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; +uniform float alpha; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; + +uniform int discardOpaque; + +uniform int primitiveMultisample; +uniform int ignoreCorners; + +void main() { + + vec4 pixColor = texture2D(tex, v_texcoord); + + if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { + discard; + return; + } + + vec2 pixCoord = fullSize * v_texcoord; + + )#" + ROUNDED_SHADER_FUNC("pixColor") + + R"#( + + gl_FragColor = pixColor * alpha; +})#"; + +inline const std::string TEXFRAGSRCRGBX = R"#( +precision mediump float; +varying vec2 v_texcoord; +uniform sampler2D tex; +uniform float alpha; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; + +uniform int discardOpaque; + +uniform int primitiveMultisample; +uniform int ignoreCorners; + +void main() { + + if (discardOpaque == 1 && alpha == 1.0) { + discard; + return; + } + + vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0); + + vec2 pixCoord = fullSize * v_texcoord; + + )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( + + gl_FragColor = pixColor * alpha; +})#"; + +inline const std::string FRAGBLUR1 = R"#( +#version 100 +precision mediump float; +varying mediump 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) * 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); + gl_FragColor = sum / 8.0; +} +)#"; + +inline const std::string FRAGBLUR2 = R"#( +#version 100 +precision mediump float; +varying mediump 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 TEXFRAGSRCEXT = R"#( +#extension GL_OES_EGL_image_external : require + +precision mediump float; +varying vec2 v_texcoord; +uniform samplerExternalOES texture0; +uniform float alpha; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; + +uniform int discardOpaque; + +uniform int primitiveMultisample; +uniform int ignoreCorners; + +void main() { + + vec4 pixColor = texture2D(texture0, v_texcoord); + + if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { + discard; + return; + } + + vec2 pixCoord = fullSize * v_texcoord; + + )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( + + gl_FragColor = pixColor * alpha; +})#";