diff --git a/README.md b/README.md index fd29b3d7..72e15c2f 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ Try it out and report bugs / suggestions! - Easily expandable and readable codebase - Config reloaded instantly upon saving -- Parabolic window animations +- Bezier-curve window animations +- Custom bezier curves - Workspaces protocol support - Tiling / floating / fullscreen windows - Window / monitor rules diff --git a/example/hyprland.conf b/example/hyprland.conf index 156192ca..a8add8f2 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -41,7 +41,9 @@ decoration { animations { enabled=1 - speed=7 + speed=7 # speed is measured in 100s of ms, 7 = 700ms + curve=default # you can customize your own bezier curves, see the wiki + windows_curve=default # specific curve for all window animations windows_speed=6 # specific speeds for components can be made with name_speed=float. 0 means use global (speed=float). If not set, will use the global value. windows=1 borders=1 diff --git a/src/Compositor.cpp b/src/Compositor.cpp index df39de94..43263dd4 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -158,6 +158,9 @@ void CCompositor::startCompositor() { Debug::log(LOG, "Creating the KeybindManager!"); g_pKeybindManager = std::make_unique(); + Debug::log(LOG, "Creating the AnimationManager!"); + g_pAnimationManager = std::make_unique(); + Debug::log(LOG, "Creating the ConfigManager!"); g_pConfigManager = std::make_unique(); @@ -178,9 +181,6 @@ void CCompositor::startCompositor() { Debug::log(LOG, "Creating the LayoutManager!"); g_pLayoutManager = std::make_unique(); - - Debug::log(LOG, "Creating the AnimationManager!"); - g_pAnimationManager = std::make_unique(); // // diff --git a/src/Window.cpp b/src/Window.cpp index a2a1aae8..334ca86f 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -2,10 +2,10 @@ #include "Compositor.hpp" CWindow::CWindow() { - m_vRealPosition.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, (void*)this); - m_vRealSize.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, (void*)this); - m_cRealBorderColor.create(AVARTYPE_COLOR, &g_pConfigManager->getConfigValuePtr("animations:borders_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:borders")->intValue, (void*)this); - m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, (void*)this); + m_vRealPosition.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*) this); + m_vRealSize.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*)this); + m_cRealBorderColor.create(AVARTYPE_COLOR, &g_pConfigManager->getConfigValuePtr("animations:borders_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:borders")->intValue, &g_pConfigManager->getConfigValuePtr("animations:borders_curve")->strValue, (void*)this); + m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, (void*)this); } CWindow::~CWindow() { diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 49af08b8..e6d0ccd1 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -43,10 +43,14 @@ void CConfigManager::setDefaultVars() { configValues["animations:enabled"].intValue = 1; configValues["animations:speed"].floatValue = 7.f; + configValues["animations:curve"].strValue = "default"; + configValues["animations:windows_curve"].strValue = "[[f]]"; configValues["animations:windows_speed"].floatValue = 0.f; configValues["animations:windows"].intValue = 1; + configValues["animations:borders_curve"].strValue = "[[f]]"; configValues["animations:borders_speed"].floatValue = 0.f; configValues["animations:borders"].intValue = 1; + configValues["animations:fadein_curve"].strValue = "[[f]]"; configValues["animations:fadein_speed"].floatValue = 0.f; configValues["animations:fadein"].intValue = 1; @@ -207,6 +211,39 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string m_dMonitorRules.push_back(newrule); } +void CConfigManager::handleBezier(const std::string& command, const std::string& args) { + std::string curitem = ""; + + std::string argZ = args; + + auto nextItem = [&]() { + auto idx = argZ.find_first_of(','); + + if (idx != std::string::npos) { + curitem = argZ.substr(0, idx); + argZ = argZ.substr(idx + 1); + } else { + curitem = argZ; + argZ = ""; + } + }; + + nextItem(); + + std::string bezierName = curitem; + + nextItem(); + float p1x = std::stof(curitem); + nextItem(); + float p1y = std::stof(curitem); + nextItem(); + float p2x = std::stof(curitem); + nextItem(); + float p2y = std::stof(curitem); + + g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y)); +} + void CConfigManager::handleBind(const std::string& command, const std::string& value) { // example: // bind=SUPER,G,exec,dmenu_run @@ -311,6 +348,8 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: handleDefaultWorkspace(COMMAND, VALUE); } else if (COMMAND == "windowrule") { handleWindowRule(COMMAND, VALUE); + } else if (COMMAND == "bezier") { + handleBezier(COMMAND, VALUE); } else { configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE); } @@ -379,10 +418,10 @@ void CConfigManager::loadConfigLoadVars() { // reset all vars before loading setDefaultVars(); - m_dMonitorRules.clear(); m_dWindowRules.clear(); g_pKeybindManager->clearKeybinds(); + g_pAnimationManager->removeAllBeziers(); const char* const ENVHOME = getenv("HOME"); const std::string CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf"); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 19d602fa..5c1e125c 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -92,6 +92,7 @@ private: void handleUnbind(const std::string&, const std::string&); void handleWindowRule(const std::string&, const std::string&); void handleDefaultWorkspace(const std::string&, const std::string&); + void handleBezier(const std::string&, const std::string&); }; inline std::unique_ptr g_pConfigManager; \ No newline at end of file diff --git a/src/helpers/AnimatedVariable.cpp b/src/helpers/AnimatedVariable.cpp index 581ea1c8..798e96e5 100644 --- a/src/helpers/AnimatedVariable.cpp +++ b/src/helpers/AnimatedVariable.cpp @@ -5,19 +5,20 @@ CAnimatedVariable::CAnimatedVariable() { ; // dummy var } -void CAnimatedVariable::create(ANIMATEDVARTYPE type, float* speed, int64_t* enabled, void* pWindow) { +void CAnimatedVariable::create(ANIMATEDVARTYPE type, float* speed, int64_t* enabled, std::string* pBezier, void* pWindow) { m_eVarType = type; m_pSpeed = speed; m_pEnabled = enabled; m_pWindow = pWindow; + m_pBezier = pBezier; g_pAnimationManager->m_lAnimatedVariables.push_back(this); m_bDummy = false; } -void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, float* speed, int64_t* enabled, void* pWindow) { - create(type, speed, enabled, pWindow); +void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, float* speed, int64_t* enabled, std::string* pBezier, void* pWindow) { + create(type, speed, enabled, pBezier, pWindow); try { switch (type) { diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index ccdd78e3..197e5d4e 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -16,8 +16,8 @@ class CAnimatedVariable { public: CAnimatedVariable(); // dummy var - void create(ANIMATEDVARTYPE, float* speed, int64_t* enabled, void* pWindow); - void create(ANIMATEDVARTYPE, std::any val, float* speed, int64_t* enabled, void* pWindow); + void create(ANIMATEDVARTYPE, float* speed, int64_t* enabled, std::string* pBezier, void* pWindow); + void create(ANIMATEDVARTYPE, std::any val, float* speed, int64_t* enabled, std::string* pBezier, void* pWindow); ~CAnimatedVariable(); @@ -60,34 +60,46 @@ public: void operator=(const Vector2D& v) { ASSERT(m_eVarType == AVARTYPE_VECTOR); m_vGoal = v; + animationBegin = std::chrono::system_clock::now(); + m_vBegun = m_vValue; } void operator=(const float& v) { ASSERT(m_eVarType == AVARTYPE_FLOAT); m_fGoal = v; + animationBegin = std::chrono::system_clock::now(); + m_fBegun = m_fValue; } void operator=(const CColor& v) { ASSERT(m_eVarType == AVARTYPE_COLOR); m_cGoal = v; + animationBegin = std::chrono::system_clock::now(); + m_cBegun = m_cValue; } - // Sets the actual stored value, without affecting the goal + // Sets the actual stored value, without affecting the goal, but resets the timer void setValue(const Vector2D& v) { ASSERT(m_eVarType == AVARTYPE_VECTOR); m_vValue = v; + animationBegin = std::chrono::system_clock::now(); + m_vBegun = m_vValue; } - // Sets the actual stored value, without affecting the goal + // Sets the actual stored value, without affecting the goal, but resets the timer void setValue(const float& v) { ASSERT(m_eVarType == AVARTYPE_FLOAT); m_fValue = v; + animationBegin = std::chrono::system_clock::now(); + m_vBegun = m_vValue; } - // Sets the actual stored value, without affecting the goal + // Sets the actual stored value, without affecting the goal, but resets the timer void setValue(const CColor& v) { ASSERT(m_eVarType == AVARTYPE_COLOR); m_cValue = v; + animationBegin = std::chrono::system_clock::now(); + m_vBegun = m_vValue; } // Sets the actual value and goal @@ -140,12 +152,19 @@ private: float m_fGoal = 0; CColor m_cGoal; + Vector2D m_vBegun = Vector2D(0,0); + float m_fBegun = 0; + CColor m_cBegun; + float* m_pSpeed = nullptr; int64_t* m_pEnabled = nullptr; void* m_pWindow = nullptr; + std::string* m_pBezier = nullptr; bool m_bDummy = true; + std::chrono::system_clock::time_point animationBegin; + ANIMATEDVARTYPE m_eVarType = AVARTYPE_INVALID; friend class CAnimationManager; diff --git a/src/helpers/BezierCurve.cpp b/src/helpers/BezierCurve.cpp new file mode 100644 index 00000000..845992bd --- /dev/null +++ b/src/helpers/BezierCurve.cpp @@ -0,0 +1,55 @@ +#include "BezierCurve.hpp" + +void CBezierCurve::setup(std::vector* pVec) { + m_dPoints.clear(); + + m_dPoints.emplace_back(Vector2D(0,0)); + + for (auto& p : *pVec) { + m_dPoints.push_back(p); + } + + m_dPoints.emplace_back(Vector2D(1,1)); + + RASSERT(m_dPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: %i)", m_dPoints.size()); + + // bake 100 points for faster lookups + // T -> X ( / 100 ) + for (int i = 0; i < 100; ++i) { + m_aPointsBaked[i] = getXForT((i + 1) / 100.f); + } +} + +float CBezierCurve::getYForT(float t) { + return 3 * t * pow(1 - t, 2) * m_dPoints[1].y + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].y + pow(t, 3); +} + +float CBezierCurve::getXForT(float t) { + return 3 * t * pow(1 - t, 2) * m_dPoints[1].x + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].x + pow(t, 3); +} + +// Todo: this probably can be done better and faster +float CBezierCurve::getYForPoint(float x) { + // binary search for the range UPDOWN X + float upperX = 1; + float lowerX = 0; + float mid = 0.5; + + while(std::abs(upperX - lowerX) > 0.01f) { + if (m_aPointsBaked[((int)(mid * 100.f))] > x) { + upperX = mid; + } else { + lowerX = mid; + } + + mid = (upperX + lowerX) / 2.f; + } + + // in the name of performance i shall make a hack + const auto PERCINDELTA = (x - m_aPointsBaked[(int)(100.f * lowerX)]) / (m_aPointsBaked[(int)(100.f * upperX)] - m_aPointsBaked[(int)(100.f * lowerX)]); + + if (std::isnan(PERCINDELTA) || std::isinf(PERCINDELTA)) // can sometimes happen for VERY small x + return 0.f; + + return getYForT(mid + PERCINDELTA * 0.01f); +} \ No newline at end of file diff --git a/src/helpers/BezierCurve.hpp b/src/helpers/BezierCurve.hpp new file mode 100644 index 00000000..20285695 --- /dev/null +++ b/src/helpers/BezierCurve.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../defines.hpp" +#include + +// an implementation of a cubic bezier curve +// might do better later +// TODO: n-point curves +class CBezierCurve { +public: + // sets up the bezier curve. + // this EXCLUDES the 0,0 and 1,1 points, + void setup(std::vector* points); + + float getYForT(float t); + float getXForT(float t); + float getYForPoint(float x); + +private: + // this INCLUDES the 0,0 and 1,1 points. + std::deque m_dPoints; + + std::array m_aPointsBaked; +}; \ No newline at end of file diff --git a/src/helpers/Color.hpp b/src/helpers/Color.hpp index 7c0d30be..c34dc787 100644 --- a/src/helpers/Color.hpp +++ b/src/helpers/Color.hpp @@ -11,5 +11,17 @@ public: float r = 0, g = 0, b = 0, a = 255; uint64_t getAsHex(); + + CColor operator- (const CColor& c2) const { + return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a); + } + + CColor operator+ (const CColor& c2) const { + return CColor(r + c2.r, g + c2.g, b + c2.b, a + c2.a); + } + + CColor operator* (const float& v) const { + return CColor(r * v, g * v, b * v, a * v); + } }; \ No newline at end of file diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index aae693a5..f54bef7c 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -451,10 +451,10 @@ void CHyprDwindleLayout::onMouseMove(const Vector2D& mousePos) { DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA); } else { if (DRAGGINGWINDOW->m_bIsFloating) { - DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(m_vBeginDragSizeXY + DELTA); + DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragSizeXY + DELTA); DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(Vector2D(std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().x, (double)20, (double)999999), std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().y, (double)20, (double)999999))); - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.vec()); + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); } else { // we need to adjust the splitratio diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 58613042..4d1ab9f8 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -1,6 +1,24 @@ #include "AnimationManager.hpp" #include "../Compositor.hpp" +CAnimationManager::CAnimationManager() { + std::vector points = {Vector2D(0, 0.75f), Vector2D(0.25f, 1.f)}; + m_mBezierCurves["default"].setup(&points); +} + +void CAnimationManager::removeAllBeziers() { + m_mBezierCurves.clear(); + + // add the default one + std::vector points = {Vector2D(0, 0.75f), Vector2D(0.25f, 1.f)}; + m_mBezierCurves["default"].setup(&points); +} + +void CAnimationManager::addBezierWithName(std::string name, const Vector2D& p1, const Vector2D& p2) { + std::vector points = {p1, p2}; + m_mBezierCurves[name].setup(&points); +} + void CAnimationManager::tick() { bool animationsDisabled = false; @@ -9,61 +27,88 @@ void CAnimationManager::tick() { animationsDisabled = true; const float ANIMSPEED = g_pConfigManager->getFloat("animations:speed"); - const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); + const auto BEZIERSTR = g_pConfigManager->getString("animations:curve"); + + auto DEFAULTBEZIER = m_mBezierCurves.find(BEZIERSTR); + if (DEFAULTBEZIER == m_mBezierCurves.end()) + DEFAULTBEZIER = m_mBezierCurves.find("default"); for (auto& av : m_lAnimatedVariables) { - // first, we check if it's disabled, if so, warp - if (av->m_pEnabled == 0 || animationsDisabled) { - av->warp(); - continue; - } - // get speed const auto SPEED = *av->m_pSpeed == 0 ? ANIMSPEED : *av->m_pSpeed; // window stuff const auto PWINDOW = (CWindow*)av->m_pWindow; - bool needsDamage = false; wlr_box WLRBOXPREV = {PWINDOW->m_vRealPosition.vec().x - BORDERSIZE - 1, PWINDOW->m_vRealPosition.vec().y - BORDERSIZE - 1, PWINDOW->m_vRealSize.vec().x + 2 * BORDERSIZE + 2, PWINDOW->m_vRealSize.vec().y + 2 * BORDERSIZE + 2}; - // TODO: curves + // check if it's disabled, if so, warp + if (av->m_pEnabled == 0 || animationsDisabled) { + av->warp(); + g_pHyprRenderer->damageBox(&WLRBOXPREV); + g_pHyprRenderer->damageWindow(PWINDOW); + continue; + } - // parabolic with a switch unforto + // beziers are with a switch unforto // TODO: maybe do something cleaner + + // get the spent % (0 - 1) + const auto DURATIONPASSED = std::chrono::duration_cast(std::chrono::system_clock::now() - av->animationBegin).count(); + const float SPENT = std::clamp((DURATIONPASSED / 100.f) / SPEED, 0.f, 1.f); + switch (av->m_eVarType) { case AVARTYPE_FLOAT: { if (!deltazero(av->m_fValue, av->m_fGoal)) { - if (deltaSmallToFlip(av->m_fValue, av->m_fGoal)) { - av->warp(); - } else { - av->m_fValue = parabolic(av->m_fValue, av->m_fGoal, SPEED); - } + const auto DELTA = av->m_fGoal - av->m_fBegun; + const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); - needsDamage = true; + if (BEZIER != m_mBezierCurves.end()) + av->m_fValue = av->m_fBegun + BEZIER->second.getYForPoint(SPENT) * DELTA; + else + av->m_fValue = av->m_fBegun + DEFAULTBEZIER->second.getYForPoint(SPENT) * DELTA; + + if (SPENT >= 1.f) { + av->warp(); + } + } else { + continue; // dont process } break; } case AVARTYPE_VECTOR: { if (!deltazero(av->m_vValue, av->m_vGoal)) { - if (deltaSmallToFlip(av->m_vValue, av->m_vGoal)) { + const auto DELTA = av->m_vGoal - av->m_vBegun; + const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); + + if (BEZIER != m_mBezierCurves.end()) + av->m_vValue = av->m_vBegun + DELTA * BEZIER->second.getYForPoint(SPENT); + else + av->m_vValue = av->m_vBegun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT); + + if (SPENT >= 1.f) { av->warp(); - } else { - av->m_vValue.x = parabolic(av->m_vValue.x, av->m_vGoal.x, SPEED); - av->m_vValue.y = parabolic(av->m_vValue.y, av->m_vGoal.y, SPEED); } - needsDamage = true; + } else { + continue; // dont process } break; } case AVARTYPE_COLOR: { if (!deltazero(av->m_cValue, av->m_cGoal)) { - if (deltaSmallToFlip(av->m_cValue, av->m_cGoal)) { + const auto DELTA = av->m_cGoal - av->m_cBegun; + const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); + + if (BEZIER != m_mBezierCurves.end()) + av->m_cValue = av->m_cBegun + DELTA * BEZIER->second.getYForPoint(SPENT); + else + av->m_cValue = av->m_cBegun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT); + + if (SPENT >= 1.f) { av->warp(); - } else { - av->m_cValue = parabolic(SPEED, av->m_cValue, av->m_cGoal); } - needsDamage = true; + } else { + continue; // dont process } break; } @@ -72,11 +117,9 @@ void CAnimationManager::tick() { } } - // invalidate the window - if (needsDamage) { - g_pHyprRenderer->damageBox(&WLRBOXPREV); - g_pHyprRenderer->damageWindow(PWINDOW); - } + // damage the window + g_pHyprRenderer->damageBox(&WLRBOXPREV); + g_pHyprRenderer->damageWindow(PWINDOW); } } @@ -102,19 +145,4 @@ bool CAnimationManager::deltazero(const float& a, const float& b) { bool CAnimationManager::deltazero(const CColor& a, const CColor& b) { return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; -} - -double CAnimationManager::parabolic(const double from, const double to, const double incline) { - return from + ((to - from) / incline); -} - -CColor CAnimationManager::parabolic(const double incline, const CColor& from, const CColor& to) { - CColor newColor; - - newColor.r = parabolic(from.r, to.r, incline); - newColor.g = parabolic(from.g, to.g, incline); - newColor.b = parabolic(from.b, to.b, incline); - newColor.a = parabolic(from.a, to.a, incline); - - return newColor; } \ No newline at end of file diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 14d6c3ac..ab0d8357 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -2,12 +2,18 @@ #include "../defines.hpp" #include +#include #include "../helpers/AnimatedVariable.hpp" +#include "../helpers/BezierCurve.hpp" class CAnimationManager { public: + CAnimationManager(); + void tick(); + void addBezierWithName(std::string, const Vector2D&, const Vector2D&); + void removeAllBeziers(); std::list m_lAnimatedVariables; @@ -18,8 +24,8 @@ private: bool deltazero(const Vector2D& a, const Vector2D& b); bool deltazero(const CColor& a, const CColor& b); bool deltazero(const float& a, const float& b); - double parabolic(const double, const double, const double); - CColor parabolic(const double, const CColor&, const CColor&); + + std::unordered_map m_mBezierCurves; }; inline std::unique_ptr g_pAnimationManager; \ No newline at end of file