summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsubhransu mohanty <sub.mohanty@samsung.com>2017-12-27 14:05:09 +0900
committersubhransu mohanty <sub.mohanty@samsung.com>2018-04-12 13:51:53 +0900
commitc35fb0e1052b71a43a780a91f21020809f482409 (patch)
treef5f35140f0691a15e719e4e2fe4ca612f2916f45
parentd97dd720783f23abb63a77fc770728d93cd1acfe (diff)
ssg: add path interpolator class
-rw-r--r--ssg/include/sginterpolator.h79
-rw-r--r--ssg/src/lottie/lottiemodel.h11
-rw-r--r--ssg/src/lottie/lottieparser.cpp4
-rw-r--r--ssg/src/util/meson.build3
-rw-r--r--ssg/src/util/sginterpolator.cpp130
5 files changed, 215 insertions, 12 deletions
diff --git a/ssg/include/sginterpolator.h b/ssg/include/sginterpolator.h
new file mode 100644
index 0000000000..f638682b46
--- /dev/null
+++ b/ssg/include/sginterpolator.h
@@ -0,0 +1,79 @@
1#ifndef SGINTERPOLATOR_H
2#define SGINTERPOLATOR_H
3
4#include "sgpoint.h"
5
6class SGInterpolator
7{
8public:
9 SGInterpolator() { /* caller must call Init later */ }
10
11 SGInterpolator(float aX1, float aY1,
12 float aX2, float aY2)
13 {
14 init(aX1, aY1, aX2, aY2);
15 }
16
17 SGInterpolator(SGPointF pt1, SGPointF pt2)
18 {
19 init(pt1.x(), pt1.y(), pt2.x(), pt2.y());
20 }
21
22 void init(float aX1, float aY1,
23 float aX2, float aY2);
24
25 float value(float aX) const;
26
27 void GetSplineDerivativeValues(float aX, float& aDX, float& aDY) const;
28private:
29 void
30 CalcSampleValues();
31
32 /**
33 * Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
34 */
35 static float
36 CalcBezier(float aT, float aA1, float aA2);
37
38 /**
39 * Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
40 */
41 static float
42 GetSlope(float aT, float aA1, float aA2);
43
44 float
45 GetTForX(float aX) const;
46
47 float
48 NewtonRaphsonIterate(float aX, float aGuessT) const;
49
50 float
51 BinarySubdivide(float aX, float aA, float aB) const;
52
53 static float
54 A(float aA1, float aA2)
55 {
56 return 1.0 - 3.0 * aA2 + 3.0 * aA1;
57 }
58
59 static float
60 B(float aA1, float aA2)
61 {
62 return 3.0 * aA2 - 6.0 * aA1;
63 }
64
65 static float
66 C(float aA1)
67 {
68 return 3.0 * aA1;
69 }
70
71 float mX1;
72 float mY1;
73 float mX2;
74 float mY2;
75 enum { kSplineTableSize = 11 };
76 float mSampleValues[kSplineTableSize];
77 static const float kSampleStepSize;
78};
79#endif // SGINTERPOLATOR_H
diff --git a/ssg/src/lottie/lottiemodel.h b/ssg/src/lottie/lottiemodel.h
index eae688b1f9..7e0d8a471d 100644
--- a/ssg/src/lottie/lottiemodel.h
+++ b/ssg/src/lottie/lottiemodel.h
@@ -6,6 +6,7 @@
6#include<unordered_map> 6#include<unordered_map>
7#include"sgpoint.h" 7#include"sgpoint.h"
8#include"sgrect.h" 8#include"sgrect.h"
9#include"sginterpolator.h"
9 10
10 11
11class LottieComposition; 12class LottieComposition;
@@ -47,12 +48,6 @@ public:
47 float b; 48 float b;
48}; 49};
49 50
50class LottieInterpolater
51{
52public:
53 SGPointF mInTangent;
54 SGPointF mOutTangent;
55};
56 51
57template<typename T> 52template<typename T>
58class LottieKeyFrame 53class LottieKeyFrame
@@ -71,7 +66,7 @@ public:
71 T mEndValue; 66 T mEndValue;
72 int mStartFrame; 67 int mStartFrame;
73 int mEndFrame; 68 int mEndFrame;
74 std::shared_ptr<LottieInterpolater> mInterpolator; 69 std::shared_ptr<SGInterpolator> mInterpolator;
75 70
76 /* this is for interpolating position along a path 71 /* this is for interpolating position along a path
77 * Need to move to other place because its only applicable 72 * Need to move to other place because its only applicable
@@ -179,7 +174,7 @@ public:
179 LottieBlendMode mBlendMode; 174 LottieBlendMode mBlendMode;
180 float mTimeStreatch; 175 float mTimeStreatch;
181 std::unordered_map<std::string, 176 std::unordered_map<std::string,
182 std::shared_ptr<LottieInterpolater>> mInterpolatorCache; 177 std::shared_ptr<SGInterpolator>> mInterpolatorCache;
183}; 178};
184 179
185class LottieLayer : public LottieGroupObject 180class LottieLayer : public LottieGroupObject
diff --git a/ssg/src/lottie/lottieparser.cpp b/ssg/src/lottie/lottieparser.cpp
index 53d6d97085..2081d54ee3 100644
--- a/ssg/src/lottie/lottieparser.cpp
+++ b/ssg/src/lottie/lottieparser.cpp
@@ -1145,9 +1145,7 @@ void LottieParser::parseKeyFrame(LottieAnimInfo<T> &obj)
1145 if (search != compRef->mInterpolatorCache.end()) { 1145 if (search != compRef->mInterpolatorCache.end()) {
1146 keyframe.mInterpolator = search->second; 1146 keyframe.mInterpolator = search->second;
1147 } else { 1147 } else {
1148 keyframe.mInterpolator = std::make_shared<LottieInterpolater>(); 1148 keyframe.mInterpolator = std::make_shared<SGInterpolator>(SGInterpolator(inTangent, outTangent));
1149 keyframe.mInterpolator.get()->mInTangent = inTangent;
1150 keyframe.mInterpolator.get()->mOutTangent = outTangent;
1151 compRef->mInterpolatorCache[interpolatorKey] = keyframe.mInterpolator; 1149 compRef->mInterpolatorCache[interpolatorKey] = keyframe.mInterpolator;
1152 } 1150 }
1153 } else { 1151 } else {
diff --git a/ssg/src/util/meson.build b/ssg/src/util/meson.build
index 5e58a5903f..d281f6f326 100644
--- a/ssg/src/util/meson.build
+++ b/ssg/src/util/meson.build
@@ -5,7 +5,8 @@ ssg_util_file = ['sgregion.cpp',
5 'sgpath.cpp', 5 'sgpath.cpp',
6 'sgmatrix.cpp', 6 'sgmatrix.cpp',
7 'sgelapsedtimer.cpp', 7 'sgelapsedtimer.cpp',
8 'sgdebug.cpp' 8 'sgdebug.cpp',
9 'sginterpolator.cpp'
9 ] 10 ]
10 11
11foreach file: ssg_util_file 12foreach file: ssg_util_file
diff --git a/ssg/src/util/sginterpolator.cpp b/ssg/src/util/sginterpolator.cpp
new file mode 100644
index 0000000000..c301aafa3f
--- /dev/null
+++ b/ssg/src/util/sginterpolator.cpp
@@ -0,0 +1,130 @@
1#include"sginterpolator.h"
2#include<cmath>
3
4#define NEWTON_ITERATIONS 4
5#define NEWTON_MIN_SLOPE 0.02
6#define SUBDIVISION_PRECISION 0.0000001
7#define SUBDIVISION_MAX_ITERATIONS 10
8
9const float SGInterpolator::kSampleStepSize =
10 1.0 / float(SGInterpolator::kSplineTableSize - 1);
11
12void
13SGInterpolator::init(float aX1, float aY1, float aX2, float aY2)
14{
15 mX1 = aX1;
16 mY1 = aY1;
17 mX2 = aX2;
18 mY2 = aY2;
19
20 if (mX1 != mY1 || mX2 != mY2)
21 CalcSampleValues();
22}
23
24/*static*/ float
25SGInterpolator::CalcBezier(float aT,
26 float aA1,
27 float aA2)
28{
29 // use Horner's scheme to evaluate the Bezier polynomial
30 return ((A(aA1, aA2)*aT + B(aA1, aA2))*aT + C(aA1))*aT;
31}
32
33void
34SGInterpolator::CalcSampleValues()
35{
36 for (int i = 0; i < kSplineTableSize; ++i) {
37 mSampleValues[i] = CalcBezier(float(i) * kSampleStepSize, mX1, mX2);
38 }
39}
40
41float
42SGInterpolator::GetSlope(float aT,
43 float aA1,
44 float aA2)
45{
46 return 3.0 * A(aA1, aA2)*aT*aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
47}
48
49
50float
51SGInterpolator::value(float aX) const
52{
53 if (mX1 == mY1 && mX2 == mY2)
54 return aX;
55
56 return CalcBezier(GetTForX(aX), mY1, mY2);
57}
58
59float
60SGInterpolator::GetTForX(float aX) const
61{
62 // Find interval where t lies
63 float intervalStart = 0.0;
64 const float* currentSample = &mSampleValues[1];
65 const float* const lastSample = &mSampleValues[kSplineTableSize - 1];
66 for (; currentSample != lastSample && *currentSample <= aX;
67 ++currentSample) {
68 intervalStart += kSampleStepSize;
69 }
70 --currentSample; // t now lies between *currentSample and *currentSample+1
71
72 // Interpolate to provide an initial guess for t
73 float dist = (aX - *currentSample) /
74 (*(currentSample+1) - *currentSample);
75 float guessForT = intervalStart + dist * kSampleStepSize;
76
77 // Check the slope to see what strategy to use. If the slope is too small
78 // Newton-Raphson iteration won't converge on a root so we use bisection
79 // instead.
80 float initialSlope = GetSlope(guessForT, mX1, mX2);
81 if (initialSlope >= NEWTON_MIN_SLOPE) {
82 return NewtonRaphsonIterate(aX, guessForT);
83 } else if (initialSlope == 0.0) {
84 return guessForT;
85 } else {
86 return BinarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize);
87 }
88}
89
90float
91SGInterpolator::NewtonRaphsonIterate(float aX, float aGuessT) const
92{
93 // Refine guess with Newton-Raphson iteration
94 for (int i = 0; i < NEWTON_ITERATIONS; ++i) {
95 // We're trying to find where f(t) = aX,
96 // so we're actually looking for a root for: CalcBezier(t) - aX
97 float currentX = CalcBezier(aGuessT, mX1, mX2) - aX;
98 float currentSlope = GetSlope(aGuessT, mX1, mX2);
99
100 if (currentSlope == 0.0)
101 return aGuessT;
102
103 aGuessT -= currentX / currentSlope;
104 }
105
106 return aGuessT;
107}
108
109float
110SGInterpolator::BinarySubdivide(float aX, float aA, float aB) const
111{
112 float currentX;
113 float currentT;
114 int i = 0;
115
116 do
117 {
118 currentT = aA + (aB - aA) / 2.0;
119 currentX = CalcBezier(currentT, mX1, mX2) - aX;
120
121 if (currentX > 0.0) {
122 aB = currentT;
123 } else {
124 aA = currentT;
125 }
126 } while (fabs(currentX) > SUBDIVISION_PRECISION
127 && ++i < SUBDIVISION_MAX_ITERATIONS);
128
129 return currentT;
130}