From 1fb68b20e97d6bfe132b78f6aadaf588ee7b0e1f Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Tue, 20 May 2025 14:57:26 +0800 Subject: [PATCH] separate Gltf/Morph/BoneAnimationComponentManager definitions move gltf animation instantiation to GltfAnimationComponentManager (this helps ensure we are creating the component on the correct entity) --- examples/flutter/animations/lib/main.dart | 53 +++--- examples/flutter/picking/web/index.html | 16 +- .../src/bindings/src/thermion_dart_ffi.g.dart | 4 +- .../src/thermion_dart_js_interop.g.dart | 121 +++++++++----- .../src/implementation/ffi_asset.dart | 20 ++- .../src/ffi/src/thermion_viewer_ffi.dart | 23 +-- .../native/include/c_api/TAnimationManager.h | 2 +- .../c_api/ThermionDartRenderThreadApi.h | 2 +- .../native/include/components/Animation.hpp | 19 +++ .../components/AnimationComponentManager.hpp | 157 ------------------ .../components/AnimationComponents.hpp | 35 ++++ .../BoneAnimationComponentManager.hpp | 68 ++++++++ .../GltfAnimationComponentManager.hpp | 74 +++++++++ .../MorphAnimationComponentManager.hpp | 67 ++++++++ .../native/include/scene/AnimationManager.hpp | 10 +- .../native/include/scene/GltfSceneAsset.hpp | 1 - .../native/src/c_api/TAnimationManager.cpp | 110 +++++++++--- .../BoneAnimationComponentManager.cpp | 2 +- .../GltfAnimationComponentManager.cpp | 68 +++++++- .../MorphAnimationComponentManager.cpp | 2 +- .../native/src/scene/AnimationManager.cpp | 80 ++------- .../native/src/scene/GltfSceneAsset.cpp | 5 +- thermion_dart/test/animation_tests.dart | 43 +++-- thermion_dart/test/assets/BusterDrone | 1 + 24 files changed, 629 insertions(+), 354 deletions(-) create mode 100644 thermion_dart/native/include/components/Animation.hpp delete mode 100644 thermion_dart/native/include/components/AnimationComponentManager.hpp create mode 100644 thermion_dart/native/include/components/AnimationComponents.hpp create mode 100644 thermion_dart/native/include/components/BoneAnimationComponentManager.hpp create mode 100644 thermion_dart/native/include/components/GltfAnimationComponentManager.hpp create mode 100644 thermion_dart/native/include/components/MorphAnimationComponentManager.hpp create mode 120000 thermion_dart/test/assets/BusterDrone diff --git a/examples/flutter/animations/lib/main.dart b/examples/flutter/animations/lib/main.dart index 3df8f78b..b1420234 100644 --- a/examples/flutter/animations/lib/main.dart +++ b/examples/flutter/animations/lib/main.dart @@ -51,24 +51,25 @@ class _MyHomePageState extends State { await _thermionViewer!.destroyAsset(_asset!); _asset = null; } - if (uri == null) { - return; - } - _asset = await _thermionViewer!.loadGltf(uri); - await _asset!.transformToUnitCube(); - final animations = await _asset!.getGltfAnimationNames(); - final durations = await Future.wait(List.generate( - animations.length, (i) => _asset!.getGltfAnimationDuration(i))); - final labels = animations - .asMap() - .map((index, animation) => - MapEntry(index, "$animation (${durations[index]}s")) - .values; - gltfAnimations.clear(); - gltfAnimations.addAll(labels); - selectedGltfAnimation = 0; _loaded = uri; + if (uri != null) { + _asset = await _thermionViewer!.loadGltf(uri); + await _asset!.transformToUnitCube(); + final animations = await _asset!.getGltfAnimationNames(); + final durations = await Future.wait(List.generate( + animations.length, (i) => _asset!.getGltfAnimationDuration(i))); + + final labels = animations + .asMap() + .map((index, animation) => + MapEntry(index, "$animation (${durations[index]}s")) + .values; + gltfAnimations.clear(); + gltfAnimations.addAll(labels); + selectedGltfAnimation = 0; + + } setState(() {}); } @@ -123,19 +124,19 @@ class _MyHomePageState extends State { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), child: Row(children: [ - Text("Asset: "), - DropdownButton( + const Text("Asset: "), + DropdownButton( value: _loaded, - items: [_droneUri, _cubeUri] - .map((uri) => DropdownMenuItem( + items: [_droneUri, _cubeUri, null] + .map((uri) => DropdownMenuItem( value: uri, child: Text( - uri, - style: TextStyle(fontSize: 12), + uri ?? "None", + style: const TextStyle(fontSize: 12), ))) .toList(), onChanged: _load), - Text("Animation: "), + const Text("Animation: "), DropdownButton( value: selectedGltfAnimation == -1 ? null @@ -143,9 +144,9 @@ class _MyHomePageState extends State { items: gltfAnimations .map((animation) => DropdownMenuItem( value: animation, - child: Text( + child: Text( animation, - style: TextStyle(fontSize: 12), + style: const TextStyle(fontSize: 12), ))) .toList(), onChanged: (value) { @@ -160,7 +161,7 @@ class _MyHomePageState extends State { icon: const Icon(Icons.play_arrow)), IconButton( onPressed: _stopGltfAnimation, icon: const Icon(Icons.stop)) - ]))) + ]))), ]); } } diff --git a/examples/flutter/picking/web/index.html b/examples/flutter/picking/web/index.html index 800e3e76..d4e09506 100644 --- a/examples/flutter/picking/web/index.html +++ b/examples/flutter/picking/web/index.html @@ -19,19 +19,23 @@ quickstart - - + - + + + + diff --git a/thermion_dart/lib/src/bindings/src/thermion_dart_ffi.g.dart b/thermion_dart/lib/src/bindings/src/thermion_dart_ffi.g.dart index 35daa86b..3ef2b774 100644 --- a/thermion_dart/lib/src/bindings/src/thermion_dart_ffi.g.dart +++ b/thermion_dart/lib/src/bindings/src/thermion_dart_ffi.g.dart @@ -3394,9 +3394,9 @@ external bool AnimationManager_setMorphTargetWeights( ); @ffi.Native< - ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Int, ffi.Int)>(isLeaf: true) -external void AnimationManager_setGltfAnimationFrame( +external bool AnimationManager_setGltfAnimationFrame( ffi.Pointer tAnimationManager, ffi.Pointer tSceneAsset, int animationIndex, diff --git a/thermion_dart/lib/src/bindings/src/thermion_dart_js_interop.g.dart b/thermion_dart/lib/src/bindings/src/thermion_dart_js_interop.g.dart index 1002a425..05185f50 100644 --- a/thermion_dart/lib/src/bindings/src/thermion_dart_js_interop.g.dart +++ b/thermion_dart/lib/src/bindings/src/thermion_dart_js_interop.g.dart @@ -255,7 +255,7 @@ sealed class Struct extends NativeType { Struct(this._address); static create() { - switch (T) { + switch (T) { case double4x4: final ptr = double4x4.stackAlloc(); final arr1 = @@ -267,7 +267,7 @@ sealed class Struct extends NativeType { final arr4 = Array._((numElements: 4, addr: ptr.cast() + 96)); return double4x4(arr1, arr2, arr3, arr4, ptr) as T; - } + } } } @@ -1831,7 +1831,6 @@ extension type NativeLibrary(JSObject _) implements JSObject { ); external void _GltfResourceLoader_createRenderThread( Pointer tEngine, - Pointer relativeResourcePath, Pointer< self .NativeFunction)>> @@ -1895,7 +1894,6 @@ extension type NativeLibrary(JSObject _) implements JSObject { ); external Pointer _GltfResourceLoader_create( Pointer tEngine, - Pointer relativeResourcePath, ); external void _GltfResourceLoader_destroy( Pointer tEngine, @@ -2069,14 +2067,30 @@ extension type NativeLibrary(JSObject _) implements JSObject { Pointer tAnimationManager, JSBigInt frameTimeInNanos, ); - external void _AnimationManager_addAnimationComponent( + external bool _AnimationManager_addGltfAnimationComponent( + Pointer tAnimationManager, + Pointer tSceneAsset, + ); + external bool _AnimationManager_removeGltfAnimationComponent( + Pointer tAnimationManager, + Pointer tSceneAsset, + ); + external void _AnimationManager_addMorphAnimationComponent( Pointer tAnimationManager, EntityId entityId, ); - external void _AnimationManager_removeAnimationComponent( + external void _AnimationManager_removeMorphAnimationComponent( Pointer tAnimationManager, EntityId entityId, ); + external bool _AnimationManager_addBoneAnimationComponent( + Pointer tAnimationManager, + Pointer tSceneAsset, + ); + external bool _AnimationManager_removeBoneAnimationComponent( + Pointer tAnimationManager, + Pointer tSceneAsset, + ); external bool _AnimationManager_setMorphAnimation( Pointer tAnimationManager, EntityId entityId, @@ -2094,7 +2108,7 @@ extension type NativeLibrary(JSObject _) implements JSObject { Pointer tAnimationManager, Pointer sceneAsset, ); - external void _AnimationManager_addBoneAnimation( + external bool _AnimationManager_addBoneAnimation( Pointer tAnimationManager, Pointer tSceneAsset, int skinIndex, @@ -2126,9 +2140,9 @@ extension type NativeLibrary(JSObject _) implements JSObject { int boneIndex, Pointer out, ); - external void _AnimationManager_playAnimation( + external bool _AnimationManager_playGltfAnimation( Pointer tAnimationManager, - Pointer sceneAsset, + Pointer tSceneAsset, int index, bool loop, bool reverse, @@ -2136,21 +2150,21 @@ extension type NativeLibrary(JSObject _) implements JSObject { double crossfade, double startOffset, ); - external void _AnimationManager_stopAnimation( + external bool _AnimationManager_stopGltfAnimation( Pointer tAnimationManager, Pointer sceneAsset, int index, ); - external double _AnimationManager_getAnimationDuration( + external double _AnimationManager_getGltfAnimationDuration( Pointer tAnimationManager, Pointer sceneAsset, int animationIndex, ); - external int _AnimationManager_getAnimationCount( + external int _AnimationManager_getGltfAnimationCount( Pointer tAnimationManager, Pointer sceneAsset, ); - external void _AnimationManager_getAnimationName( + external void _AnimationManager_getGltfAnimationName( Pointer tAnimationManager, Pointer sceneAsset, Pointer outPtr, @@ -2189,7 +2203,7 @@ extension type NativeLibrary(JSObject _) implements JSObject { Pointer morphData, int numWeights, ); - external void _AnimationManager_setGltfAnimationFrame( + external bool _AnimationManager_setGltfAnimationFrame( Pointer tAnimationManager, Pointer tSceneAsset, int animationIndex, @@ -5133,12 +5147,11 @@ void GltfAssetLoader_createRenderThread( void GltfResourceLoader_createRenderThread( self.Pointer tEngine, - self.Pointer relativeResourcePath, self.Pointer)>> callback, ) { final result = _lib._GltfResourceLoader_createRenderThread( - tEngine.cast(), relativeResourcePath, callback.cast()); + tEngine.cast(), callback.cast()); return result; } @@ -5263,10 +5276,8 @@ void Gizmo_createRenderThread( self.Pointer GltfResourceLoader_create( self.Pointer tEngine, - self.Pointer relativeResourcePath, ) { - final result = - _lib._GltfResourceLoader_create(tEngine.cast(), relativeResourcePath); + final result = _lib._GltfResourceLoader_create(tEngine.cast()); return self.Pointer(result); } @@ -5641,24 +5652,60 @@ void AnimationManager_update( return result; } -void AnimationManager_addAnimationComponent( +bool AnimationManager_addGltfAnimationComponent( + self.Pointer tAnimationManager, + self.Pointer tSceneAsset, +) { + final result = _lib._AnimationManager_addGltfAnimationComponent( + tAnimationManager.cast(), tSceneAsset.cast()); + return result; +} + +bool AnimationManager_removeGltfAnimationComponent( + self.Pointer tAnimationManager, + self.Pointer tSceneAsset, +) { + final result = _lib._AnimationManager_removeGltfAnimationComponent( + tAnimationManager.cast(), tSceneAsset.cast()); + return result; +} + +void AnimationManager_addMorphAnimationComponent( self.Pointer tAnimationManager, DartEntityId entityId, ) { - final result = _lib._AnimationManager_addAnimationComponent( + final result = _lib._AnimationManager_addMorphAnimationComponent( tAnimationManager.cast(), entityId); return result; } -void AnimationManager_removeAnimationComponent( +void AnimationManager_removeMorphAnimationComponent( self.Pointer tAnimationManager, DartEntityId entityId, ) { - final result = _lib._AnimationManager_removeAnimationComponent( + final result = _lib._AnimationManager_removeMorphAnimationComponent( tAnimationManager.cast(), entityId); return result; } +bool AnimationManager_addBoneAnimationComponent( + self.Pointer tAnimationManager, + self.Pointer tSceneAsset, +) { + final result = _lib._AnimationManager_addBoneAnimationComponent( + tAnimationManager.cast(), tSceneAsset.cast()); + return result; +} + +bool AnimationManager_removeBoneAnimationComponent( + self.Pointer tAnimationManager, + self.Pointer tSceneAsset, +) { + final result = _lib._AnimationManager_removeBoneAnimationComponent( + tAnimationManager.cast(), tSceneAsset.cast()); + return result; +} + bool AnimationManager_setMorphAnimation( self.Pointer tAnimationManager, DartEntityId entityId, @@ -5697,7 +5744,7 @@ void AnimationManager_resetToRestPose( return result; } -void AnimationManager_addBoneAnimation( +bool AnimationManager_addBoneAnimation( self.Pointer tAnimationManager, self.Pointer tSceneAsset, int skinIndex, @@ -5758,9 +5805,9 @@ void AnimationManager_getInverseBindMatrix( return result; } -void AnimationManager_playAnimation( +bool AnimationManager_playGltfAnimation( self.Pointer tAnimationManager, - self.Pointer sceneAsset, + self.Pointer tSceneAsset, int index, bool loop, bool reverse, @@ -5768,9 +5815,9 @@ void AnimationManager_playAnimation( double crossfade, double startOffset, ) { - final result = _lib._AnimationManager_playAnimation( + final result = _lib._AnimationManager_playGltfAnimation( tAnimationManager.cast(), - sceneAsset.cast(), + tSceneAsset.cast(), index, loop, reverse, @@ -5780,42 +5827,42 @@ void AnimationManager_playAnimation( return result; } -void AnimationManager_stopAnimation( +bool AnimationManager_stopGltfAnimation( self.Pointer tAnimationManager, self.Pointer sceneAsset, int index, ) { - final result = _lib._AnimationManager_stopAnimation( + final result = _lib._AnimationManager_stopGltfAnimation( tAnimationManager.cast(), sceneAsset.cast(), index); return result; } -double AnimationManager_getAnimationDuration( +double AnimationManager_getGltfAnimationDuration( self.Pointer tAnimationManager, self.Pointer sceneAsset, int animationIndex, ) { - final result = _lib._AnimationManager_getAnimationDuration( + final result = _lib._AnimationManager_getGltfAnimationDuration( tAnimationManager.cast(), sceneAsset.cast(), animationIndex); return result; } -int AnimationManager_getAnimationCount( +int AnimationManager_getGltfAnimationCount( self.Pointer tAnimationManager, self.Pointer sceneAsset, ) { - final result = _lib._AnimationManager_getAnimationCount( + final result = _lib._AnimationManager_getGltfAnimationCount( tAnimationManager.cast(), sceneAsset.cast()); return result; } -void AnimationManager_getAnimationName( +void AnimationManager_getGltfAnimationName( self.Pointer tAnimationManager, self.Pointer sceneAsset, self.Pointer outPtr, int index, ) { - final result = _lib._AnimationManager_getAnimationName( + final result = _lib._AnimationManager_getGltfAnimationName( tAnimationManager.cast(), sceneAsset.cast(), outPtr, index); return result; } @@ -5883,7 +5930,7 @@ bool AnimationManager_setMorphTargetWeights( return result; } -void AnimationManager_setGltfAnimationFrame( +bool AnimationManager_setGltfAnimationFrame( self.Pointer tAnimationManager, self.Pointer tSceneAsset, int animationIndex, diff --git a/thermion_dart/lib/src/filament/src/implementation/ffi_asset.dart b/thermion_dart/lib/src/filament/src/implementation/ffi_asset.dart index 20ede093..db9a72ae 100644 --- a/thermion_dart/lib/src/filament/src/implementation/ffi_asset.dart +++ b/thermion_dart/lib/src/filament/src/implementation/ffi_asset.dart @@ -621,8 +621,12 @@ class FFIAsset extends ThermionAsset { /// @override Future getGltfAnimationDuration(int animationIndex) async { - return AnimationManager_getGltfAnimationDuration( + final duration = AnimationManager_getGltfAnimationDuration( animationManager, asset, animationIndex); + if (duration < 0) { + throw Exception("Failed to get glTF animation duration"); + } + return duration; } /// @@ -1030,6 +1034,18 @@ class FFIAsset extends ThermionAsset { /// /// Future removeAnimationComponent() async { - AnimationManager_removeGltfAnimationComponent(animationManager, this.asset); + if (!AnimationManager_removeGltfAnimationComponent( + animationManager, asset)) { + throw Exception("Failed to remove glTF animation component"); + } + if (!AnimationManager_removeBoneAnimationComponent( + animationManager, asset)) { + throw Exception("Failed to remove bone animation component"); + } + AnimationManager_removeMorphAnimationComponent(animationManager, entity); + + for (final child in await getChildEntities()) { + AnimationManager_removeMorphAnimationComponent(animationManager, child); + } } } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart index 4570de96..b0a0c32a 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart @@ -116,14 +116,14 @@ class ThermionViewerFFI extends ThermionViewer { /// @override Future render() async { - await withVoidCallback((requestId,cb) => - RenderTicker_renderRenderThread(app.renderTicker, 0.toBigInt, requestId,cb)); + await withVoidCallback((requestId, cb) => RenderTicker_renderRenderThread( + app.renderTicker, 0.toBigInt, requestId, cb)); if (FILAMENT_SINGLE_THREADED) { - await withVoidCallback( - (requestId,cb) => Engine_executeRenderThread(app.engine, requestId,cb)); + await withVoidCallback((requestId, cb) => + Engine_executeRenderThread(app.engine, requestId, cb)); } else { - await withVoidCallback( - (requestId,cb) => Engine_flushAndWaitRenderThread(app.engine, requestId,cb)); + await withVoidCallback((requestId, cb) => + Engine_flushAndWaitRenderThread(app.engine, requestId, cb)); } } @@ -300,8 +300,8 @@ class ThermionViewerFFI extends ThermionViewer { } if (skybox != null) { - await withVoidCallback( - (requestId,cb) => Engine_destroySkyboxRenderThread(app.engine, skybox!, requestId,cb)); + await withVoidCallback((requestId, cb) => + Engine_destroySkyboxRenderThread(app.engine, skybox!, requestId, cb)); skybox = null; } } @@ -313,8 +313,9 @@ class ThermionViewerFFI extends ThermionViewer { Future removeIbl() async { if (indirectLight != null) { Scene_setIndirectLight(scene.scene, nullptr); - await withVoidCallback((requestId,cb) => Engine_destroyIndirectLightRenderThread( - app.engine, indirectLight!, requestId,cb)); + await withVoidCallback((requestId, cb) => + Engine_destroyIndirectLightRenderThread( + app.engine, indirectLight!, requestId, cb)); indirectLight = null; } } @@ -439,7 +440,9 @@ class ThermionViewerFFI extends ThermionViewer { /// @override Future destroyAsset(covariant FFIAsset asset) async { + await asset.removeAnimationComponent(); await scene.remove(asset); + if (asset.boundingBoxAsset != null) { await scene.remove(asset.boundingBoxAsset! as FFIAsset); await FilamentApp.instance!.destroyAsset(asset.boundingBoxAsset!); diff --git a/thermion_dart/native/include/c_api/TAnimationManager.h b/thermion_dart/native/include/c_api/TAnimationManager.h index f2a5ddd7..76ca55bd 100644 --- a/thermion_dart/native/include/c_api/TAnimationManager.h +++ b/thermion_dart/native/include/c_api/TAnimationManager.h @@ -129,7 +129,7 @@ extern "C" const float *const morphData, int numWeights); - EMSCRIPTEN_KEEPALIVE void AnimationManager_setGltfAnimationFrame( + EMSCRIPTEN_KEEPALIVE bool AnimationManager_setGltfAnimationFrame( TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset, int animationIndex, diff --git a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h index ece7c8ba..0b62dcd4 100644 --- a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h +++ b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h @@ -301,7 +301,7 @@ namespace thermion void AnimationManager_resetToRestPoseRenderThread(TAnimationManager *tAnimationManager, EntityId entityId, uint32_t requestId, VoidCallback onComplete); void GltfAssetLoader_createRenderThread(TEngine *tEngine, TMaterialProvider *tMaterialProvider, void (*callback)(TGltfAssetLoader *)); - void GltfResourceLoader_createRenderThread(TEngine *tEngine, const char* relativeResourcePath, void (*callback)(TGltfResourceLoader *)); + void GltfResourceLoader_createRenderThread(TEngine *tEngine, void (*callback)(TGltfResourceLoader *)); void GltfResourceLoader_destroyRenderThread(TEngine *tEngine, TGltfResourceLoader *tResourceLoader, uint32_t requestId, VoidCallback onComplete); void GltfResourceLoader_loadResourcesRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool)); void GltfResourceLoader_addResourceDataRenderThread(TGltfResourceLoader *tGltfResourceLoader, const char *uri, uint8_t *data, size_t length, uint32_t requestId, VoidCallback onComplete); diff --git a/thermion_dart/native/include/components/Animation.hpp b/thermion_dart/native/include/components/Animation.hpp new file mode 100644 index 00000000..192e8c99 --- /dev/null +++ b/thermion_dart/native/include/components/Animation.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace thermion +{ + using namespace std::chrono; + + typedef std::chrono::time_point time_point_t; + + struct Animation + { + time_point_t start = time_point_t::max(); + float startOffset; + bool loop = false; + bool reverse = false; + float durationInSecs = 0; + }; +} \ No newline at end of file diff --git a/thermion_dart/native/include/components/AnimationComponentManager.hpp b/thermion_dart/native/include/components/AnimationComponentManager.hpp deleted file mode 100644 index b31ccdd6..00000000 --- a/thermion_dart/native/include/components/AnimationComponentManager.hpp +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include "Log.hpp" - -template class std::vector; -namespace thermion -{ - using namespace filament; - using namespace filament::gltfio; - using namespace utils; - using namespace std::chrono; - - typedef std::chrono::time_point time_point_t; - - struct Animation - { - time_point_t start = time_point_t::max(); - float startOffset; - bool loop = false; - bool reverse = false; - float durationInSecs = 0; - }; - - /// @brief - /// The status of an animation embedded in a glTF object. - /// @param index refers to the index of the animation in the animations property of the underlying object. - /// - struct GltfAnimation : Animation - { - int index = -1; - }; - - // - // The status of a morph target animation created dynamically at runtime (not glTF embedded). - // - struct MorphAnimation : Animation - { - int lengthInFrames; - float frameLengthInMs = 0; - std::vector frameData; - std::vector morphIndices; - }; - - struct BoneAnimation : Animation { - int lengthInFrames; - size_t boneIndex; - size_t skinIndex = 0; - float frameLengthInMs = 0; - std::vector frameData; - float fadeOutInSecs = 0; - float fadeInInSecs = 0; - float maxDelta = 1.0f; - }; - - /// @brief - /// - /// - struct BoneAnimationComponent - { - FilamentInstance * target; - std::vector animations; - }; - - /// @brief - /// - /// - struct MorphAnimationComponent - { - std::vector animations; - }; - - /// @brief - /// - /// - struct GltfAnimationComponent - { - FilamentInstance * target; - // the index of the last active glTF animation, - // used to cross-fade - int fadeGltfAnimationIndex = -1; - float fadeDuration = 0.0f; - float fadeOutAnimationStart = 0.0f; - std::vector animations; - }; - - - class GltfAnimationComponentManager : public utils::SingleInstanceComponentManager { - public: - GltfAnimationComponentManager( - filament::TransformManager &transformManager, - filament::RenderableManager &renderableManager) : - mTransformManager(transformManager), mRenderableManager(renderableManager) {}; - ~GltfAnimationComponentManager() = default; - void addAnimationComponent(FilamentInstance *target); - void removeAnimationComponent(FilamentInstance *target); - void update(); - - private: - filament::TransformManager &mTransformManager; - filament::RenderableManager &mRenderableManager; - }; - - class BoneAnimationComponentManager : public utils::SingleInstanceComponentManager { - public: - BoneAnimationComponentManager( - filament::TransformManager &transformManager, - filament::RenderableManager &renderableManager) : - mTransformManager(transformManager), mRenderableManager(renderableManager) {}; - ~BoneAnimationComponentManager() {}; - - void addAnimationComponent(FilamentInstance *target); - void removeAnimationComponent(FilamentInstance *target); - void update(); - - private: - filament::TransformManager &mTransformManager; - filament::RenderableManager &mRenderableManager; - }; - - class MorphAnimationComponentManager : public utils::SingleInstanceComponentManager { - public: - MorphAnimationComponentManager( - filament::TransformManager &transformManager, - filament::RenderableManager &renderableManager) : - mTransformManager(transformManager), mRenderableManager(renderableManager) {}; - ~MorphAnimationComponentManager() {}; - - void addAnimationComponent(Entity entity); - void removeAnimationComponent(Entity entity); - void update(); - - private: - filament::TransformManager &mTransformManager; - filament::RenderableManager &mRenderableManager; - }; - -} diff --git a/thermion_dart/native/include/components/AnimationComponents.hpp b/thermion_dart/native/include/components/AnimationComponents.hpp new file mode 100644 index 00000000..b9d39f3e --- /dev/null +++ b/thermion_dart/native/include/components/AnimationComponents.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include + +#include +#include +#include +#include + +#include "Log.hpp" + +namespace thermion +{ + using namespace filament; + using namespace std::chrono; + + typedef std::chrono::time_point time_point_t; + + struct Animation + { + time_point_t start = time_point_t::max(); + float startOffset; + bool loop = false; + bool reverse = false; + float durationInSecs = 0; + }; + + + + + +} diff --git a/thermion_dart/native/include/components/BoneAnimationComponentManager.hpp b/thermion_dart/native/include/components/BoneAnimationComponentManager.hpp new file mode 100644 index 00000000..b60f91fd --- /dev/null +++ b/thermion_dart/native/include/components/BoneAnimationComponentManager.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "Log.hpp" +#include "components/Animation.hpp" + +namespace thermion +{ + using namespace filament; + using namespace filament::gltfio; + using namespace utils; + + struct BoneAnimation : Animation { + int lengthInFrames; + size_t boneIndex; + size_t skinIndex = 0; + float frameLengthInMs = 0; + std::vector frameData; + float fadeOutInSecs = 0; + float fadeInInSecs = 0; + float maxDelta = 1.0f; + }; + + /// @brief + /// + /// + struct BoneAnimationComponent + { + filament::gltfio::FilamentInstance * target; + std::vector animations; + }; + + class BoneAnimationComponentManager : public utils::SingleInstanceComponentManager { + public: + BoneAnimationComponentManager( + filament::TransformManager &transformManager, + filament::RenderableManager &renderableManager) : + mTransformManager(transformManager), mRenderableManager(renderableManager) {}; + ~BoneAnimationComponentManager() {}; + + void addAnimationComponent(FilamentInstance *target); + void removeAnimationComponent(FilamentInstance *target); + void update(); + + private: + filament::TransformManager &mTransformManager; + filament::RenderableManager &mRenderableManager; + }; + + + +} diff --git a/thermion_dart/native/include/components/GltfAnimationComponentManager.hpp b/thermion_dart/native/include/components/GltfAnimationComponentManager.hpp new file mode 100644 index 00000000..a3da08a3 --- /dev/null +++ b/thermion_dart/native/include/components/GltfAnimationComponentManager.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "Log.hpp" +#include "scene/GltfSceneAssetInstance.hpp" +#include "components/Animation.hpp" + +template class std::vector; +namespace thermion +{ + using namespace filament; + using namespace filament::gltfio; + using namespace utils; + using namespace std::chrono; + + /// @brief + /// The status of an animation embedded in a glTF object. + /// @param index refers to the index of the animation in the animations property of the underlying object. + /// + struct GltfAnimation : Animation + { + int index = -1; + }; + + + /// @brief + /// + /// + struct GltfAnimationComponent + { + filament::gltfio::FilamentInstance * target; + // the index of the last active glTF animation, + // used to cross-fade + int fadeGltfAnimationIndex = -1; + float fadeDuration = 0.0f; + float fadeOutAnimationStart = 0.0f; + std::vector animations; + }; + + class GltfAnimationComponentManager : public utils::SingleInstanceComponentManager { + public: + GltfAnimationComponentManager( + filament::TransformManager &transformManager, + filament::RenderableManager &renderableManager) : + mTransformManager(transformManager), mRenderableManager(renderableManager) {}; + ~GltfAnimationComponentManager() = default; + void addAnimationComponent(FilamentInstance *target); + void removeAnimationComponent(FilamentInstance *target); + + bool addGltfAnimation(FilamentInstance *target, int index, bool loop, bool reverse, bool replaceActive, float crossfade, float startOffset); + // GltfAnimationComponent getAnimationComponentInstance(FilamentInstance *target); + void update(); + + private: + filament::TransformManager &mTransformManager; + filament::RenderableManager &mRenderableManager; + }; +} \ No newline at end of file diff --git a/thermion_dart/native/include/components/MorphAnimationComponentManager.hpp b/thermion_dart/native/include/components/MorphAnimationComponentManager.hpp new file mode 100644 index 00000000..89683ccd --- /dev/null +++ b/thermion_dart/native/include/components/MorphAnimationComponentManager.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "Log.hpp" +#include "components/Animation.hpp" + +namespace thermion +{ + using namespace filament; + using namespace filament::gltfio; + using namespace utils; + using namespace std::chrono; + + // + // The status of a morph target animation created dynamically at runtime (not glTF embedded). + // + struct MorphAnimation : Animation + { + int lengthInFrames; + float frameLengthInMs = 0; + std::vector frameData; + std::vector morphIndices; + }; + + + /// @brief + /// + /// + struct MorphAnimationComponent + { + std::vector animations; + }; + + class MorphAnimationComponentManager : public utils::SingleInstanceComponentManager { + public: + MorphAnimationComponentManager( + filament::TransformManager &transformManager, + filament::RenderableManager &renderableManager) : + mTransformManager(transformManager), mRenderableManager(renderableManager) {}; + ~MorphAnimationComponentManager() {}; + + void addAnimationComponent(Entity entity); + void removeAnimationComponent(Entity entity); + void update(); + + private: + filament::TransformManager &mTransformManager; + filament::RenderableManager &mRenderableManager; + }; + +} diff --git a/thermion_dart/native/include/scene/AnimationManager.hpp b/thermion_dart/native/include/scene/AnimationManager.hpp index 30713c9f..533dad8a 100644 --- a/thermion_dart/native/include/scene/AnimationManager.hpp +++ b/thermion_dart/native/include/scene/AnimationManager.hpp @@ -9,10 +9,12 @@ #include "c_api/APIBoundaryTypes.h" #include "components/CollisionComponentManager.hpp" -#include "components/AnimationComponentManager.hpp" -#include "GltfSceneAssetInstance.hpp" -#include "GltfSceneAsset.hpp" -#include "SceneAsset.hpp" +#include "components/GltfAnimationComponentManager.hpp" +#include "components/MorphAnimationComponentManager.hpp" +#include "components/BoneAnimationComponentManager.hpp" +#include "scene/GltfSceneAssetInstance.hpp" +#include "scene/GltfSceneAsset.hpp" +#include "scene/SceneAsset.hpp" namespace thermion { diff --git a/thermion_dart/native/include/scene/GltfSceneAsset.hpp b/thermion_dart/native/include/scene/GltfSceneAsset.hpp index debae4b1..f4f11afb 100644 --- a/thermion_dart/native/include/scene/GltfSceneAsset.hpp +++ b/thermion_dart/native/include/scene/GltfSceneAsset.hpp @@ -14,7 +14,6 @@ #include #include "scene/GltfSceneAssetInstance.hpp" -#include "components/AnimationComponentManager.hpp" #include "components/CollisionComponentManager.hpp" #include "scene/SceneAsset.hpp" diff --git a/thermion_dart/native/src/c_api/TAnimationManager.cpp b/thermion_dart/native/src/c_api/TAnimationManager.cpp index bcf61753..86f65592 100644 --- a/thermion_dart/native/src/c_api/TAnimationManager.cpp +++ b/thermion_dart/native/src/c_api/TAnimationManager.cpp @@ -31,49 +31,93 @@ extern "C" EMSCRIPTEN_KEEPALIVE bool AnimationManager_addGltfAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset) { auto sceneAsset = reinterpret_cast(tSceneAsset); - if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf || !sceneAsset->isInstance()) { + if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) { return false; } + + GltfSceneAssetInstance *instance; + + if (sceneAsset->isInstance()) + { + instance = reinterpret_cast(sceneAsset); + } else { + instance = reinterpret_cast(sceneAsset->getInstanceAt(0)); + } auto animationManager = reinterpret_cast(tAnimationManager); - animationManager->addGltfAnimationComponent(reinterpret_cast(sceneAsset)); + animationManager->addGltfAnimationComponent(instance); return true; } EMSCRIPTEN_KEEPALIVE bool AnimationManager_removeGltfAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset) { auto sceneAsset = reinterpret_cast(tSceneAsset); - if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf || !sceneAsset->isInstance()) { + + if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) { return false; } + GltfSceneAssetInstance *instance; + + if (sceneAsset->isInstance()) + { + instance = reinterpret_cast(sceneAsset); + } else { + instance = reinterpret_cast(sceneAsset->getInstanceAt(0)); + } + + auto animationManager = reinterpret_cast(tAnimationManager); - animationManager->removeGltfAnimationComponent(reinterpret_cast(sceneAsset)); + animationManager->removeGltfAnimationComponent(instance); return true; } EMSCRIPTEN_KEEPALIVE bool AnimationManager_addBoneAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset) { auto sceneAsset = reinterpret_cast(tSceneAsset); - if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf || !sceneAsset->isInstance()) { + + if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) { return false; } + + GltfSceneAssetInstance *instance; + + if (sceneAsset->isInstance()) + { + instance = reinterpret_cast(sceneAsset); + } else { + instance = reinterpret_cast(sceneAsset->getInstanceAt(0)); + } auto animationManager = reinterpret_cast(tAnimationManager); - animationManager->addBoneAnimationComponent(reinterpret_cast(sceneAsset)); + animationManager->addBoneAnimationComponent(instance); return true; } EMSCRIPTEN_KEEPALIVE bool AnimationManager_removeBoneAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset) { auto sceneAsset = reinterpret_cast(tSceneAsset); - if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf || !sceneAsset->isInstance()) { + if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) { return false; } + + if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) { + return false; + } + + GltfSceneAssetInstance *instance; + + if (sceneAsset->isInstance()) + { + instance = reinterpret_cast(sceneAsset); + } else { + instance = reinterpret_cast(sceneAsset->getInstanceAt(0)); + } + auto animationManager = reinterpret_cast(tAnimationManager); - animationManager->removeBoneAnimationComponent(reinterpret_cast(sceneAsset)); + animationManager->removeBoneAnimationComponent(instance); return true; } @@ -124,15 +168,27 @@ extern "C" return true; } - EMSCRIPTEN_KEEPALIVE void AnimationManager_resetToRestPose(TAnimationManager *tAnimationManager, TSceneAsset *sceneAsset) + EMSCRIPTEN_KEEPALIVE void AnimationManager_resetToRestPose(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset) { auto *animationManager = reinterpret_cast(tAnimationManager); - auto asset = reinterpret_cast(sceneAsset); - if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance()) - { - auto *instance = reinterpret_cast(asset); - animationManager->resetToRestPose(instance); + auto sceneAsset = reinterpret_cast(tSceneAsset); + if (sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) { + Log("Error - incorrect asset type, cannot reset to reset pose"); + return; } + + + GltfSceneAssetInstance *instance; + + if (sceneAsset->isInstance()) + { + instance = reinterpret_cast(sceneAsset); + } else { + instance = reinterpret_cast(sceneAsset->getInstanceAt(0)); + } + + animationManager->resetToRestPose(instance); + } EMSCRIPTEN_KEEPALIVE bool AnimationManager_addBoneAnimation( @@ -297,19 +353,31 @@ extern "C" return true; } - EMSCRIPTEN_KEEPALIVE void AnimationManager_setGltfAnimationFrame( + EMSCRIPTEN_KEEPALIVE bool AnimationManager_setGltfAnimationFrame( TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset, int animationIndex, int frame) { auto *animationManager = reinterpret_cast(tAnimationManager); - auto asset = reinterpret_cast(tSceneAsset); - if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance()) - { - auto *instance = reinterpret_cast(asset); - animationManager->setGltfAnimationFrame(instance, animationIndex, frame); + auto sceneAsset = reinterpret_cast(tSceneAsset); + if (sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) { + return false; } + + GltfSceneAssetInstance *instance; + + if (sceneAsset->isInstance()) + { + instance = reinterpret_cast(sceneAsset); + } else { + instance = reinterpret_cast(sceneAsset->getInstanceAt(0)); + } + + animationManager->setGltfAnimationFrame(instance, animationIndex, frame); + + return true; + } EMSCRIPTEN_KEEPALIVE float AnimationManager_getGltfAnimationDuration( @@ -320,7 +388,7 @@ extern "C" auto sceneAsset = reinterpret_cast(tSceneAsset); if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) { - return false; + return -1.0; } auto animationManager = reinterpret_cast(tAnimationManager); diff --git a/thermion_dart/native/src/components/BoneAnimationComponentManager.cpp b/thermion_dart/native/src/components/BoneAnimationComponentManager.cpp index 166a2a3d..86837dc0 100644 --- a/thermion_dart/native/src/components/BoneAnimationComponentManager.cpp +++ b/thermion_dart/native/src/components/BoneAnimationComponentManager.cpp @@ -1,7 +1,7 @@ #include #include -#include "components/AnimationComponentManager.hpp" +#include "components/BoneAnimationComponentManager.hpp" #include "Log.hpp" diff --git a/thermion_dart/native/src/components/GltfAnimationComponentManager.cpp b/thermion_dart/native/src/components/GltfAnimationComponentManager.cpp index f8f513ac..79cf8239 100644 --- a/thermion_dart/native/src/components/GltfAnimationComponentManager.cpp +++ b/thermion_dart/native/src/components/GltfAnimationComponentManager.cpp @@ -1,7 +1,7 @@ #include #include -#include "components/AnimationComponentManager.hpp" +#include "components/GltfAnimationComponentManager.hpp" #include "Log.hpp" @@ -15,9 +15,75 @@ namespace thermion } } + bool GltfAnimationComponentManager::addGltfAnimation(FilamentInstance *target, int index, bool loop, bool reverse, bool replaceActive, float crossfade, float startOffset) { + + EntityInstanceBase::Type componentInstance = getInstance(target->getRoot()); + + auto &animationComponent = this->elementAt<0>(componentInstance); + + animationComponent.target = target; + + if (replaceActive) + { + if (animationComponent.animations.size() > 0) + { + auto &last = animationComponent.animations.back(); + animationComponent.fadeGltfAnimationIndex = last.index; + animationComponent.fadeDuration = crossfade; + auto now = high_resolution_clock::now(); + auto elapsedInSecs = float(std::chrono::duration_cast(now - last.start).count()) / 1000.0f; + animationComponent.fadeOutAnimationStart = elapsedInSecs; + animationComponent.animations.clear(); + } + else + { + animationComponent.fadeGltfAnimationIndex = -1; + animationComponent.fadeDuration = 0.0f; + } + } + else if (crossfade > 0) + { + Log("ERROR: crossfade only supported when replaceActive is true."); + return false; + } + else + { + animationComponent.fadeGltfAnimationIndex = -1; + animationComponent.fadeDuration = 0.0f; + } + + GltfAnimation animation; + animation.startOffset = startOffset; + animation.index = index; + animation.start = std::chrono::high_resolution_clock::now(); + animation.loop = loop; + animation.reverse = reverse; + animation.durationInSecs = target->getAnimator()->getAnimationDuration(index); + + bool found = false; + + // don't play the animation if it's already running + for (int i = 0; i < animationComponent.animations.size(); i++) + { + if (animationComponent.animations[i].index == index) + { + found = true; + break; + } + } + if (!found) + { + animationComponent.animations.push_back(animation); + } + return true; + } + void GltfAnimationComponentManager::removeAnimationComponent(FilamentInstance *target) { if(hasComponent(target->getRoot())) { removeComponent(target->getRoot()); + TRACE("Found component, component removed"); + } else { + TRACE("Component not found, skipping removal"); } } diff --git a/thermion_dart/native/src/components/MorphAnimationComponentManager.cpp b/thermion_dart/native/src/components/MorphAnimationComponentManager.cpp index 0fa29e40..e2c52e11 100644 --- a/thermion_dart/native/src/components/MorphAnimationComponentManager.cpp +++ b/thermion_dart/native/src/components/MorphAnimationComponentManager.cpp @@ -1,7 +1,7 @@ #include #include -#include "components/AnimationComponentManager.hpp" +#include "components/MorphAnimationComponentManager.hpp" #include "Log.hpp" diff --git a/thermion_dart/native/src/scene/AnimationManager.cpp b/thermion_dart/native/src/scene/AnimationManager.cpp index 4325a5e8..972ecd76 100644 --- a/thermion_dart/native/src/scene/AnimationManager.cpp +++ b/thermion_dart/native/src/scene/AnimationManager.cpp @@ -11,8 +11,6 @@ #include "Log.hpp" -#include "components/AnimationComponentManager.hpp" -#include "components/AnimationComponentManager.hpp" #include "scene/AnimationManager.hpp" #include "scene/SceneAsset.hpp" #include "scene/GltfSceneAssetInstance.hpp" @@ -334,71 +332,7 @@ namespace thermion return; } - if (!_gltfAnimationComponentManager->hasComponent(instance->getEntity())) - { - _gltfAnimationComponentManager->addComponent(instance->getEntity()); - Log("ERROR: specified entity is not animatable (has no animation component attached)."); - return; - } - - auto animationComponentInstance = _gltfAnimationComponentManager->getInstance(instance->getEntity()); - - auto &animationComponent = _gltfAnimationComponentManager->elementAt<0>(animationComponentInstance); - - animationComponent.target = instance->getInstance(); - - if (replaceActive) - { - if (animationComponent.animations.size() > 0) - { - auto &last = animationComponent.animations.back(); - animationComponent.fadeGltfAnimationIndex = last.index; - animationComponent.fadeDuration = crossfade; - auto now = high_resolution_clock::now(); - auto elapsedInSecs = float(std::chrono::duration_cast(now - last.start).count()) / 1000.0f; - animationComponent.fadeOutAnimationStart = elapsedInSecs; - animationComponent.animations.clear(); - } - else - { - animationComponent.fadeGltfAnimationIndex = -1; - animationComponent.fadeDuration = 0.0f; - } - } - else if (crossfade > 0) - { - Log("ERROR: crossfade only supported when replaceActive is true."); - return; - } - else - { - animationComponent.fadeGltfAnimationIndex = -1; - animationComponent.fadeDuration = 0.0f; - } - - GltfAnimation animation; - animation.startOffset = startOffset; - animation.index = index; - animation.start = std::chrono::high_resolution_clock::now(); - animation.loop = loop; - animation.reverse = reverse; - animation.durationInSecs = instance->getInstance()->getAnimator()->getAnimationDuration(index); - - bool found = false; - - // don't play the animation if it's already running - for (int i = 0; i < animationComponent.animations.size(); i++) - { - if (animationComponent.animations[i].index == index) - { - found = true; - break; - } - } - if (!found) - { - animationComponent.animations.push_back(animation); - } + _gltfAnimationComponentManager->addGltfAnimation(instance->getInstance(), index, loop, reverse, replaceActive, crossfade, startOffset); } void AnimationManager::stopGltfAnimation(GltfSceneAssetInstance *instance, int index) @@ -515,35 +449,47 @@ namespace thermion bool AnimationManager::addGltfAnimationComponent(GltfSceneAssetInstance *instance) { + std::lock_guard lock(_mutex); _gltfAnimationComponentManager->addAnimationComponent(instance->getInstance()); + TRACE("Added glTF animation component"); return true; } void AnimationManager::removeGltfAnimationComponent(GltfSceneAssetInstance *instance) { + std::lock_guard lock(_mutex); _gltfAnimationComponentManager->removeAnimationComponent(instance->getInstance()); + TRACE("Removed glTF animation component"); } bool AnimationManager::addBoneAnimationComponent(GltfSceneAssetInstance *instance) { + std::lock_guard lock(_mutex); _boneAnimationComponentManager->addAnimationComponent(instance->getInstance()); + TRACE("Added bone animation component"); return true; } void AnimationManager::removeBoneAnimationComponent(GltfSceneAssetInstance *instance) { + std::lock_guard lock(_mutex); _boneAnimationComponentManager->removeAnimationComponent(instance->getInstance()); + TRACE("Removed bone animation component"); } bool AnimationManager::addMorphAnimationComponent(utils::Entity entity) { + std::lock_guard lock(_mutex); _morphAnimationComponentManager->addAnimationComponent(entity); + TRACE("Added morph animation component"); return true; } void AnimationManager::removeMorphAnimationComponent(utils::Entity entity) { + std::lock_guard lock(_mutex); _morphAnimationComponentManager->removeAnimationComponent(entity); + TRACE("Removed morph animation component"); } } \ No newline at end of file diff --git a/thermion_dart/native/src/scene/GltfSceneAsset.cpp b/thermion_dart/native/src/scene/GltfSceneAsset.cpp index be20c778..4194095f 100644 --- a/thermion_dart/native/src/scene/GltfSceneAsset.cpp +++ b/thermion_dart/native/src/scene/GltfSceneAsset.cpp @@ -12,19 +12,18 @@ #include #include #include +#include #include +#include #include #include #include "scene/GltfSceneAssetInstance.hpp" -#include "components/AnimationComponentManager.hpp" #include "components/CollisionComponentManager.hpp" #include "scene/SceneAsset.hpp" - - namespace thermion { diff --git a/thermion_dart/test/animation_tests.dart b/thermion_dart/test/animation_tests.dart index 24924660..f73e4700 100644 --- a/thermion_dart/test/animation_tests.dart +++ b/thermion_dart/test/animation_tests.dart @@ -38,52 +38,69 @@ void main() async { test('set morph target weights', () async { await testHelper.withViewer((viewer) async { - final cube = await viewer.loadGltf( - "${testHelper.testDir}/assets/cube_with_morph_targets.glb"); + final cube = await viewer + .loadGltf("${testHelper.testDir}/assets/cube_with_morph_targets.glb"); await viewer.addToScene(cube); await testHelper.capture(viewer.view, "cube_no_morph"); - await cube.setMorphTargetWeights((await cube.getChildEntities()).first, [1.0]); + await cube + .setMorphTargetWeights((await cube.getChildEntities()).first, [1.0]); await testHelper.capture(viewer.view, "cube_with_morph"); - - }, bg:kRed, cameraPosition: Vector3(3, 2, 6)); + }, bg: kRed, cameraPosition: Vector3(3, 2, 6)); }); test('set morph target animation', () async { await testHelper.withViewer((viewer) async { - final cube = await viewer.loadGltf( - "${testHelper.testDir}/assets/cube_with_morph_targets.glb"); + final cube = await viewer + .loadGltf("${testHelper.testDir}/assets/cube_with_morph_targets.glb"); await viewer.addToScene(cube); + await testHelper.capture(viewer.view, "cube_morph_animation_reset"); + var morphData = MorphAnimationData(Float32List.fromList([1.0]), ["Key 1"], frameLengthInMs: 1000.0 / 60.0); await cube.setMorphAnimationData(morphData); await viewer.render(); - await testHelper.capture(viewer.view, "cube_with_morph_animation"); - - }, bg:kRed, cameraPosition: Vector3(3, 2, -6)); + await testHelper.capture(viewer.view, "cube_morph_animation_playing"); + }, bg: kRed, cameraPosition: Vector3(3, 2, -6)); }); - test('get gltf animation names', () async { + test('play/stop gltf animation', () async { await testHelper.withViewer((viewer) async { final cube = await viewer .loadGltf("${testHelper.testDir}/assets/cube_with_morph_targets.glb"); await viewer.addToScene(cube); - await testHelper.capture(viewer.view, "gltf_animation_stopped"); final animationNames = await cube.getGltfAnimationNames(); expect(animationNames.first, "CubeAction"); + await testHelper.capture(viewer.view, "gltf_animation_rest"); + + await viewer.render(); + await cube.playGltfAnimation(0); - await Future.delayed(Duration(seconds: 1)); + + await Future.delayed(Duration(milliseconds: 750)); await viewer.render(); await testHelper.capture(viewer.view, "gltf_animation_started"); + await viewer.render(); + await Future.delayed(Duration(milliseconds: 1000)); + await viewer.render(); + await cube.stopGltfAnimation(0); + await viewer.render(); + await testHelper.capture(viewer.view, "gltf_animation_stopped"); + + await viewer.destroyAsset(cube); + + await viewer.render(); + + await testHelper.capture(viewer.view, "gltf_asset_destroyed"); }, bg: kRed); }); } diff --git a/thermion_dart/test/assets/BusterDrone b/thermion_dart/test/assets/BusterDrone new file mode 120000 index 00000000..d05a47ec --- /dev/null +++ b/thermion_dart/test/assets/BusterDrone @@ -0,0 +1 @@ +../../../examples/assets/BusterDrone \ No newline at end of file