| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- /**
- Copyright (c) 2014-present, Facebook, Inc.
- All rights reserved.
- This source code is licensed under the BSD-style license found in the
- LICENSE file in the root directory of this source tree. An additional grant
- of patent rights can be found in the PATENTS file in the same directory.
- */
- #import "POPAnimationInternal.h"
- #import "POPPropertyAnimation.h"
- static void clampValue(CGFloat &value, CGFloat fromValue, CGFloat toValue, NSUInteger clamp)
- {
- BOOL increasing = (toValue > fromValue);
- // Clamp start of animation.
- if ((kPOPAnimationClampStart & clamp) &&
- ((increasing && (value < fromValue)) || (!increasing && (value > fromValue)))) {
- value = fromValue;
- }
- // Clamp end of animation.
- if ((kPOPAnimationClampEnd & clamp) &&
- ((increasing && (value > toValue)) || (!increasing && (value < toValue)))) {
- value = toValue;
- }
- }
- struct _POPPropertyAnimationState : _POPAnimationState
- {
- POPAnimatableProperty *property;
- POPValueType valueType;
- NSUInteger valueCount;
- VectorRef fromVec;
- VectorRef toVec;
- VectorRef currentVec;
- VectorRef previousVec;
- VectorRef previous2Vec;
- VectorRef velocityVec;
- VectorRef originalVelocityVec;
- VectorRef distanceVec;
- CGFloat roundingFactor;
- NSUInteger clampMode;
- NSArray *progressMarkers;
- POPProgressMarker *progressMarkerState;
- NSUInteger progressMarkerCount;
- NSUInteger nextProgressMarkerIdx;
- CGFloat dynamicsThreshold;
- _POPPropertyAnimationState(id __unsafe_unretained anim) : _POPAnimationState(anim),
- property(nil),
- valueType((POPValueType)0),
- valueCount(0),
- fromVec(nullptr),
- toVec(nullptr),
- currentVec(nullptr),
- previousVec(nullptr),
- previous2Vec(nullptr),
- velocityVec(nullptr),
- originalVelocityVec(nullptr),
- distanceVec(nullptr),
- roundingFactor(0),
- clampMode(0),
- progressMarkers(nil),
- progressMarkerState(nil),
- progressMarkerCount(0),
- nextProgressMarkerIdx(0),
- dynamicsThreshold(0)
- {
- type = kPOPAnimationBasic;
- }
- ~_POPPropertyAnimationState()
- {
- if (progressMarkerState) {
- free(progressMarkerState);
- progressMarkerState = NULL;
- }
- }
- bool canProgress() {
- return hasValue();
- }
- bool shouldRound() {
- return 0 != roundingFactor;
- }
- bool hasValue() {
- return 0 != valueCount;
- }
- bool isDone() {
- // inherit done
- if (_POPAnimationState::isDone()) {
- return true;
- }
- // consider an animation with no values done
- if (!hasValue() && !isCustom()) {
- return true;
- }
- return false;
- }
- // returns a copy of the currentVec, rounding if needed
- VectorRef currentValue() {
- VectorRef vec = VectorRef(Vector::new_vector(currentVec.get()));
- if (shouldRound()) {
- vec->subRound(1 / roundingFactor);
- }
- return vec;
- }
- void resetProgressMarkerState()
- {
- for (NSUInteger idx = 0; idx < progressMarkerCount; idx++)
- progressMarkerState[idx].reached = false;
- nextProgressMarkerIdx = 0;
- }
- void updatedProgressMarkers()
- {
- if (progressMarkerState) {
- free(progressMarkerState);
- progressMarkerState = NULL;
- }
- progressMarkerCount = progressMarkers.count;
- if (0 != progressMarkerCount) {
- progressMarkerState = (POPProgressMarker *)malloc(progressMarkerCount * sizeof(POPProgressMarker));
- [progressMarkers enumerateObjectsUsingBlock:^(NSNumber *progressMarker, NSUInteger idx, BOOL *stop) {
- progressMarkerState[idx].reached = false;
- progressMarkerState[idx].progress = [progressMarker floatValue];
- }];
- }
- nextProgressMarkerIdx = 0;
- }
- virtual void updatedDynamicsThreshold()
- {
- dynamicsThreshold = property.threshold;
- }
- void finalizeProgress()
- {
- progress = 1.0;
- NSUInteger count = valueCount;
- VectorRef outVec(Vector::new_vector(count, NULL));
- if (outVec && toVec) {
- *outVec = *toVec;
- }
- currentVec = outVec;
- clampCurrentValue();
- delegateProgress();
- }
- void computeProgress() {
- if (!canProgress()) {
- return;
- }
- static ComputeProgressFunctor<Vector4r> func;
- Vector4r v = vector4(currentVec);
- Vector4r f = vector4(fromVec);
- Vector4r t = vector4(toVec);
- progress = func(v, f, t);
- }
- void delegateProgress() {
- if (!canProgress()) {
- return;
- }
- if (delegateDidProgress && progressMarkerState) {
- while (nextProgressMarkerIdx < progressMarkerCount) {
- if (progress < progressMarkerState[nextProgressMarkerIdx].progress)
- break;
- if (!progressMarkerState[nextProgressMarkerIdx].reached) {
- ActionEnabler enabler;
- [delegate pop_animation:self didReachProgress:progressMarkerState[nextProgressMarkerIdx].progress];
- progressMarkerState[nextProgressMarkerIdx].reached = true;
- }
- nextProgressMarkerIdx++;
- }
- }
- if (!didReachToValue) {
- bool didReachToValue = false;
- if (0 == valueCount) {
- didReachToValue = true;
- } else {
- Vector4r distance = toVec->vector4r();
- distance -= currentVec->vector4r();
- if (0 == distance.squaredNorm()) {
- didReachToValue = true;
- } else {
- // components
- if (distanceVec) {
- didReachToValue = true;
- const CGFloat *distanceValues = distanceVec->data();
- for (NSUInteger idx = 0; idx < valueCount; idx++) {
- didReachToValue &= (signbit(distance[idx]) != signbit(distanceValues[idx]));
- }
- }
- }
- }
- if (didReachToValue) {
- handleDidReachToValue();
- }
- }
- }
- void handleDidReachToValue() {
- didReachToValue = true;
- if (delegateDidReachToValue) {
- ActionEnabler enabler;
- [delegate pop_animationDidReachToValue:self];
- }
- POPAnimationDidReachToValueBlock block = animationDidReachToValueBlock;
- if (block != NULL) {
- ActionEnabler enabler;
- block(self);
- }
- if (tracing) {
- [tracer didReachToValue:POPBox(currentValue(), valueType, true)];
- }
- }
- void readObjectValue(VectorRef *ptrVec, id obj)
- {
- // use current object value as from value
- pop_animatable_read_block read = property.readBlock;
- if (NULL != read) {
- Vector4r vec = read_values(read, obj, valueCount);
- *ptrVec = VectorRef(Vector::new_vector(valueCount, vec));
- if (tracing) {
- [tracer readPropertyValue:POPBox(*ptrVec, valueType, true)];
- }
- }
- }
- virtual void willRun(bool started, id obj) {
- // ensure from value initialized
- if (NULL == fromVec) {
- readObjectValue(&fromVec, obj);
- }
- // ensure to value initialized
- if (NULL == toVec) {
- // compute decay to value
- if (kPOPAnimationDecay == type) {
- [self toValue];
- } else {
- // read to value
- readObjectValue(&toVec, obj);
- }
- }
- // handle one time value initialization on start
- if (started) {
- // initialize current vec
- if (!currentVec) {
- currentVec = VectorRef(Vector::new_vector(valueCount, NULL));
- // initialize current value with from value
- // only do this on initial creation to avoid overwriting current value
- // on paused animation continuation
- if (currentVec && fromVec) {
- *currentVec = *fromVec;
- }
- }
- // ensure velocity values
- if (!velocityVec) {
- velocityVec = VectorRef(Vector::new_vector(valueCount, NULL));
- }
- if (!originalVelocityVec) {
- originalVelocityVec = VectorRef(Vector::new_vector(valueCount, NULL));
- }
- }
- // ensure distance value initialized
- // depends on current value set on one time start
- if (NULL == distanceVec) {
- // not yet started animations may not have current value
- VectorRef fromVec2 = NULL != currentVec ? currentVec : fromVec;
- if (fromVec2 && toVec) {
- Vector4r distance = toVec->vector4r();
- distance -= fromVec2->vector4r();
- if (0 != distance.squaredNorm()) {
- distanceVec = VectorRef(Vector::new_vector(valueCount, distance));
- }
- }
- }
- }
- virtual void reset(bool all) {
- _POPAnimationState::reset(all);
- if (all) {
- currentVec = NULL;
- previousVec = NULL;
- previous2Vec = NULL;
- }
- progress = 0;
- resetProgressMarkerState();
- didReachToValue = false;
- distanceVec = NULL;
- }
- void clampCurrentValue(NSUInteger clamp)
- {
- if (kPOPAnimationClampNone == clamp)
- return;
- // Clamp all vector values
- CGFloat *currentValues = currentVec->data();
- const CGFloat *fromValues = fromVec->data();
- const CGFloat *toValues = toVec->data();
- for (NSUInteger idx = 0; idx < valueCount; idx++) {
- clampValue(currentValues[idx], fromValues[idx], toValues[idx], clamp);
- }
- }
- void clampCurrentValue()
- {
- clampCurrentValue(clampMode);
- }
- };
- typedef struct _POPPropertyAnimationState POPPropertyAnimationState;
- @interface POPPropertyAnimation ()
- @end
|