POPPropertyAnimationInternal.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /**
  2. Copyright (c) 2014-present, Facebook, Inc.
  3. All rights reserved.
  4. This source code is licensed under the BSD-style license found in the
  5. LICENSE file in the root directory of this source tree. An additional grant
  6. of patent rights can be found in the PATENTS file in the same directory.
  7. */
  8. #import "POPAnimationInternal.h"
  9. #import "POPPropertyAnimation.h"
  10. static void clampValue(CGFloat &value, CGFloat fromValue, CGFloat toValue, NSUInteger clamp)
  11. {
  12. BOOL increasing = (toValue > fromValue);
  13. // Clamp start of animation.
  14. if ((kPOPAnimationClampStart & clamp) &&
  15. ((increasing && (value < fromValue)) || (!increasing && (value > fromValue)))) {
  16. value = fromValue;
  17. }
  18. // Clamp end of animation.
  19. if ((kPOPAnimationClampEnd & clamp) &&
  20. ((increasing && (value > toValue)) || (!increasing && (value < toValue)))) {
  21. value = toValue;
  22. }
  23. }
  24. struct _POPPropertyAnimationState : _POPAnimationState
  25. {
  26. POPAnimatableProperty *property;
  27. POPValueType valueType;
  28. NSUInteger valueCount;
  29. VectorRef fromVec;
  30. VectorRef toVec;
  31. VectorRef currentVec;
  32. VectorRef previousVec;
  33. VectorRef previous2Vec;
  34. VectorRef velocityVec;
  35. VectorRef originalVelocityVec;
  36. VectorRef distanceVec;
  37. CGFloat roundingFactor;
  38. NSUInteger clampMode;
  39. NSArray *progressMarkers;
  40. POPProgressMarker *progressMarkerState;
  41. NSUInteger progressMarkerCount;
  42. NSUInteger nextProgressMarkerIdx;
  43. CGFloat dynamicsThreshold;
  44. _POPPropertyAnimationState(id __unsafe_unretained anim) : _POPAnimationState(anim),
  45. property(nil),
  46. valueType((POPValueType)0),
  47. valueCount(0),
  48. fromVec(nullptr),
  49. toVec(nullptr),
  50. currentVec(nullptr),
  51. previousVec(nullptr),
  52. previous2Vec(nullptr),
  53. velocityVec(nullptr),
  54. originalVelocityVec(nullptr),
  55. distanceVec(nullptr),
  56. roundingFactor(0),
  57. clampMode(0),
  58. progressMarkers(nil),
  59. progressMarkerState(nil),
  60. progressMarkerCount(0),
  61. nextProgressMarkerIdx(0),
  62. dynamicsThreshold(0)
  63. {
  64. type = kPOPAnimationBasic;
  65. }
  66. ~_POPPropertyAnimationState()
  67. {
  68. if (progressMarkerState) {
  69. free(progressMarkerState);
  70. progressMarkerState = NULL;
  71. }
  72. }
  73. bool canProgress() {
  74. return hasValue();
  75. }
  76. bool shouldRound() {
  77. return 0 != roundingFactor;
  78. }
  79. bool hasValue() {
  80. return 0 != valueCount;
  81. }
  82. bool isDone() {
  83. // inherit done
  84. if (_POPAnimationState::isDone()) {
  85. return true;
  86. }
  87. // consider an animation with no values done
  88. if (!hasValue() && !isCustom()) {
  89. return true;
  90. }
  91. return false;
  92. }
  93. // returns a copy of the currentVec, rounding if needed
  94. VectorRef currentValue() {
  95. VectorRef vec = VectorRef(Vector::new_vector(currentVec.get()));
  96. if (shouldRound()) {
  97. vec->subRound(1 / roundingFactor);
  98. }
  99. return vec;
  100. }
  101. void resetProgressMarkerState()
  102. {
  103. for (NSUInteger idx = 0; idx < progressMarkerCount; idx++)
  104. progressMarkerState[idx].reached = false;
  105. nextProgressMarkerIdx = 0;
  106. }
  107. void updatedProgressMarkers()
  108. {
  109. if (progressMarkerState) {
  110. free(progressMarkerState);
  111. progressMarkerState = NULL;
  112. }
  113. progressMarkerCount = progressMarkers.count;
  114. if (0 != progressMarkerCount) {
  115. progressMarkerState = (POPProgressMarker *)malloc(progressMarkerCount * sizeof(POPProgressMarker));
  116. [progressMarkers enumerateObjectsUsingBlock:^(NSNumber *progressMarker, NSUInteger idx, BOOL *stop) {
  117. progressMarkerState[idx].reached = false;
  118. progressMarkerState[idx].progress = [progressMarker floatValue];
  119. }];
  120. }
  121. nextProgressMarkerIdx = 0;
  122. }
  123. virtual void updatedDynamicsThreshold()
  124. {
  125. dynamicsThreshold = property.threshold;
  126. }
  127. void finalizeProgress()
  128. {
  129. progress = 1.0;
  130. NSUInteger count = valueCount;
  131. VectorRef outVec(Vector::new_vector(count, NULL));
  132. if (outVec && toVec) {
  133. *outVec = *toVec;
  134. }
  135. currentVec = outVec;
  136. clampCurrentValue();
  137. delegateProgress();
  138. }
  139. void computeProgress() {
  140. if (!canProgress()) {
  141. return;
  142. }
  143. static ComputeProgressFunctor<Vector4r> func;
  144. Vector4r v = vector4(currentVec);
  145. Vector4r f = vector4(fromVec);
  146. Vector4r t = vector4(toVec);
  147. progress = func(v, f, t);
  148. }
  149. void delegateProgress() {
  150. if (!canProgress()) {
  151. return;
  152. }
  153. if (delegateDidProgress && progressMarkerState) {
  154. while (nextProgressMarkerIdx < progressMarkerCount) {
  155. if (progress < progressMarkerState[nextProgressMarkerIdx].progress)
  156. break;
  157. if (!progressMarkerState[nextProgressMarkerIdx].reached) {
  158. ActionEnabler enabler;
  159. [delegate pop_animation:self didReachProgress:progressMarkerState[nextProgressMarkerIdx].progress];
  160. progressMarkerState[nextProgressMarkerIdx].reached = true;
  161. }
  162. nextProgressMarkerIdx++;
  163. }
  164. }
  165. if (!didReachToValue) {
  166. bool didReachToValue = false;
  167. if (0 == valueCount) {
  168. didReachToValue = true;
  169. } else {
  170. Vector4r distance = toVec->vector4r();
  171. distance -= currentVec->vector4r();
  172. if (0 == distance.squaredNorm()) {
  173. didReachToValue = true;
  174. } else {
  175. // components
  176. if (distanceVec) {
  177. didReachToValue = true;
  178. const CGFloat *distanceValues = distanceVec->data();
  179. for (NSUInteger idx = 0; idx < valueCount; idx++) {
  180. didReachToValue &= (signbit(distance[idx]) != signbit(distanceValues[idx]));
  181. }
  182. }
  183. }
  184. }
  185. if (didReachToValue) {
  186. handleDidReachToValue();
  187. }
  188. }
  189. }
  190. void handleDidReachToValue() {
  191. didReachToValue = true;
  192. if (delegateDidReachToValue) {
  193. ActionEnabler enabler;
  194. [delegate pop_animationDidReachToValue:self];
  195. }
  196. POPAnimationDidReachToValueBlock block = animationDidReachToValueBlock;
  197. if (block != NULL) {
  198. ActionEnabler enabler;
  199. block(self);
  200. }
  201. if (tracing) {
  202. [tracer didReachToValue:POPBox(currentValue(), valueType, true)];
  203. }
  204. }
  205. void readObjectValue(VectorRef *ptrVec, id obj)
  206. {
  207. // use current object value as from value
  208. pop_animatable_read_block read = property.readBlock;
  209. if (NULL != read) {
  210. Vector4r vec = read_values(read, obj, valueCount);
  211. *ptrVec = VectorRef(Vector::new_vector(valueCount, vec));
  212. if (tracing) {
  213. [tracer readPropertyValue:POPBox(*ptrVec, valueType, true)];
  214. }
  215. }
  216. }
  217. virtual void willRun(bool started, id obj) {
  218. // ensure from value initialized
  219. if (NULL == fromVec) {
  220. readObjectValue(&fromVec, obj);
  221. }
  222. // ensure to value initialized
  223. if (NULL == toVec) {
  224. // compute decay to value
  225. if (kPOPAnimationDecay == type) {
  226. [self toValue];
  227. } else {
  228. // read to value
  229. readObjectValue(&toVec, obj);
  230. }
  231. }
  232. // handle one time value initialization on start
  233. if (started) {
  234. // initialize current vec
  235. if (!currentVec) {
  236. currentVec = VectorRef(Vector::new_vector(valueCount, NULL));
  237. // initialize current value with from value
  238. // only do this on initial creation to avoid overwriting current value
  239. // on paused animation continuation
  240. if (currentVec && fromVec) {
  241. *currentVec = *fromVec;
  242. }
  243. }
  244. // ensure velocity values
  245. if (!velocityVec) {
  246. velocityVec = VectorRef(Vector::new_vector(valueCount, NULL));
  247. }
  248. if (!originalVelocityVec) {
  249. originalVelocityVec = VectorRef(Vector::new_vector(valueCount, NULL));
  250. }
  251. }
  252. // ensure distance value initialized
  253. // depends on current value set on one time start
  254. if (NULL == distanceVec) {
  255. // not yet started animations may not have current value
  256. VectorRef fromVec2 = NULL != currentVec ? currentVec : fromVec;
  257. if (fromVec2 && toVec) {
  258. Vector4r distance = toVec->vector4r();
  259. distance -= fromVec2->vector4r();
  260. if (0 != distance.squaredNorm()) {
  261. distanceVec = VectorRef(Vector::new_vector(valueCount, distance));
  262. }
  263. }
  264. }
  265. }
  266. virtual void reset(bool all) {
  267. _POPAnimationState::reset(all);
  268. if (all) {
  269. currentVec = NULL;
  270. previousVec = NULL;
  271. previous2Vec = NULL;
  272. }
  273. progress = 0;
  274. resetProgressMarkerState();
  275. didReachToValue = false;
  276. distanceVec = NULL;
  277. }
  278. void clampCurrentValue(NSUInteger clamp)
  279. {
  280. if (kPOPAnimationClampNone == clamp)
  281. return;
  282. // Clamp all vector values
  283. CGFloat *currentValues = currentVec->data();
  284. const CGFloat *fromValues = fromVec->data();
  285. const CGFloat *toValues = toVec->data();
  286. for (NSUInteger idx = 0; idx < valueCount; idx++) {
  287. clampValue(currentValues[idx], fromValues[idx], toValues[idx], clamp);
  288. }
  289. }
  290. void clampCurrentValue()
  291. {
  292. clampCurrentValue(clampMode);
  293. }
  294. };
  295. typedef struct _POPPropertyAnimationState POPPropertyAnimationState;
  296. @interface POPPropertyAnimation ()
  297. @end