SkInterpolator.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Copyright 2008 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. #include "include/utils/SkInterpolator.h"
  8. #include "include/core/SkMath.h"
  9. #include "include/private/SkFixed.h"
  10. #include "include/private/SkMalloc.h"
  11. #include "include/private/SkTo.h"
  12. #include "src/core/SkTSearch.h"
  13. SkInterpolatorBase::SkInterpolatorBase() {
  14. fStorage = nullptr;
  15. fTimes = nullptr;
  16. SkDEBUGCODE(fTimesArray = nullptr;)
  17. }
  18. SkInterpolatorBase::~SkInterpolatorBase() {
  19. if (fStorage) {
  20. sk_free(fStorage);
  21. }
  22. }
  23. void SkInterpolatorBase::reset(int elemCount, int frameCount) {
  24. fFlags = 0;
  25. fElemCount = SkToU8(elemCount);
  26. fFrameCount = SkToS16(frameCount);
  27. fRepeat = SK_Scalar1;
  28. if (fStorage) {
  29. sk_free(fStorage);
  30. fStorage = nullptr;
  31. fTimes = nullptr;
  32. SkDEBUGCODE(fTimesArray = nullptr);
  33. }
  34. }
  35. /* Each value[] run is formated as:
  36. <time (in msec)>
  37. <blend>
  38. <data[fElemCount]>
  39. Totaling fElemCount+2 entries per keyframe
  40. */
  41. bool SkInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const {
  42. if (fFrameCount == 0) {
  43. return false;
  44. }
  45. if (startTime) {
  46. *startTime = fTimes[0].fTime;
  47. }
  48. if (endTime) {
  49. *endTime = fTimes[fFrameCount - 1].fTime;
  50. }
  51. return true;
  52. }
  53. SkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime,
  54. SkMSec nextTime, const SkScalar blend[4]) {
  55. SkASSERT(time > prevTime && time < nextTime);
  56. SkScalar t = (SkScalar)(time - prevTime) / (SkScalar)(nextTime - prevTime);
  57. return blend ?
  58. SkUnitCubicInterp(t, blend[0], blend[1], blend[2], blend[3]) : t;
  59. }
  60. SkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T,
  61. int* indexPtr, bool* exactPtr) const {
  62. SkASSERT(fFrameCount > 0);
  63. Result result = kNormal_Result;
  64. if (fRepeat != SK_Scalar1) {
  65. SkMSec startTime = 0, endTime = 0; // initialize to avoid warning
  66. this->getDuration(&startTime, &endTime);
  67. SkMSec totalTime = endTime - startTime;
  68. SkMSec offsetTime = time - startTime;
  69. endTime = SkScalarFloorToInt(fRepeat * totalTime);
  70. if (offsetTime >= endTime) {
  71. SkScalar fraction = SkScalarFraction(fRepeat);
  72. offsetTime = fraction == 0 && fRepeat > 0 ? totalTime :
  73. (SkMSec) SkScalarFloorToInt(fraction * totalTime);
  74. result = kFreezeEnd_Result;
  75. } else {
  76. int mirror = fFlags & kMirror;
  77. offsetTime = offsetTime % (totalTime << mirror);
  78. if (offsetTime > totalTime) { // can only be true if fMirror is true
  79. offsetTime = (totalTime << 1) - offsetTime;
  80. }
  81. }
  82. time = offsetTime + startTime;
  83. }
  84. int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time,
  85. sizeof(SkTimeCode));
  86. bool exact = true;
  87. if (index < 0) {
  88. index = ~index;
  89. if (index == 0) {
  90. result = kFreezeStart_Result;
  91. } else if (index == fFrameCount) {
  92. if (fFlags & kReset) {
  93. index = 0;
  94. } else {
  95. index -= 1;
  96. }
  97. result = kFreezeEnd_Result;
  98. } else {
  99. exact = false;
  100. }
  101. }
  102. SkASSERT(index < fFrameCount);
  103. const SkTimeCode* nextTime = &fTimes[index];
  104. SkMSec nextT = nextTime[0].fTime;
  105. if (exact) {
  106. *T = 0;
  107. } else {
  108. SkMSec prevT = nextTime[-1].fTime;
  109. *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend);
  110. }
  111. *indexPtr = index;
  112. *exactPtr = exact;
  113. return result;
  114. }
  115. SkInterpolator::SkInterpolator() {
  116. INHERITED::reset(0, 0);
  117. fValues = nullptr;
  118. SkDEBUGCODE(fScalarsArray = nullptr;)
  119. }
  120. SkInterpolator::SkInterpolator(int elemCount, int frameCount) {
  121. SkASSERT(elemCount > 0);
  122. this->reset(elemCount, frameCount);
  123. }
  124. void SkInterpolator::reset(int elemCount, int frameCount) {
  125. INHERITED::reset(elemCount, frameCount);
  126. fStorage = sk_malloc_throw((sizeof(SkScalar) * elemCount +
  127. sizeof(SkTimeCode)) * frameCount);
  128. fTimes = (SkTimeCode*) fStorage;
  129. fValues = (SkScalar*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount);
  130. #ifdef SK_DEBUG
  131. fTimesArray = (SkTimeCode(*)[10]) fTimes;
  132. fScalarsArray = (SkScalar(*)[10]) fValues;
  133. #endif
  134. }
  135. #define SK_Fixed1Third (SK_Fixed1/3)
  136. #define SK_Fixed2Third (SK_Fixed1*2/3)
  137. static const SkScalar gIdentityBlend[4] = {
  138. 0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f
  139. };
  140. bool SkInterpolator::setKeyFrame(int index, SkMSec time,
  141. const SkScalar values[], const SkScalar blend[4]) {
  142. SkASSERT(values != nullptr);
  143. if (blend == nullptr) {
  144. blend = gIdentityBlend;
  145. }
  146. bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time,
  147. sizeof(SkTimeCode));
  148. SkASSERT(success);
  149. if (success) {
  150. SkTimeCode* timeCode = &fTimes[index];
  151. timeCode->fTime = time;
  152. memcpy(timeCode->fBlend, blend, sizeof(timeCode->fBlend));
  153. SkScalar* dst = &fValues[fElemCount * index];
  154. memcpy(dst, values, fElemCount * sizeof(SkScalar));
  155. }
  156. return success;
  157. }
  158. SkInterpolator::Result SkInterpolator::timeToValues(SkMSec time,
  159. SkScalar values[]) const {
  160. SkScalar T;
  161. int index;
  162. bool exact;
  163. Result result = timeToT(time, &T, &index, &exact);
  164. if (values) {
  165. const SkScalar* nextSrc = &fValues[index * fElemCount];
  166. if (exact) {
  167. memcpy(values, nextSrc, fElemCount * sizeof(SkScalar));
  168. } else {
  169. SkASSERT(index > 0);
  170. const SkScalar* prevSrc = nextSrc - fElemCount;
  171. for (int i = fElemCount - 1; i >= 0; --i) {
  172. values[i] = SkScalarInterp(prevSrc[i], nextSrc[i], T);
  173. }
  174. }
  175. }
  176. return result;
  177. }
  178. ///////////////////////////////////////////////////////////////////////////////
  179. typedef int Dot14;
  180. #define Dot14_ONE (1 << 14)
  181. #define Dot14_HALF (1 << 13)
  182. #define Dot14ToFloat(x) ((x) / 16384.f)
  183. static inline Dot14 Dot14Mul(Dot14 a, Dot14 b) {
  184. return (a * b + Dot14_HALF) >> 14;
  185. }
  186. static inline Dot14 eval_cubic(Dot14 t, Dot14 A, Dot14 B, Dot14 C) {
  187. return Dot14Mul(Dot14Mul(Dot14Mul(C, t) + B, t) + A, t);
  188. }
  189. static inline Dot14 pin_and_convert(SkScalar x) {
  190. if (x <= 0) {
  191. return 0;
  192. }
  193. if (x >= SK_Scalar1) {
  194. return Dot14_ONE;
  195. }
  196. return SkScalarToFixed(x) >> 2;
  197. }
  198. SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by,
  199. SkScalar cx, SkScalar cy) {
  200. // pin to the unit-square, and convert to 2.14
  201. Dot14 x = pin_and_convert(value);
  202. if (x == 0) return 0;
  203. if (x == Dot14_ONE) return SK_Scalar1;
  204. Dot14 b = pin_and_convert(bx);
  205. Dot14 c = pin_and_convert(cx);
  206. // Now compute our coefficients from the control points
  207. // t -> 3b
  208. // t^2 -> 3c - 6b
  209. // t^3 -> 3b - 3c + 1
  210. Dot14 A = 3*b;
  211. Dot14 B = 3*(c - 2*b);
  212. Dot14 C = 3*(b - c) + Dot14_ONE;
  213. // Now search for a t value given x
  214. Dot14 t = Dot14_HALF;
  215. Dot14 dt = Dot14_HALF;
  216. for (int i = 0; i < 13; i++) {
  217. dt >>= 1;
  218. Dot14 guess = eval_cubic(t, A, B, C);
  219. if (x < guess) {
  220. t -= dt;
  221. } else {
  222. t += dt;
  223. }
  224. }
  225. // Now we have t, so compute the coeff for Y and evaluate
  226. b = pin_and_convert(by);
  227. c = pin_and_convert(cy);
  228. A = 3*b;
  229. B = 3*(c - 2*b);
  230. C = 3*(b - c) + Dot14_ONE;
  231. return SkFixedToScalar(eval_cubic(t, A, B, C) << 2);
  232. }