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