/** * @file easing_functions.hpp * @brief Colección de funciones de suavizado (easing) para animaciones * * Todas las funciones toman un parámetro t (0.0 a 1.0) que representa * el progreso de la animación y retornan el valor suavizado. * * Convenciones: * - In: Aceleración (slow -> fast) * - Out: Desaceleración (fast -> slow) * - InOut: Aceleración + Desaceleración (slow -> fast -> slow) */ #pragma once #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif namespace Easing { // LINEAR inline auto linear(float t) -> float { return t; } // QUAD (Cuadrática: t^2) inline auto quadIn(float t) -> float { return t * t; } inline auto quadOut(float t) -> float { return t * (2.0F - t); } inline auto quadInOut(float t) -> float { if (t < 0.5F) { return 2.0F * t * t; } return -1.0F + ((4.0F - 2.0F * t) * t); } // CUBIC (Cúbica: t^3) inline auto cubicIn(float t) -> float { return t * t * t; } inline auto cubicOut(float t) -> float { const float F = t - 1.0F; return (F * F * F) + 1.0F; } inline auto cubicInOut(float t) -> float { if (t < 0.5F) { return 4.0F * t * t * t; } const float F = ((2.0F * t) - 2.0F); return (0.5F * F * F * F) + 1.0F; } // QUART (Cuártica: t^4) inline auto quartIn(float t) -> float { return t * t * t * t; } inline auto quartOut(float t) -> float { const float F = t - 1.0F; return 1.0F - (F * F * F * F); } inline auto quartInOut(float t) -> float { if (t < 0.5F) { return 8.0F * t * t * t * t; } const float F = t - 1.0F; return 1.0F - (8.0F * F * F * F * F); } // QUINT (Quíntica: t^5) inline auto quintIn(float t) -> float { return t * t * t * t * t; } inline auto quintOut(float t) -> float { const float F = t - 1.0F; return (F * F * F * F * F) + 1.0F; } inline auto quintInOut(float t) -> float { if (t < 0.5F) { return 16.0F * t * t * t * t * t; } const float F = ((2.0F * t) - 2.0F); return (0.5F * F * F * F * F * F) + 1.0F; } // SINE (Sinusoidal) inline auto sineIn(float t) -> float { return 1.0F - std::cos(t * std::numbers::pi_v * 0.5F); } inline auto sineOut(float t) -> float { return std::sin(t * std::numbers::pi_v * 0.5F); } inline auto sineInOut(float t) -> float { return 0.5F * (1.0F - std::cos(std::numbers::pi_v * t)); } // EXPO (Exponencial) inline auto expoIn(float t) -> float { if (t == 0.0F) { return 0.0F; } return std::pow(2.0F, 10.0F * (t - 1.0F)); } inline auto expoOut(float t) -> float { if (t == 1.0F) { return 1.0F; } return 1.0F - std::pow(2.0F, -10.0F * t); } inline auto expoInOut(float t) -> float { if (t == 0.0F || t == 1.0F) { return t; } if (t < 0.5F) { return 0.5F * std::pow(2.0F, (20.0F * t) - 10.0F); } return 0.5F * (2.0F - std::pow(2.0F, (-20.0F * t) + 10.0F)); } // CIRC (Circular) inline auto circIn(float t) -> float { return 1.0F - std::sqrt(1.0F - (t * t)); } inline auto circOut(float t) -> float { const float F = t - 1.0F; return std::sqrt(1.0F - (F * F)); } inline auto circInOut(float t) -> float { if (t < 0.5F) { return 0.5F * (1.0F - std::sqrt(1.0F - (4.0F * t * t))); } const float F = (2.0F * t) - 2.0F; return 0.5F * (std::sqrt(1.0F - (F * F)) + 1.0F); } // BACK (Overshoot - retrocede antes de avanzar) inline auto backIn(float t, float overshoot = 1.70158F) -> float { return t * t * ((overshoot + 1.0F) * t - overshoot); } inline auto backOut(float t, float overshoot = 1.70158F) -> float { const float F = t - 1.0F; return (F * F * ((overshoot + 1.0F) * F + overshoot)) + 1.0F; } inline auto backInOut(float t, float overshoot = 1.70158F) -> float { const float S = overshoot * 1.525F; if (t < 0.5F) { const float F = 2.0F * t; return 0.5F * (F * F * ((S + 1.0F) * F - S)); } const float F = (2.0F * t) - 2.0F; return 0.5F * (F * F * ((S + 1.0F) * F + S) + 2.0F); } // ELASTIC (Oscilación elástica - efecto de resorte) inline auto elasticIn(float t, float amplitude = 1.0F, float period = 0.3F) -> float { if (t == 0.0F || t == 1.0F) { return t; } const float S = period / (2.0F * std::numbers::pi_v)*std::asin(1.0F / amplitude); const float F = t - 1.0F; return -(amplitude * std::pow(2.0F, 10.0F * F) * std::sin((F - S) * (2.0F * std::numbers::pi_v) / period)); } inline auto elasticOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float { if (t == 0.0F || t == 1.0F) { return t; } const float S = period / (2.0F * std::numbers::pi_v)*std::asin(1.0F / amplitude); return (amplitude * std::pow(2.0F, -10.0F * t) * std::sin((t - S) * (2.0F * std::numbers::pi_v) / period)) + 1.0F; } inline auto elasticInOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float { if (t == 0.0F || t == 1.0F) { return t; } const float S = period / (2.0F * std::numbers::pi_v)*std::asin(1.0F / amplitude); if (t < 0.5F) { const float F = (2.0F * t) - 1.0F; return -0.5F * (amplitude * std::pow(2.0F, 10.0F * F) * std::sin((F - S) * (2.0F * std::numbers::pi_v) / period)); } const float F = (2.0F * t) - 1.0F; return (0.5F * amplitude * std::pow(2.0F, -10.0F * F) * std::sin((F - S) * (2.0F * std::numbers::pi_v) / period)) + 1.0F; } // BOUNCE (Rebote - simula física de rebote) inline auto bounceOut(float t) -> float { const float N1 = 7.5625F; const float D1 = 2.75F; if (t < 1.0F / D1) { return N1 * t * t; } if (t < 2.0F / D1) { const float F = t - (1.5F / D1); return (N1 * F * F) + 0.75F; } if (t < 2.5F / D1) { const float F = t - (2.25F / D1); return (N1 * F * F) + 0.9375F; } const float F = t - (2.625F / D1); return (N1 * F * F) + 0.984375F; } inline auto bounceIn(float t) -> float { return 1.0F - bounceOut(1.0F - t); } inline auto bounceInOut(float t) -> float { if (t < 0.5F) { return 0.5F * bounceIn(2.0F * t); } return (0.5F * bounceOut((2.0F * t) - 1.0F)) + 0.5F; } } // namespace Easing