diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml index 26660ce6..e22f514e 100644 --- a/.github/actions/setup_base/action.yml +++ b/.github/actions/setup_base/action.yml @@ -33,7 +33,9 @@ runs: libfontenc \ libglvnd \ libinput \ + libjxl \ libliftoff \ + libwebp \ libxcursor \ libxcvt \ libxfont2 \ @@ -69,6 +71,11 @@ runs: cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --install build + - name: Get hyprgraphics-git + shell: bash + run: | + git clone https://github.com/hyprwm/hyprgraphics && cd hyprgraphics && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprgraphics && cmake --install build + - name: Get hyprutils-git shell: bash run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e2a1fe6..aa0d4b03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,11 +107,13 @@ pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.2.3) +pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}") add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}") add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}") +add_compile_definitions(HYPRGRAPHICS_VERSION="${hyprgraphics_dep_VERSION}") pkg_check_modules( deps @@ -247,7 +249,7 @@ target_precompile_headers(Hyprland PRIVATE message(STATUS "Setting link libraries") -target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::deps) +target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::hyprgraphics_dep PkgConfig::deps) if(udis_dep_FOUND) target_link_libraries(Hyprland PkgConfig::udis_dep) else() diff --git a/flake.lock b/flake.lock index 0db2ee60..23bd37a9 100644 --- a/flake.lock +++ b/flake.lock @@ -92,6 +92,32 @@ "type": "github" } }, + "hyprgraphics": { + "inputs": { + "hyprutils": [ + "hyprutils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1733248371, + "narHash": "sha256-FFLJzFTyNhS7tBEEECx0B8Ye/bpmxhFVEKlECgMLc6c=", + "owner": "hyprwm", + "repo": "hyprgraphics", + "rev": "cc95e5babc6065bc3ab4cd195429a9900836ef13", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprgraphics", + "type": "github" + } + }, "hyprland-protocols": { "inputs": { "nixpkgs": [ @@ -246,6 +272,7 @@ "inputs": { "aquamarine": "aquamarine", "hyprcursor": "hyprcursor", + "hyprgraphics": "hyprgraphics", "hyprland-protocols": "hyprland-protocols", "hyprlang": "hyprlang", "hyprutils": "hyprutils", diff --git a/flake.nix b/flake.nix index e3419ef8..f26f1c31 100644 --- a/flake.nix +++ b/flake.nix @@ -22,6 +22,13 @@ inputs.hyprlang.follows = "hyprlang"; }; + hyprgraphics = { + url = "github:hyprwm/hyprgraphics"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + inputs.hyprutils.follows = "hyprutils"; + }; + hyprland-protocols = { url = "github:hyprwm/hyprland-protocols"; inputs.nixpkgs.follows = "nixpkgs"; diff --git a/meson.build b/meson.build index 39a5a6d0..c46b199c 100644 --- a/meson.build +++ b/meson.build @@ -33,10 +33,12 @@ endif aquamarine = dependency('aquamarine', version: '>=0.4.5') hyprcursor = dependency('hyprcursor', version: '>=0.1.7') +hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1') hyprlang = dependency('hyprlang', version: '>= 0.3.2') hyprutils = dependency('hyprutils', version: '>= 0.2.3') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp') +add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp') add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp') add_project_arguments(['-DHYPRUTILS_VERSION="@0@"'.format(hyprutils.version())], language: 'cpp') diff --git a/nix/default.nix b/nix/default.nix index 69174d4d..dbe4879e 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -12,6 +12,7 @@ cairo, git, hyprcursor, + hyprgraphics, hyprland-protocols, hyprlang, hyprutils, @@ -113,6 +114,7 @@ in cairo git hyprcursor + hyprgraphics hyprland-protocols hyprlang hyprutils diff --git a/nix/overlays.nix b/nix/overlays.nix index a7106315..c2103f31 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -22,6 +22,7 @@ in { # Dependencies inputs.aquamarine.overlays.default inputs.hyprcursor.overlays.default + inputs.hyprgraphics.overlays.default inputs.hyprland-protocols.overlays.default inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default 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 m_vColors; + std::vector m_vColors; + + /* Vector containing pure colors for shoving into opengl */ + std::vector 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(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 CConfigManager::generateConfig(std::string configPath) { @@ -883,14 +885,14 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { m_szConfigErrors = ""; if (result.error && !std::any_cast(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(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(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(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(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(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()).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, 3 /* backends */> ICONS_ARRAY = { std::array{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array{"", "", "", "", "", "󰸞", ""}, std::array{"", "", "", "", "", ""}}; -static const std::array 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 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 m_fActiveInactiveAlpha; // animated shadow color - CAnimatedVariable m_cRealShadowColor; + CAnimatedVariable m_cRealShadowColor; // animated tint CAnimatedVariable 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 { }; template <> -struct typeToANIMATEDVARTYPE_t { +struct typeToANIMATEDVARTYPE_t { static constexpr ANIMATEDVARTYPE value = AVARTYPE_COLOR; }; @@ -63,7 +63,7 @@ concept OneOf = (... or std::same_as); // This is mainly to get better errors if we put a type that's not supported // Otherwise template errors are ugly template -concept Animable = OneOf; +concept Animable = OneOf; 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 +#include +#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; + uint32_t getAsHex() const; + Hyprgraphics::CColor::SSRGB asRGB() const; + Hyprgraphics::CColor::SOkLab asOkLab() const; + Hyprgraphics::CColor::SHSL asHSL() const; + CHyprColor stripA() const; - CColor operator-(const CColor& c2) const { - return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a); + // + 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("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 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 + int wlTick(SP 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 = [&](CAnimatedVariable& av) { + static const auto updateVariable = [&](CAnimatedVariable& 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& 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*>(av); - updateVariable(*typedAv); + auto typedAv = static_cast*>(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 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 CPointerManager::renderHWCursorBuffer(SPbind(); 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(iterator->second); + const auto COLOR = std::any_cast(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 #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(id, client, color); if (!buffer->good()) @@ -89,8 +89,8 @@ CSinglePixelBufferManagerResource::CSinglePixelBufferManagerResource(SPsetOnDestroy([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::max(), g / (float)std::numeric_limits::max(), b / (float)std::numeric_limits::max(), - a / (float)std::numeric_limits::max()}; + CHyprColor color{r / (float)std::numeric_limits::max(), g / (float)std::numeric_limits::max(), b / (float)std::numeric_limits::max(), + a / (float)std::numeric_limits::max()}; const auto RESOURCE = PROTO::singlePixel->m_vBuffers.emplace_back(makeShared(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 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 CHyprOpenGLImpl::loadAsset(const std::string& filename) { return tex; } -SP CHyprOpenGLImpl::renderText(const std::string& text, CColor col, int pt, bool italic) { +SP CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col, int pt, bool italic) { SP tex = makeShared(); static auto FONT = CConfigValue("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 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, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); void renderTextureWithDamage(SP, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false, SP waitTimeline = nullptr, uint64_t waitPoint = 0); void renderTextureWithBlur(SP, CBox*, float a, SP 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 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 loadAsset(const std::string& file); - SP renderText(const std::string& text, CColor col, int pt, bool italic = false); + SP 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 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("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(); - szContent = pWindow->m_szTitle; - pWindowOwner = pWindow; - const auto LAYOUTSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); - const auto LAYOUTCAIRO = cairo_create(LAYOUTSURFACE); + tex = makeShared(); + 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("misc:font_family"); - static auto PTITLEFONTFAMILY = CConfigValue("group:groupbar:font_family"); - static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); - static auto PTEXTCOLOR = CConfigValue("group:groupbar:text_color"); + static auto FALLBACKFONT = CConfigValue("misc:font_family"); + static auto PTITLEFONTFAMILY = CConfigValue("group:groupbar:font_family"); + static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); + static auto PTEXTCOLOR = CConfigValue("group:groupbar:text_color"); - const CColor COLOR = CColor(*PTEXTCOLOR); - const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT; + 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);