Skip to content

Commit

Permalink
fix: adjust animations API
Browse files Browse the repository at this point in the history
  • Loading branch information
nartc committed Mar 8, 2023
1 parent 1d9e4f5 commit ec34683
Showing 1 changed file with 49 additions and 44 deletions.
93 changes: 49 additions & 44 deletions libs/angular-three-soba/misc/src/lib/animations/animations.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,73 @@
import { injectBeforeRender, injectNgtDestroy, injectNgtRef, is, NgtInjectedRef } from 'angular-three';
import { isObservable, Observable, Subscription } from 'rxjs';
import { AnimationMixer } from 'three';

type Api<T extends THREE.AnimationClip> = {
(clips: T[], object?: THREE.Object3D | NgtInjectedRef<THREE.Object3D>): void;
ref: NgtInjectedRef<THREE.Object3D>;
clips: THREE.AnimationClip[];
mixer: THREE.AnimationMixer;
names: T['name'][];
actions: { [key in T['name']]: THREE.AnimationAction | null };
};

export function injectNgtsAnimations<T extends THREE.AnimationClip>(
clips: T[],
object?: Observable<THREE.Object3D> | THREE.Object3D | NgtInjectedRef<THREE.Object3D>
): Api<T> {
export function injectNgtsAnimations<T extends THREE.AnimationClip>() {
let ref = injectNgtRef<THREE.Object3D>();

let sub: Subscription;
const mixer = new AnimationMixer(null!);
const cleanUps = [] as (() => void)[];

if (object) {
if (isObservable(object)) {
sub = object.subscribe((val) => {
ref.nativeElement = val;
});
} else if (is.ref(object)) {
ref = object;
} else {
ref.nativeElement = object;
}
}
injectNgtDestroy(() => {
cleanUps.forEach((cleanUp) => cleanUp());
});

const mixer = new AnimationMixer(ref.nativeElement);
injectBeforeRender(({ delta }) => mixer.update(delta));

const api = <T extends THREE.AnimationClip>(
clips: T[],
object?: THREE.Object3D | NgtInjectedRef<THREE.Object3D>
) => {
let cached = {} as { [key in T['name']]: THREE.AnimationAction | null };
const actions = {} as { [key in T['name']]: THREE.AnimationAction | null };
const names = [] as T['name'][];

if (object) {
if (is.ref(object)) {
ref = object;
} else {
ref.nativeElement = object;
}
}

let cached = {} as { [key in T['name']]: THREE.AnimationAction | null };
const actions = {} as { [key in T['name']]: THREE.AnimationAction | null };
const names = [] as T['name'][];
for (const clip of clips) {
names.push(clip.name);
Object.defineProperty(actions, clip.name, {
enumerable: true,
get: () => {
if (ref.nativeElement) {
const name = clip.name as keyof typeof cached;
return cached[name] || (cached[name] = mixer.clipAction(clip, ref.nativeElement));
}
},
});
}

for (const clip of clips) {
names.push(clip.name);
Object.defineProperty(actions, clip.name, {
enumerable: true,
get: () => {
cleanUps.push(() => {
cached = {} as { [key in T['name']]: THREE.AnimationAction | null };
Object.values(actions).forEach((action) => {
if (ref.nativeElement) {
const name = clip.name as keyof typeof cached;
return cached[name] || (cached[name] = mixer.clipAction(clip, ref.nativeElement));
mixer.uncacheAction(action as THREE.AnimationClip, ref.nativeElement);
}
},
});
mixer.stopAllAction();
});
}

const api = { ref, clips, actions, names, mixer };
(api as Api<T>).clips = clips;
(api as Api<T>).actions = actions;
(api as Api<T>).names = names;
};

injectNgtDestroy(() => {
if (sub) sub.unsubscribe();
cached = {} as { [key in T['name']]: THREE.AnimationAction | null };
Object.values(api.actions).forEach((action) => {
if (ref.nativeElement) {
mixer.uncacheAction(action as THREE.AnimationClip, ref.nativeElement);
}
});
mixer.stopAllAction();
});

injectBeforeRender(({ delta }) => mixer.update(delta));
api.ref = ref;
api.mixer = mixer;

return api;
return api as Api<T>;
}

0 comments on commit ec34683

Please sign in to comment.