aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorVaxry <[email protected]>2024-12-03 18:58:24 +0000
committerGitHub <[email protected]>2024-12-03 18:58:24 +0000
commit320144ae7288fe23686935ebb235d9fe0c900862 (patch)
tree351b04e228926f98c12c340284c25450bb1fed4f /src
parent92186898c0ca1b3f72922b72c4af1723f0d9b888 (diff)
downloadHyprland-320144ae7288fe23686935ebb235d9fe0c900862.tar.gz
Hyprland-320144ae7288fe23686935ebb235d9fe0c900862.zip
core: move colorspace handling to oklab (#8635)
* Meson: add hyprgraphics * Nix: add hyprgraphics * CI/setup_base: get hyprgraphics-git --------- Co-authored-by: Mihai Fufezan <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/Compositor.cpp10
-rw-r--r--src/config/ConfigDataValues.hpp22
-rw-r--r--src/config/ConfigManager.cpp23
-rw-r--r--src/config/ConfigManager.hpp2
-rw-r--r--src/debug/HyprCtl.cpp15
-rw-r--r--src/debug/HyprNotificationOverlay.cpp4
-rw-r--r--src/debug/HyprNotificationOverlay.hpp18
-rw-r--r--src/desktop/Window.cpp4
-rw-r--r--src/desktop/Window.hpp2
-rw-r--r--src/helpers/AnimatedVariable.hpp4
-rw-r--r--src/helpers/Color.cpp56
-rw-r--r--src/helpers/Color.hpp50
-rw-r--r--src/hyprerror/HyprError.cpp6
-rw-r--r--src/hyprerror/HyprError.hpp4
-rw-r--r--src/managers/AnimationManager.cpp55
-rw-r--r--src/managers/AnimationManager.hpp4
-rw-r--r--src/managers/KeybindManager.cpp2
-rw-r--r--src/managers/PointerManager.cpp2
-rw-r--r--src/meson.build1
-rw-r--r--src/plugins/PluginAPI.cpp4
-rw-r--r--src/plugins/PluginAPI.hpp4
-rw-r--r--src/protocols/SinglePixel.cpp8
-rw-r--r--src/protocols/SinglePixel.hpp4
-rw-r--r--src/protocols/ToplevelExport.cpp4
-rw-r--r--src/render/OpenGL.cpp157
-rw-r--r--src/render/OpenGL.hpp13
-rw-r--r--src/render/Renderer.cpp20
-rw-r--r--src/render/Shader.hpp10
-rw-r--r--src/render/decorations/CHyprBorderDecoration.cpp11
-rw-r--r--src/render/decorations/CHyprDropShadowDecoration.cpp10
-rw-r--r--src/render/decorations/CHyprDropShadowDecoration.hpp2
-rw-r--r--src/render/decorations/CHyprGroupBarDecoration.cpp28
-rw-r--r--src/render/shaders/Border.hpp62
33 files changed, 446 insertions, 175 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 53eaa467..3573996d 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -1873,11 +1873,11 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
// shadow
if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) {
if (pWindow == m_pLastWindow)
- pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL);
+ pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOL);
else
- pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
+ pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
} else {
- pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow
+ pWindow->m_cRealShadowColor.setValueAndWarp(CHyprColor(0, 0, 0, 0)); // no shadow
}
pWindow->updateWindowDecos();
@@ -2608,14 +2608,14 @@ void CCompositor::performUserChecks() {
g_pHyprNotificationOverlay->addNotification(
std::format("Your XDG_CURRENT_DESKTOP environment seems to be managed externally, and the current value is {}.\nThis might cause issues unless it's intentional.",
CURRENT_DESKTOP_ENV ? CURRENT_DESKTOP_ENV : "unset"),
- CColor{}, 15000, ICON_WARNING);
+ CHyprColor{}, 15000, ICON_WARNING);
}
}
if (g_pHyprOpenGL->failedAssetsNo > 0) {
g_pHyprNotificationOverlay->addNotification(std::format("Hyprland failed to load {} essential asset{}, blame your distro's packager for doing a bad job at packaging!",
g_pHyprOpenGL->failedAssetsNo, g_pHyprOpenGL->failedAssetsNo > 1 ? "s" : ""),
- CColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR);
+ CHyprColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR);
}
}
diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp
index 37c9fc92..212f26fa 100644
--- a/src/config/ConfigDataValues.hpp
+++ b/src/config/ConfigDataValues.hpp
@@ -21,8 +21,9 @@ class ICustomConfigValueData {
class CGradientValueData : public ICustomConfigValueData {
public:
CGradientValueData() {};
- CGradientValueData(CColor col) {
+ CGradientValueData(CHyprColor col) {
m_vColors.push_back(col);
+ updateColorsOk();
};
virtual ~CGradientValueData() {};
@@ -30,14 +31,29 @@ class CGradientValueData : public ICustomConfigValueData {
return CVD_TYPE_GRADIENT;
}
- void reset(CColor col) {
+ void reset(CHyprColor col) {
m_vColors.clear();
m_vColors.emplace_back(col);
m_fAngle = 0;
+ updateColorsOk();
+ }
+
+ void updateColorsOk() {
+ m_vColorsOkLabA.clear();
+ for (auto& c : m_vColors) {
+ const auto OKLAB = c.asOkLab();
+ m_vColorsOkLabA.emplace_back(OKLAB.l);
+ m_vColorsOkLabA.emplace_back(OKLAB.a);
+ m_vColorsOkLabA.emplace_back(OKLAB.b);
+ m_vColorsOkLabA.emplace_back(c.a);
+ }
}
/* Vector containing the colors */
- std::vector<CColor> m_vColors;
+ std::vector<CHyprColor> m_vColors;
+
+ /* Vector containing pure colors for shoving into opengl */
+ std::vector<float> m_vColorsOkLabA;
/* Float corresponding to the angle (rad) */
float m_fAngle = 0;
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 07de8c24..820844eb 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -70,7 +70,7 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void**
const auto COL = configStringToInt(var);
if (!COL)
throw std::runtime_error(std::format("failed to parse {} as a color", var));
- DATA->m_vColors.push_back(CColor(COL.value()));
+ DATA->m_vColors.push_back(CHyprColor(COL.value()));
} catch (std::exception& e) {
Debug::log(WARN, "Error parsing gradient {}", V);
parseError = "Error parsing gradient " + V + ": " + e.what();
@@ -85,6 +85,8 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void**
DATA->m_vColors.push_back(0); // transparent
}
+ DATA->updateColorsOk();
+
Hyprlang::CParseResult result;
if (!parseError.empty())
result.setError(parseError.c_str());
@@ -676,7 +678,7 @@ CConfigManager::CConfigManager() {
Debug::disableTime = reinterpret_cast<int64_t* const*>(m_pConfig->getConfigValuePtr("debug:disable_time")->getDataStaticPtr());
if (ERR.has_value())
- g_pHyprError->queueCreate(ERR.value(), CColor{1.0, 0.1, 0.1, 1.0});
+ g_pHyprError->queueCreate(ERR.value(), CHyprColor{1.0, 0.1, 0.1, 1.0});
}
std::optional<std::string> CConfigManager::generateConfig(std::string configPath) {
@@ -883,14 +885,14 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
m_szConfigErrors = "";
if (result.error && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:suppress_errors")))
- g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+ g_pHyprError->queueCreate(result.getError(), CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1)
g_pHyprError->queueCreate(
"Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() +
" )\nSUPER+Q -> kitty (if it doesn't launch, make sure it's installed or choose a different terminal in the config)\nSUPER+M -> exit Hyprland",
- CColor(1.0, 1.0, 70.0 / 255.0, 1.0));
+ CHyprColor(1.0, 1.0, 70.0 / 255.0, 1.0));
else if (*PENABLEEXPLICIT != prevEnabledExplicit)
- g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
+ g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CHyprColor(0.9, 0.76, 0.221, 1.0));
else
g_pHyprError->destroy();
@@ -948,7 +950,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
// manual crash
if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:manual_crash")) && !m_bManualCrashInitiated) {
m_bManualCrashInitiated = true;
- g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000, ICON_INFO);
+ g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CHyprColor(0), 5000,
+ ICON_INFO);
} else if (m_bManualCrashInitiated && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:manual_crash"))) {
// cowabunga it is
g_pHyprRenderer->initiateManualCrash();
@@ -1015,7 +1018,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
if (COMMAND.contains("explicit")) {
if (*PENABLEEXPLICIT != prevEnabledExplicit)
- g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
+ g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CHyprColor(0.9, 0.76, 0.221, 1.0));
else
g_pHyprError->destroy();
}
@@ -1027,7 +1030,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:manual_crash")) && !m_bManualCrashInitiated) {
m_bManualCrashInitiated = true;
if (g_pHyprNotificationOverlay) {
- g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000,
+ g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CHyprColor(0), 5000,
ICON_INFO);
}
} else if (m_bManualCrashInitiated && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:manual_crash"))) {
@@ -1671,7 +1674,7 @@ SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::
}
void CConfigManager::addParseError(const std::string& err) {
- g_pHyprError->queueCreate(err + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+ g_pHyprError->queueCreate(err + "\nHyprland may not work correctly.", CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
}
PHLMONITOR CConfigManager::getBoundMonitorForWS(const std::string& wsname) {
@@ -1716,7 +1719,7 @@ void CConfigManager::handlePluginLoads() {
error << "\n" << path;
}
- g_pHyprError->queueCreate(error.str(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+ g_pHyprError->queueCreate(error.str(), CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
}
if (pluginsChanged) {
diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp
index 88b74b6e..a3b86e69 100644
--- a/src/config/ConfigManager.hpp
+++ b/src/config/ConfigManager.hpp
@@ -119,7 +119,7 @@ struct SConfigOptionDescription {
};
struct SColorData {
- CColor color;
+ CHyprColor color;
};
struct SChoiceData {
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index 6b62ec8d..74b2a3a1 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -875,9 +875,9 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n"
"Date: {}\n"
"Tag: {}, commits: {}\n"
- "built against:\n aquamarine {}\n hyprlang {}\n hyprutils {}\n hyprcursor {}\n\n\n",
+ "built against:\n aquamarine {}\n hyprlang {}\n hyprutils {}\n hyprcursor {}\n hyprgraphics {}\n\n\n",
HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION,
- HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION);
+ HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION);
#if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND))
result += "no flags were set\n";
@@ -909,9 +909,10 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
"buildHyprlang": "{}",
"buildHyprutils": "{}",
"buildHyprcursor": "{}",
+ "buildHyprgraphics": "{}",
"flags": [)#",
GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG,
- GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION);
+ GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION);
#ifdef LEGACY_RENDERER
result += "\"legacyrenderer\",";
@@ -1290,7 +1291,7 @@ std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
return "ok";
}
- const CColor COLOR = configStringToInt(vars[1]).value_or(0);
+ const CHyprColor COLOR = configStringToInt(vars[1]).value_or(0);
for (size_t i = 2; i < vars.size(); ++i)
errorMessage += vars[i] + ' ';
@@ -1545,10 +1546,10 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
const auto COLOR_RESULT = configStringToInt(vars[3]);
if (!COLOR_RESULT)
return "invalid arg 3";
- CColor color = *COLOR_RESULT;
+ CHyprColor color = *COLOR_RESULT;
- size_t msgidx = 4;
- float fontsize = 13.f;
+ size_t msgidx = 4;
+ float fontsize = 13.f;
if (vars[msgidx].length() > 9 && vars[msgidx].compare(0, 9, "fontsize:") == 0) {
const auto FONTSIZE = vars[msgidx].substr(9);
diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp
index e46999e6..482db541 100644
--- a/src/debug/HyprNotificationOverlay.cpp
+++ b/src/debug/HyprNotificationOverlay.cpp
@@ -34,11 +34,11 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() {
cairo_surface_destroy(m_pCairoSurface);
}
-void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) {
+void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) {
const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text;
- PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color;
+ PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color;
PNOTIF->started.reset();
PNOTIF->timeMs = timeMs;
PNOTIF->icon = icon;
diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp
index 0bba8b04..67603e49 100644
--- a/src/debug/HyprNotificationOverlay.hpp
+++ b/src/debug/HyprNotificationOverlay.hpp
@@ -19,17 +19,17 @@ enum eIconBackend {
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""},
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "󰸞", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
-static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
- CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
- CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
- CColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
- CColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
- CColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
- CColor{0, 0, 0, 1.0}};
+static const std::array<CHyprColor, ICON_NONE + 1> ICONS_COLORS = {CHyprColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
+ CHyprColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
+ CHyprColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
+ CHyprColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
+ CHyprColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
+ CHyprColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
+ CHyprColor{0, 0, 0, 1.0}};
struct SNotification {
std::string text = "";
- CColor color;
+ CHyprColor color;
CTimer started;
float timeMs = 0;
eIcons icon = ICON_NONE;
@@ -42,7 +42,7 @@ class CHyprNotificationOverlay {
~CHyprNotificationOverlay();
void draw(PHLMONITOR pMonitor);
- void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
+ void addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
void dismissNotifications(const int amount);
bool hasAny();
diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp
index 12e81b76..b015d61f 100644
--- a/src/desktop/Window.cpp
+++ b/src/desktop/Window.cpp
@@ -674,8 +674,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
// Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
- m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority);
- m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority);
+ m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority);
+ m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority);
return;
}
diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp
index 5dd59437..672ff6ec 100644
--- a/src/desktop/Window.hpp
+++ b/src/desktop/Window.hpp
@@ -356,7 +356,7 @@ class CWindow {
CAnimatedVariable<float> m_fActiveInactiveAlpha;
// animated shadow color
- CAnimatedVariable<CColor> m_cRealShadowColor;
+ CAnimatedVariable<CHyprColor> m_cRealShadowColor;
// animated tint
CAnimatedVariable<float> m_fDimPercent;
diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp
index 6310afb7..7cea72a0 100644
--- a/src/helpers/AnimatedVariable.hpp
+++ b/src/helpers/AnimatedVariable.hpp
@@ -34,7 +34,7 @@ struct typeToANIMATEDVARTYPE_t<Vector2D> {
};
template <>
-struct typeToANIMATEDVARTYPE_t<CColor> {
+struct typeToANIMATEDVARTYPE_t<CHyprColor> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_COLOR;
};
@@ -63,7 +63,7 @@ concept OneOf = (... or std::same_as<T, U>);
// This is mainly to get better errors if we put a type that's not supported
// Otherwise template errors are ugly
template <class T>
-concept Animable = OneOf<T, Vector2D, float, CColor>;
+concept Animable = OneOf<T, Vector2D, float, CHyprColor>;
class CBaseAnimatedVariable {
public:
diff --git a/src/helpers/Color.cpp b/src/helpers/Color.cpp
index f9a207bb..fe217c0f 100644
--- a/src/helpers/Color.cpp
+++ b/src/helpers/Color.cpp
@@ -5,22 +5,52 @@
#define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0)
#define BLUE(c) ((double)(((c)) & 0xff) / 255.0)
-CColor::CColor() {}
+CHyprColor::CHyprColor() {}
-CColor::CColor(float r, float g, float b, float a) {
- this->r = r;
- this->g = g;
- this->b = b;
- this->a = a;
+CHyprColor::CHyprColor(float r_, float g_, float b_, float a_) {
+ r = r_;
+ g = g_;
+ b = b_;
+ a = a_;
+
+ okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab();
}
-CColor::CColor(uint64_t hex) {
- this->r = RED(hex);
- this->g = GREEN(hex);
- this->b = BLUE(hex);
- this->a = ALPHA(hex);
+CHyprColor::CHyprColor(uint64_t hex) {
+ r = RED(hex);
+ g = GREEN(hex);
+ b = BLUE(hex);
+ a = ALPHA(hex);
+
+ okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab();
}
-uint32_t CColor::getAsHex() const {
+CHyprColor::CHyprColor(const Hyprgraphics::CColor& color, float a_) {
+ const auto SRGB = color.asRgb();
+ r = SRGB.r;
+ g = SRGB.g;
+ b = SRGB.b;
+ a = a_;
+
+ okLab = color.asOkLab();
+}
+
+uint32_t CHyprColor::getAsHex() const {
return (uint32_t)(a * 255.f) * 0x1000000 + (uint32_t)(r * 255.f) * 0x10000 + (uint32_t)(g * 255.f) * 0x100 + (uint32_t)(b * 255.f) * 0x1;
-} \ No newline at end of file
+}
+
+Hyprgraphics::CColor::SSRGB CHyprColor::asRGB() const {
+ return {r, g, b};
+}
+
+Hyprgraphics::CColor::SOkLab CHyprColor::asOkLab() const {
+ return okLab;
+}
+
+Hyprgraphics::CColor::SHSL CHyprColor::asHSL() const {
+ return Hyprgraphics::CColor(okLab).asHSL();
+}
+
+CHyprColor CHyprColor::stripA() const {
+ return {r, g, b, 1.F};
+}
diff --git a/src/helpers/Color.hpp b/src/helpers/Color.hpp
index 32ed39ee..cf7f7943 100644
--- a/src/helpers/Color.hpp
+++ b/src/helpers/Color.hpp
@@ -1,35 +1,47 @@
#pragma once
#include <cstdint>
+#include <hyprgraphics/color/Color.hpp>
+#include "../debug/Log.hpp"
+#include "../macros.hpp"
-class CColor {
+class CHyprColor {
public:
- CColor();
- CColor(float r, float g, float b, float a);
- CColor(uint64_t);
-
- float r = 0, g = 0, b = 0, a = 1.f;
+ CHyprColor();
+ CHyprColor(float r, float g, float b, float a);
+ CHyprColor(const Hyprgraphics::CColor& col, float a);
+ CHyprColor(uint64_t);
// AR32
- uint32_t getAsHex() const;
-
- CColor operator-(const CColor& c2) const {
- return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a);
+ uint32_t getAsHex() const;
+ Hyprgraphics::CColor::SSRGB asRGB() const;
+ Hyprgraphics::CColor::SOkLab asOkLab() const;
+ Hyprgraphics::CColor::SHSL asHSL() const;
+ CHyprColor stripA() const;
+
+ //
+ bool operator==(const CHyprColor& c2) const {
+ return c2.r == r && c2.g == g && c2.b == b && c2.a == a;
}
- CColor operator+(const CColor& c2) const {
- return CColor(r + c2.r, g + c2.g, b + c2.b, a + c2.a);
+ // stubs for the AnimationMgr
+ CHyprColor operator-(const CHyprColor& c2) const {
+ RASSERT(false, "CHyprColor: - is a STUB");
+ return {};
}
- CColor operator*(const float& v) const {
- return CColor(r * v, g * v, b * v, a * v);
+ CHyprColor operator+(const CHyprColor& c2) const {
+ RASSERT(false, "CHyprColor: + is a STUB");
+ return {};
}
- bool operator==(const CColor& c2) const {
- return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
+ CHyprColor operator*(const float& c2) const {
+ RASSERT(false, "CHyprColor: * is a STUB");
+ return {};
}
- CColor stripA() const {
- return {r, g, b, 1};
- }
+ double r = 0, g = 0, b = 0, a = 0;
+
+ private:
+ Hyprgraphics::CColor::SOkLab okLab; // cache for the OkLab representation
};
diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp
index 4761346e..74a3030c 100644
--- a/src/hyprerror/HyprError.cpp
+++ b/src/hyprerror/HyprError.cpp
@@ -33,7 +33,7 @@ CHyprError::~CHyprError() {
m_fFadeOpacity.unregister();
}
-void CHyprError::queueCreate(std::string message, const CColor& color) {
+void CHyprError::queueCreate(std::string message, const CHyprColor& color) {
m_szQueued = message;
m_cQueued = color;
}
@@ -98,7 +98,7 @@ void CHyprError::createQueued() {
cairo_stroke(CAIRO);
// draw the text with a common font
- const CColor textColor = CColor(0.9, 0.9, 0.9, 1.0);
+ const CHyprColor textColor = CHyprColor(0.9, 0.9, 0.9, 1.0);
cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a);
static auto fontFamily = CConfigValue<std::string>("misc:font_family");
@@ -160,7 +160,7 @@ void CHyprError::createQueued() {
m_bIsCreated = true;
m_szQueued = "";
- m_cQueued = CColor();
+ m_cQueued = CHyprColor();
g_pHyprRenderer->damageMonitor(PMONITOR);
diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp
index a553614c..042dccd0 100644
--- a/src/hyprerror/HyprError.hpp
+++ b/src/hyprerror/HyprError.hpp
@@ -11,7 +11,7 @@ class CHyprError {
CHyprError();
~CHyprError();
- void queueCreate(std::string message, const CColor& color);
+ void queueCreate(std::string message, const CHyprColor& color);
void draw();
void destroy();
@@ -21,7 +21,7 @@ class CHyprError {
private:
void createQueued();
std::string m_szQueued = "";
- CColor m_cQueued;
+ CHyprColor m_cQueued;
bool m_bQueuedDestroy = false;
bool m_bIsCreated = false;
SP<CTexture> m_pTexture;
diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp
index 68dbdda1..7525bf6b 100644
--- a/src/managers/AnimationManager.cpp
+++ b/src/managers/AnimationManager.cpp
@@ -8,6 +8,8 @@
#include "eventLoop/EventLoopManager.hpp"
#include "../helpers/varlist/VarList.hpp"
+#include <hyprgraphics/color/Color.hpp>
+
int wlTick(SP<CEventLoopTimer> self, void* data) {
if (g_pAnimationManager)
g_pAnimationManager->onTicked();
@@ -154,7 +156,7 @@ void CAnimationManager::tick() {
// beziers are with a switch unforto
// TODO: maybe do something cleaner
- auto updateVariable = [&]<Animable T>(CAnimatedVariable<T>& av) {
+ static const auto updateVariable = [&]<Animable T>(CAnimatedVariable<T>& av) {
// for disabled anims just warp
if (av.m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av.warp(false);
@@ -166,13 +168,50 @@ void CAnimationManager::tick() {
return;
}
- const auto DELTA = av.m_Goal - av.m_Begun;
const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier);
+ const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER->second.getYForPoint(SPENT);
+
+ const auto DELTA = av.m_Goal - av.m_Begun;
if (BEZIER != m_mBezierCurves.end())
- av.m_Value = av.m_Begun + DELTA * BEZIER->second.getYForPoint(SPENT);
+ av.m_Value = av.m_Begun + DELTA * POINTY;
else
- av.m_Value = av.m_Begun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT);
+ av.m_Value = av.m_Begun + DELTA * POINTY;
+ };
+
+ static const auto updateColorVariable = [&](CAnimatedVariable<CHyprColor>& av) {
+ // for disabled anims just warp
+ if (av.m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
+ av.warp(false);
+ return;
+ }
+
+ if (SPENT >= 1.f || av.m_Begun == av.m_Goal) {
+ av.warp(false);
+ return;
+ }
+
+ const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier);
+ const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER->second.getYForPoint(SPENT);
+
+ // convert both to OkLab, then lerp that, and convert back.
+ // This is not as fast as just lerping rgb, but it's WAY more precise...
+ // Use the CHyprColor cache for OkLab
+
+ const auto& L1 = av.m_Begun.asOkLab();
+ const auto& L2 = av.m_Goal.asOkLab();
+
+ static const auto lerp = [](const float one, const float two, const float progress) -> float { return one + (two - one) * progress; };
+
+ const Hyprgraphics::CColor lerped = Hyprgraphics::CColor::SOkLab{
+ .l = lerp(L1.l, L2.l, POINTY),
+ .a = lerp(L1.a, L2.a, POINTY),
+ .b = lerp(L1.b, L2.b, POINTY),
+ };
+
+ av.m_Value = {lerped, lerp(av.m_Begun.a, av.m_Goal.a, POINTY)};
+
+ return;
};
switch (av->m_Type) {
@@ -187,8 +226,8 @@ void CAnimationManager::tick() {
break;
}
case AVARTYPE_COLOR: {
- auto typedAv = static_cast<CAnimatedVariable<CColor>*>(av);
- updateVariable(*typedAv);
+ auto typedAv = static_cast<CAnimatedVariable<CHyprColor>*>(av);
+ updateColorVariable(*typedAv);
break;
}
default: UNREACHABLE();
@@ -272,7 +311,7 @@ bool CAnimationManager::deltaSmallToFlip(const Vector2D& a, const Vector2D& b) {
return std::abs(a.x - b.x) < 0.5f && std::abs(a.y - b.y) < 0.5f;
}
-bool CAnimationManager::deltaSmallToFlip(const CColor& a, const CColor& b) {
+bool CAnimationManager::deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b) {
return std::abs(a.r - b.r) < 0.5f && std::abs(a.g - b.g) < 0.5f && std::abs(a.b - b.b) < 0.5f && std::abs(a.a - b.a) < 0.5f;
}
@@ -288,7 +327,7 @@ bool CAnimationManager::deltazero(const float& a, const float& b) {
return a == b;
}
-bool CAnimationManager::deltazero(const CColor& a, const CColor& b) {
+bool CAnimationManager::deltazero(const CHyprColor& a, const CHyprColor& b) {
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp
index 601a38b3..3960f261 100644
--- a/src/managers/AnimationManager.hpp
+++ b/src/managers/AnimationManager.hpp
@@ -39,10 +39,10 @@ class CAnimationManager {
private:
bool deltaSmallToFlip(const Vector2D& a, const Vector2D& b);
- bool deltaSmallToFlip(const CColor& a, const CColor& b);
+ bool deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b);
bool deltaSmallToFlip(const float& a, const float& b);
bool deltazero(const Vector2D& a, const Vector2D& b);
- bool deltazero(const CColor& a, const CColor& b);
+ bool deltazero(const CHyprColor& a, const CHyprColor& b);
bool deltazero(const float& a, const float& b);
std::unordered_map<std::string, CBezierCurve> m_mBezierCurves;
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
index 7f10249a..cfb7453c 100644
--- a/src/managers/KeybindManager.cpp
+++ b/src/managers/KeybindManager.cpp
@@ -275,7 +275,7 @@ void CKeybindManager::updateXKBTranslationState() {
if (!PKEYMAP) {
g_pHyprError->queueCreate("[Runtime Error] Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS +
", layout: " + LAYOUT + " )",
- CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
+ CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
Debug::log(ERR, "[XKBTranslationState] Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant,
rules.rules, rules.model, rules.options);
diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp
index 0580c9be..c0c190dd 100644
--- a/src/managers/PointerManager.cpp
+++ b/src/managers/PointerManager.cpp
@@ -505,7 +505,7 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
RBO->bind();
g_pHyprOpenGL->beginSimple(state->monitor.lock(), {0, 0, INT16_MAX, INT16_MAX}, RBO);
- g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F});
+ g_pHyprOpenGL->clear(CHyprColor{0.F, 0.F, 0.F, 0.F});
CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()};
Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, cursorSize,
diff --git a/src/meson.build b/src/meson.build
index 61ca06d5..754cd55a 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -10,6 +10,7 @@ executable(
server_protos,
aquamarine,
hyprcursor,
+ hyprgraphics,
hyprlang,
hyprutils,
dependency('gbm'),
diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp
index ef3ae06a..1a7f25ab 100644
--- a/src/plugins/PluginAPI.cpp
+++ b/src/plugins/PluginAPI.cpp
@@ -71,7 +71,7 @@ APICALL bool HyprlandAPI::reloadConfig() {
return true;
}
-APICALL bool HyprlandAPI::addNotification(HANDLE handle, const std::string& text, const CColor& color, const float timeMs) {
+APICALL bool HyprlandAPI::addNotification(HANDLE handle, const std::string& text, const CHyprColor& color, const float timeMs) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
if (!PLUGIN)
@@ -244,7 +244,7 @@ APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map<std::stri
if (iterator == data.end())
return false;
- const auto COLOR = std::any_cast<CColor>(iterator->second);
+ const auto COLOR = std::any_cast<CHyprColor>(iterator->second);
// optional
eIcons icon = ICON_NONE;
diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp
index 4dcf4ba5..bd257699 100644
--- a/src/plugins/PluginAPI.hpp
+++ b/src/plugins/PluginAPI.hpp
@@ -187,7 +187,7 @@ namespace HyprlandAPI {
returns: true on success. False otherwise.
*/
- APICALL bool addNotification(HANDLE handle, const std::string& text, const CColor& color, const float timeMs);
+ APICALL bool addNotification(HANDLE handle, const std::string& text, const CHyprColor& color, const float timeMs);
/*
Creates a trampoline function hook to an internal hl func.
@@ -251,7 +251,7 @@ namespace HyprlandAPI {
data has to contain:
- text: std::string or const char*
- time: uint64_t
- - color: CColor -> CColor(0) will apply the default color for the notification icon
+ - color: CHyprColor -> CHyprColor(0) will apply the default color for the notification icon
data may contain:
- icon: eIcons
diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp
index d800539d..41771ce2 100644
--- a/src/protocols/SinglePixel.cpp
+++ b/src/protocols/SinglePixel.cpp
@@ -2,7 +2,7 @@
#include <limits>
#include "render/Renderer.hpp"
-CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col_) {
+CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColor col_) {
LOGM(LOG, "New single-pixel buffer with color 0x{:x}", col_.getAsHex());
color = col_.getAsHex();
@@ -59,7 +59,7 @@ bool CSinglePixelBuffer::good() {
return resource->good();
}
-CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color) {
+CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* client, CHyprColor color) {
buffer = makeShared<CSinglePixelBuffer>(id, client, color);
if (!buffer->good())
@@ -89,8 +89,8 @@ CSinglePixelBufferManagerResource::CSinglePixelBufferManagerResource(SP<CWpSingl
resource->setOnDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); });
resource->setCreateU32RgbaBuffer([this](CWpSinglePixelBufferManagerV1* res, uint32_t id, uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
- CColor color{r / (float)std::numeric_limits<uint32_t>::max(), g / (float)std::numeric_limits<uint32_t>::max(), b / (float)std::numeric_limits<uint32_t>::max(),
- a / (float)std::numeric_limits<uint32_t>::max()};
+ CHyprColor color{r / (float)std::numeric_limits<uint32_t>::max(), g / (float)std::numeric_limits<uint32_t>::max(), b / (float)std::numeric_limits<uint32_t>::max(),
+ a / (float)std::numeric_limits<uint32_t>::max()};
const auto RESOURCE = PROTO::singlePixel->m_vBuffers.emplace_back(makeShared<CSinglePixelBufferResource>(id, resource->client(), color));
if (!RESOURCE->good()) {
diff --git a/src/protocols/SinglePixel.hpp b/src/protocols/SinglePixel.hpp
index ab74825c..b20f582a 100644
--- a/src/protocols/SinglePixel.hpp
+++ b/src/protocols/SinglePixel.hpp
@@ -9,7 +9,7 @@
class CSinglePixelBuffer : public IHLBuffer {
public:
- CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col);
+ CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColor col);
virtual ~CSinglePixelBuffer();
virtual Aquamarine::eBufferCapability caps();
@@ -33,7 +33,7 @@ class CSinglePixelBuffer : public IHLBuffer {
class CSinglePixelBufferResource {
public:
- CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color);
+ CSinglePixelBufferResource(uint32_t id, wl_client* client, CHyprColor color);
~CSinglePixelBufferResource();
bool good();
diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp
index 04c089d7..d00e9dce 100644
--- a/src/protocols/ToplevelExport.cpp
+++ b/src/protocols/ToplevelExport.cpp
@@ -255,7 +255,7 @@ bool CToplevelExportFrame::copyShm(timespec* now) {
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB))
return false;
- g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
+ g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 1.0));
// render client at 0,0
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(pWindow); // block the feedback to avoid spamming the surface if it's visible
@@ -308,7 +308,7 @@ bool CToplevelExportFrame::copyDmabuf(timespec* now) {
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock()))
return false;
- g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
+ g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 1.0));
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(pWindow); // block the feedback to avoid spamming the surface if it's visible
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true);
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 9c00daee..9b878317 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -566,7 +566,11 @@ void CHyprOpenGLImpl::logShaderError(const GLuint& shader, bool program) {
glGetShaderInfoLog(shader, maxLength, &maxLength, errorLog.data());
std::string errorStr(errorLog.begin(), errorLog.end());
- g_pConfigManager->addParseError((program ? "Screen shader parser: Error linking program:" : "Screen shader parser: Error compiling shader: ") + errorStr);
+ const auto FULLERROR = (program ? "Screen shader parser: Error linking program:" : "Screen shader parser: Error compiling shader: ") + errorStr;
+
+ Debug::log(ERR, "Failed to link shader: {}", FULLERROR);
+
+ g_pConfigManager->addParseError(FULLERROR);
}
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag, bool dynamic) {
@@ -604,6 +608,8 @@ GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string
return 0;
}
} else {
+ if (ok != GL_TRUE)
+ logShaderError(prog, true);
RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!");
}
@@ -627,6 +633,8 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool
return 0;
}
} else {
+ if (ok != GL_TRUE)
+ logShaderError(shader, false);
RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!");
}
@@ -1114,8 +1122,12 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter = glGetUniformLocation(prog, "radiusOuter");
m_RenderData.pCurrentMonData->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient");
+ m_RenderData.pCurrentMonData->m_shBORDER1.gradient2 = glGetUniformLocation(prog, "gradient2");
m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength");
+ m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length = glGetUniformLocation(prog, "gradient2Length");
m_RenderData.pCurrentMonData->m_shBORDER1.angle = glGetUniformLocation(prog, "angle");
+ m_RenderData.pCurrentMonData->m_shBORDER1.angle2 = glGetUniformLocation(prog, "angle2");
+ m_RenderData.pCurrentMonData->m_shBORDER1.gradientLerp = glGetUniformLocation(prog, "gradientLerp");
m_RenderData.pCurrentMonData->m_shBORDER1.alpha = glGetUniformLocation(prog, "alpha");
m_RenderData.pCurrentMonData->m_bShadersInitialized = true;
@@ -1167,7 +1179,7 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
m_sFinalScreenShader.posAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "pos");
}
-void CHyprOpenGLImpl::clear(const CColor& color) {
+void CHyprOpenGLImpl::clear(const CHyprColor& color) {
RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!");
TRACY_GPU_ZONE("RenderClear");
@@ -1231,12 +1243,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 CHyprColor& col, int round) {
if (!m_RenderData.damage.empty())
renderRectWithDamage(box, col, &m_RenderData.damage, round);
}
-void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round, float blurA, bool xray) {
+void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int round, float blurA, bool xray) {
if (m_RenderData.damage.empty())
return;
@@ -1258,7 +1270,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, CHyprColor(0, 0, 0, 0), round);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, 1, 0xFF);
@@ -1283,7 +1295,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round
renderRectWithDamage(box, col, &m_RenderData.damage, round);
}
-void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion* damage, int round) {
+void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, CRegion* damage, int round) {
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()!");
@@ -1981,7 +1993,7 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
m_RenderData.pMonitor->output->state->state().drmFormat);
m_RenderData.pCurrentMonData->blurFB.bind();
- clear(CColor(0, 0, 0, 0));
+ clear(CHyprColor(0, 0, 0, 0));
m_bEndFrame = true; // fix transformed
renderTextureInternalWithDamage(POUTFB->getTexture(), &wholeMonitor, 1, &fakeDamage, 0, false, true, false);
@@ -2100,7 +2112,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP<CTexture> tex, CBox* pBox, float
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, CHyprColor(0, 0, 0, 0), round);
else
renderTexture(tex, pBox, a, round, true, true); // discard opaque
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@@ -2184,12 +2196,107 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
#endif
- static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail
-
- glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad.m_vColors.size(), (float*)grad.m_vColors.data());
- glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad.m_vColors.size());
+ glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad.m_vColorsOkLabA.size(), (float*)grad.m_vColorsOkLabA.data());
+ glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad.m_vColorsOkLabA.size() / 4);
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle, (int)(grad.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0));
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a);
+ glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length, 0);
+
+ CBox transformedBox = *box;
+ transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
+ m_RenderData.pMonitor->vecTransformedSize.y);
+
+ const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
+ const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
+
+ 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);
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize);
+
+ glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
+ glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
+
+ glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib);
+ glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
+
+ if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) {
+ CRegion damageClip{m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height};
+ damageClip.intersect(m_RenderData.damage);
+
+ if (!damageClip.empty()) {
+ for (auto const& RECT : damageClip.getRects()) {
+ scissor(&RECT);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ }
+ }
+ } else {
+ for (auto const& RECT : m_RenderData.damage.getRects()) {
+ scissor(&RECT);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ }
+ }
+
+ glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib);
+ glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
+
+ blend(BLEND);
+}
+
+void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, const CGradientValueData& grad2, float lerp, int round, int borderSize, float a, int outerRound) {
+ 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()!");
+
+ TRACY_GPU_ZONE("RenderBorder2");
+
+ if (m_RenderData.damage.empty() || (m_pCurrentWindow.lock() && m_pCurrentWindow->m_sWindowData.noBorder.valueOrDefault()))
+ return;
+
+ CBox newBox = *box;
+ m_RenderData.renderModif.applyToBox(newBox);
+
+ box = &newBox;
+
+ if (borderSize < 1)
+ return;
+
+ int scaledBorderSize = std::round(borderSize * m_RenderData.pMonitor->scale);
+ scaledBorderSize = std::round(scaledBorderSize * m_RenderData.renderModif.combinedScale());
+
+ // adjust box
+ box->x -= scaledBorderSize;
+ box->y -= scaledBorderSize;
+ box->width += 2 * scaledBorderSize;
+ box->height += 2 * scaledBorderSize;
+
+ round += round == 0 ? 0 : scaledBorderSize;
+
+ Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(
+ newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot);
+ Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
+
+ const auto BLEND = m_bBlend;
+ blend(true);
+
+ glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program);
+
+#ifndef GLES2
+ glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
+#else
+ glMatrix.transpose();
+ glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
+#endif
+
+ glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad1.m_vColorsOkLabA.size(), (float*)grad1.m_vColorsOkLabA.data());
+ glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad1.m_vColorsOkLabA.size() / 4);
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle, (int)(grad1.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0));
+ glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2, grad2.m_vColorsOkLabA.size(), (float*)grad2.m_vColorsOkLabA.data());
+ glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length, grad2.m_vColorsOkLabA.size() / 4);
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle2, (int)(grad2.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0));
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a);
+ glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLerp, lerp);
CBox transformedBox = *box;
transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
@@ -2253,7 +2360,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr
g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, pFramebuffer);
- clear(CColor(0, 0, 0, 0)); // JIC
+ clear(CHyprColor(0, 0, 0, 0)); // JIC
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -2272,7 +2379,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr
m_RenderData.currentFB = pFramebuffer;
- clear(CColor(0, 0, 0, 0)); // JIC
+ clear(CHyprColor(0, 0, 0, 0)); // JIC
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, false, RENDER_PASS_ALL, true);
@@ -2308,7 +2415,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) {
g_pHyprRenderer->m_bRenderingSnapshot = true;
- clear(CColor(0, 0, 0, 0)); // JIC
+ clear(CHyprColor(0, 0, 0, 0)); // JIC
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -2322,7 +2429,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) {
const auto BLURVAL = **PBLUR;
**PBLUR = 0;
- clear(CColor(0, 0, 0, 0)); // JIC
+ clear(CHyprColor(0, 0, 0, 0)); // JIC
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders, RENDER_PASS_ALL);
@@ -2355,7 +2462,7 @@ void CHyprOpenGLImpl::makeLayerSnapshot(PHLLS pLayer) {
g_pHyprRenderer->m_bRenderingSnapshot = true;
- clear(CColor(0, 0, 0, 0)); // JIC
+ clear(CHyprColor(0, 0, 0, 0)); // JIC
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -2405,7 +2512,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) {
if (*PDIMAROUND && pWindow->m_sWindowData.dimAround.valueOrDefault()) {
CBox monbox = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y};
- g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMAROUND * pWindow->m_fAlpha.value()));
+ g_pHyprOpenGL->renderRect(&monbox, CHyprColor(0, 0, 0, *PDIMAROUND * pWindow->m_fAlpha.value()));
g_pHyprRenderer->damageMonitor(PMONITOR);
}
@@ -2449,7 +2556,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLLS pLayer) {
m_bEndFrame = false;
}
-void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const CColor& color, float a) {
+void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const CHyprColor& 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.lock(), "Tried to render shadow without a window!");
@@ -2568,7 +2675,7 @@ void CHyprOpenGLImpl::renderMirrored() {
.translate(-monitor->vecTransformedSize / 2.0);
// clear stuff outside of mirrored area (e.g. when changing to mirrored)
- clear(CColor(0, 0, 0, 0));
+ clear(CHyprColor(0, 0, 0, 0));
renderTexture(PFB->getTexture(), &monbox, 1.f, 0, false, false);
@@ -2583,7 +2690,7 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const
const auto FONTFAMILY = *PSPLASHFONT != STRVAL_EMPTY ? *PSPLASHFONT : *FALLBACKFONT;
const auto FONTSIZE = (int)(size.y / 76);
- const auto COLOR = CColor(*PSPLASHCOLOR);
+ const auto COLOR = CHyprColor(*PSPLASHCOLOR);
PangoLayout* layoutText = pango_cairo_create_layout(CAIRO);
PangoFontDescription* pangoFD = pango_font_description_new();
@@ -2671,7 +2778,7 @@ SP<CTexture> CHyprOpenGLImpl::loadAsset(const std::string& filename) {
return tex;
}
-SP<CTexture> CHyprOpenGLImpl::renderText(const std::string& text, CColor col, int pt, bool italic) {
+SP<CTexture> CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col, int pt, bool italic) {
SP<CTexture> tex = makeShared<CTexture>();
static auto FONT = CConfigValue<std::string>("misc:font_family");
@@ -2804,7 +2911,7 @@ void CHyprOpenGLImpl::initAssets() {
g_pCompositor->m_pAqBackend->hasSession() && g_pCompositor->m_pAqBackend->session->vt > 0 ?
std::to_string(g_pCompositor->m_pAqBackend->session->vt) :
"unknown"),
- CColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true);
+ CHyprColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true);
// create the default background texture
{
@@ -2889,7 +2996,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) {
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
blend(true);
- clear(CColor{0, 0, 0, 1});
+ clear(CHyprColor{0, 0, 0, 1});
// first render the background
if (m_pBackgroundTexture) {
@@ -2981,7 +3088,7 @@ void CHyprOpenGLImpl::restoreMatrix() {
void CHyprOpenGLImpl::bindOffMain() {
m_RenderData.pCurrentMonData->offMainFB.bind();
- clear(CColor(0, 0, 0, 0));
+ clear(CHyprColor(0, 0, 0, 0));
m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offMainFB;
}
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index c594a7cc..6c0632dd 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -153,15 +153,16 @@ class CHyprOpenGLImpl {
void beginSimple(PHLMONITOR, const CRegion& damage, SP<CRenderbuffer> rb = nullptr, CFramebuffer* fb = nullptr);
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 renderRect(CBox*, const CHyprColor&, int round = 0);
+ void renderRectWithBlur(CBox*, const CHyprColor&, int round = 0, float blurA = 1.f, bool xray = false);
+ void renderRectWithDamage(CBox*, const CHyprColor&, CRegion* damage, int round = 0);
void renderTexture(SP<CTexture>, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
void renderTextureWithDamage(SP<CTexture>, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false,
SP<CSyncTimeline> waitTimeline = nullptr, uint64_t waitPoint = 0);
void renderTextureWithBlur(SP<CTexture>, CBox*, float a, SP<CWLSurfaceResource> 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 renderRoundedShadow(CBox*, int round, int range, const CHyprColor& color, float a = 1.0);
void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */);
+ void renderBorder(CBox*, const CGradientValueData&, const CGradientValueData&, float lerp, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */);
void renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuffer& matte);
void setMonitorTransformEnabled(bool enabled);
@@ -180,7 +181,7 @@ class CHyprOpenGLImpl {
void renderSnapshot(PHLLS);
bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow);
- void clear(const CColor&);
+ void clear(const CHyprColor&);
void clearWithTex();
void scissor(const CBox*, bool transform = true);
void scissor(const pixman_box32*, bool transform = true);
@@ -289,7 +290,7 @@ class CHyprOpenGLImpl {
void initEGL(bool gbm);
EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
SP<CTexture> loadAsset(const std::string& file);
- SP<CTexture> renderText(const std::string& text, CColor col, int pt, bool italic = false);
+ SP<CTexture> renderText(const std::string& text, CHyprColor col, int pt, bool italic = false);
void initAssets();
void initMissingAssetTexture();
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index bba133d9..7e44e64e 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -619,7 +619,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe
if (*PDIMAROUND && pWindow->m_sWindowData.dimAround.valueOrDefault() && !m_bRenderingSnapshot && mode != RENDER_PASS_POPUP) {
CBox monbox = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.y};
- g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMAROUND * renderdata.alpha * renderdata.fadeAlpha));
+ g_pHyprOpenGL->renderRect(&monbox, CHyprColor(0, 0, 0, *PDIMAROUND * renderdata.alpha * renderdata.fadeAlpha));
}
renderdata.x += pWindow->m_vFloatingOffset.x;
@@ -668,7 +668,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe
if (!pWindow->m_sWindowData.noBlur.valueOrDefault() && 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, CHyprColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha,
g_pHyprOpenGL->shouldUseNewBlurOptimizations(nullptr, pWindow));
renderdata.blur = false;
}
@@ -780,7 +780,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim
if (*PDIMAROUND && pLayer->dimAround && !m_bRenderingSnapshot && !popups) {
CBox monbox = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.y};
- g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMAROUND * pLayer->alpha.value()));
+ g_pHyprOpenGL->renderRect(&monbox, CHyprColor(0, 0, 0, *PDIMAROUND * pLayer->alpha.value()));
}
if (pLayer->fadingOut) {
@@ -919,7 +919,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA
g_pHyprOpenGL->blend(false);
if (!canSkipBackBufferClear(pMonitor)) {
if (*PRENDERTEX /* inverted cfg flag */)
- g_pHyprOpenGL->clear(CColor(*PBACKGROUNDCOLOR));
+ g_pHyprOpenGL->clear(CHyprColor(*PBACKGROUNDCOLOR));
else
g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
}
@@ -959,7 +959,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA
g_pHyprOpenGL->blend(false);
if (!canSkipBackBufferClear(pMonitor)) {
if (*PRENDERTEX /* inverted cfg flag */)
- g_pHyprOpenGL->clear(CColor(*PBACKGROUNDCOLOR));
+ g_pHyprOpenGL->clear(CHyprColor(*PBACKGROUNDCOLOR));
else
g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
}
@@ -995,12 +995,12 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA
if (*PDIMSPECIAL != 0.f) {
CBox monbox = {translate.x, translate.y, pMonitor->vecTransformedSize.x * scale, pMonitor->vecTransformedSize.y * scale};
- g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMSPECIAL * (ANIMOUT ? (1.0 - SPECIALANIMPROGRS) : SPECIALANIMPROGRS)));
+ g_pHyprOpenGL->renderRect(&monbox, CHyprColor(0, 0, 0, *PDIMSPECIAL * (ANIMOUT ? (1.0 - SPECIALANIMPROGRS) : SPECIALANIMPROGRS)));
}
if (*PBLURSPECIAL && *PBLUR) {
CBox monbox = {translate.x, translate.y, pMonitor->vecTransformedSize.x * scale, pMonitor->vecTransformedSize.y * scale};
- g_pHyprOpenGL->renderRectWithBlur(&monbox, CColor(0, 0, 0, 0), 0, (ANIMOUT ? (1.0 - SPECIALANIMPROGRS) : SPECIALANIMPROGRS));
+ g_pHyprOpenGL->renderRectWithBlur(&monbox, CHyprColor(0, 0, 0, 0), 0, (ANIMOUT ? (1.0 - SPECIALANIMPROGRS) : SPECIALANIMPROGRS));
}
break;
@@ -1447,7 +1447,7 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) {
if (*PDAMAGEBLINK && damageBlinkCleanup == 0) {
CBox monrect = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y};
- g_pHyprOpenGL->renderRect(&monrect, CColor(1.0, 0.0, 1.0, 100.0 / 255.0), 0);
+ g_pHyprOpenGL->renderRect(&monrect, CHyprColor(1.0, 0.0, 1.0, 100.0 / 255.0), 0);
damageBlinkCleanup = 1;
} else if (*PDAMAGEBLINK) {
damageBlinkCleanup++;
@@ -2526,7 +2526,7 @@ std::tuple<float, float, float> CHyprRenderer::getRenderTimes(PHLMONITOR pMonito
static int handleCrashLoop(void* data) {
- g_pHyprNotificationOverlay->addNotification("Hyprland will crash in " + std::to_string(10 - (int)(g_pHyprRenderer->m_fCrashingDistort * 2.f)) + "s.", CColor(0), 5000,
+ g_pHyprNotificationOverlay->addNotification("Hyprland will crash in " + std::to_string(10 - (int)(g_pHyprRenderer->m_fCrashingDistort * 2.f)) + "s.", CHyprColor(0), 5000,
ICON_INFO);
g_pHyprRenderer->m_fCrashingDistort += 0.5f;
@@ -2540,7 +2540,7 @@ static int handleCrashLoop(void* data) {
}
void CHyprRenderer::initiateManualCrash() {
- g_pHyprNotificationOverlay->addNotification("Manual crash initiated. Farewell...", CColor(0), 5000, ICON_INFO);
+ g_pHyprNotificationOverlay->addNotification("Manual crash initiated. Farewell...", CHyprColor(0), 5000, ICON_INFO);
m_pCrashingLoop = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleCrashLoop, nullptr);
wl_event_source_timer_update(m_pCrashingLoop, 1000);
diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp
index d5a312c3..eaf9da96 100644
--- a/src/render/Shader.hpp
+++ b/src/render/Shader.hpp
@@ -38,9 +38,13 @@ class CShader {
GLint applyTint = -1;
GLint tint = -1;
- GLint gradient = -1;
- GLint gradientLength = -1;
- GLint angle = -1;
+ GLint gradient = -1;
+ GLint gradientLength = -1;
+ GLint angle = -1;
+ GLint gradient2 = -1;
+ GLint gradient2Length = -1;
+ GLint angle2 = -1;
+ GLint gradientLerp = -1;
float initialTime = 0;
GLint time = -1;
diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp
index d62e67c4..b0de4a64 100644
--- a/src/render/decorations/CHyprBorderDecoration.cpp
+++ b/src/render/decorations/CHyprBorderDecoration.cpp
@@ -60,7 +60,6 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) {
auto grad = m_pWindow->m_cRealBorderColor;
const bool ANIMATED = m_pWindow->m_fBorderFadeAnimationProgress.isBeingAnimated();
- float a1 = a * (ANIMATED ? m_pWindow->m_fBorderFadeAnimationProgress.value() : 1.f);
if (m_pWindow->m_fBorderAngleAnimationProgress.getConfig()->pValues->internalEnabled) {
grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress.value() * M_PI * 2;
@@ -70,12 +69,10 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) {
int borderSize = m_pWindow->getRealBorderSize();
const auto ROUNDING = m_pWindow->rounding() * pMonitor->scale;
- g_pHyprOpenGL->renderBorder(&windowBox, grad, ROUNDING, borderSize, a1);
-
- if (ANIMATED) {
- float a2 = a * (1.f - m_pWindow->m_fBorderFadeAnimationProgress.value());
- g_pHyprOpenGL->renderBorder(&windowBox, m_pWindow->m_cRealBorderColorPrevious, ROUNDING, borderSize, a2);
- }
+ if (ANIMATED)
+ g_pHyprOpenGL->renderBorder(&windowBox, m_pWindow->m_cRealBorderColorPrevious, grad, m_pWindow->m_fBorderFadeAnimationProgress.value(), ROUNDING, borderSize, a);
+ else
+ g_pHyprOpenGL->renderBorder(&windowBox, grad, ROUNDING, borderSize, a);
}
eDecorationType CHyprBorderDecoration::getDecorationType() {
diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp
index 893ad498..39398878 100644
--- a/src/render/decorations/CHyprDropShadowDecoration.cpp
+++ b/src/render/decorations/CHyprDropShadowDecoration.cpp
@@ -93,7 +93,7 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) {
if (!validMapped(PWINDOW))
return;
- if (PWINDOW->m_cRealShadowColor.value() == CColor(0, 0, 0, 0))
+ if (PWINDOW->m_cRealShadowColor.value() == CHyprColor(0, 0, 0, 0))
return; // don't draw invisible shadows
if (!PWINDOW->m_sWindowData.decorate.valueOrDefault())
@@ -181,13 +181,13 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) {
// 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_pHyprOpenGL->renderRect(&fullBox, CColor(0, 0, 0, 1), 0);
+ g_pHyprOpenGL->renderRect(&fullBox, CHyprColor(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)
- drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a);
+ drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a);
// render black window box ("clip")
- g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale);
+ g_pHyprOpenGL->renderRect(&windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale);
alphaSwapFB.bind();
@@ -215,7 +215,7 @@ eDecorationLayer CHyprDropShadowDecoration::getDecorationLayer() {
return DECORATION_LAYER_BOTTOM;
}
-void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, int range, CColor color, float a) {
+void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, int range, CHyprColor color, float a) {
static auto PSHADOWSHARP = CConfigValue<Hyprlang::INT>("decoration:shadow:sharp");
g_pHyprOpenGL->blend(true);
diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp
index 933ee0ef..650f8c92 100644
--- a/src/render/decorations/CHyprDropShadowDecoration.hpp
+++ b/src/render/decorations/CHyprDropShadowDecoration.hpp
@@ -34,7 +34,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration {
Vector2D m_vLastWindowPos;
Vector2D m_vLastWindowSize;
- void drawShadowInternal(CBox* box, int round, int range, CColor color, float a);
+ void drawShadowInternal(CBox* box, int round, int range, CHyprColor color, float a);
CBox m_bLastWindowBox = {0};
CBox m_bLastWindowBoxWithDecos = {0};
diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp
index b5189be5..937c913d 100644
--- a/src/render/decorations/CHyprGroupBarDecoration.cpp
+++ b/src/render/decorations/CHyprGroupBarDecoration.cpp
@@ -147,7 +147,7 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) {
const auto* const PCOLACTIVE = GROUPLOCKED ? GROUPCOLACTIVELOCKED : GROUPCOLACTIVE;
const auto* const PCOLINACTIVE = GROUPLOCKED ? GROUPCOLINACTIVELOCKED : GROUPCOLINACTIVE;
- CColor color = m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? PCOLACTIVE->m_vColors[0] : PCOLINACTIVE->m_vColors[0];
+ CHyprColor color = m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? PCOLACTIVE->m_vColors[0] : PCOLINACTIVE->m_vColors[0];
color.a *= a;
g_pHyprOpenGL->renderRect(&rect, color);
@@ -205,19 +205,19 @@ void CHyprGroupBarDecoration::invalidateTextures() {
}
CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale) {
- tex = makeShared<CTexture>();
- szContent = pWindow->m_szTitle;
- pWindowOwner = pWindow;
- const auto LAYOUTSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
- const auto LAYOUTCAIRO = cairo_create(LAYOUTSURFACE);
-
- static auto FALLBACKFONT = CConfigValue<std::string>("misc:font_family");
- static auto PTITLEFONTFAMILY = CConfigValue<std::string>("group:groupbar:font_family");
- static auto PTITLEFONTSIZE = CConfigValue<Hyprlang::INT>("group:groupbar:font_size");
- static auto PTEXTCOLOR = CConfigValue<Hyprlang::INT>("group:groupbar:text_color");
-
- const CColor COLOR = CColor(*PTEXTCOLOR);
- const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT;
+ tex = makeShared<CTexture>();
+ szContent = pWindow->m_szTitle;
+ pWindowOwner = pWindow;
+ const auto LAYOUTSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
+ const auto LAYOUTCAIRO = cairo_create(LAYOUTSURFACE);
+
+ static auto FALLBACKFONT = CConfigValue<std::string>("misc:font_family");
+ static auto PTITLEFONTFAMILY = CConfigValue<std::string>("group:groupbar:font_family");
+ static auto PTITLEFONTSIZE = CConfigValue<Hyprlang::INT>("group:groupbar:font_size");
+ static auto PTEXTCOLOR = CConfigValue<Hyprlang::INT>("group:groupbar:text_color");
+
+ const CHyprColor COLOR = CHyprColor(*PTEXTCOLOR);
+ const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT;
cairo_surface_destroy(LAYOUTSURFACE);
diff --git a/src/render/shaders/Border.hpp b/src/render/shaders/Border.hpp
index 1f4a1d97..acd3f3ff 100644
--- a/src/render/shaders/Border.hpp
+++ b/src/render/shaders/Border.hpp
@@ -17,12 +17,32 @@ uniform float radius;
uniform float radiusOuter;
uniform float thick;
+// Gradients are in OkLabA!!!! {l, a, b, alpha}
uniform vec4 gradient[10];
+uniform vec4 gradient2[10];
uniform int gradientLength;
+uniform int gradient2Length;
uniform float angle;
+uniform float angle2;
+uniform float gradientLerp;
uniform float alpha;
-vec4 getColorForCoord(vec2 normalizedCoord) {
+float linearToGamma(float x) {
+ return x >= 0.0031308 ? 1.055 * pow(x, 0.416666666) - 0.055 : 12.92 * x;
+}
+
+vec4 okLabAToSrgb(vec4 lab) {
+ float l = pow(lab[0] + lab[1] * 0.3963377774 + lab[2] * 0.2158037573, 3.0);
+ float m = pow(lab[0] + lab[1] * (-0.1055613458) + lab[2] * (-0.0638541728), 3.0);
+ float s = pow(lab[0] + lab[1] * (-0.0894841775) + lab[2] * (-1.2914855480), 3.0);
+
+ return vec4(linearToGamma(l * 4.0767416621 + m * -3.3077115913 + s * 0.2309699292),
+ linearToGamma(l * (-1.2684380046) + m * 2.6097574011 + s * (-0.3413193965)),
+ linearToGamma(l * (-0.0041960863) + m * (-0.7034186147) + s * 1.7076147010),
+ lab[3]);
+}
+
+vec4 getOkColorForCoordArray1(vec2 normalizedCoord) {
if (gradientLength < 2)
return gradient[0];
@@ -51,6 +71,46 @@ vec4 getColorForCoord(vec2 normalizedCoord) {
return gradient[top] * (progress - float(bottom)) + gradient[bottom] * (float(top) - progress);
}
+vec4 getOkColorForCoordArray2(vec2 normalizedCoord) {
+ if (gradient2Length < 2)
+ return gradient2[0];
+
+ float finalAng = 0.0;
+
+ if (angle2 > 4.71 /* 270 deg */) {
+ normalizedCoord[1] = 1.0 - normalizedCoord[1];
+ finalAng = 6.28 - angle;
+ } else if (angle2 > 3.14 /* 180 deg */) {
+ normalizedCoord[0] = 1.0 - normalizedCoord[0];
+ normalizedCoord[1] = 1.0 - normalizedCoord[1];
+ finalAng = angle - 3.14;
+ } else if (angle2 > 1.57 /* 90 deg */) {
+ normalizedCoord[0] = 1.0 - normalizedCoord[0];
+ finalAng = 3.14 - angle2;
+ } else {
+ finalAng = angle2;
+ }
+
+ float sine = sin(finalAng);
+
+ float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradient2Length - 1);
+ int bottom = int(floor(progress));
+ int top = bottom + 1;
+
+ return gradient2[top] * (progress - float(bottom)) + gradient2[bottom] * (float(top) - progress);
+}
+
+vec4 getColorForCoord(vec2 normalizedCoord) {
+ vec4 result1 = getOkColorForCoordArray1(normalizedCoord);
+
+ if (gradient2Length <= 0)
+ return okLabAToSrgb(result1);
+
+ vec4 result2 = getOkColorForCoordArray2(normalizedCoord);
+
+ return okLabAToSrgb(mix(result1, result2, gradientLerp));
+}
+
void main() {
highp vec2 pixCoord = vec2(gl_FragCoord);