forked from facebookarchive/pop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPOPSpringAnimationInternal.h
130 lines (104 loc) · 3.37 KB
/
POPSpringAnimationInternal.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
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 "POPAnimationExtras.h"
#import "POPPropertyAnimationInternal.h"
struct _POPSpringAnimationState : _POPPropertyAnimationState
{
SpringSolver4d *solver;
CGFloat springSpeed;
CGFloat springBounciness; // normalized springiness
CGFloat dynamicsTension; // tension
CGFloat dynamicsFriction; // friction
CGFloat dynamicsMass; // mass
_POPSpringAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim),
solver(nullptr),
springSpeed(12.),
springBounciness(4.),
dynamicsTension(0),
dynamicsFriction(0),
dynamicsMass(0)
{
type = kPOPAnimationSpring;
}
bool hasConverged()
{
NSUInteger count = valueCount;
if (shouldRound()) {
return vec_equal(previous2Vec, previousVec) && vec_equal(previousVec, toVec);
} else {
if (!previousVec || !previous2Vec)
return false;
CGFloat t = dynamicsThreshold / 5;
const CGFloat *toValues = toVec->data();
const CGFloat *previousValues = previousVec->data();
const CGFloat *previous2Values = previous2Vec->data();
for (NSUInteger idx = 0; idx < count; idx++) {
if ((fabsf(toValues[idx] - previousValues[idx]) >= t) || (fabsf(previous2Values[idx] - previousValues[idx]) >= t)) {
return false;
}
}
return true;
}
}
bool isDone() {
if (_POPPropertyAnimationState::isDone()) {
return true;
}
return solver->started() && (hasConverged() || solver->hasConverged());
}
void updatedDynamics()
{
if (NULL != solver) {
solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass);
}
}
void updatedDynamicsThreshold()
{
_POPPropertyAnimationState::updatedDynamicsThreshold();
if (NULL != solver) {
solver->setThreshold(dynamicsThreshold);
}
}
void updatedBouncinessAndSpeed() {
[POPSpringAnimation convertBounciness:springBounciness speed:springSpeed toTension:&dynamicsTension friction:&dynamicsFriction mass:&dynamicsMass];
updatedDynamics();
}
bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) {
// advance past not yet initialized animations
if (NULL == currentVec) {
return false;
}
CFTimeInterval localTime = time - startTime;
Vector4d value = vector4d(currentVec);
Vector4d toValue = vector4d(toVec);
Vector4d velocity = vector4d(velocityVec);
SSState4d state;
state.p = toValue - value;
// the solver assumes a spring of size zero
// flip the velocity from user perspective to solver perspective
state.v = velocity * -1;
solver->advance(state, localTime, dt);
value = toValue - state.p;
// flip velocity back to user perspective
velocity = state.v * -1;
*currentVec = value;
if (velocityVec) {
*velocityVec = velocity;
}
clampCurrentValue();
return true;
}
virtual void reset(bool all) {
_POPPropertyAnimationState::reset(all);
if (solver) {
solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass);
solver->reset();
}
}
};
typedef struct _POPSpringAnimationState POPSpringAnimationState;