UNPKG

babylon-mmd

Version:
187 lines (186 loc) 12.6 kB
import { MmdAnimationBase } from "../../../Loader/Animation/mmdAnimationBase"; import { MmdCameraAnimationTrack, MmdPropertyAnimationTrack } from "../../../Loader/Animation/mmdAnimationTrack"; import { AnimationPoolWrapper } from "./animationPoolWrapper"; import { MmdWasmBoneAnimationTrack, MmdWasmMorphAnimationTrack, MmdWasmMovableBoneAnimationTrack, MmdWasmPropertyAnimationTrack } from "./mmdWasmAnimationTrack"; /** * MmdWasmAnimation is a Mmd animation data container that allocates data in WASM memory * * It is used to pass animation data to WASM * * IMPORTANT: The typed arrays in the track are pointers to wasm memory. * It is important to note that when wasm memory is resized, the typed arrays will no longer be valid. * It is designed to always return a valid typed array at the time of a get, * so as long as you don't copy the typed array references inside this container elsewhere, you are safe. */ export class MmdWasmAnimation extends MmdAnimationBase { /** * Pointer to the animation data in wasm memory */ ptr; /** * @internal */ _poolWrapper; _disposed; _bindedDispose; _disposeObservableObject; /** * Create a MmdWasmAnimation instance * * In general disposeObservable should be `Scene` of Babylon.js * * @param disposeObservable Objects that limit the lifetime of this instance */ constructor(mmdAnimation, wasmInstance, disposeObservable) { const animationPoolWrapper = AnimationPoolWrapper.Get(wasmInstance); animationPoolWrapper.addReference(); const animationPool = animationPoolWrapper.pool; const mmdAnimationBoneTracks = mmdAnimation.boneTracks; const boneTrackLengthsBufferPtr = animationPool.allocateLengthsBuffer(mmdAnimationBoneTracks.length); const boneTrackLengthsBuffer = wasmInstance.createTypedArray(Uint32Array, boneTrackLengthsBufferPtr, mmdAnimationBoneTracks.length).array; for (let i = 0; i < mmdAnimationBoneTracks.length; ++i) boneTrackLengthsBuffer[i] = mmdAnimationBoneTracks[i].frameNumbers.length; const boneTracksPtr = animationPool.createBoneTracks(boneTrackLengthsBufferPtr, boneTrackLengthsBuffer.length); animationPool.deallocateLengthsBuffer(boneTrackLengthsBufferPtr, boneTrackLengthsBuffer.length); const newBoneTracks = new Array(mmdAnimationBoneTracks.length); for (let i = 0; i < mmdAnimationBoneTracks.length; ++i) { const mmdAnimationBoneTrack = mmdAnimationBoneTracks[i]; const frameNumbersPtr = animationPool.getBoneTrackFrameNumbers(boneTracksPtr, i); const rotationsPtr = animationPool.getBoneTrackRotations(boneTracksPtr, i); const rotationInterpolationsPtr = animationPool.getBoneTrackRotationInterpolations(boneTracksPtr, i); const physicsTogglesPtr = animationPool.getBoneTrackPhysicsToggles(boneTracksPtr, i); const newBoneTrack = new MmdWasmBoneAnimationTrack(mmdAnimationBoneTrack.name, mmdAnimationBoneTrack.frameNumbers.length, wasmInstance, frameNumbersPtr, rotationsPtr, rotationInterpolationsPtr, physicsTogglesPtr); newBoneTrack.frameNumbers.set(mmdAnimationBoneTrack.frameNumbers); newBoneTrack.rotations.set(mmdAnimationBoneTrack.rotations); newBoneTrack.rotationInterpolations.set(mmdAnimationBoneTrack.rotationInterpolations); newBoneTrack.physicsToggles.set(mmdAnimationBoneTrack.physicsToggles); newBoneTracks[i] = newBoneTrack; } const mmdAnimationMovableBoneTracks = mmdAnimation.movableBoneTracks; const movableBoneTrackLengthsBufferPtr = animationPool.allocateLengthsBuffer(mmdAnimationMovableBoneTracks.length); const movableBoneTrackLengthsBuffer = wasmInstance.createTypedArray(Uint32Array, movableBoneTrackLengthsBufferPtr, mmdAnimationMovableBoneTracks.length).array; for (let i = 0; i < mmdAnimationMovableBoneTracks.length; ++i) movableBoneTrackLengthsBuffer[i] = mmdAnimationMovableBoneTracks[i].frameNumbers.length; const movableBoneTracksPtr = animationPool.createMovableBoneTracks(movableBoneTrackLengthsBufferPtr, movableBoneTrackLengthsBuffer.length); animationPool.deallocateLengthsBuffer(movableBoneTrackLengthsBufferPtr, movableBoneTrackLengthsBuffer.length); const newMovableBoneTracks = new Array(mmdAnimationMovableBoneTracks.length); for (let i = 0; i < mmdAnimationMovableBoneTracks.length; ++i) { const mmdAnimationMovableBoneTrack = mmdAnimationMovableBoneTracks[i]; const frameNumbersPtr = animationPool.getMovableBoneTrackFrameNumbers(movableBoneTracksPtr, i); const positionsPtr = animationPool.getMovableBoneTrackPositions(movableBoneTracksPtr, i); const positionInterpolationsPtr = animationPool.getMovableBoneTrackPositionInterpolations(movableBoneTracksPtr, i); const rotationsPtr = animationPool.getMovableBoneTrackRotations(movableBoneTracksPtr, i); const rotationInterpolationsPtr = animationPool.getMovableBoneTrackRotationInterpolations(movableBoneTracksPtr, i); const physicsTogglesPtr = animationPool.getMovableBoneTrackPhysicsToggles(movableBoneTracksPtr, i); const newMovableBoneTrack = new MmdWasmMovableBoneAnimationTrack(mmdAnimationMovableBoneTrack.name, mmdAnimationMovableBoneTrack.frameNumbers.length, wasmInstance, frameNumbersPtr, positionsPtr, positionInterpolationsPtr, rotationsPtr, rotationInterpolationsPtr, physicsTogglesPtr); newMovableBoneTrack.frameNumbers.set(mmdAnimationMovableBoneTrack.frameNumbers); newMovableBoneTrack.positions.set(mmdAnimationMovableBoneTrack.positions); newMovableBoneTrack.positionInterpolations.set(mmdAnimationMovableBoneTrack.positionInterpolations); newMovableBoneTrack.rotations.set(mmdAnimationMovableBoneTrack.rotations); newMovableBoneTrack.rotationInterpolations.set(mmdAnimationMovableBoneTrack.rotationInterpolations); newMovableBoneTrack.physicsToggles.set(mmdAnimationMovableBoneTrack.physicsToggles); newMovableBoneTracks[i] = newMovableBoneTrack; } const mmdAnimationMorphTracks = mmdAnimation.morphTracks; const morphTrackLengthsBufferPtr = animationPool.allocateLengthsBuffer(mmdAnimationMorphTracks.length); const morphTrackLengthsBuffer = wasmInstance.createTypedArray(Uint32Array, morphTrackLengthsBufferPtr, mmdAnimationMorphTracks.length).array; for (let i = 0; i < mmdAnimationMorphTracks.length; ++i) morphTrackLengthsBuffer[i] = mmdAnimationMorphTracks[i].frameNumbers.length; const morphTracksPtr = animationPool.createMorphTracks(morphTrackLengthsBufferPtr, morphTrackLengthsBuffer.length); animationPool.deallocateLengthsBuffer(morphTrackLengthsBufferPtr, morphTrackLengthsBuffer.length); const newMorphTracks = new Array(mmdAnimationMorphTracks.length); for (let i = 0; i < mmdAnimationMorphTracks.length; ++i) { const mmdAnimationMorphTrack = mmdAnimationMorphTracks[i]; const frameNumbersPtr = animationPool.getMorphTrackFrameNumbers(morphTracksPtr, i); const weightsPtr = animationPool.getMorphTrackWeights(morphTracksPtr, i); const newMorphTrack = new MmdWasmMorphAnimationTrack(mmdAnimationMorphTrack.name, mmdAnimationMorphTrack.frameNumbers.length, wasmInstance, frameNumbersPtr, weightsPtr); newMorphTrack.frameNumbers.set(mmdAnimationMorphTrack.frameNumbers); newMorphTrack.weights.set(mmdAnimationMorphTrack.weights); newMorphTracks[i] = newMorphTrack; } const mmdAnimationPropertyTrack = mmdAnimation.propertyTrack; const animationPtr = animationPool.createAnimation(boneTracksPtr, newBoneTracks.length, movableBoneTracksPtr, newMovableBoneTracks.length, morphTracksPtr, newMorphTracks.length, mmdAnimationPropertyTrack.frameNumbers.length, mmdAnimationPropertyTrack.ikBoneNames.length); const propertyTrackFrameNumbersPtr = animationPool.getPropertyTrackFrameNumbers(animationPtr); let visibles; if (mmdAnimationPropertyTrack.visibles.buffer.byteLength - mmdAnimationPropertyTrack.visibles.byteLength < mmdAnimationPropertyTrack.visibles.byteLength) { visibles = mmdAnimationPropertyTrack.visibles; } else { visibles = new Uint8Array(mmdAnimationPropertyTrack.visibles.length); visibles.set(mmdAnimationPropertyTrack.visibles); } const ikStateByteOffsets = []; for (let i = 0; i < mmdAnimationPropertyTrack.ikBoneNames.length; ++i) { const ikStatesPtr = animationPool.getPropertyTrackIkStates(animationPtr, i); ikStateByteOffsets.push(ikStatesPtr); } const newPropertyTrack = new MmdWasmPropertyAnimationTrack(mmdAnimationPropertyTrack.frameNumbers.length, mmdAnimationPropertyTrack.ikBoneNames, wasmInstance, propertyTrackFrameNumbersPtr, visibles, ikStateByteOffsets); newPropertyTrack.frameNumbers.set(mmdAnimationPropertyTrack.frameNumbers); for (let i = 0; i < mmdAnimationPropertyTrack.ikBoneNames.length; ++i) { const mmdAnimationPropertyTrackIkStates = mmdAnimationPropertyTrack.getIkState(i); newPropertyTrack.getIkState(i).set(mmdAnimationPropertyTrackIkStates); } const mmdAnimationCameraTrack = mmdAnimation.cameraTrack; const cameraTrackByteLength = mmdAnimationCameraTrack.frameNumbers.byteLength + mmdAnimationCameraTrack.positions.byteLength + mmdAnimationCameraTrack.positionInterpolations.byteLength + mmdAnimationCameraTrack.rotations.byteLength + mmdAnimationCameraTrack.rotationInterpolations.byteLength + mmdAnimationCameraTrack.distances.byteLength + mmdAnimationCameraTrack.distanceInterpolations.byteLength + mmdAnimationCameraTrack.fovs.byteLength + mmdAnimationCameraTrack.fovInterpolations.byteLength; let cameraTrack; if (mmdAnimationCameraTrack.frameNumbers.buffer.byteLength - cameraTrackByteLength < cameraTrackByteLength) { cameraTrack = mmdAnimationCameraTrack; } else { cameraTrack = new MmdCameraAnimationTrack(mmdAnimationCameraTrack.frameNumbers.length); cameraTrack.frameNumbers.set(mmdAnimationCameraTrack.frameNumbers); cameraTrack.positions.set(mmdAnimationCameraTrack.positions); cameraTrack.positionInterpolations.set(mmdAnimationCameraTrack.positionInterpolations); cameraTrack.rotations.set(mmdAnimationCameraTrack.rotations); cameraTrack.rotationInterpolations.set(mmdAnimationCameraTrack.rotationInterpolations); cameraTrack.distances.set(mmdAnimationCameraTrack.distances); cameraTrack.distanceInterpolations.set(mmdAnimationCameraTrack.distanceInterpolations); cameraTrack.fovs.set(mmdAnimationCameraTrack.fovs); cameraTrack.fovInterpolations.set(mmdAnimationCameraTrack.fovInterpolations); } super(mmdAnimation.name, newBoneTracks, newMovableBoneTracks, newMorphTracks, newPropertyTrack, cameraTrack); this.ptr = animationPtr; this._poolWrapper = animationPoolWrapper; this._disposed = false; this._bindedDispose = this.dispose.bind(this); this._disposeObservableObject = disposeObservable; if (this._disposeObservableObject !== null) { this._disposeObservableObject.onDisposeObservable.add(this._bindedDispose); } } /** * Dispose this instance * * all typed arrays in this instance will be invalid after this method is called */ dispose() { if (this._disposed) return; this._disposed = true; this._poolWrapper.pool.destroyAnimation(this.ptr); this._poolWrapper.removeReference(); this._poolWrapper = null; this.boneTracks.length = 0; this.movableBoneTracks.length = 0; this.morphTracks.length = 0; this.propertyTrack = new MmdPropertyAnimationTrack(0, []); this.cameraTrack = new MmdCameraAnimationTrack(0); if (this._disposeObservableObject !== null) { this._disposeObservableObject.onDisposeObservable.removeCallback(this._bindedDispose); } } /** * Whether this instance is disposed */ get isDisposed() { return this._disposed; } }