mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-08 17:38:19 +02:00
renderer: simplify shadows (#14047)
This commit is contained in:
parent
593fd5650a
commit
d50ad2475c
8 changed files with 79 additions and 140 deletions
|
|
@ -622,7 +622,6 @@ CConfigManager::CConfigManager() {
|
|||
registerConfigVar("decoration:shadow:enabled", Hyprlang::INT{1});
|
||||
registerConfigVar("decoration:shadow:range", Hyprlang::INT{4});
|
||||
registerConfigVar("decoration:shadow:render_power", Hyprlang::INT{3});
|
||||
registerConfigVar("decoration:shadow:ignore_window", Hyprlang::INT{1});
|
||||
registerConfigVar("decoration:shadow:offset", Hyprlang::VEC2{0, 0});
|
||||
registerConfigVar("decoration:shadow:scale", {1.f});
|
||||
registerConfigVar("decoration:shadow:sharp", Hyprlang::INT{0});
|
||||
|
|
|
|||
|
|
@ -279,12 +279,6 @@ namespace Config::Supplementary {
|
|||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:ignore_window",
|
||||
.description = "if true, the shadow will not be rendered behind the window itself, only around it.",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "decoration:shadow:color",
|
||||
.description = "shadow's color. Alpha dictates shadow's opacity.",
|
||||
|
|
|
|||
|
|
@ -2253,30 +2253,33 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
|
|||
shader->setUniformFloat2(SHADER_TOP_LEFT, sc<float>(TOPLEFT.x), sc<float>(TOPLEFT.y));
|
||||
shader->setUniformFloat2(SHADER_BOTTOM_RIGHT, sc<float>(BOTTOMRIGHT.x), sc<float>(BOTTOMRIGHT.y));
|
||||
shader->setUniformFloat2(SHADER_FULL_SIZE, sc<float>(FULLSIZE.x), sc<float>(FULLSIZE.y));
|
||||
shader->setUniformFloat(SHADER_RADIUS, range + round);
|
||||
shader->setUniformFloat(SHADER_RADIUS, round);
|
||||
shader->setUniformFloat(SHADER_ROUNDING_POWER, roundingPower);
|
||||
shader->setUniformFloat(SHADER_RANGE, range);
|
||||
shader->setUniformFloat(SHADER_SHADOW_POWER, SHADOWPOWER);
|
||||
|
||||
glBindVertexArray(shader->getUniformLocation(SHADER_SHADER_VAO));
|
||||
|
||||
if (g_pHyprRenderer->m_renderData.clipBox.width != 0 && g_pHyprRenderer->m_renderData.clipBox.height != 0) {
|
||||
CRegion damageClip{g_pHyprRenderer->m_renderData.clipBox.x, g_pHyprRenderer->m_renderData.clipBox.y, g_pHyprRenderer->m_renderData.clipBox.width,
|
||||
g_pHyprRenderer->m_renderData.clipBox.height};
|
||||
damageClip.intersect(g_pHyprRenderer->m_renderData.damage);
|
||||
CRegion drawRegion;
|
||||
|
||||
if (!damageClip.empty()) {
|
||||
damageClip.forEachRect([this](const auto& RECT) {
|
||||
scissor(&RECT, g_pHyprRenderer->m_renderData.transformDamage);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
g_pHyprRenderer->m_renderData.damage.forEachRect([this](const auto& RECT) {
|
||||
if (g_pHyprRenderer->m_renderData.clipBox.width != 0 && g_pHyprRenderer->m_renderData.clipBox.height != 0) {
|
||||
drawRegion = {g_pHyprRenderer->m_renderData.clipBox.x, g_pHyprRenderer->m_renderData.clipBox.y, g_pHyprRenderer->m_renderData.clipBox.width,
|
||||
g_pHyprRenderer->m_renderData.clipBox.height};
|
||||
drawRegion.intersect(g_pHyprRenderer->m_renderData.damage);
|
||||
} else
|
||||
drawRegion = g_pHyprRenderer->m_renderData.damage;
|
||||
|
||||
if (g_pHyprRenderer->m_renderData.currentWindow) {
|
||||
auto PWINDOW = g_pHyprRenderer->m_renderData.currentWindow.lock();
|
||||
shader->setUniformFloat(SHADER_THICK, PWINDOW->getRealBorderSize() + PWINDOW->rounding());
|
||||
drawRegion.subtract(PWINDOW->surfaceLogicalBox().value().copy().scale(g_pHyprRenderer->m_renderData.pMonitor->m_scale).expand(-PWINDOW->rounding()));
|
||||
}
|
||||
|
||||
if (!drawRegion.empty())
|
||||
drawRegion.forEachRect([this](const auto& RECT) {
|
||||
scissor(&RECT, g_pHyprRenderer->m_renderData.transformDamage);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
});
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,17 +58,7 @@ void CHyprDropShadowDecoration::damageEntire() {
|
|||
|
||||
applyOffset(shadowBox);
|
||||
|
||||
static auto PSHADOWIGNOREWINDOW = CConfigValue<Hyprlang::INT>("decoration:shadow:ignore_window");
|
||||
const auto ROUNDING = PWINDOW->rounding();
|
||||
const auto ROUNDINGSIZE = ROUNDING - M_SQRT1_2 * ROUNDING + 1;
|
||||
|
||||
CRegion shadowRegion(shadowBox);
|
||||
if (*PSHADOWIGNOREWINDOW) {
|
||||
CBox surfaceBox = PWINDOW->getWindowMainSurfaceBox();
|
||||
applyOffset(surfaceBox);
|
||||
surfaceBox.expand(-ROUNDINGSIZE);
|
||||
shadowRegion.subtract(CRegion(surfaceBox));
|
||||
}
|
||||
CRegion shadowRegion(shadowBox);
|
||||
|
||||
for (auto const& m : g_pCompositor->m_monitors) {
|
||||
if (!g_pHyprRenderer->shouldRenderWindow(PWINDOW, m)) {
|
||||
|
|
@ -125,10 +115,9 @@ SShadowRenderData CHyprDropShadowDecoration::getRenderData(PHLMONITOR pMonitor,
|
|||
|
||||
const auto PWINDOW = m_window.lock();
|
||||
|
||||
static auto PSHADOWSIZE = CConfigValue<Hyprlang::INT>("decoration:shadow:range");
|
||||
static auto PSHADOWIGNOREWINDOW = CConfigValue<Hyprlang::INT>("decoration:shadow:ignore_window");
|
||||
static auto PSHADOWSCALE = CConfigValue<Hyprlang::FLOAT>("decoration:shadow:scale");
|
||||
static auto PSHADOWOFFSET = CConfigValue<Hyprlang::VEC2>("decoration:shadow:offset");
|
||||
static auto PSHADOWSIZE = CConfigValue<Hyprlang::INT>("decoration:shadow:range");
|
||||
static auto PSHADOWSCALE = CConfigValue<Hyprlang::FLOAT>("decoration:shadow:scale");
|
||||
static auto PSHADOWOFFSET = CConfigValue<Hyprlang::VEC2>("decoration:shadow:offset");
|
||||
|
||||
const auto BORDERSIZE = PWINDOW->getRealBorderSize();
|
||||
const auto ROUNDINGBASE = PWINDOW->rounding();
|
||||
|
|
@ -173,43 +162,11 @@ SShadowRenderData CHyprDropShadowDecoration::getRenderData(PHLMONITOR pMonitor,
|
|||
|
||||
g_pHyprRenderer->m_renderData.currentWindow = m_window;
|
||||
|
||||
CBox windowBox;
|
||||
CRegion saveDamage;
|
||||
fullBox.scale(pMonitor->m_scale).round();
|
||||
if (*PSHADOWIGNOREWINDOW) {
|
||||
windowBox = m_lastWindowBox;
|
||||
CBox withDecos = m_lastWindowBoxWithDecos;
|
||||
|
||||
// get window box
|
||||
windowBox.translate(-pMonitor->m_position + WORKSPACEOFFSET);
|
||||
withDecos.translate(-pMonitor->m_position + WORKSPACEOFFSET);
|
||||
|
||||
windowBox.translate(PWINDOW->m_floatingOffset);
|
||||
withDecos.translate(PWINDOW->m_floatingOffset);
|
||||
|
||||
auto scaledExtentss = withDecos.extentsFrom(windowBox);
|
||||
scaledExtentss = scaledExtentss * pMonitor->m_scale;
|
||||
scaledExtentss = scaledExtentss.round();
|
||||
|
||||
// add extents
|
||||
windowBox.scale(pMonitor->m_scale).round().addExtents(scaledExtentss);
|
||||
|
||||
if (windowBox.width < 1 || windowBox.height < 1)
|
||||
return {}; // prevent assert failed
|
||||
|
||||
saveDamage = g_pHyprRenderer->m_renderData.damage;
|
||||
|
||||
g_pHyprRenderer->m_renderData.damage = fullBox;
|
||||
g_pHyprRenderer->m_renderData.damage.subtract(windowBox.copy().expand(-ROUNDING * pMonitor->m_scale)).intersect(saveDamage);
|
||||
g_pHyprRenderer->m_renderData.renderModif.applyToRegion(g_pHyprRenderer->m_renderData.damage);
|
||||
}
|
||||
|
||||
return {
|
||||
.ignoreWindow = *PSHADOWIGNOREWINDOW,
|
||||
.valid = true,
|
||||
.fullBox = fullBox,
|
||||
.windowBox = windowBox,
|
||||
.saveDamage = saveDamage,
|
||||
.rounding = ROUNDING,
|
||||
.roundingPower = ROUNDINGPOWER,
|
||||
.size = *PSHADOWSIZE,
|
||||
|
|
@ -233,58 +190,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
|
|||
|
||||
g_pHyprRenderer->disableScissor();
|
||||
|
||||
if (data.ignoreWindow) {
|
||||
const auto alphaFB = g_pHyprRenderer->m_renderData.pMonitor->resources()->getUnusedWorkBuffer();
|
||||
const auto alphaSwapFB = g_pHyprRenderer->m_renderData.pMonitor->resources()->getUnusedWorkBuffer();
|
||||
|
||||
CBox monbox = {0, 0, pMonitor->m_transformedSize.x, pMonitor->m_transformedSize.y};
|
||||
|
||||
auto guard = g_pHyprRenderer->bindTempFB(alphaFB); // store current FB inside guard
|
||||
|
||||
// TODO not needed for 8bpc and 16fp?
|
||||
// build the matte
|
||||
// 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest.
|
||||
// first, clear region of interest with black (fully transparent)
|
||||
g_pHyprRenderer->draw(CRectPassElement::SRectData{.box = data.fullBox, .color = CHyprColor(0, 0, 0, 1), .round = 0}, monbox);
|
||||
|
||||
// render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit)
|
||||
drawShadowInternal(data.fullBox, data.rounding * pMonitor->m_scale, data.roundingPower, data.size * pMonitor->m_scale,
|
||||
CHyprColor(1, 1, 1, PWINDOW->m_realShadowColor->value().a), a);
|
||||
|
||||
// render black window box ("clip")
|
||||
g_pHyprRenderer->draw(
|
||||
CRectPassElement::SRectData{
|
||||
.box = data.windowBox,
|
||||
.color = CHyprColor(0, 0, 0, 1),
|
||||
.round = (data.rounding + 1 /* This fixes small pixel gaps. */) * pMonitor->m_scale,
|
||||
.roundingPower = data.roundingPower,
|
||||
},
|
||||
monbox);
|
||||
|
||||
g_pHyprRenderer->bindFB(alphaSwapFB);
|
||||
|
||||
// alpha swap just has the shadow color. It will be the "texture" to render.
|
||||
g_pHyprRenderer->draw(CRectPassElement::SRectData{.box = data.fullBox, .color = PWINDOW->m_realShadowColor->value().stripA(), .round = 0}, monbox);
|
||||
|
||||
guard.reset(); // restore FB
|
||||
|
||||
g_pHyprRenderer->pushMonitorTransformEnabled(true);
|
||||
g_pHyprRenderer->m_renderData.renderModif.enabled = false;
|
||||
|
||||
g_pHyprRenderer->draw(
|
||||
CTextureMatteElement::STextureMatteData{
|
||||
.box = monbox,
|
||||
.tex = alphaSwapFB->getTexture(),
|
||||
.fb = alphaFB,
|
||||
},
|
||||
{});
|
||||
|
||||
g_pHyprRenderer->m_renderData.renderModif.enabled = true;
|
||||
g_pHyprRenderer->popMonitorTransformEnabled();
|
||||
|
||||
g_pHyprRenderer->m_renderData.damage = data.saveDamage;
|
||||
} else
|
||||
drawShadowInternal(data.fullBox, data.rounding * pMonitor->m_scale, data.roundingPower, data.size * pMonitor->m_scale, PWINDOW->m_realShadowColor->value(), a);
|
||||
drawShadowInternal(data.fullBox, data.rounding * pMonitor->m_scale, data.roundingPower, data.size * pMonitor->m_scale, PWINDOW->m_realShadowColor->value(), a);
|
||||
|
||||
reposition();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,11 @@
|
|||
#include "IHyprWindowDecoration.hpp"
|
||||
|
||||
struct SShadowRenderData {
|
||||
bool ignoreWindow = false;
|
||||
bool valid = false;
|
||||
CBox fullBox;
|
||||
CBox windowBox;
|
||||
CRegion saveDamage;
|
||||
float rounding = 0;
|
||||
float roundingPower = 0;
|
||||
int size = 0;
|
||||
bool valid = false;
|
||||
CBox fullBox;
|
||||
float rounding = 0;
|
||||
float roundingPower = 0;
|
||||
int size = 0;
|
||||
};
|
||||
|
||||
class CHyprDropShadowDecoration : public IHyprWindowDecoration {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@
|
|||
#define M_PI 3.1415926535897932384626433832795
|
||||
#define SMOOTHING_CONSTANT (M_PI / 5.34665792551)
|
||||
|
||||
float distanceWithRounding(vec2 coords, float roundingPower) {
|
||||
return pow(pow(coords.x, roundingPower) + pow(coords.y, roundingPower), 1.0 / roundingPower);
|
||||
}
|
||||
|
||||
vec4 rounding(vec4 color, float radius, float roundingPower, vec2 topLeft, vec2 fullSize) {
|
||||
vec2 pixCoord = vec2(gl_FragCoord);
|
||||
pixCoord -= topLeft + fullSize * 0.5;
|
||||
|
|
@ -12,7 +16,7 @@ vec4 rounding(vec4 color, float radius, float roundingPower, vec2 topLeft, vec2
|
|||
pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix don't make it top-left
|
||||
|
||||
if (pixCoord.x + pixCoord.y > radius) {
|
||||
float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0 / roundingPower);
|
||||
float dist = distanceWithRounding(pixCoord, roundingPower);
|
||||
|
||||
if (dist > radius + SMOOTHING_CONSTANT)
|
||||
discard;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ uniform float radius;
|
|||
uniform float roundingPower;
|
||||
uniform float range;
|
||||
uniform float shadowPower;
|
||||
uniform float thick;
|
||||
|
||||
#if USE_CM
|
||||
#include "cm_helpers.glsl"
|
||||
|
|
@ -38,7 +39,7 @@ void main() {
|
|||
#else
|
||||
fragColor =
|
||||
#endif
|
||||
getShadow(pixColor, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight
|
||||
getShadow(pixColor, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight, thick
|
||||
#if USE_CM
|
||||
,
|
||||
sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#define SHADOW_GLSL
|
||||
|
||||
#include "cm_helpers.glsl"
|
||||
#include "rounding.glsl"
|
||||
|
||||
float pixAlphaRoundedDistance(float distanceToCorner, float radius, float range, float shadowPower) {
|
||||
if (distanceToCorner > radius) {
|
||||
|
|
@ -28,7 +29,8 @@ vec4[2]
|
|||
#else
|
||||
vec4
|
||||
#endif
|
||||
getShadow(vec4 pixColor, vec2 v_texcoord, float radius, float roundingPower, vec2 topLeft, vec2 fullSize, float range, float shadowPower, vec2 bottomRight
|
||||
getShadow(vec4 pixColor, vec2 v_texcoord, float borderRadius, float roundingPower, vec2 topLeft, vec2 fullSize, float range, float shadowPower, vec2 bottomRight,
|
||||
float decoWidth
|
||||
#if USE_CM
|
||||
,
|
||||
int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
|
||||
|
|
@ -51,6 +53,7 @@ vec4
|
|||
#endif
|
||||
#endif
|
||||
) {
|
||||
float radius = range + borderRadius;
|
||||
float originalAlpha = pixColor[3];
|
||||
|
||||
bool done = false;
|
||||
|
|
@ -58,29 +61,50 @@ vec4
|
|||
vec2 pixCoord = fullSize * v_texcoord;
|
||||
|
||||
// ok, now we check the distance to a border.
|
||||
|
||||
// corners
|
||||
if (pixCoord[0] < topLeft[0]) {
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top left
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - topLeft, roundingPower), radius, range, shadowPower);
|
||||
done = true;
|
||||
float distance = distanceWithRounding(vec2(topLeft.x - pixCoord.x, topLeft.y - pixCoord.y), roundingPower);
|
||||
if (borderRadius > 0.0 && distance < decoWidth) {
|
||||
pixColor[3] = 0.0;
|
||||
} else {
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - topLeft, roundingPower), radius, range, shadowPower);
|
||||
}
|
||||
done = true;
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom left
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(topLeft[0], bottomRight[1]), roundingPower), radius, range, shadowPower);
|
||||
done = true;
|
||||
float distance = distanceWithRounding(vec2(topLeft.x - pixCoord.x, pixCoord.y - bottomRight.y), roundingPower);
|
||||
if (borderRadius > 0.0 && distance < decoWidth) {
|
||||
pixColor[3] = 0.0;
|
||||
} else {
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(topLeft[0], bottomRight[1]), roundingPower), radius, range, shadowPower);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
} else if (pixCoord[0] > bottomRight[0]) {
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top right
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(bottomRight[0], topLeft[1]), roundingPower), radius, range, shadowPower);
|
||||
done = true;
|
||||
float distance = distanceWithRounding(vec2(pixCoord.x - bottomRight.x, topLeft.y - pixCoord.y), roundingPower);
|
||||
if (borderRadius > 0.0 && distance < decoWidth) {
|
||||
pixColor[3] = 0.0;
|
||||
} else {
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(bottomRight[0], topLeft[1]), roundingPower), radius, range, shadowPower);
|
||||
}
|
||||
done = true;
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom right
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - bottomRight, roundingPower), radius, range, shadowPower);
|
||||
done = true;
|
||||
float distance = distanceWithRounding(vec2(pixCoord.x - bottomRight.x, pixCoord.y - bottomRight.y), roundingPower);
|
||||
if (borderRadius > 0.0 && distance < decoWidth) {
|
||||
pixColor[3] = 0.0;
|
||||
} else {
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - bottomRight, roundingPower), radius, range, shadowPower);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
// edges
|
||||
if (!done) {
|
||||
// distance to all straight bb borders
|
||||
float distanceT = pixCoord[1];
|
||||
|
|
@ -92,13 +116,24 @@ vec4
|
|||
float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR));
|
||||
|
||||
if (smallest < range) {
|
||||
// between border and max shadow distance
|
||||
pixColor[3] = pixColor[3] * pow((smallest / range), shadowPower);
|
||||
} else {
|
||||
// inside border or window
|
||||
pixColor[3] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (pixColor[3] == 0.0) {
|
||||
discard;
|
||||
#if USE_MIRROR
|
||||
vec4[2] pixColors;
|
||||
pixColors[0] = pixColor;
|
||||
pixColors[1] = pixColor;
|
||||
return pixColors;
|
||||
#else
|
||||
return pixColor;
|
||||
#endif
|
||||
}
|
||||
|
||||
// premultiply
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue