-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathanim.ts
75 lines (68 loc) · 1.98 KB
/
anim.ts
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
type Anim = (now: number) => Booleanish;
type Easing = (p: number) => number;
const EASE_LINEAR = 0;
const EASE_IN_QUAD = 1;
const EASE_OUT_QUAD = 2;
const EASE_IN_OUT_QUAD = 3;
type EasingId =
| typeof EASE_LINEAR
| typeof EASE_IN_QUAD
| typeof EASE_OUT_QUAD
| typeof EASE_IN_OUT_QUAD
;
const EASINGS: Easing[] = [
p => p,
p => p * p,
p => p*(2-p),
p => p<.5 ? 2*p*p : -1+(4-2*p)*p
];
const animDeltaRotation = (from: Vector3, to: Vector3) => {
const fromNormal = vector3TransformMatrix4(matrix4RotateInOrder(...from), 1, 0, 0);
const toNormal = vector3TransformMatrix4(matrix4RotateInOrder(...to), 1, 0, 0);
const cosDiffNormal = vectorNDotProduct(fromNormal, toNormal);
return Math.acos(cosDiffNormal);
}
const animLerp = <T, F extends keyof T>(
start: number,
on: T,
field: F,
to: Vector3,
duration: number,
easing: Easing,
wrapAngles?: Booleanish,
onComplete?: (() => void) | Falsey,
///logPrefix?: string,
) => {
// TODO is there a way to specify that the field has to be a Vector3?
const from: Vector3 = on[field] as any;
return (now: number): Booleanish => {
const delta = now - start;
const proportion = duration ? Math.min(delta / duration, 1) : 1;
const progress = easing(proportion);
on[field] = from.map((v, i) => {
const diff = wrapAngles ? mathAngleDiff(v, to[i]) : to[i] - v;
const result = from[i] + diff * progress;
return result;
}) as any;
if (proportion | 0) {
onComplete && onComplete();
return 1;
}
}
};
const animComposite = (...anims: ((start: number) => Anim)[]): Anim => {
let currentAnim: Anim | Falsey = 0;
if (FLAG_CHECK_FOR_EMPTY_ANIMATIONS && !anims.length) {
throw new Error();
}
return (now: number): Booleanish => {
if (!currentAnim) {
// TODO how can anims be empty here?
currentAnim = anims.shift()?.(now);
}
if (!currentAnim || currentAnim(now)) {
currentAnim = 0;
return !anims.length;
}
}
};