11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
20910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2008 The Android Open Source Project
40910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
70910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */
80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
91cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkInterpolator.h"
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkMath.h"
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTSearch.h"
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkInterpolatorBase::SkInterpolatorBase() {
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fStorage    = NULL;
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fTimes      = NULL;
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(fTimesArray = NULL;)
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkInterpolatorBase::~SkInterpolatorBase() {
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fStorage) {
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        sk_free(fStorage);
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkInterpolatorBase::reset(int elemCount, int frameCount) {
270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fFlags = 0;
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fElemCount = SkToU8(elemCount);
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fFrameCount = SkToS16(frameCount);
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fRepeat = SK_Scalar1;
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fStorage) {
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        sk_free(fStorage);
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fStorage = NULL;
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fTimes = NULL;
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDEBUGCODE(fTimesArray = NULL);
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*  Each value[] run is formated as:
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        <time (in msec)>
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        <blend>
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        <data[fElemCount]>
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Totaling fElemCount+2 entries per keyframe
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const {
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fFrameCount == 0) {
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (startTime) {
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *startTime = fTimes[0].fTime;
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (endTime) {
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *endTime = fTimes[fFrameCount - 1].fTime;
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime,
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                  SkMSec nextTime, const SkScalar blend[4]) {
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(time > prevTime && time < nextTime);
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar t = SkScalarDiv((SkScalar)(time - prevTime),
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                             (SkScalar)(nextTime - prevTime));
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return blend ?
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkUnitCubicInterp(t, blend[0], blend[1], blend[2], blend[3]) : t;
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T,
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                        int* indexPtr, SkBool* exactPtr) const {
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(fFrameCount > 0);
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Result  result = kNormal_Result;
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fRepeat != SK_Scalar1) {
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkMSec startTime = 0, endTime = 0;  // initialize to avoid warning
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        this->getDuration(&startTime, &endTime);
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkMSec totalTime = endTime - startTime;
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkMSec offsetTime = time - startTime;
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        endTime = SkScalarMulFloor(fRepeat, totalTime);
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (offsetTime >= endTime) {
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkScalar fraction = SkScalarFraction(fRepeat);
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            offsetTime = fraction == 0 && fRepeat > 0 ? totalTime :
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkScalarMulFloor(fraction, totalTime);
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            result = kFreezeEnd_Result;
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int mirror = fFlags & kMirror;
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            offsetTime = offsetTime % (totalTime << mirror);
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (offsetTime > totalTime) { // can only be true if fMirror is true
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                offsetTime = (totalTime << 1) - offsetTime;
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        time = offsetTime + startTime;
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time,
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                  sizeof(SkTimeCode));
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool    exact = true;
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (index < 0) {
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        index = ~index;
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (index == 0) {
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            result = kFreezeStart_Result;
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else if (index == fFrameCount) {
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (fFlags & kReset) {
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                index = 0;
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                index -= 1;
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            result = kFreezeEnd_Result;
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            exact = false;
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(index < fFrameCount);
1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkTimeCode* nextTime = &fTimes[index];
1180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMSec   nextT = nextTime[0].fTime;
1190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (exact) {
1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *T = 0;
1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
1220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkMSec prevT = nextTime[-1].fTime;
1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend);
1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *indexPtr = index;
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *exactPtr = exact;
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return result;
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkInterpolator::SkInterpolator() {
1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    INHERITED::reset(0, 0);
1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fValues = NULL;
1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDEBUGCODE(fScalarsArray = NULL;)
1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkInterpolator::SkInterpolator(int elemCount, int frameCount) {
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(elemCount > 0);
1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->reset(elemCount, frameCount);
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkInterpolator::reset(int elemCount, int frameCount) {
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    INHERITED::reset(elemCount, frameCount);
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fStorage = sk_malloc_throw((sizeof(SkScalar) * elemCount +
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                sizeof(SkTimeCode)) * frameCount);
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fTimes = (SkTimeCode*) fStorage;
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fValues = (SkScalar*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount);
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_DEBUG
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fTimesArray = (SkTimeCode(*)[10]) fTimes;
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fScalarsArray = (SkScalar(*)[10]) fValues;
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define SK_Fixed1Third      (SK_Fixed1/3)
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define SK_Fixed2Third      (SK_Fixed1*2/3)
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic const SkScalar gIdentityBlend[4] = {
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_SCALAR_IS_FLOAT
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SK_Fixed1Third, SK_Fixed1Third, SK_Fixed2Third, SK_Fixed2Third
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkInterpolator::setKeyFrame(int index, SkMSec time,
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                            const SkScalar values[], const SkScalar blend[4]) {
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(values != NULL);
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (blend == NULL) {
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        blend = gIdentityBlend;
1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time,
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                               sizeof(SkTimeCode));
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(success);
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (success) {
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkTimeCode* timeCode = &fTimes[index];
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        timeCode->fTime = time;
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        memcpy(timeCode->fBlend, blend, sizeof(timeCode->fBlend));
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar* dst = &fValues[fElemCount * index];
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        memcpy(dst, values, fElemCount * sizeof(SkScalar));
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return success;
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkInterpolator::Result SkInterpolator::timeToValues(SkMSec time,
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                                    SkScalar values[]) const {
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar T;
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int index;
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkBool exact;
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Result result = timeToT(time, &T, &index, &exact);
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (values) {
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const SkScalar* nextSrc = &fValues[index * fElemCount];
1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (exact) {
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            memcpy(values, nextSrc, fElemCount * sizeof(SkScalar));
1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {
1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(index > 0);
1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const SkScalar* prevSrc = nextSrc - fElemCount;
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            for (int i = fElemCount - 1; i >= 0; --i) {
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                values[i] = SkScalarInterp(prevSrc[i], nextSrc[i], T);
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return result;
2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projecttypedef int Dot14;
2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define Dot14_ONE       (1 << 14)
2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define Dot14_HALF      (1 << 13)
2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define Dot14ToFloat(x) ((x) / 16384.f)
2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline Dot14 Dot14Mul(Dot14 a, Dot14 b) {
2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return (a * b + Dot14_HALF) >> 14;
2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline Dot14 eval_cubic(Dot14 t, Dot14 A, Dot14 B, Dot14 C) {
2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return Dot14Mul(Dot14Mul(Dot14Mul(C, t) + B, t) + A, t);
2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline Dot14 pin_and_convert(SkScalar x) {
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (x <= 0) {
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return 0;
2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (x >= SK_Scalar1) {
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return Dot14_ONE;
2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkScalarToFixed(x) >> 2;
2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by,
2370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                           SkScalar cx, SkScalar cy) {
2380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // pin to the unit-square, and convert to 2.14
2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Dot14 x = pin_and_convert(value);
2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (x == 0) return 0;
2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (x == Dot14_ONE) return SK_Scalar1;
2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Dot14 b = pin_and_convert(bx);
2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Dot14 c = pin_and_convert(cx);
2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // Now compute our coefficients from the control points
2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //  t   -> 3b
2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //  t^2 -> 3c - 6b
2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //  t^3 -> 3b - 3c + 1
2510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Dot14 A = 3*b;
2520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Dot14 B = 3*(c - 2*b);
2530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Dot14 C = 3*(b - c) + Dot14_ONE;
2540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // Now search for a t value given x
2560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Dot14   t = Dot14_HALF;
2570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Dot14   dt = Dot14_HALF;
2580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < 13; i++) {
2590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dt >>= 1;
2600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        Dot14 guess = eval_cubic(t, A, B, C);
2610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (x < guess) {
2620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            t -= dt;
2630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {
2640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            t += dt;
2650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // Now we have t, so compute the coeff for Y and evaluate
2690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    b = pin_and_convert(by);
2700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    c = pin_and_convert(cy);
2710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    A = 3*b;
2720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    B = 3*(c - 2*b);
2730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    C = 3*(b - c) + Dot14_ONE;
2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkFixedToScalar(eval_cubic(t, A, B, C) << 2);
2750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
2780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
2790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_DEBUG
2810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_SUPPORT_UNITTEST
2830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static SkScalar* iset(SkScalar array[3], int a, int b, int c) {
2840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        array[0] = SkIntToScalar(a);
2850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        array[1] = SkIntToScalar(b);
2860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        array[2] = SkIntToScalar(c);
2870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return array;
2880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
2900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkInterpolator::UnitTest() {
2920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_SUPPORT_UNITTEST
2930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkInterpolator  inter(3, 2);
2940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar        v1[3], v2[3], v[3], vv[3];
2950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Result          result;
2960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0);
2980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330));
2990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = inter.timeToValues(0, v);
3010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result == kFreezeStart_Result);
3020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
3030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = inter.timeToValues(99, v);
3050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result == kFreezeStart_Result);
3060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
3070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = inter.timeToValues(100, v);
3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result == kNormal_Result);
3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = inter.timeToValues(200, v);
3130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result == kNormal_Result);
3140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
3150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = inter.timeToValues(201, v);
3170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result == kFreezeEnd_Result);
3180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
3190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = inter.timeToValues(150, v);
3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result == kNormal_Result);
3220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0);
3230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = inter.timeToValues(125, v);
3250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result == kNormal_Result);
3260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = inter.timeToValues(175, v);
3270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result == kNormal_Result);
3280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
3290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
3320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
333