From 2cf2a0d986cec937623cd582bc3c71324c07f267 Mon Sep 17 00:00:00 2001 From: Micovec Date: Mon, 8 Jan 2024 12:51:18 +0100 Subject: [PATCH] corner radii --- src/Window.cpp | 44 +++---- src/Window.hpp | 46 +++---- src/config/ConfigDataValues.hpp | 74 +++++++++++- src/config/ConfigManager.cpp | 16 ++- src/debug/HyprCtl.cpp | 2 +- src/helpers/MiscFunctions.cpp | 18 +++ src/helpers/MiscFunctions.hpp | 2 + src/helpers/WLClasses.hpp | 2 +- src/render/OpenGL.cpp | 112 ++++++++++-------- src/render/OpenGL.hpp | 18 +-- src/render/Renderer.cpp | 50 ++++---- src/render/Shader.hpp | 6 +- .../decorations/CHyprBorderDecoration.cpp | 6 +- .../decorations/CHyprDropShadowDecoration.cpp | 20 +++- src/render/shaders/Border.hpp | 20 +++- src/render/shaders/Shadow.hpp | 41 +++---- src/render/shaders/Textures.hpp | 37 ++++-- 17 files changed, 332 insertions(+), 182 deletions(-) diff --git a/src/Window.cpp b/src/Window.cpp index 01b58253..53dd0c8d 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -563,7 +563,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { m_sAdditionalConfigData.nearestNeighbor = true; } else if (r.szRule.starts_with("rounding")) { try { - m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); + m_sAdditionalConfigData.cornerRadii = configStringToRadii(r.szRule); } catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); } } else if (r.szRule.starts_with("bordersize")) { try { @@ -656,7 +656,7 @@ void CWindow::updateDynamicRules() { m_sAdditionalConfigData.forceOpaque = false; m_sAdditionalConfigData.forceNoAnims = false; m_sAdditionalConfigData.animationStyle = std::string(""); - m_sAdditionalConfigData.rounding = -1; + m_sAdditionalConfigData.cornerRadii = -1; m_sAdditionalConfigData.dimAround = false; m_sAdditionalConfigData.forceRGBX = false; m_sAdditionalConfigData.borderSize = -1; @@ -678,27 +678,29 @@ void CWindow::updateDynamicRules() { // it is assumed that the point is within the real window box (m_vRealPosition, m_vRealSize) // otherwise behaviour is undefined bool CWindow::isInCurvedCorner(double x, double y) { - const int ROUNDING = rounding(); - if (getRealBorderSize() >= ROUNDING) + const CCornerRadiiData ROUNDING = getCornerRadii(); + const int BORDER = getRealBorderSize(); + + if (BORDER >= ROUNDING.topLeft && BORDER >= ROUNDING.topRight && BORDER >= ROUNDING.bottomLeft && BORDER >= ROUNDING.bottomRight) return false; - // (x0, y0), (x0, y1), ... are the center point of rounding at each corner - double x0 = m_vRealPosition.vec().x + ROUNDING; - double y0 = m_vRealPosition.vec().y + ROUNDING; - double x1 = m_vRealPosition.vec().x + m_vRealSize.vec().x - ROUNDING; - double y1 = m_vRealPosition.vec().y + m_vRealSize.vec().y - ROUNDING; + // topLeft, topRight, bottomLeft, bottomRight, ... are the center point of rounding at each corner + Vector2D topLeft = {m_vRealPosition.vec().x + ROUNDING.topLeft, m_vRealPosition.vec().y + ROUNDING.topLeft}; + Vector2D topRight = {m_vRealPosition.vec().x + m_vRealSize.vec().x + ROUNDING.topRight, m_vRealPosition.vec().y + ROUNDING.topRight}; + Vector2D bottomLeft = {m_vRealPosition.vec().x + ROUNDING.bottomLeft, m_vRealPosition.vec().y + m_vRealSize.vec().y + ROUNDING.bottomLeft}; + Vector2D bottomRight = {m_vRealPosition.vec().x + m_vRealSize.vec().x + ROUNDING.bottomRight, m_vRealPosition.vec().y + m_vRealSize.vec().y + ROUNDING.bottomRight}; - if (x < x0 && y < y0) { - return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING; + if (x < topLeft.x && y < topLeft.y) { + return topLeft.distance(Vector2D{x, y}) > (double)ROUNDING.topLeft; } - if (x > x1 && y < y0) { - return Vector2D{x1, y0}.distance(Vector2D{x, y}) > (double)ROUNDING; + if (x > topRight.x && y < topRight.y) { + return topRight.distance(Vector2D{x, y}) > (double)ROUNDING.topRight; } - if (x < x0 && y > y1) { - return Vector2D{x0, y1}.distance(Vector2D{x, y}) > (double)ROUNDING; + if (x < bottomLeft.x && y > bottomLeft.y) { + return bottomLeft.distance(Vector2D{x, y}) > (double)ROUNDING.bottomLeft; } - if (x > x1 && y > y1) { - return Vector2D{x1, y1}.distance(Vector2D{x, y}) > (double)ROUNDING; + if (x > bottomRight.x && y > bottomRight.y) { + return bottomRight.distance(Vector2D{x, y}) > (double)ROUNDING.bottomRight; } return false; @@ -989,12 +991,12 @@ bool CWindow::opaque() { return false; } -float CWindow::rounding() { - static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; +CCornerRadiiData CWindow::getCornerRadii() { + static auto* const PRADII = (CCornerRadiiData*)g_pConfigManager->getConfigValuePtr("decoration:rounding")->data.get(); - float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying(); + CCornerRadiiData radii = m_sAdditionalConfigData.cornerRadii.toUnderlying() == -1 ? *PRADII : m_sAdditionalConfigData.cornerRadii.toUnderlying(); - return m_sSpecialRenderData.rounding ? rounding : 0; + return m_sSpecialRenderData.rounding ? radii : 0; } void CWindow::updateSpecialRenderData() { diff --git a/src/Window.hpp b/src/Window.hpp index 559e4c90..e37ffd59 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -35,8 +35,8 @@ class IWindowTransformer; template class CWindowOverridableVar { public: - CWindowOverridableVar(T val) { - value = val; + CWindowOverridableVar(T val) + : value(val) { } ~CWindowOverridableVar() = default; @@ -51,7 +51,7 @@ class CWindowOverridableVar { return *this; } - T operator=(T& other) { + T operator=(const T& other) { if (locked) return value; value = other; @@ -123,25 +123,25 @@ struct SWindowSpecialRenderData { }; struct SWindowAdditionalConfigData { - std::string animationStyle = std::string(""); - CWindowOverridableVar rounding = -1; // -1 means no - CWindowOverridableVar forceNoBlur = false; - CWindowOverridableVar forceOpaque = false; - CWindowOverridableVar forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher. - CWindowOverridableVar forceAllowsInput = false; - CWindowOverridableVar forceNoAnims = false; - CWindowOverridableVar forceNoBorder = false; - CWindowOverridableVar forceNoShadow = false; - CWindowOverridableVar forceNoDim = false; - CWindowOverridableVar windowDanceCompat = false; - CWindowOverridableVar noMaxSize = false; - CWindowOverridableVar dimAround = false; - CWindowOverridableVar forceRGBX = false; - CWindowOverridableVar keepAspectRatio = false; - CWindowOverridableVar xray = -1; // -1 means unset, takes precedence over the renderdata one - CWindowOverridableVar borderSize = -1; // -1 means unset, takes precedence over the renderdata one - CWindowOverridableVar forceTearing = false; - CWindowOverridableVar nearestNeighbor = false; + std::string animationStyle = std::string(""); + CWindowOverridableVar cornerRadii = CCornerRadiiData(-1); // -1 means no + CWindowOverridableVar forceNoBlur = false; + CWindowOverridableVar forceOpaque = false; + CWindowOverridableVar forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher. + CWindowOverridableVar forceAllowsInput = false; + CWindowOverridableVar forceNoAnims = false; + CWindowOverridableVar forceNoBorder = false; + CWindowOverridableVar forceNoShadow = false; + CWindowOverridableVar forceNoDim = false; + CWindowOverridableVar windowDanceCompat = false; + CWindowOverridableVar noMaxSize = false; + CWindowOverridableVar dimAround = false; + CWindowOverridableVar forceRGBX = false; + CWindowOverridableVar keepAspectRatio = false; + CWindowOverridableVar xray = -1; // -1 means unset, takes precedence over the renderdata one + CWindowOverridableVar borderSize = -1; // -1 means unset, takes precedence over the renderdata one + CWindowOverridableVar forceTearing = false; + CWindowOverridableVar nearestNeighbor = false; }; struct SWindowRule { @@ -368,7 +368,7 @@ class CWindow { SWindowDecorationExtents getFullWindowReservedArea(); Vector2D middle(); bool opaque(); - float rounding(); + CCornerRadiiData getCornerRadii(); bool canBeTorn(); bool shouldSendFullscreenState(); void setSuspended(bool suspend); diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp index f6bf9881..d5e548ab 100644 --- a/src/config/ConfigDataValues.hpp +++ b/src/config/ConfigDataValues.hpp @@ -4,7 +4,8 @@ enum eConfigValueDataTypes { CVD_TYPE_INVALID = -1, - CVD_TYPE_GRADIENT = 0 + CVD_TYPE_GRADIENT = 0, + CVD_TYPE_CORNER_RADII = 1 }; class ICustomConfigValueData { @@ -49,3 +50,74 @@ class CGradientValueData : public ICustomConfigValueData { return true; } }; + +// This class is probably going to be refactored once hyprlang is used +class CCornerRadiiData : public ICustomConfigValueData { + public: + CCornerRadiiData() + : CCornerRadiiData(0) { + } + + CCornerRadiiData(int radius) + : CCornerRadiiData(radius, radius, radius, radius) { + } + + CCornerRadiiData(int topL, int topR, int bottomR, int bottomL) + : topLeft(topL), topRight(topR), bottomRight(bottomR), bottomLeft(bottomL) { + } + + virtual ~CCornerRadiiData(){} + + virtual eConfigValueDataTypes getDataType() { + return CVD_TYPE_CORNER_RADII; + } + + void reset(int radius) { + topLeft = topRight = bottomRight = bottomLeft = radius; + } + + CCornerRadiiData operator+(int a) const { + return CCornerRadiiData(topLeft + a, topRight + a, bottomRight + a, bottomLeft + a); + } + + CCornerRadiiData operator-(int a) const { + return CCornerRadiiData(topLeft - a, topRight - a, bottomRight - a, bottomLeft - a); + } + + CCornerRadiiData operator*(int a) const { + return CCornerRadiiData(topLeft * a, topRight * a, bottomRight * a, bottomLeft * a); + } + + CCornerRadiiData operator/(int a) const { + return CCornerRadiiData(topLeft / a, topRight / a, bottomRight / a, bottomLeft / a); + } + + bool operator==(int a) const { + return topLeft == a && topRight == a && bottomRight == a && bottomLeft == a; + } + + bool operator!=(int a) const { + return topLeft != a && topRight != a && bottomRight != a && bottomLeft != a; + } + + CCornerRadiiData& operator+=(int a) { + topLeft += a; + topRight += a; + bottomRight += a; + bottomLeft += a; + return *this; + } + + CCornerRadiiData& operator-=(int a) { + topLeft -= a; + topRight -= a; + bottomRight -= a; + bottomLeft -= a; + return *this; + } + + int topLeft; + int topRight; + int bottomRight; + int bottomLeft; +}; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 44b5374b..dc5a035b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -33,6 +33,8 @@ CConfigManager::CConfigManager() { configValues["group:groupbar:col.locked_active"].data = std::make_shared(0x66ff5500); configValues["group:groupbar:col.locked_inactive"].data = std::make_shared(0x66775500); + configValues["decoration:rounding"].data = std::make_shared(0); + Debug::log(LOG, "NOTE: further logs to stdout / logfile are disabled by default. Use debug:disable_logs and debug:enable_stdout_logs to override this."); setDefaultVars(); @@ -161,7 +163,7 @@ void CConfigManager::setDefaultVars() { configValues["debug:watchdog_timeout"].intValue = 5; configValues["debug:disable_scale_checks"].intValue = 0; - configValues["decoration:rounding"].intValue = 0; + ((CCornerRadiiData*)configValues["decoration:rounding"].data.get())->reset(0xffffffff); configValues["decoration:blur:enabled"].intValue = 1; configValues["decoration:blur:size"].intValue = 8; configValues["decoration:blur:passes"].intValue = 1; @@ -543,6 +545,18 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s break; } + case CVD_TYPE_CORNER_RADII: { + CCornerRadiiData* data = static_cast(CONFIGENTRY->data.get()); + + try { + *data = configStringToRadii(VALUE); + } catch (std::exception& e) { + Debug::log(WARN, "Error reading value of {}", COMMAND); + parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what(); + } + + break; + } default: { UNREACHABLE(); } diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 78d20903..03532de2 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1106,7 +1106,7 @@ std::string dispatchSetProp(std::string request) { if (PROP == "animationstyle") { PWINDOW->m_sAdditionalConfigData.animationStyle = VAL; } else if (PROP == "rounding") { - PWINDOW->m_sAdditionalConfigData.rounding.forceSetIgnoreLocked(configStringToInt(VAL), lock); + PWINDOW->m_sAdditionalConfigData.cornerRadii.forceSetIgnoreLocked(configStringToRadii(VAL), lock); } else if (PROP == "forcenoblur") { PWINDOW->m_sAdditionalConfigData.forceNoBlur.forceSetIgnoreLocked(configStringToInt(VAL), lock); } else if (PROP == "forceopaque") { diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 5eb99bfd..21a022dc 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -715,6 +715,24 @@ int64_t configStringToInt(const std::string& VALUE) { return std::stoll(VALUE); } +CCornerRadiiData configStringToRadii(const std::string& VALUE) { + CVarList vars(VALUE); + + CCornerRadiiData radii; + if (vars.size() == 1) { + radii.reset(std::stoi(vars[0])); + } else if (vars.size() == 4) { + radii.topLeft = std::stoi(vars[0]); + radii.topRight = std::stoi(vars[1]); + radii.bottomRight = std::stoi(vars[2]); + radii.bottomLeft = std::stoi(vars[3]); + } else { + throw std::invalid_argument("not enough or too many values (1 or 4 separated by comma)"); + } + + return radii; +} + double normalizeAngleRad(double ang) { if (ang > M_PI * 2) { while (ang > M_PI * 2) diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 1ccbdc0e..08d3ac26 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -5,6 +5,7 @@ #include #include #include "Vector2D.hpp" +#include "../config/ConfigDataValues.hpp" #include #include @@ -27,6 +28,7 @@ void logSystemInfo(); std::string execAndGet(const char*); int64_t getPPIDof(int64_t pid); int64_t configStringToInt(const std::string&); +CCornerRadiiData configStringToRadii(const std::string&); std::optional getPlusMinusKeywordResult(std::string in, float relative); void matrixProjection(float mat[9], int w, int h, wl_output_transform tr); double normalizeAngleRad(double ang); diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index be0fd005..1b897dde 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -86,7 +86,7 @@ struct SRenderData { bool decorate = false; // for custom round values - int rounding = -1; // -1 means not set + CCornerRadiiData cornerRadii = -1; // -1 means not set // for blurring bool blur = false; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index cb468932..0b97dc18 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -313,14 +313,14 @@ void CHyprOpenGLImpl::end() { } void CHyprOpenGLImpl::initShaders() { - GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); - m_RenderData.pCurrentMonData->m_shQUAD.program = prog; - m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color"); - m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius"); + GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); + m_RenderData.pCurrentMonData->m_shQUAD.program = prog; + m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); + m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color"); + m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); + m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft"); + m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize"); + m_RenderData.pCurrentMonData->m_shQUAD.cornerRadii = glGetUniformLocation(prog, "cornerRadii"); prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA); m_RenderData.pCurrentMonData->m_shRGBA.program = prog; @@ -336,7 +336,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shRGBA.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); m_RenderData.pCurrentMonData->m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shRGBA.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shRGBA.cornerRadii = glGetUniformLocation(prog, "cornerRadii"); m_RenderData.pCurrentMonData->m_shRGBA.applyTint = glGetUniformLocation(prog, "applyTint"); m_RenderData.pCurrentMonData->m_shRGBA.tint = glGetUniformLocation(prog, "tint"); m_RenderData.pCurrentMonData->m_shRGBA.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); @@ -378,7 +378,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shRGBX.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); m_RenderData.pCurrentMonData->m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shRGBX.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shRGBX.cornerRadii = glGetUniformLocation(prog, "cornerRadii"); m_RenderData.pCurrentMonData->m_shRGBX.applyTint = glGetUniformLocation(prog, "applyTint"); m_RenderData.pCurrentMonData->m_shRGBX.tint = glGetUniformLocation(prog, "tint"); @@ -394,7 +394,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shEXT.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); m_RenderData.pCurrentMonData->m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shEXT.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shEXT.cornerRadii = glGetUniformLocation(prog, "cornerRadii"); m_RenderData.pCurrentMonData->m_shEXT.applyTint = glGetUniformLocation(prog, "applyTint"); m_RenderData.pCurrentMonData->m_shEXT.tint = glGetUniformLocation(prog, "tint"); @@ -405,21 +405,21 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shBLUR1.proj = glGetUniformLocation(prog, "proj"); m_RenderData.pCurrentMonData->m_shBLUR1.posAttrib = glGetAttribLocation(prog, "pos"); m_RenderData.pCurrentMonData->m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shBLUR1.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shBLUR1.cornerRadii = glGetUniformLocation(prog, "cornerRadii"); m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel = glGetUniformLocation(prog, "halfpixel"); m_RenderData.pCurrentMonData->m_shBLUR1.passes = glGetUniformLocation(prog, "passes"); m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy = glGetUniformLocation(prog, "vibrancy"); m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy_darkness = glGetUniformLocation(prog, "vibrancy_darkness"); - prog = createProgram(TEXVERTSRC, FRAGBLUR2); - m_RenderData.pCurrentMonData->m_shBLUR2.program = prog; - m_RenderData.pCurrentMonData->m_shBLUR2.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shBLUR2.alpha = glGetUniformLocation(prog, "alpha"); - m_RenderData.pCurrentMonData->m_shBLUR2.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shBLUR2.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel"); + prog = createProgram(TEXVERTSRC, FRAGBLUR2); + m_RenderData.pCurrentMonData->m_shBLUR2.program = prog; + m_RenderData.pCurrentMonData->m_shBLUR2.tex = glGetUniformLocation(prog, "tex"); + m_RenderData.pCurrentMonData->m_shBLUR2.alpha = glGetUniformLocation(prog, "alpha"); + m_RenderData.pCurrentMonData->m_shBLUR2.proj = glGetUniformLocation(prog, "proj"); + m_RenderData.pCurrentMonData->m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos"); + m_RenderData.pCurrentMonData->m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord"); + m_RenderData.pCurrentMonData->m_shBLUR2.cornerRadii = glGetUniformLocation(prog, "cornerRadii"); + m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel"); prog = createProgram(TEXVERTSRC, FRAGBLURPREPARE); m_RenderData.pCurrentMonData->m_shBLURPREPARE.program = prog; @@ -445,9 +445,11 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); m_RenderData.pCurrentMonData->m_shSHADOW.topLeft = glGetUniformLocation(prog, "topLeft"); + m_RenderData.pCurrentMonData->m_shSHADOW.topRight = glGetUniformLocation(prog, "topRight"); m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight = glGetUniformLocation(prog, "bottomRight"); + m_RenderData.pCurrentMonData->m_shSHADOW.bottomLeft = glGetUniformLocation(prog, "bottomLeft"); m_RenderData.pCurrentMonData->m_shSHADOW.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shSHADOW.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shSHADOW.cornerRadii = glGetUniformLocation(prog, "cornerRadii"); m_RenderData.pCurrentMonData->m_shSHADOW.range = glGetUniformLocation(prog, "range"); m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower"); m_RenderData.pCurrentMonData->m_shSHADOW.color = glGetUniformLocation(prog, "color"); @@ -462,8 +464,8 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight = glGetUniformLocation(prog, "bottomRight"); m_RenderData.pCurrentMonData->m_shBORDER1.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed = glGetUniformLocation(prog, "fullSizeUntransformed"); - m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter = glGetUniformLocation(prog, "radiusOuter"); + m_RenderData.pCurrentMonData->m_shBORDER1.cornerRadii = glGetUniformLocation(prog, "cornerRadii"); + m_RenderData.pCurrentMonData->m_shBORDER1.cornerRadiiOuter = glGetUniformLocation(prog, "cornerRadiiOuter"); m_RenderData.pCurrentMonData->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient"); m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength"); m_RenderData.pCurrentMonData->m_shBORDER1.angle = glGetUniformLocation(prog, "angle"); @@ -578,12 +580,12 @@ void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h scissor(&box, transform); } -void CHyprOpenGLImpl::renderRect(CBox* box, const CColor& col, int round) { +void CHyprOpenGLImpl::renderRect(CBox* box, const CColor& col, CCornerRadiiData radii) { if (!m_RenderData.damage.empty()) - renderRectWithDamage(box, col, &m_RenderData.damage, round); + renderRectWithDamage(box, col, &m_RenderData.damage, radii); } -void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round, float blurA, bool xray) { +void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, CCornerRadiiData radii, float blurA, bool xray) { if (m_RenderData.damage.empty()) return; @@ -605,7 +607,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - renderRect(box, CColor(0, 0, 0, 0), round); + renderRect(box, CColor(0, 0, 0, 0), radii); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 1, -1); @@ -627,10 +629,10 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round glStencilFunc(GL_ALWAYS, 1, 0xFF); scissor((CBox*)nullptr); - renderRectWithDamage(box, col, &m_RenderData.damage, round); + renderRectWithDamage(box, col, &m_RenderData.damage, radii); } -void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion* damage, int round) { +void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion* damage, CCornerRadiiData radii) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); @@ -670,7 +672,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion // Rounded corners glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.radius, round); + glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.cornerRadii, radii.topLeft, radii.topRight, radii.bottomRight, radii.bottomLeft); glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -696,21 +698,21 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib); } -void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, CBox* pBox, float alpha, int round, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, CBox* pBox, float alpha, CCornerRadiiData radii, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV); + renderTexture(CTexture(tex), pBox, alpha, radii, false, allowCustomUV); } -void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha, CCornerRadiiData radii, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, &m_RenderData.damage, round, discardActive, false, allowCustomUV, true); + renderTextureInternalWithDamage(tex, pBox, alpha, &m_RenderData.damage, radii, discardActive, false, allowCustomUV, true); scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, +void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* pBox, float alpha, CRegion* damage, CCornerRadiiData radii, bool discardActive, bool noAA, bool allowCustomUV, bool allowDim) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); @@ -824,7 +826,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* // Rounded corners glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y); glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y); - glUniform1f(shader->radius, round); + glUniform4f(shader->cornerRadii, radii.topLeft, radii.topRight, radii.bottomRight, radii.bottomLeft); if (allowDim && m_pCurrentWindow && *PDIMINACTIVE) { glUniform1i(shader->applyTint, 1); @@ -1094,7 +1096,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o wlr_matrix_transpose(glMatrix, glMatrix); glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); #endif - glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a + glUniform4f(pShader->cornerRadii, *PBLURSIZE * a, *PBLURSIZE * a, *PBLURSIZE * a, *PBLURSIZE * a); // this makes the blursize change with a if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) { glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); @@ -1361,7 +1363,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(SLayerSurface* pLayer, CWind return false; } -void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, float a, wlr_surface* pSurface, int round, bool blockBlurOptimization, float blurA) { +void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, float a, wlr_surface* pSurface, CCornerRadiiData radii, bool blockBlurOptimization, float blurA) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue; @@ -1378,7 +1380,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && (m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur || m_pCurrentWindow->m_sAdditionalConfigData.forceRGBX))) { - renderTexture(tex, pBox, a, round, false, true); + renderTexture(tex, pBox, a, radii, false, true); return; } @@ -1391,7 +1393,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale); if (inverseOpaque.empty()) { - renderTexture(tex, pBox, a, round, false, true); + renderTexture(tex, pBox, a, radii, false, true); return; } } else { @@ -1426,9 +1428,9 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); if (USENEWOPTIMIZE && !(m_RenderData.discardMode & DISCARD_ALPHA)) - renderRect(pBox, CColor(0, 0, 0, 0), round); + renderRect(pBox, CColor(0, 0, 0, 0), radii); else - renderTexture(tex, pBox, a, round, true, true); // discard opaque + renderTexture(tex, pBox, a, radii, true, true); // discard opaque glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 1, -1); @@ -1451,7 +1453,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo // draw window glDisable(GL_STENCIL_TEST); - renderTextureInternalWithDamage(tex, pBox, a, &texDamage, round, false, false, true, true); + renderTextureInternalWithDamage(tex, pBox, a, &texDamage, radii, false, false, true, true); glStencilMask(-1); glStencilFunc(GL_ALWAYS, 1, 0xFF); @@ -1465,7 +1467,7 @@ void pushVert2D(float x, float y, float* arr, int& counter, CBox* box) { counter++; } -void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, int round, int borderSize, float a, int outerRound) { +void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, CCornerRadiiData radii, int borderSize, float a, CCornerRadiiData outerRadii) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); @@ -1490,7 +1492,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in box->width += 2 * scaledBorderSize; box->height += 2 * scaledBorderSize; - round += round == 0 ? 0 : scaledBorderSize; + radii += radii == 0 ? 0 : scaledBorderSize; float matrix[9]; wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, @@ -1528,8 +1530,10 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); + glUniform4f(m_RenderData.pCurrentMonData->m_shBORDER1.cornerRadii, radii.topLeft, radii.topRight, radii.bottomRight, radii.bottomLeft); + + CCornerRadiiData actualOuterRadii = outerRadii == -1 ? radii : outerRadii; + glUniform4f(m_RenderData.pCurrentMonData->m_shBORDER1.cornerRadiiOuter, actualOuterRadii.topLeft, actualOuterRadii.topRight, actualOuterRadii.bottomRight, actualOuterRadii.bottomLeft); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize); glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -1768,7 +1772,7 @@ void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) { m_bEndFrame = false; } -void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const CColor& color, float a) { +void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, CCornerRadiiData radii, int range, const CColor& color, float a) { 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!"); RASSERT(m_pCurrentWindow, "Tried to render shadow without a window!"); @@ -1808,15 +1812,19 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const #endif glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); - const auto TOPLEFT = Vector2D(range + round, range + round); - const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round)); + const auto TOPLEFT = Vector2D(range + radii.topLeft, range + radii.topLeft); + const auto TOPRIGHT = Vector2D(box->width - range - radii.topRight, range + radii.topRight); + const auto BOTTOMRIGHT = Vector2D(box->width - (range + radii.bottomRight), box->height - (range + radii.bottomRight)); + const auto BOTTOMLEFT = Vector2D(range + radii.bottomLeft, box->height - (range + radii.bottomLeft)); const auto FULLSIZE = Vector2D(box->width, box->height); // Rounded corners glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.topRight, (float)TOPRIGHT.x, (float)TOPRIGHT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.bottomLeft, (float)BOTTOMLEFT.x, (float)BOTTOMLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.radius, range + round); + glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.cornerRadii, range + radii.topLeft, range + radii.topRight, range + radii.bottomRight, range + radii.bottomLeft); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.range, range); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower, SHADOWPOWER); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index cd52fe3e..d54e3f0c 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -118,14 +118,14 @@ class CHyprOpenGLImpl { void begin(CMonitor*, CRegion*, CFramebuffer* fb = nullptr /* if provided, it's not a real frame */); void end(); - void renderRect(CBox*, const CColor&, int round = 0); - void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); - void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); - void renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false); - void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); - void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); - void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); + void renderRect(CBox*, const CColor&, CCornerRadiiData radii = 0); + void renderRectWithBlur(CBox*, const CColor&, CCornerRadiiData radii = 0, float blurA = 1.f, bool xray = false); + void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, CCornerRadiiData radii = 0); + void renderTexture(wlr_texture*, CBox*, float a, CCornerRadiiData radii = 0, bool allowCustomUV = false); + void renderTexture(const CTexture&, CBox*, float a, CCornerRadiiData radii = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, CCornerRadiiData radii = 0, bool blockBlurOptimization = false, float blurA = 1.f); + void renderRoundedShadow(CBox*, CCornerRadiiData radii, int range, const CColor& color, float a = 1.0); + void renderBorder(CBox*, const CGradientValueData&, CCornerRadiiData radii, int borderSize, float a = 1.0, CCornerRadiiData outerRadii = -1 /* use round */); void renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte); void setMonitorTransformEnabled(bool enabled); @@ -216,7 +216,7 @@ class CHyprOpenGLImpl { // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); - void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false, + void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, CCornerRadiiData radii = 0, bool discardOpaque = false, bool noAA = false, bool allowCustomUV = false, bool allowDim = false); void renderTexturePrimitive(const CTexture& tex, CBox* pBox); void renderSplash(cairo_t* const, cairo_surface_t* const, double); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 533215ce..d5a833f5 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -122,15 +122,15 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; - float rounding = RDATA->rounding; + CCornerRadiiData radii = RDATA->cornerRadii; - rounding -= 1; // to fix a border issue + radii -= 1; // to fix a border issue if (RDATA->dontRound) - rounding = 0; + radii = 0; const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface.wlr() == surface ? RDATA->pWindow->opaque() : false; - const bool CANDISABLEBLEND = RDATA->alpha * RDATA->fadeAlpha >= 1.f && rounding == 0 && (WINDOWOPAQUE || surface->opaque); + const bool CANDISABLEBLEND = RDATA->alpha * RDATA->fadeAlpha >= 1.f && radii == 0 && (WINDOWOPAQUE || surface->opaque); if (CANDISABLEBLEND) g_pHyprOpenGL->blend(false); @@ -139,12 +139,12 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) if (RDATA->surface && surface == RDATA->surface) { if (wlr_xwayland_surface_try_from_wlr_surface(surface) && !wlr_xwayland_surface_try_from_wlr_surface(surface)->has_alpha && RDATA->fadeAlpha * RDATA->alpha == 1.f) { - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, radii, true); } else { if (RDATA->blur) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, radii, RDATA->blockBlurOptimization, RDATA->fadeAlpha); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, radii, true); } } else { if (RDATA->blur && RDATA->popup && *PBLURPOPUPS) { @@ -154,10 +154,10 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) g_pHyprOpenGL->m_RenderData.discardOpacity = *PBLURPOPUPSIGNOREALPHA; } - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, true); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, radii, true); g_pHyprOpenGL->m_RenderData.discardMode &= ~DISCARD_ALPHA; } else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, radii, true); } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { @@ -424,14 +424,14 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* if (ignoreAllGeometry) decorate = false; - renderdata.surface = pWindow->m_pWLSurface.wlr(); - renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding); - renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.fl()); - renderdata.alpha = pWindow->m_fActiveInactiveAlpha.fl(); - renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL); - renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; - renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later - renderdata.pWindow = pWindow; + renderdata.surface = pWindow->m_pWLSurface.wlr(); + renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding); + renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.fl()); + renderdata.alpha = pWindow->m_fActiveInactiveAlpha.fl(); + renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL); + renderdata.cornerRadii = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->getCornerRadii() * pMonitor->scale; + renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later + renderdata.pWindow = pWindow; if (ignoreAllGeometry) { renderdata.alpha = 1.f; @@ -524,7 +524,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { CBox wb = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h}; wb.scale(pMonitor->scale).round(); - g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha, + g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.cornerRadii - 1, renderdata.fadeAlpha, g_pHyprOpenGL->shouldUseNewBlurOptimizations(nullptr, pWindow)); renderdata.blur = false; } @@ -2250,9 +2250,10 @@ void CHyprRenderer::setOccludedForMainWorkspace(CRegion& region, CWorkspace* pWo if (!w->opaque()) continue; - const auto ROUNDING = w->rounding() * PMONITOR->scale; - const Vector2D POS = w->m_vRealPosition.vec() + Vector2D{ROUNDING, ROUNDING} - PMONITOR->vecPosition + (w->m_bPinned ? Vector2D{} : pWorkspace->m_vRenderOffset.vec()); - const Vector2D SIZE = w->m_vRealSize.vec() - Vector2D{ROUNDING * 2, ROUNDING * 2}; + const auto RADII = w->getCornerRadii() * PMONITOR->scale; + const int MINRADIUS = std::min(std::min(RADII.topLeft, RADII.topRight), std::min(RADII.bottomLeft, RADII.bottomRight)); + const Vector2D POS = w->m_vRealPosition.vec() + Vector2D{MINRADIUS, MINRADIUS} - PMONITOR->vecPosition + (w->m_bPinned ? Vector2D{} : pWorkspace->m_vRenderOffset.vec()); + const Vector2D SIZE = w->m_vRealSize.vec() - Vector2D{MINRADIUS * 2, MINRADIUS * 2}; CBox box = {POS.x, POS.y, SIZE.x, SIZE.y}; @@ -2276,9 +2277,10 @@ void CHyprRenderer::setOccludedForBackLayers(CRegion& region, CWorkspace* pWorks if (!w->opaque()) continue; - const auto ROUNDING = w->rounding() * PMONITOR->scale; - const Vector2D POS = w->m_vRealPosition.vec() + Vector2D{ROUNDING, ROUNDING} - PMONITOR->vecPosition + (w->m_bPinned ? Vector2D{} : pWorkspace->m_vRenderOffset.vec()); - const Vector2D SIZE = w->m_vRealSize.vec() - Vector2D{ROUNDING * 2, ROUNDING * 2}; + const auto RADII = w->getCornerRadii() * PMONITOR->scale; + const int MINRADIUS = std::min(std::min(RADII.topLeft, RADII.topRight), std::min(RADII.bottomLeft, RADII.bottomRight)); + const Vector2D POS = w->m_vRealPosition.vec() + Vector2D{MINRADIUS, MINRADIUS} - PMONITOR->vecPosition + (w->m_bPinned ? Vector2D{} : pWorkspace->m_vRenderOffset.vec()); + const Vector2D SIZE = w->m_vRealSize.vec() - Vector2D{MINRADIUS * 2, MINRADIUS * 2}; CBox box = {POS.x, POS.y, SIZE.x, SIZE.y}; diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp index 70fe468c..ccc5ace5 100644 --- a/src/render/Shader.hpp +++ b/src/render/Shader.hpp @@ -21,11 +21,13 @@ class CShader { GLfloat discardAlphaValue = -1; GLint topLeft = -1; + GLint topRight = -1; GLint bottomRight = -1; + GLint bottomLeft = -1; GLint fullSize = -1; GLint fullSizeUntransformed = -1; - GLint radius = -1; - GLint radiusOuter = -1; + GLint cornerRadii = -1; + GLint cornerRadiiOuter = -1; GLint thick = -1; diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 77ebdd57..2f4d8529 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -66,13 +66,13 @@ void CHyprBorderDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& of } int borderSize = m_pWindow->getRealBorderSize(); - const auto ROUNDING = m_pWindow->rounding() * pMonitor->scale; + const auto RADII = m_pWindow->getCornerRadii() * pMonitor->scale; - g_pHyprOpenGL->renderBorder(&windowBox, grad, ROUNDING, borderSize, a1); + g_pHyprOpenGL->renderBorder(&windowBox, grad, RADII, borderSize, a1); if (ANIMATED) { float a2 = a * (1.f - m_pWindow->m_fBorderFadeAnimationProgress.fl()); - g_pHyprOpenGL->renderBorder(&windowBox, m_pWindow->m_cRealBorderColorPrevious, ROUNDING, borderSize, a2); + g_pHyprOpenGL->renderBorder(&windowBox, m_pWindow->m_cRealBorderColorPrevious, RADII, borderSize, a2); } } diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 0e5e9d94..e8e42ac7 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -79,8 +79,8 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D if (*PSHADOWS != 1) return; // disabled - const auto ROUNDINGBASE = m_pWindow->rounding(); - const auto ROUNDING = ROUNDINGBASE > 0 ? ROUNDINGBASE + m_pWindow->getRealBorderSize() : 0; + const auto RADIIBASE = m_pWindow->getCornerRadii(); + const auto RADII = RADIIBASE.topLeft > 0|| RADIIBASE.topRight > 0 || RADIIBASE.bottomRight > 0 || RADIIBASE.bottomLeft > 0 ? RADIIBASE + m_pWindow->getRealBorderSize() : 0; const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID); const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D(); @@ -137,7 +137,15 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D CRegion saveDamage = g_pHyprOpenGL->m_RenderData.damage; g_pHyprOpenGL->m_RenderData.damage = fullBox; - g_pHyprOpenGL->m_RenderData.damage.subtract(windowBox.copy().expand(-ROUNDING * pMonitor->scale)).intersect(saveDamage); + + // TODO: check if CBox has the right params + CBox substract = windowBox.copy(); + substract.x -= -std::min(RADII.topLeft, RADII.bottomLeft) * pMonitor->scale; + substract.y -= -std::min(RADII.topRight, RADII.bottomRight) * pMonitor->scale; + substract.w += -(std::min(RADII.topLeft, RADII.bottomLeft) + std::min(RADII.topRight, RADII.bottomRight)) * pMonitor->scale; + substract.h += -(std::min(RADII.topLeft, RADII.topRight) + std::min(RADII.bottomLeft, RADII.bottomRight)) * pMonitor->scale; + + g_pHyprOpenGL->m_RenderData.damage.subtract(substract).intersect(saveDamage); alphaFB.bind(); @@ -147,10 +155,10 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D g_pHyprOpenGL->renderRect(&fullBox, CColor(0, 0, 0, 1), 0); // render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit) - g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CColor(1, 1, 1, m_pWindow->m_cRealShadowColor.col().a), a); + g_pHyprOpenGL->renderRoundedShadow(&fullBox, RADII * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CColor(1, 1, 1, m_pWindow->m_cRealShadowColor.col().a), a); // render black window box ("clip") - g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 1.0), ROUNDING * pMonitor->scale); + g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 1.0), RADII * pMonitor->scale); alphaSwapFB.bind(); @@ -166,7 +174,7 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D g_pHyprOpenGL->m_RenderData.damage = saveDamage; } else { - g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, m_pWindow->m_cRealShadowColor.col(), a); + g_pHyprOpenGL->renderRoundedShadow(&fullBox, RADII * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, m_pWindow->m_cRealShadowColor.col(), a); } if (m_seExtents != m_seReportedExtents) diff --git a/src/render/shaders/Border.hpp b/src/render/shaders/Border.hpp index 79493da9..633c879b 100644 --- a/src/render/shaders/Border.hpp +++ b/src/render/shaders/Border.hpp @@ -11,8 +11,8 @@ varying vec2 v_texcoord; uniform vec2 topLeft; uniform vec2 fullSize; uniform vec2 fullSizeUntransformed; -uniform float radius; -uniform float radiusOuter; +uniform vec4 cornerRadii; +uniform vec4 cornerRadiiOuter; uniform float thick; uniform vec4 gradient[10]; @@ -62,8 +62,24 @@ void main() { bool done = false; pixCoord -= topLeft + fullSize * 0.5; + + bvec2 positive = lessThan(vec2(0.0), pixCoord); + + vec4 pick = vec4( + !positive.x && !positive.y, + positive.x && !positive.y, + positive.x && positive.y, + !positive.x && positive.y); + + vec4 result = pick * cornerRadii; + vec4 resultOuter = pick * cornerRadiiOuter; + + float radius = result.x + result.y + result.z + result.w; + float radiusOuter = resultOuter.x + resultOuter.y + resultOuter.z + resultOuter.w; + pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0; pixCoordOuter = pixCoord; + pixCoord -= fullSize * 0.5 - radius; pixCoordOuter -= fullSize * 0.5 - radiusOuter; diff --git a/src/render/shaders/Shadow.hpp b/src/render/shaders/Shadow.hpp index 2c7b07b2..df1a0064 100644 --- a/src/render/shaders/Shadow.hpp +++ b/src/render/shaders/Shadow.hpp @@ -8,14 +8,16 @@ varying vec4 v_color; varying vec2 v_texcoord; uniform vec2 topLeft; +uniform vec2 topRight; uniform vec2 bottomRight; +uniform vec2 bottomLeft; uniform vec2 fullSize; -uniform float radius; +uniform vec4 cornerRadii; uniform float range; uniform float shadowPower; -float pixAlphaRoundedDistance(float distanceToCorner) { - if (distanceToCorner > radius) { +float pixAlphaRoundedDistance(float distanceToCorner, float radius) { + if (distanceToCorner > radius) { return 0.0; } @@ -36,27 +38,18 @@ void main() { 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 (pixCoord[0] < topLeft[0] && pixCoord[1] < topLeft[1]) { + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, topLeft), cornerRadii.x); + done = true; + } else if (pixCoord[0] > topRight[0] && pixCoord[1] < topRight[1]) { + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, topRight), cornerRadii.y); + done = true; + } else if (pixCoord[0] > bottomRight[0] && pixCoord[1] > bottomRight[1]) { + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, bottomRight), cornerRadii.z); + done = true; + } else if (pixCoord[0] < bottomLeft[0] && pixCoord[1] > bottomLeft[1]) { + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, bottomLeft), cornerRadii.w); + done = true; } if (!done) { diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp index e78f39fc..dac80f0e 100644 --- a/src/render/shaders/Textures.hpp +++ b/src/render/shaders/Textures.hpp @@ -8,6 +8,19 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar // branchless baby! highp vec2 pixCoord = vec2(gl_FragCoord); pixCoord -= topLeft + fullSize * 0.5; + + bvec2 positive = lessThan(vec2(0.0), pixCoord); + + vec4 pick = vec4( + !positive.x && !positive.y, + positive.x && !positive.y, + positive.x && positive.y, + !positive.x && positive.y); + + vec4 result = pick * cornerRadii; + + float radius = result.x + result.y + result.z + result.w; + pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0; pixCoord -= fullSize * 0.5 - radius; pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix dont make it top-left @@ -20,8 +33,6 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar discard; if (dist > radius - 1.0) { - float dist = length(pixCoord); - float normalized = 1.0 - smoothstep(0.0, 1.0, dist - radius + 0.5); )#" + @@ -55,13 +66,13 @@ varying vec4 v_color; uniform vec2 topLeft; uniform vec2 fullSize; -uniform float radius; +uniform vec4 cornerRadii; void main() { vec4 pixColor = v_color; - if (radius > 0.0) { + if (cornerRadii != vec4(0, 0, 0, 0)) { )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( } @@ -88,7 +99,7 @@ uniform float alpha; uniform vec2 topLeft; uniform vec2 fullSize; -uniform float radius; +uniform vec4 cornerRadii; uniform int discardOpaque; uniform int discardAlpha; @@ -113,7 +124,7 @@ void main() { pixColor[2] = pixColor[2] * tint[2]; } - if (radius > 0.0) { + if (cornerRadii != vec4(0, 0, 0, 0)) { )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( } @@ -148,7 +159,7 @@ uniform float alpha; uniform vec2 topLeft; uniform vec2 fullSize; -uniform float radius; +uniform vec4 cornerRadii; uniform int discardOpaque; uniform int discardAlpha; @@ -170,7 +181,7 @@ void main() { pixColor[2] = pixColor[2] * tint[2]; } - if (radius > 0.0) { + if (cornerRadii != vec4(0, 0, 0, 0)) { )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( } @@ -184,7 +195,7 @@ precision mediump float; varying mediump vec2 v_texcoord; // is in 0-1 uniform sampler2D tex; -uniform float radius; +uniform vec4 cornerRadii; uniform vec2 halfpixel; uniform int passes; uniform float vibrancy; @@ -292,6 +303,7 @@ void main() { vec2 uv = v_texcoord * 2.0; vec4 sum = texture2D(tex, uv) * 4.0; + float radius = cornerRadii.x; sum += texture2D(tex, uv - halfpixel.xy * radius); sum += texture2D(tex, uv + halfpixel.xy * radius); sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius); @@ -328,12 +340,13 @@ precision mediump float; varying mediump vec2 v_texcoord; // is in 0-1 uniform sampler2D tex; -uniform float radius; +uniform vec4 cornerRadii; uniform vec2 halfpixel; void main() { vec2 uv = v_texcoord / 2.0; + float radius = cornerRadii.x; 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; @@ -419,7 +432,7 @@ uniform float alpha; uniform vec2 topLeft; uniform vec2 fullSize; -uniform float radius; +uniform vec4 cornerRadii; uniform int discardOpaque; uniform int discardAlpha; @@ -441,7 +454,7 @@ void main() { pixColor[2] = pixColor[2] * tint[2]; } - if (radius > 0.0) { + if (cornerRadii != vec4(0, 0, 0, 0)) { )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( }