[Adaptation Layer] Added rive-tizen adaptation layer class.
[platform/core/uifw/rive-tizen.git] / submodule / src / animation / cubic_interpolator.cpp
1 #include "animation/cubic_interpolator.hpp"
2 #include "artboard.hpp"
3 #include "importers/artboard_importer.hpp"
4 #include "importers/import_stack.hpp"
5 #include <cmath>
6
7 using namespace rive;
8
9 const int NewtonIterations = 4;
10 const float NewtonMinSlope = 0.001f;
11 const float SubdivisionPrecision = 0.0000001f;
12 const int SubdivisionMaxIterations = 10;
13
14 // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
15 static float calcBezier(float aT, float aA1, float aA2)
16 {
17         return (((1.0f - 3.0f * aA2 + 3.0f * aA1) * aT +
18                  (3.0f * aA2 - 6.0f * aA1)) *
19                     aT +
20                 (3.0f * aA1)) *
21                aT;
22 }
23
24 // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
25 static float getSlope(float aT, float aA1, float aA2)
26 {
27         return 3.0f * (1.0f - 3.0f * aA2 + 3.0f * aA1) * aT * aT +
28                2.0f * (3.0f * aA2 - 6.0f * aA1) * aT + (3.0f * aA1);
29 }
30
31 StatusCode CubicInterpolator::onAddedDirty(CoreContext* context)
32 {
33         for (int i = 0; i < SplineTableSize; ++i)
34         {
35                 m_Values[i] = calcBezier(i * SampleStepSize, x1(), x2());
36         }
37         return StatusCode::Ok;
38 }
39
40 float CubicInterpolator::getT(float x) const
41 {
42         float intervalStart = 0.0f;
43         int currentSample = 1;
44         int lastSample = SplineTableSize - 1;
45
46         for (; currentSample != lastSample && m_Values[currentSample] <= x;
47              ++currentSample)
48         {
49                 intervalStart += SampleStepSize;
50         }
51         --currentSample;
52
53         // Interpolate to provide an initial guess for t
54         float dist = (x - m_Values[currentSample]) /
55                      (m_Values[currentSample + 1] - m_Values[currentSample]);
56         float guessForT = intervalStart + dist * SampleStepSize;
57
58         float _x1 = x1(), _x2 = x2();
59
60         float initialSlope = getSlope(guessForT, _x1, _x2);
61         if (initialSlope >= NewtonMinSlope)
62         {
63                 for (int i = 0; i < NewtonIterations; ++i)
64                 {
65                         float currentSlope = getSlope(guessForT, _x1, _x2);
66                         if (currentSlope == 0.0f)
67                         {
68                                 return guessForT;
69                         }
70                         float currentX = calcBezier(guessForT, _x1, _x2) - x;
71                         guessForT -= currentX / currentSlope;
72                 }
73                 return guessForT;
74         }
75         else if (initialSlope == 0.0f)
76         {
77                 return guessForT;
78         }
79         else
80         {
81                 float aB = intervalStart + SampleStepSize;
82                 float currentX, currentT;
83                 int i = 0;
84                 do
85                 {
86                         currentT = intervalStart + (aB - intervalStart) / 2.0f;
87                         currentX = calcBezier(currentT, _x1, _x2) - x;
88                         if (currentX > 0.0f)
89                         {
90                                 aB = currentT;
91                         }
92                         else
93                         {
94                                 intervalStart = currentT;
95                         }
96                 } while (std::abs(currentX) > SubdivisionPrecision &&
97                          ++i < SubdivisionMaxIterations);
98                 return currentT;
99         }
100 }
101
102 float CubicInterpolator::transform(float mix) const
103 {
104         return calcBezier(getT(mix), y1(), y2());
105 }
106
107 StatusCode CubicInterpolator::import(ImportStack& importStack)
108 {
109         auto artboardImporter =
110             importStack.latest<ArtboardImporter>(ArtboardBase::typeKey);
111         if (artboardImporter == nullptr)
112         {
113                 return StatusCode::MissingObject;
114         }
115         artboardImporter->addComponent(this);
116         return Super::import(importStack);
117 }