|
- #include "sww/tween.h"
-
- #include <stdint.h>
- #include <stdio.h> /* printf */
-
- #include "sww/app.h"
- #include "sww/vmath.h"
-
- typedef struct {
- uint32_t factor_i;
- uint32_t factor_n;
- uint32_t factor_ni;
- } BernsteinParams;
-
- // NOTE(anjingyu): uint32_t can only present 12!
- BernsteinParams FactorialForBernstein(uint32_t n, uint32_t i) {
- static const uint32_t kFactorials[12] = {
- 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628000, 39916800, 479001600};
-
- BernsteinParams params = {1, 1, 1};
- if (n > 12 || i > n) {
- printf("[W] n = %u, i = %u, n > 12 or i > n\n", n, i);
- return params;
- }
-
- params.factor_i = kFactorials[i];
- params.factor_n = kFactorials[n];
- params.factor_ni = kFactorials[n - i];
-
- return params;
- }
-
- float Bernstein(uint32_t n, uint32_t i) {
- BernsteinParams p = FactorialForBernstein(n, i);
-
- return p.factor_n / p.factor_i / p.factor_ni;
- }
-
- float CatmullRom(float p0, float p1, float p2, float p3, float t) {
- const float v0 = (p2 - p0) * 0.5;
- const float v1 = (p3 - p1) * 0.5;
- const float t2 = t * t;
- const float t3 = t * t2;
-
- return (2 * p1 - 2 * p2 + v0 + v1) * t3 +
- (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
- }
-
- float Interpolation_Linear(float *v, uint32_t len, float k) {
- const int32_t m = (int32_t)len - 1;
- const float f = m * k;
- const int32_t i = floor(f);
-
- if (k < 0) {
- return Interpolatef(v[0], v[1], f);
- }
-
- if (k > 1) {
- return Interpolatef(v[m], v[m - 1], m - f);
- }
-
- return Interpolatef(v[i], v[i + 1 > m ? m : i + 1], f - i);
- }
-
- float Interpolation_Bezier(float *v, uint32_t len, float k) {
- float b = 0;
- const uint32_t n = len - 1;
- uint32_t i = 0;
-
- for (; i <= n; i++) {
- b += pow(1 - k, n - i) * pow(k, i) * v[i] * Bernstein(n, i);
- }
-
- return b;
- }
-
- float Interpolation_CatmullRom(float *v, uint32_t len, float k) {
- const int32_t m = (int32_t)(len - 1);
- float f = m * k;
- int32_t i = (int32_t)floor(f);
-
- if (v[0] == v[m]) {
- if (k < 0) {
- f = m * (1 + k);
- i = floor(f);
- }
-
- return CatmullRom(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m],
- f - i);
- } else {
- if (k < 0) {
- return v[0] - (CatmullRom(v[0], v[0], v[1], v[1], -f) - v[0]);
- }
-
- if (k > 1) {
- return v[m] - (CatmullRom(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]);
- }
-
- return CatmullRom(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1],
- v[m < i + 2 ? m : i + 2], f - i);
- }
- }
-
- // Linear
- static float Linear(float amount) { return amount; }
-
- // Quadratic
- static float QuadraticIn(float amount) { return amount * amount; }
-
- static float QuadraticOut(float amount) { return amount * (2.f - amount); }
-
- static float QuadraticInOut(float amount) {
- amount *= 2.f;
- if (amount < 1.f) {
- return 0.5f * amount * amount;
- }
-
- --amount;
- return -0.5f * (amount * (amount - 2.f) - 1.f);
- }
-
- // Cubic
- static float CubicIn(float amount) { return amount * amount * amount; }
-
- static float CubicOut(float amount) {
- --amount;
- return amount * amount * amount + 1;
- }
-
- static float CubicInOut(float amount) {
- amount *= 2.f;
- if (amount < 1.f) {
- return 0.5f * amount * amount * amount;
- }
-
- amount -= 2.f;
- return 0.5f * (amount * amount * amount + 2.f);
- }
-
- // Quartic
- static float QuarticIn(float amount) {
- return amount * amount * amount * amount;
- }
-
- static float QuarticOut(float amount) {
- --amount;
- return 1.f - amount * amount * amount * amount;
- }
-
- static float QuarticInOut(float amount) {
- amount *= 2.f;
- if (amount < 1) {
- return 0.5f * amount * amount * amount * amount;
- }
-
- amount -= 2.f;
- return -0.5 * (amount * amount * amount * amount - 2.f);
- }
-
- // Quintic
- static float QuinticIn(float amount) {
- return amount * amount * amount * amount * amount;
- }
-
- static float QuinticOut(float amount) {
- --amount;
- return amount * amount * amount * amount * amount + 1.f;
- }
-
- static float QuinticInOut(float amount) {
- amount *= 2.f;
- if (amount < 1.f) {
- return 0.5 * amount * amount * amount * amount * amount;
- }
-
- amount -= 2.f;
- return 0.5f * (amount * amount * amount * amount * amount + 2.f);
- }
-
- // Sinusoidal
- static float SinusoidalIn(float amount) {
- return 1.f - sin(((1.f - amount) * M_PI) / 2.f);
- }
-
- static float SinusoidalOut(float amount) { return sin((amount * M_PI) / 2.f); }
-
- static float SinusoidalInOut(float amount) {
- return 0.5f * (1.f - sin(M_PI * (0.5f - amount)));
- }
-
- // Exponential
- static float ExponentialIn(float amount) {
- return amount == 0 ? 0 : pow(1024, amount - 1.f);
- }
-
- static float ExponentialOut(float amount) {
- return amount == 1.f ? 1.f : 1.f - pow(2.f, -10.f * amount);
- }
-
- static float ExponentialInOut(float amount) {
- if (amount == 0) {
- return 0;
- }
-
- if (amount == 1.f) {
- return 1;
- }
-
- amount *= 2.f;
- if (amount < 1.f) {
- return 0.5f * pow(1024, amount - 1);
- }
-
- return 0.5f * (-pow(2, -10 * (amount - 1)) + 2);
- }
-
- // Circular
- static float CircularIn(float amount) {
- return 1.f - sqrt(1.f - amount * amount);
- }
-
- static float CircularOut(float amount) {
- --amount;
- return (float)sqrt(1.f - amount * amount);
- }
-
- static float CircularInOut(float amount) {
- amount *= 2.f;
- if (amount < 1.f) {
- return -0.5 * (sqrt(1 - amount * amount) - 1);
- }
- amount -= 2.f;
- return 0.5f * (sqrt(1 - amount * amount) + 1);
- }
-
- // Elastic
- static float ElasticIn(float amount) {
- if (amount == 0) {
- return 0;
- }
-
- if (amount == 1) {
- return 1;
- }
-
- return -pow(2, 10 * (amount - 1)) * sin((amount - 1.1) * 5 * M_PI);
- }
-
- static float ElasticOut(float amount) {
- if (amount == 0) {
- return 0;
- }
-
- if (amount == 1) {
- return 1;
- }
- return pow(2, -10 * amount) * sin((amount - 0.1) * 5 * M_PI) + 1;
- }
-
- static float ElasticInOut(float amount) {
- if (amount == 0) {
- return 0;
- }
-
- if (amount == 1) {
- return 1;
- }
-
- amount *= 2;
-
- if (amount < 1) {
- return -0.5 * pow(2, 10 * (amount - 1)) * sin((amount - 1.1) * 5 * M_PI);
- }
-
- return 0.5 * pow(2, -10 * (amount - 1)) * sin((amount - 1.1) * 5 * M_PI) + 1;
- }
-
- // Back
- static float BackIn(float amount) {
- const float s = 1.70158f;
- return amount == 1.f ? 1.f : amount * amount * ((s + 1) * amount - s);
- }
-
- static float BackOut(float amount) {
- const float s = 1.70158f;
- --amount;
- return amount == 0 ? 0 : amount * amount * ((s + 1) * amount + s) + 1;
- }
-
- static float BackInOut(float amount) {
- const float s = 1.70158f * 1.525f;
- amount *= 2.f;
- if (amount < 1) {
- return 0.5f * (amount * amount * ((s + 1) * amount - s));
- }
- amount -= 2.f;
- return 0.5f * (amount * amount * ((s + 1) * amount + s) + 2);
- }
-
- // Bounce
- static float BounceOut(float amount) {
- if (amount < 1 / 2.75) {
- return 7.5625 * amount * amount;
- } else if (amount < 2 / 2.75) {
- amount -= 1.5 / 2.75;
- return 7.5625 * amount * amount + 0.75;
- } else if (amount < 2.5 / 2.75) {
- amount -= 2.25 / 2.75;
- return 7.5625 * amount * amount + 0.9375;
- } else {
- amount -= 2.625 / 2.75;
- return 7.5625 * amount * amount + 0.984375;
- }
- }
-
- static float BounceIn(float amount) { return 1.f - BounceOut(1.f - amount); }
-
- static float BounceInOut(float amount) {
- if (amount < 0.5) {
- return BounceIn(amount * 2) * 0.5;
- }
- return BounceOut(amount * 2 - 1) * 0.5 + 0.5;
- }
-
- /*
- // Pow
- static float PowIn(float amount) {
- return pow(amount, power);
- }
-
- static float PowOut(float amount) {
- return pow(1 - (1 - amount), power);
- }
-
- static float PowInOut(float amount) {
- if (amount < 0.5) {
- return pow((amount * 2), power / 2);
- }
- return (1 - pow((2 - amount * 2), power)) / 2 + 0.5;
- }
- */
-
- static const EasingFunction kEasingFunctions[] = {
- // Linear
- Linear, // kEasingLinearIn
- Linear, // kEasingLinearOut
- Linear, // kEasingLinearInOut
-
- // Quadratic
- QuadraticIn, // kEasingQuadraticIn
- QuadraticOut, // kEasingQuadraticOut
- QuadraticInOut, // kEasingQuadraticInOut
-
- // Cubic
- CubicIn, // kEasingCubicIn
- CubicOut, // kEasingCubicOut
- CubicInOut, // kEasingCubicInOut
-
- // Quartic
- QuarticIn, // kEasingQuarticIn
- QuarticOut, // kEasingQuarticOut
- QuarticInOut, // kEasingQuarticInOut
-
- // Quintic
- QuinticIn, // kEasingQuinticIn
- QuinticOut, // kEasingQuinticOut
- QuinticInOut, // kEasingQuinticInOut
-
- // Sinusoidal
- SinusoidalIn, // kEasingSinusoidalIn
- SinusoidalOut, // kEasingSinusoidalOut
- SinusoidalInOut, // kEasingSinusoidalInOut
-
- // Exponential
- ExponentialIn, // kEasingExponentialIn
- ExponentialOut, // kEasingExponentialOut
- ExponentialInOut, // kEasingExponentialInOut
-
- // Circular
- CircularIn, // kEasingCircularIn
- CircularOut, // kEasingCircularOut
- CircularInOut, // kEasingCircularInOut
-
- // Elastic
- ElasticIn, // kEasingElasticIn
- ElasticOut, // kEasingElasticOut
- ElasticInOut, // kEasingElasticInOut
-
- // Back
- BackIn, // kEasingBackIn
- BackOut, // kEasingBackOut
- BackInOut, // kEasingBackInOut
-
- // Bounce
- BounceIn, // kEasingBounceIn
- BounceOut, // kEasingBounceOut
- BounceInOut, // kEasingBounceInOut
- };
-
- void swwTween_Construct(swwTween *o, const swwTweenConfig *config) {
- o->start_callback = config->start_callback;
- o->stop_callback = config->stop_callback;
- o->update_callback = config->update_callback;
- o->easing = kEasingFunctions[config->easing_type];
- o->start_time = swwApp_GetTime() + config->delay_time;
- o->stop_time = config->duration + o->start_time + config->delay_time;
- o->user_data = config->user_data;
- o->next = NULL;
- o->started = 0; // false;
- }
-
- /* Non-thread safe */
- void swwTween_Chain(swwTween *o, swwTween *next) {
- if (!o->started) {
- o->next = next;
- } else {
- printf("[W] Can not change the chain of a started tween!\n");
- }
- }
-
- void swwTween_UpdateWithValue(swwTween *o, float v) {
- if (v >= o->start_time) {
- if (!o->started) {
- o->started = 1; // true
- if (o->start_callback != NULL) {
- o->start_callback(o);
- }
- }
-
- if (o->started) {
- float elapsed = 0.f;
- if (v >= o->stop_time) {
- elapsed = 1.f;
- } else {
- elapsed = Normalizef(v, (Rangef){o->start_time, o->stop_time});
- }
-
- float updated_v = o->easing(elapsed);
-
- if (o->update_callback != NULL) {
- o->update_callback(o, updated_v);
- }
-
- if (v >= o->stop_time) {
- if (o->stop_callback != NULL) {
- o->stop_callback(o);
- }
- }
- }
- }
- }
-
- void swwTween_Update(swwTween *o) {
- swwTween_UpdateWithValue(o, swwApp_GetTime());
- }
|