gfx/skia/trunk/src/utils/SkInterpolator.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/utils/SkInterpolator.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,327 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2008 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "SkInterpolator.h"
    1.14 +#include "SkMath.h"
    1.15 +#include "SkTSearch.h"
    1.16 +
    1.17 +SkInterpolatorBase::SkInterpolatorBase() {
    1.18 +    fStorage    = NULL;
    1.19 +    fTimes      = NULL;
    1.20 +    SkDEBUGCODE(fTimesArray = NULL;)
    1.21 +}
    1.22 +
    1.23 +SkInterpolatorBase::~SkInterpolatorBase() {
    1.24 +    if (fStorage) {
    1.25 +        sk_free(fStorage);
    1.26 +    }
    1.27 +}
    1.28 +
    1.29 +void SkInterpolatorBase::reset(int elemCount, int frameCount) {
    1.30 +    fFlags = 0;
    1.31 +    fElemCount = SkToU8(elemCount);
    1.32 +    fFrameCount = SkToS16(frameCount);
    1.33 +    fRepeat = SK_Scalar1;
    1.34 +    if (fStorage) {
    1.35 +        sk_free(fStorage);
    1.36 +        fStorage = NULL;
    1.37 +        fTimes = NULL;
    1.38 +        SkDEBUGCODE(fTimesArray = NULL);
    1.39 +    }
    1.40 +}
    1.41 +
    1.42 +/*  Each value[] run is formated as:
    1.43 +        <time (in msec)>
    1.44 +        <blend>
    1.45 +        <data[fElemCount]>
    1.46 +
    1.47 +    Totaling fElemCount+2 entries per keyframe
    1.48 +*/
    1.49 +
    1.50 +bool SkInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const {
    1.51 +    if (fFrameCount == 0) {
    1.52 +        return false;
    1.53 +    }
    1.54 +
    1.55 +    if (startTime) {
    1.56 +        *startTime = fTimes[0].fTime;
    1.57 +    }
    1.58 +    if (endTime) {
    1.59 +        *endTime = fTimes[fFrameCount - 1].fTime;
    1.60 +    }
    1.61 +    return true;
    1.62 +}
    1.63 +
    1.64 +SkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime,
    1.65 +                                  SkMSec nextTime, const SkScalar blend[4]) {
    1.66 +    SkASSERT(time > prevTime && time < nextTime);
    1.67 +
    1.68 +    SkScalar t = SkScalarDiv((SkScalar)(time - prevTime),
    1.69 +                             (SkScalar)(nextTime - prevTime));
    1.70 +    return blend ?
    1.71 +            SkUnitCubicInterp(t, blend[0], blend[1], blend[2], blend[3]) : t;
    1.72 +}
    1.73 +
    1.74 +SkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T,
    1.75 +                                        int* indexPtr, SkBool* exactPtr) const {
    1.76 +    SkASSERT(fFrameCount > 0);
    1.77 +    Result  result = kNormal_Result;
    1.78 +    if (fRepeat != SK_Scalar1) {
    1.79 +        SkMSec startTime = 0, endTime = 0;  // initialize to avoid warning
    1.80 +        this->getDuration(&startTime, &endTime);
    1.81 +        SkMSec totalTime = endTime - startTime;
    1.82 +        SkMSec offsetTime = time - startTime;
    1.83 +        endTime = SkScalarFloorToInt(fRepeat * totalTime);
    1.84 +        if (offsetTime >= endTime) {
    1.85 +            SkScalar fraction = SkScalarFraction(fRepeat);
    1.86 +            offsetTime = fraction == 0 && fRepeat > 0 ? totalTime :
    1.87 +                (SkMSec) SkScalarFloorToInt(fraction * totalTime);
    1.88 +            result = kFreezeEnd_Result;
    1.89 +        } else {
    1.90 +            int mirror = fFlags & kMirror;
    1.91 +            offsetTime = offsetTime % (totalTime << mirror);
    1.92 +            if (offsetTime > totalTime) { // can only be true if fMirror is true
    1.93 +                offsetTime = (totalTime << 1) - offsetTime;
    1.94 +            }
    1.95 +        }
    1.96 +        time = offsetTime + startTime;
    1.97 +    }
    1.98 +
    1.99 +    int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time,
   1.100 +                                  sizeof(SkTimeCode));
   1.101 +
   1.102 +    bool    exact = true;
   1.103 +
   1.104 +    if (index < 0) {
   1.105 +        index = ~index;
   1.106 +        if (index == 0) {
   1.107 +            result = kFreezeStart_Result;
   1.108 +        } else if (index == fFrameCount) {
   1.109 +            if (fFlags & kReset) {
   1.110 +                index = 0;
   1.111 +            } else {
   1.112 +                index -= 1;
   1.113 +            }
   1.114 +            result = kFreezeEnd_Result;
   1.115 +        } else {
   1.116 +            exact = false;
   1.117 +        }
   1.118 +    }
   1.119 +    SkASSERT(index < fFrameCount);
   1.120 +    const SkTimeCode* nextTime = &fTimes[index];
   1.121 +    SkMSec   nextT = nextTime[0].fTime;
   1.122 +    if (exact) {
   1.123 +        *T = 0;
   1.124 +    } else {
   1.125 +        SkMSec prevT = nextTime[-1].fTime;
   1.126 +        *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend);
   1.127 +    }
   1.128 +    *indexPtr = index;
   1.129 +    *exactPtr = exact;
   1.130 +    return result;
   1.131 +}
   1.132 +
   1.133 +
   1.134 +SkInterpolator::SkInterpolator() {
   1.135 +    INHERITED::reset(0, 0);
   1.136 +    fValues = NULL;
   1.137 +    SkDEBUGCODE(fScalarsArray = NULL;)
   1.138 +}
   1.139 +
   1.140 +SkInterpolator::SkInterpolator(int elemCount, int frameCount) {
   1.141 +    SkASSERT(elemCount > 0);
   1.142 +    this->reset(elemCount, frameCount);
   1.143 +}
   1.144 +
   1.145 +void SkInterpolator::reset(int elemCount, int frameCount) {
   1.146 +    INHERITED::reset(elemCount, frameCount);
   1.147 +    fStorage = sk_malloc_throw((sizeof(SkScalar) * elemCount +
   1.148 +                                sizeof(SkTimeCode)) * frameCount);
   1.149 +    fTimes = (SkTimeCode*) fStorage;
   1.150 +    fValues = (SkScalar*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount);
   1.151 +#ifdef SK_DEBUG
   1.152 +    fTimesArray = (SkTimeCode(*)[10]) fTimes;
   1.153 +    fScalarsArray = (SkScalar(*)[10]) fValues;
   1.154 +#endif
   1.155 +}
   1.156 +
   1.157 +#define SK_Fixed1Third      (SK_Fixed1/3)
   1.158 +#define SK_Fixed2Third      (SK_Fixed1*2/3)
   1.159 +
   1.160 +static const SkScalar gIdentityBlend[4] = {
   1.161 +    0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f
   1.162 +};
   1.163 +
   1.164 +bool SkInterpolator::setKeyFrame(int index, SkMSec time,
   1.165 +                            const SkScalar values[], const SkScalar blend[4]) {
   1.166 +    SkASSERT(values != NULL);
   1.167 +
   1.168 +    if (blend == NULL) {
   1.169 +        blend = gIdentityBlend;
   1.170 +    }
   1.171 +
   1.172 +    bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time,
   1.173 +                                               sizeof(SkTimeCode));
   1.174 +    SkASSERT(success);
   1.175 +    if (success) {
   1.176 +        SkTimeCode* timeCode = &fTimes[index];
   1.177 +        timeCode->fTime = time;
   1.178 +        memcpy(timeCode->fBlend, blend, sizeof(timeCode->fBlend));
   1.179 +        SkScalar* dst = &fValues[fElemCount * index];
   1.180 +        memcpy(dst, values, fElemCount * sizeof(SkScalar));
   1.181 +    }
   1.182 +    return success;
   1.183 +}
   1.184 +
   1.185 +SkInterpolator::Result SkInterpolator::timeToValues(SkMSec time,
   1.186 +                                                    SkScalar values[]) const {
   1.187 +    SkScalar T;
   1.188 +    int index;
   1.189 +    SkBool exact;
   1.190 +    Result result = timeToT(time, &T, &index, &exact);
   1.191 +    if (values) {
   1.192 +        const SkScalar* nextSrc = &fValues[index * fElemCount];
   1.193 +
   1.194 +        if (exact) {
   1.195 +            memcpy(values, nextSrc, fElemCount * sizeof(SkScalar));
   1.196 +        } else {
   1.197 +            SkASSERT(index > 0);
   1.198 +
   1.199 +            const SkScalar* prevSrc = nextSrc - fElemCount;
   1.200 +
   1.201 +            for (int i = fElemCount - 1; i >= 0; --i) {
   1.202 +                values[i] = SkScalarInterp(prevSrc[i], nextSrc[i], T);
   1.203 +            }
   1.204 +        }
   1.205 +    }
   1.206 +    return result;
   1.207 +}
   1.208 +
   1.209 +///////////////////////////////////////////////////////////////////////////////
   1.210 +
   1.211 +typedef int Dot14;
   1.212 +#define Dot14_ONE       (1 << 14)
   1.213 +#define Dot14_HALF      (1 << 13)
   1.214 +
   1.215 +#define Dot14ToFloat(x) ((x) / 16384.f)
   1.216 +
   1.217 +static inline Dot14 Dot14Mul(Dot14 a, Dot14 b) {
   1.218 +    return (a * b + Dot14_HALF) >> 14;
   1.219 +}
   1.220 +
   1.221 +static inline Dot14 eval_cubic(Dot14 t, Dot14 A, Dot14 B, Dot14 C) {
   1.222 +    return Dot14Mul(Dot14Mul(Dot14Mul(C, t) + B, t) + A, t);
   1.223 +}
   1.224 +
   1.225 +static inline Dot14 pin_and_convert(SkScalar x) {
   1.226 +    if (x <= 0) {
   1.227 +        return 0;
   1.228 +    }
   1.229 +    if (x >= SK_Scalar1) {
   1.230 +        return Dot14_ONE;
   1.231 +    }
   1.232 +    return SkScalarToFixed(x) >> 2;
   1.233 +}
   1.234 +
   1.235 +SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by,
   1.236 +                           SkScalar cx, SkScalar cy) {
   1.237 +    // pin to the unit-square, and convert to 2.14
   1.238 +    Dot14 x = pin_and_convert(value);
   1.239 +
   1.240 +    if (x == 0) return 0;
   1.241 +    if (x == Dot14_ONE) return SK_Scalar1;
   1.242 +
   1.243 +    Dot14 b = pin_and_convert(bx);
   1.244 +    Dot14 c = pin_and_convert(cx);
   1.245 +
   1.246 +    // Now compute our coefficients from the control points
   1.247 +    //  t   -> 3b
   1.248 +    //  t^2 -> 3c - 6b
   1.249 +    //  t^3 -> 3b - 3c + 1
   1.250 +    Dot14 A = 3*b;
   1.251 +    Dot14 B = 3*(c - 2*b);
   1.252 +    Dot14 C = 3*(b - c) + Dot14_ONE;
   1.253 +
   1.254 +    // Now search for a t value given x
   1.255 +    Dot14   t = Dot14_HALF;
   1.256 +    Dot14   dt = Dot14_HALF;
   1.257 +    for (int i = 0; i < 13; i++) {
   1.258 +        dt >>= 1;
   1.259 +        Dot14 guess = eval_cubic(t, A, B, C);
   1.260 +        if (x < guess) {
   1.261 +            t -= dt;
   1.262 +        } else {
   1.263 +            t += dt;
   1.264 +        }
   1.265 +    }
   1.266 +
   1.267 +    // Now we have t, so compute the coeff for Y and evaluate
   1.268 +    b = pin_and_convert(by);
   1.269 +    c = pin_and_convert(cy);
   1.270 +    A = 3*b;
   1.271 +    B = 3*(c - 2*b);
   1.272 +    C = 3*(b - c) + Dot14_ONE;
   1.273 +    return SkFixedToScalar(eval_cubic(t, A, B, C) << 2);
   1.274 +}
   1.275 +
   1.276 +///////////////////////////////////////////////////////////////////////////////
   1.277 +///////////////////////////////////////////////////////////////////////////////
   1.278 +
   1.279 +#ifdef SK_DEBUG
   1.280 +
   1.281 +#ifdef SK_SUPPORT_UNITTEST
   1.282 +    static SkScalar* iset(SkScalar array[3], int a, int b, int c) {
   1.283 +        array[0] = SkIntToScalar(a);
   1.284 +        array[1] = SkIntToScalar(b);
   1.285 +        array[2] = SkIntToScalar(c);
   1.286 +        return array;
   1.287 +    }
   1.288 +#endif
   1.289 +
   1.290 +void SkInterpolator::UnitTest() {
   1.291 +#ifdef SK_SUPPORT_UNITTEST
   1.292 +    SkInterpolator  inter(3, 2);
   1.293 +    SkScalar        v1[3], v2[3], v[3], vv[3];
   1.294 +    Result          result;
   1.295 +
   1.296 +    inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0);
   1.297 +    inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330));
   1.298 +
   1.299 +    result = inter.timeToValues(0, v);
   1.300 +    SkASSERT(result == kFreezeStart_Result);
   1.301 +    SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
   1.302 +
   1.303 +    result = inter.timeToValues(99, v);
   1.304 +    SkASSERT(result == kFreezeStart_Result);
   1.305 +    SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
   1.306 +
   1.307 +    result = inter.timeToValues(100, v);
   1.308 +    SkASSERT(result == kNormal_Result);
   1.309 +    SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
   1.310 +
   1.311 +    result = inter.timeToValues(200, v);
   1.312 +    SkASSERT(result == kNormal_Result);
   1.313 +    SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
   1.314 +
   1.315 +    result = inter.timeToValues(201, v);
   1.316 +    SkASSERT(result == kFreezeEnd_Result);
   1.317 +    SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
   1.318 +
   1.319 +    result = inter.timeToValues(150, v);
   1.320 +    SkASSERT(result == kNormal_Result);
   1.321 +    SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0);
   1.322 +
   1.323 +    result = inter.timeToValues(125, v);
   1.324 +    SkASSERT(result == kNormal_Result);
   1.325 +    result = inter.timeToValues(175, v);
   1.326 +    SkASSERT(result == kNormal_Result);
   1.327 +#endif
   1.328 +}
   1.329 +
   1.330 +#endif

mercurial