1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkOperandInterpolator.h"
9 #include "SkScript.h"
10 
SkOperandInterpolator()11 SkOperandInterpolator::SkOperandInterpolator() {
12     INHERITED::reset(0, 0);
13     fType = SkType_Unknown;
14 }
15 
SkOperandInterpolator(int elemCount,int frameCount,SkDisplayTypes type)16 SkOperandInterpolator::SkOperandInterpolator(int elemCount, int frameCount,
17                                              SkDisplayTypes type)
18 {
19     this->reset(elemCount, frameCount, type);
20 }
21 
reset(int elemCount,int frameCount,SkDisplayTypes type)22 void SkOperandInterpolator::reset(int elemCount, int frameCount, SkDisplayTypes type)
23 {
24 //  SkASSERT(type == SkType_String || type == SkType_Float || type == SkType_Int ||
25 //      type == SkType_Displayable || type == SkType_Drawable);
26     INHERITED::reset(elemCount, frameCount);
27     fType = type;
28     fStorage = sk_malloc_throw((sizeof(SkOperand) * elemCount + sizeof(SkTimeCode)) * frameCount);
29     fTimes = (SkTimeCode*) fStorage;
30     fValues = (SkOperand*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount);
31 #ifdef SK_DEBUG
32     fTimesArray = (SkTimeCode(*)[10]) fTimes;
33     fValuesArray = (SkOperand(*)[10]) fValues;
34 #endif
35 }
36 
setKeyFrame(int index,SkMSec time,const SkOperand values[],SkScalar blend)37 bool SkOperandInterpolator::setKeyFrame(int index, SkMSec time, const SkOperand values[], SkScalar blend)
38 {
39     SkASSERT(values != nullptr);
40     blend = SkScalarPin(blend, 0, SK_Scalar1);
41 
42     bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time, sizeof(SkTimeCode));
43     SkASSERT(success);
44     if (success) {
45         SkTimeCode* timeCode = &fTimes[index];
46         timeCode->fTime = time;
47         timeCode->fBlend[0] = SK_Scalar1 - blend;
48         timeCode->fBlend[1] = 0;
49         timeCode->fBlend[2] = 0;
50         timeCode->fBlend[3] = SK_Scalar1 - blend;
51         SkOperand* dst = &fValues[fElemCount * index];
52         memcpy(dst, values, fElemCount * sizeof(SkOperand));
53     }
54     return success;
55 }
56 
timeToValues(SkMSec time,SkOperand values[]) const57 SkInterpolatorBase::Result SkOperandInterpolator::timeToValues(SkMSec time, SkOperand values[]) const
58 {
59     SkScalar T;
60     int index;
61     bool exact;
62     Result result = timeToT(time, &T, &index, &exact);
63     if (values)
64     {
65         const SkOperand* nextSrc = &fValues[index * fElemCount];
66 
67         if (exact)
68             memcpy(values, nextSrc, fElemCount * sizeof(SkScalar));
69         else
70         {
71             SkASSERT(index > 0);
72 
73             const SkOperand* prevSrc = nextSrc - fElemCount;
74 
75             if (fType == SkType_Float || fType == SkType_3D_Point) {
76                 for (int i = fElemCount - 1; i >= 0; --i)
77                     values[i].fScalar = SkScalarInterp(prevSrc[i].fScalar, nextSrc[i].fScalar, T);
78             } else if (fType == SkType_Int || fType == SkType_MSec) {
79                 for (int i = fElemCount - 1; i >= 0; --i) {
80                     int32_t a = prevSrc[i].fS32;
81                     int32_t b = nextSrc[i].fS32;
82                     values[i].fS32 = a + SkScalarRoundToInt((b - a) * T);
83                 }
84             } else
85                 memcpy(values, prevSrc, sizeof(SkOperand) * fElemCount);
86         }
87     }
88     return result;
89 }
90 
91 ///////////////////////////////////////////////////////////////////////////////////////
92 ///////////////////////////////////////////////////////////////////////////////////////
93 
94 #ifdef SK_DEBUG
95 
96 #ifdef SK_SUPPORT_UNITTEST
iset(SkOperand array[3],int a,int b,int c)97     static SkOperand* iset(SkOperand array[3], int a, int b, int c)
98     {
99         array[0].fScalar = SkIntToScalar(a);
100         array[1].fScalar = SkIntToScalar(b);
101         array[2].fScalar = SkIntToScalar(c);
102         return array;
103     }
104 #endif
105 
UnitTest()106 void SkOperandInterpolator::UnitTest()
107 {
108 #ifdef SK_SUPPORT_UNITTEST
109     SkOperandInterpolator   inter(3, 2, SkType_Float);
110     SkOperand       v1[3], v2[3], v[3], vv[3];
111     Result          result;
112 
113     inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0);
114     inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330));
115 
116     result = inter.timeToValues(0, v);
117     SkASSERT(result == kFreezeStart_Result);
118     SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
119 
120     result = inter.timeToValues(99, v);
121     SkASSERT(result == kFreezeStart_Result);
122     SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
123 
124     result = inter.timeToValues(100, v);
125     SkASSERT(result == kNormal_Result);
126     SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
127 
128     result = inter.timeToValues(200, v);
129     SkASSERT(result == kNormal_Result);
130     SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
131 
132     result = inter.timeToValues(201, v);
133     SkASSERT(result == kFreezeEnd_Result);
134     SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
135 
136     result = inter.timeToValues(150, v);
137     SkASSERT(result == kNormal_Result);
138     SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0);
139 
140     result = inter.timeToValues(125, v);
141     SkASSERT(result == kNormal_Result);
142     result = inter.timeToValues(175, v);
143     SkASSERT(result == kNormal_Result);
144 #endif
145 }
146 
147 #endif
148