blob: c5bb4480fbc6963f48b069a44c9e8147f37c1e3c [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SkInterpolator.h"
18#include "SkMath.h"
19#include "SkTSearch.h"
20
21SkInterpolatorBase::SkInterpolatorBase() {
22 fStorage = NULL;
23 fTimes = NULL;
24 SkDEBUGCODE(fTimesArray = NULL;)
25}
26
27SkInterpolatorBase::~SkInterpolatorBase() {
28 if (fStorage) {
29 sk_free(fStorage);
30 }
31}
32
33void SkInterpolatorBase::reset(int elemCount, int frameCount) {
34 fFlags = 0;
35 fElemCount = SkToU8(elemCount);
36 fFrameCount = SkToS16(frameCount);
37 fRepeat = SK_Scalar1;
38 if (fStorage) {
39 sk_free(fStorage);
40 fStorage = NULL;
41 fTimes = NULL;
42 SkDEBUGCODE(fTimesArray = NULL);
43 }
44}
45
46/* Each value[] run is formated as:
47 <time (in msec)>
48 <blend>
49 <data[fElemCount]>
50
51 Totaling fElemCount+2 entries per keyframe
52*/
53
54bool SkInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const {
55 if (fFrameCount == 0) {
56 return false;
57 }
58
59 if (startTime) {
60 *startTime = fTimes[0].fTime;
61 }
62 if (endTime) {
63 *endTime = fTimes[fFrameCount - 1].fTime;
64 }
65 return true;
66}
67
68SkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime,
69 SkMSec nextTime, const SkScalar blend[4]) {
70 SkASSERT(time > prevTime && time < nextTime);
71
72 SkScalar t = SkScalarDiv((SkScalar)(time - prevTime),
73 (SkScalar)(nextTime - prevTime));
74 return blend ?
75 SkUnitCubicInterp(t, blend[0], blend[1], blend[2], blend[3]) : t;
76}
77
78SkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T,
79 int* indexPtr, SkBool* exactPtr) const {
80 SkASSERT(fFrameCount > 0);
81 Result result = kNormal_Result;
82 if (fRepeat != SK_Scalar1) {
reed@android.comf523e252009-01-26 23:15:37 +000083 SkMSec startTime = 0, endTime = 0; // initialize to avoid warning
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 this->getDuration(&startTime, &endTime);
85 SkMSec totalTime = endTime - startTime;
86 SkMSec offsetTime = time - startTime;
87 endTime = SkScalarMulFloor(fRepeat, totalTime);
88 if (offsetTime >= endTime) {
89 SkScalar fraction = SkScalarFraction(fRepeat);
90 offsetTime = fraction == 0 && fRepeat > 0 ? totalTime :
91 SkScalarMulFloor(fraction, totalTime);
92 result = kFreezeEnd_Result;
93 } else {
94 int mirror = fFlags & kMirror;
95 offsetTime = offsetTime % (totalTime << mirror);
96 if (offsetTime > totalTime) { // can only be true if fMirror is true
97 offsetTime = (totalTime << 1) - offsetTime;
98 }
99 }
100 time = offsetTime + startTime;
101 }
102
103 int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time,
104 sizeof(SkTimeCode));
105
106 bool exact = true;
107
108 if (index < 0) {
109 index = ~index;
110 if (index == 0) {
111 result = kFreezeStart_Result;
112 } else if (index == fFrameCount) {
113 if (fFlags & kReset) {
114 index = 0;
115 } else {
116 index -= 1;
117 }
118 result = kFreezeEnd_Result;
119 } else {
120 exact = false;
121 }
122 }
123 SkASSERT(index < fFrameCount);
124 const SkTimeCode* nextTime = &fTimes[index];
125 SkMSec nextT = nextTime[0].fTime;
126 if (exact) {
127 *T = 0;
128 } else {
129 SkMSec prevT = nextTime[-1].fTime;
130 *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend);
131 }
132 *indexPtr = index;
133 *exactPtr = exact;
134 return result;
135}
136
137
138SkInterpolator::SkInterpolator() {
139 INHERITED::reset(0, 0);
140 fValues = NULL;
141 SkDEBUGCODE(fScalarsArray = NULL;)
142}
143
144SkInterpolator::SkInterpolator(int elemCount, int frameCount) {
145 SkASSERT(elemCount > 0);
146 this->reset(elemCount, frameCount);
147}
148
149void SkInterpolator::reset(int elemCount, int frameCount) {
150 INHERITED::reset(elemCount, frameCount);
151 fStorage = sk_malloc_throw((sizeof(SkScalar) * elemCount +
152 sizeof(SkTimeCode)) * frameCount);
153 fTimes = (SkTimeCode*) fStorage;
154 fValues = (SkScalar*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount);
155#ifdef SK_DEBUG
156 fTimesArray = (SkTimeCode(*)[10]) fTimes;
157 fScalarsArray = (SkScalar(*)[10]) fValues;
158#endif
159}
160
161#define SK_Fixed1Third (SK_Fixed1/3)
162#define SK_Fixed2Third (SK_Fixed1*2/3)
163
164static const SkScalar gIdentityBlend[4] = {
165#ifdef SK_SCALAR_IS_FLOAT
166 0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f
167#else
168 SK_Fixed1Third, SK_Fixed1Third, SK_Fixed2Third, SK_Fixed2Third
169#endif
170};
171
172bool SkInterpolator::setKeyFrame(int index, SkMSec time,
173 const SkScalar values[], const SkScalar blend[4]) {
174 SkASSERT(values != NULL);
175
176 if (blend == NULL) {
177 blend = gIdentityBlend;
178 }
179
180 bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time,
181 sizeof(SkTimeCode));
182 SkASSERT(success);
183 if (success) {
184 SkTimeCode* timeCode = &fTimes[index];
185 timeCode->fTime = time;
186 memcpy(timeCode->fBlend, blend, sizeof(timeCode->fBlend));
187 SkScalar* dst = &fValues[fElemCount * index];
188 memcpy(dst, values, fElemCount * sizeof(SkScalar));
189 }
190 return success;
191}
192
193SkInterpolator::Result SkInterpolator::timeToValues(SkMSec time,
194 SkScalar values[]) const {
195 SkScalar T;
196 int index;
197 SkBool exact;
198 Result result = timeToT(time, &T, &index, &exact);
199 if (values) {
200 const SkScalar* nextSrc = &fValues[index * fElemCount];
201
202 if (exact) {
203 memcpy(values, nextSrc, fElemCount * sizeof(SkScalar));
204 } else {
205 SkASSERT(index > 0);
206
207 const SkScalar* prevSrc = nextSrc - fElemCount;
208
209 for (int i = fElemCount - 1; i >= 0; --i) {
210 values[i] = SkScalarInterp(prevSrc[i], nextSrc[i], T);
211 }
212 }
213 }
214 return result;
215}
216
217///////////////////////////////////////////////////////////////////////////////
218
219typedef int Dot14;
220#define Dot14_ONE (1 << 14)
221#define Dot14_HALF (1 << 13)
222
223#define Dot14ToFloat(x) ((x) / 16384.f)
224
225static inline Dot14 Dot14Mul(Dot14 a, Dot14 b) {
226 return (a * b + Dot14_HALF) >> 14;
227}
228
229static inline Dot14 eval_cubic(Dot14 t, Dot14 A, Dot14 B, Dot14 C) {
230 return Dot14Mul(Dot14Mul(Dot14Mul(C, t) + B, t) + A, t);
231}
232
233static inline Dot14 pin_and_convert(SkScalar x) {
234 if (x <= 0) {
235 return 0;
236 }
237 if (x >= SK_Scalar1) {
238 return Dot14_ONE;
239 }
240 return SkScalarToFixed(x) >> 2;
241}
242
243SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by,
244 SkScalar cx, SkScalar cy) {
245 // pin to the unit-square, and convert to 2.14
246 Dot14 x = pin_and_convert(value);
247
248 if (x == 0) return 0;
249 if (x == Dot14_ONE) return SK_Scalar1;
250
251 Dot14 b = pin_and_convert(bx);
252 Dot14 c = pin_and_convert(cx);
253
254 // Now compute our coefficients from the control points
255 // t -> 3b
256 // t^2 -> 3c - 6b
257 // t^3 -> 3b - 3c + 1
258 Dot14 A = 3*b;
259 Dot14 B = 3*(c - 2*b);
260 Dot14 C = 3*(b - c) + Dot14_ONE;
261
262 // Now search for a t value given x
263 Dot14 t = Dot14_HALF;
264 Dot14 dt = Dot14_HALF;
265 for (int i = 0; i < 13; i++) {
266 dt >>= 1;
267 Dot14 guess = eval_cubic(t, A, B, C);
268 if (x < guess) {
269 t -= dt;
270 } else {
271 t += dt;
272 }
273 }
274
275 // Now we have t, so compute the coeff for Y and evaluate
276 b = pin_and_convert(by);
277 c = pin_and_convert(cy);
278 A = 3*b;
279 B = 3*(c - 2*b);
280 C = 3*(b - c) + Dot14_ONE;
281 return SkFixedToScalar(eval_cubic(t, A, B, C) << 2);
282}
283
284///////////////////////////////////////////////////////////////////////////////
285///////////////////////////////////////////////////////////////////////////////
286
287#ifdef SK_DEBUG
288
289#ifdef SK_SUPPORT_UNITTEST
290 static SkScalar* iset(SkScalar array[3], int a, int b, int c) {
291 array[0] = SkIntToScalar(a);
292 array[1] = SkIntToScalar(b);
293 array[2] = SkIntToScalar(c);
294 return array;
295 }
296#endif
297
298void SkInterpolator::UnitTest() {
299#ifdef SK_SUPPORT_UNITTEST
300 SkInterpolator inter(3, 2);
301 SkScalar v1[3], v2[3], v[3], vv[3];
302 Result result;
303
304 inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0);
305 inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330));
306
307 result = inter.timeToValues(0, v);
308 SkASSERT(result == kFreezeStart_Result);
309 SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
310
311 result = inter.timeToValues(99, v);
312 SkASSERT(result == kFreezeStart_Result);
313 SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
314
315 result = inter.timeToValues(100, v);
316 SkASSERT(result == kNormal_Result);
317 SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
318
319 result = inter.timeToValues(200, v);
320 SkASSERT(result == kNormal_Result);
321 SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
322
323 result = inter.timeToValues(201, v);
324 SkASSERT(result == kFreezeEnd_Result);
325 SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
326
327 result = inter.timeToValues(150, v);
328 SkASSERT(result == kNormal_Result);
329 SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0);
330
331 result = inter.timeToValues(125, v);
332 SkASSERT(result == kNormal_Result);
333 result = inter.timeToValues(175, v);
334 SkASSERT(result == kNormal_Result);
335#endif
336}
337
338#endif
339