From 572a9450253c2b588168143bbf806f57ad5fc105 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Fri, 17 Nov 2023 23:44:30 +0800 Subject: [PATCH] add support for multiple bone animations using quaternions --- example/lib/main.dart | 2 + example/lib/menus/asset_submenu.dart | 23 +- ios/include/AssetManager.hpp | 174 +-- ios/include/FlutterFilamentApi.h | 245 ++-- ios/include/FlutterFilamentFFIApi.h | 11 - ios/include/SceneAsset.hpp | 73 +- ios/src/AssetManager.cpp | 1868 +++++++++++++------------- ios/src/FlutterFilamentApi.cpp | 34 +- ios/src/FlutterFilamentFFIApi.cpp | 12 - lib/animations/animation_data.dart | 4 +- lib/filament_controller.dart | 7 +- lib/filament_controller_ffi.dart | 55 +- lib/generated_bindings.dart | 12 +- 13 files changed, 1266 insertions(+), 1254 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index da2500fb..52eedd42 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -97,6 +97,8 @@ class ExampleWidgetState extends State { await _filamentController!.setRendering(true); shapes = await _filamentController!.loadGlb("assets/shapes/shapes.glb"); + ExampleWidgetState.animations = await _filamentController! + .getAnimationNames(ExampleWidgetState.shapes!); hasSkybox = true; rendering = true; }); diff --git a/example/lib/menus/asset_submenu.dart b/example/lib/menus/asset_submenu.dart index 5eaa68b3..b1e9990d 100644 --- a/example/lib/menus/asset_submenu.dart +++ b/example/lib/menus/asset_submenu.dart @@ -2,10 +2,13 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; +import 'package:flutter_filament/animations/animation_data.dart'; import 'package:flutter_filament/filament_controller.dart'; import 'package:flutter_filament_example/main.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:vector_math/vector_math_64.dart' as v; + class AssetSubmenu extends StatefulWidget { final FilamentController controller; const AssetSubmenu({super.key, required this.controller}); @@ -65,7 +68,25 @@ class _AssetSubmenuState extends State { 0, Matrix4.rotationX(pi / 2)); }, - child: const Text('Set bone tranform to identity for Cylinder')), + child: + const Text('Set bone transform for Cylinder (pi/2 rotation X)')), + MenuItemButton( + onPressed: ExampleWidgetState.shapes == null + ? null + : () async { + await widget.controller.addBoneAnimation( + ExampleWidgetState.shapes!, + BoneAnimationData( + "Bone", + ["Cylinder"], + List.generate( + 60, + (idx) => v.Quaternion.axisAngle( + v.Vector3(0, 0, 1), pi * (idx / 60)) + .normalized()), + 1000.0 / 30.0)); + }, + child: const Text('Set bone transform animation for Cylinder')), MenuItemButton( onPressed: () async { var names = await widget.controller diff --git a/ios/include/AssetManager.hpp b/ios/include/AssetManager.hpp index 14e70ab6..64b631d5 100644 --- a/ios/include/AssetManager.hpp +++ b/ios/include/AssetManager.hpp @@ -13,92 +13,108 @@ typedef int32_t EntityId; -namespace polyvox { +namespace polyvox +{ using namespace filament; using namespace filament::gltfio; - class AssetManager { - public: - AssetManager(const ResourceLoaderWrapper* const loader, - NameComponentManager* ncm, - Engine* engine, - Scene* scene, - const char* uberArchivePath); - ~AssetManager(); - EntityId loadGltf(const char* uri, const char* relativeResourcePath); - EntityId loadGlb(const char* uri, bool unlit); - FilamentAsset* getAssetByEntityId(EntityId entityId); - void remove(EntityId entity); - void destroyAll(); - unique_ptr> getAnimationNames(EntityId entity); - float getAnimationDuration(EntityId entity, int animationIndex); - unique_ptr> getMorphTargetNames(EntityId entity, const char *meshName); - void transformToUnitCube(EntityId e); - inline void updateTransform(EntityId e); - void setScale(EntityId e, float scale); - void setPosition(EntityId e, float x, float y, float z); - void setRotation(EntityId e, float rads, float x, float y, float z); - const utils::Entity *getCameraEntities(EntityId e); - size_t getCameraEntityCount(EntityId e); - const utils::Entity* getLightEntities(EntityId e) const noexcept; - size_t getLightEntityCount(EntityId e) const noexcept; - void updateAnimations(); - bool setMaterialColor(EntityId e, const char* meshName, int materialInstance, const float r, const float g, const float b, const float a); + class AssetManager + { + public: + AssetManager(const ResourceLoaderWrapper *const loader, + NameComponentManager *ncm, + Engine *engine, + Scene *scene, + const char *uberArchivePath); + ~AssetManager(); + EntityId loadGltf(const char *uri, const char *relativeResourcePath); + EntityId loadGlb(const char *uri, bool unlit); + FilamentAsset *getAssetByEntityId(EntityId entityId); + void remove(EntityId entity); + void destroyAll(); + unique_ptr> getAnimationNames(EntityId entity); + float getAnimationDuration(EntityId entity, int animationIndex); + unique_ptr> getMorphTargetNames(EntityId entity, const char *meshName); + void transformToUnitCube(EntityId e); + inline void updateTransform(EntityId e); + void setScale(EntityId e, float scale); + void setPosition(EntityId e, float x, float y, float z); + void setRotation(EntityId e, float rads, float x, float y, float z); + const utils::Entity *getCameraEntities(EntityId e); + size_t getCameraEntityCount(EntityId e); + const utils::Entity *getLightEntities(EntityId e) const noexcept; + size_t getLightEntityCount(EntityId e) const noexcept; + void updateAnimations(); + bool setMaterialColor(EntityId e, const char *meshName, int materialInstance, const float r, const float g, const float b, const float a); - bool setMorphAnimationBuffer( - EntityId entityId, - const char* entityName, - const float* const morphData, - const int* const morphIndices, - int numMorphTargets, - int numFrames, - float frameLengthInMs); - - void setMorphTargetWeights(EntityId entityId, const char* const entityName, const float* const weights, int count); + bool setMorphAnimationBuffer( + EntityId entityId, + const char *entityName, + const float *const morphData, + const int *const morphIndices, + int numMorphTargets, + int numFrames, + float frameLengthInMs); - bool setBoneAnimationBuffer( - EntityId entity, - const float* const frameData, - int numFrames, - int numBones, - const char** const boneNames, - const char** const meshName, - int numMeshTargets, - float frameLengthInMs); - void playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f); - void stopAnimation(EntityId e, int index); - void setMorphTargetWeights(const char* const entityName, float *weights, int count); - void loadTexture(EntityId entity, const char* resourcePath, int renderableIndex); - void setAnimationFrame(EntityId entity, int animationIndex, int animationFrame); - bool hide(EntityId entity, const char* meshName); - bool reveal(EntityId entity, const char* meshName); - const char* getNameForEntity(EntityId entityId); + void setMorphTargetWeights(EntityId entityId, const char *const entityName, const float *const weights, int count); - bool setBoneTransform(EntityId entityId, const char* entityName, int skinIndex, int boneIndex, math::mat4f transform); - - private: - AssetLoader* _assetLoader = nullptr; - const ResourceLoaderWrapper* const _resourceLoaderWrapper; - NameComponentManager* _ncm = nullptr; - Engine* _engine; - Scene* _scene; - MaterialProvider* _ubershaderProvider = nullptr; - gltfio::ResourceLoader* _gltfResourceLoader = nullptr; - gltfio::TextureProvider* _stbDecoder = nullptr; - gltfio::TextureProvider* _ktxDecoder = nullptr; - std::mutex _animationMutex; - - vector _assets; - tsl::robin_map _entityIdLookup; - - utils::Entity findEntityByName( - SceneAsset asset, - const char* entityName - ); - - inline void updateTransform(SceneAsset& asset); + /// @brief Set the local transform for the bone at boneIndex/skinIndex in the given entity. + /// @param entityId + /// @param entityName + /// @param skinIndex + /// @param boneIndex + /// @param transform + /// @return + bool setBoneTransform(EntityId entityId, const char *entityName, int skinIndex, int boneIndex, math::mat4f transform); - inline void setBoneTransformFromAnimation(SceneAsset& asset, int frameNumber); + /// @brief Set frame data to animate the given bones/entities. + /// @param entity + /// @param frameData frame data as quaternions + /// @param numFrames + /// @param boneName + /// @param meshName + /// @param numMeshTargets + /// @param frameLengthInMs + /// @return + bool addBoneAnimation( + EntityId entity, + const float *const frameData, + int numFrames, + const char *const boneName, + const char **const meshName, + int numMeshTargets, + float frameLengthInMs); + void playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f); + void stopAnimation(EntityId e, int index); + void setMorphTargetWeights(const char *const entityName, float *weights, int count); + void loadTexture(EntityId entity, const char *resourcePath, int renderableIndex); + void setAnimationFrame(EntityId entity, int animationIndex, int animationFrame); + bool hide(EntityId entity, const char *meshName); + bool reveal(EntityId entity, const char *meshName); + const char *getNameForEntity(EntityId entityId); + + private: + AssetLoader *_assetLoader = nullptr; + const ResourceLoaderWrapper *const _resourceLoaderWrapper; + NameComponentManager *_ncm = nullptr; + Engine *_engine; + Scene *_scene; + MaterialProvider *_ubershaderProvider = nullptr; + gltfio::ResourceLoader *_gltfResourceLoader = nullptr; + gltfio::TextureProvider *_stbDecoder = nullptr; + gltfio::TextureProvider *_ktxDecoder = nullptr; + std::mutex _animationMutex; + + vector _assets; + tsl::robin_map _entityIdLookup; + + utils::Entity findEntityByName( + SceneAsset asset, + const char *entityName); + + inline void updateTransform(SceneAsset &asset); + + void updateBoneTransformFromAnimationBuffer(const BoneAnimation& animation, int frameNumber); }; } diff --git a/ios/include/FlutterFilamentApi.h b/ios/include/FlutterFilamentApi.h index ea2a71ac..0478e732 100644 --- a/ios/include/FlutterFilamentApi.h +++ b/ios/include/FlutterFilamentApi.h @@ -1,17 +1,17 @@ #ifndef _FLUTTER_FILAMENT_API_H #define _FLUTTER_FILAMENT_API_H -#ifdef _WIN32 +#ifdef _WIN32 #ifdef IS_DLL -#define FLUTTER_PLUGIN_EXPORT __declspec( dllimport ) +#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) #else -#define FLUTTER_PLUGIN_EXPORT __declspec( dllexport ) +#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) #endif #else #define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) #endif -// we copy the LLVM here rather than including, +// we copy the LLVM here rather than including, // because on Windows it's difficult to pin the exact location which confuses dart ffigen #ifndef __STDBOOL_H @@ -50,131 +50,126 @@ typedef int32_t EntityId; typedef int32_t _ManipulatorMode; #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -FLUTTER_PLUGIN_EXPORT const void* create_filament_viewer(const void* const context, const ResourceLoaderWrapper* const loader, void* const platform, const char* uberArchivePath); -FLUTTER_PLUGIN_EXPORT void destroy_filament_viewer(const void* const viewer); -FLUTTER_PLUGIN_EXPORT ResourceLoaderWrapper* make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void* owner); -FLUTTER_PLUGIN_EXPORT void* get_asset_manager(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void create_render_target(const void* const viewer, intptr_t texture, uint32_t width, uint32_t height); -FLUTTER_PLUGIN_EXPORT void clear_background_image(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void set_background_image(const void* const viewer, const char *path, bool fillHeight); -FLUTTER_PLUGIN_EXPORT void set_background_image_position(const void* const viewer, float x, float y, bool clamp); -FLUTTER_PLUGIN_EXPORT void set_background_color(const void* const viewer, const float r, const float g, const float b, const float a); -FLUTTER_PLUGIN_EXPORT void set_tone_mapping(const void* const viewer, int toneMapping); -FLUTTER_PLUGIN_EXPORT void set_bloom(const void* const viewer, float strength); -FLUTTER_PLUGIN_EXPORT void load_skybox(const void* const viewer, const char *skyboxPath); -FLUTTER_PLUGIN_EXPORT void load_ibl(const void* const viewer, const char *iblPath, float intensity); -FLUTTER_PLUGIN_EXPORT void remove_skybox(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void remove_ibl(const void* const viewer); -FLUTTER_PLUGIN_EXPORT EntityId add_light(const void* const viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows); -FLUTTER_PLUGIN_EXPORT void remove_light(const void* const viewer, EntityId entityId); -FLUTTER_PLUGIN_EXPORT void clear_lights(const void* const viewer); -FLUTTER_PLUGIN_EXPORT EntityId load_glb(void *assetManager, const char *assetPath, bool unlit); -FLUTTER_PLUGIN_EXPORT EntityId load_gltf(void *assetManager, const char *assetPath, const char *relativePath); -FLUTTER_PLUGIN_EXPORT bool set_camera(const void* const viewer, EntityId asset, const char *nodeName); -FLUTTER_PLUGIN_EXPORT void set_view_frustum_culling(const void* const viewer, bool enabled); -FLUTTER_PLUGIN_EXPORT void render( - const void* const viewer, - uint64_t frameTimeInNanos, - void* pixelBuffer, - void (*callback)(void *buf, size_t size, void *data), - void* data - ); -FLUTTER_PLUGIN_EXPORT void create_swap_chain(const void* const viewer, const void* const window, uint32_t width, uint32_t height); -FLUTTER_PLUGIN_EXPORT void destroy_swap_chain(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void set_frame_interval(const void* const viewer, float interval); -FLUTTER_PLUGIN_EXPORT void update_viewport_and_camera_projection(const void* const viewer, uint32_t width, uint32_t height, float scaleFactor); -FLUTTER_PLUGIN_EXPORT void scroll_begin(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void scroll_update(const void* const viewer, float x, float y, float z); -FLUTTER_PLUGIN_EXPORT void scroll_end(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void grab_begin(const void* const viewer, float x, float y, bool pan); -FLUTTER_PLUGIN_EXPORT void grab_update(const void* const viewer, float x, float y); -FLUTTER_PLUGIN_EXPORT void grab_end(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void apply_weights( - void* assetManager, - EntityId asset, - const char *const entityName, - float *const weights, - int count - ); -FLUTTER_PLUGIN_EXPORT void set_morph_target_weights( - void* assetManager, - EntityId asset, - const char *const entityName, - const float *const morphData, - int numWeights - ); -FLUTTER_PLUGIN_EXPORT bool set_morph_animation( - void* assetManager, - EntityId asset, - const char *const entityName, - const float *const morphData, - const int* const morphIndices, - int numMorphTargets, - int numFrames, - float frameLengthInMs); -FLUTTER_PLUGIN_EXPORT void set_bone_animation( - void* assetManager, - EntityId asset, - const float* const frameData, - int numFrames, - int numBones, - const char** const boneNames, - const char** const meshName, - int numMeshTargets, - float frameLengthInMs); -FLUTTER_PLUGIN_EXPORT bool set_bone_transform( - void* assetManager, - EntityId asset, - const char* entityName, - const float* const transform, - int boneIndex - ); -FLUTTER_PLUGIN_EXPORT void play_animation(void* assetManager, EntityId asset, int index, bool loop, bool reverse, bool replaceActive, float crossfade); -FLUTTER_PLUGIN_EXPORT void set_animation_frame(void* assetManager, EntityId asset, int animationIndex, int animationFrame); -FLUTTER_PLUGIN_EXPORT void stop_animation(void* assetManager, EntityId asset, int index); -FLUTTER_PLUGIN_EXPORT int get_animation_count(void* assetManager, EntityId asset); -FLUTTER_PLUGIN_EXPORT void get_animation_name(void* assetManager, EntityId asset, char *const outPtr, int index); -FLUTTER_PLUGIN_EXPORT float get_animation_duration(void* assetManager, EntityId asset, int index); -FLUTTER_PLUGIN_EXPORT void get_morph_target_name(void* assetManager, EntityId asset, const char *meshName, char *const outPtr, int index); -FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count(void* assetManager, EntityId asset, const char *meshName); -FLUTTER_PLUGIN_EXPORT void remove_asset(const void* const viewer, EntityId asset); -FLUTTER_PLUGIN_EXPORT void clear_assets(const void* const viewer); -FLUTTER_PLUGIN_EXPORT bool set_material_color(void* assetManager, EntityId asset, const char* meshName, int materialIndex, const float r, const float g, const float b, const float a); -FLUTTER_PLUGIN_EXPORT void transform_to_unit_cube(void* assetManager, EntityId asset); -FLUTTER_PLUGIN_EXPORT void set_position(void* assetManager, EntityId asset, float x, float y, float z); -FLUTTER_PLUGIN_EXPORT void set_rotation(void* assetManager, EntityId asset, float rads, float x, float y, float z); -FLUTTER_PLUGIN_EXPORT void set_scale(void* assetManager, EntityId asset, float scale); + FLUTTER_PLUGIN_EXPORT const void *create_filament_viewer(const void *const context, const ResourceLoaderWrapper *const loader, void *const platform, const char *uberArchivePath); + FLUTTER_PLUGIN_EXPORT void destroy_filament_viewer(const void *const viewer); + FLUTTER_PLUGIN_EXPORT ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *owner); + FLUTTER_PLUGIN_EXPORT void *get_asset_manager(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void create_render_target(const void *const viewer, intptr_t texture, uint32_t width, uint32_t height); + FLUTTER_PLUGIN_EXPORT void clear_background_image(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void set_background_image(const void *const viewer, const char *path, bool fillHeight); + FLUTTER_PLUGIN_EXPORT void set_background_image_position(const void *const viewer, float x, float y, bool clamp); + FLUTTER_PLUGIN_EXPORT void set_background_color(const void *const viewer, const float r, const float g, const float b, const float a); + FLUTTER_PLUGIN_EXPORT void set_tone_mapping(const void *const viewer, int toneMapping); + FLUTTER_PLUGIN_EXPORT void set_bloom(const void *const viewer, float strength); + FLUTTER_PLUGIN_EXPORT void load_skybox(const void *const viewer, const char *skyboxPath); + FLUTTER_PLUGIN_EXPORT void load_ibl(const void *const viewer, const char *iblPath, float intensity); + FLUTTER_PLUGIN_EXPORT void remove_skybox(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void remove_ibl(const void *const viewer); + FLUTTER_PLUGIN_EXPORT EntityId add_light(const void *const viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows); + FLUTTER_PLUGIN_EXPORT void remove_light(const void *const viewer, EntityId entityId); + FLUTTER_PLUGIN_EXPORT void clear_lights(const void *const viewer); + FLUTTER_PLUGIN_EXPORT EntityId load_glb(void *assetManager, const char *assetPath, bool unlit); + FLUTTER_PLUGIN_EXPORT EntityId load_gltf(void *assetManager, const char *assetPath, const char *relativePath); + FLUTTER_PLUGIN_EXPORT bool set_camera(const void *const viewer, EntityId asset, const char *nodeName); + FLUTTER_PLUGIN_EXPORT void set_view_frustum_culling(const void *const viewer, bool enabled); + FLUTTER_PLUGIN_EXPORT void render( + const void *const viewer, + uint64_t frameTimeInNanos, + void *pixelBuffer, + void (*callback)(void *buf, size_t size, void *data), + void *data); + FLUTTER_PLUGIN_EXPORT void create_swap_chain(const void *const viewer, const void *const window, uint32_t width, uint32_t height); + FLUTTER_PLUGIN_EXPORT void destroy_swap_chain(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void set_frame_interval(const void *const viewer, float interval); + FLUTTER_PLUGIN_EXPORT void update_viewport_and_camera_projection(const void *const viewer, uint32_t width, uint32_t height, float scaleFactor); + FLUTTER_PLUGIN_EXPORT void scroll_begin(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void scroll_update(const void *const viewer, float x, float y, float z); + FLUTTER_PLUGIN_EXPORT void scroll_end(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void grab_begin(const void *const viewer, float x, float y, bool pan); + FLUTTER_PLUGIN_EXPORT void grab_update(const void *const viewer, float x, float y); + FLUTTER_PLUGIN_EXPORT void grab_end(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void apply_weights( + void *assetManager, + EntityId asset, + const char *const entityName, + float *const weights, + int count); + FLUTTER_PLUGIN_EXPORT void set_morph_target_weights( + void *assetManager, + EntityId asset, + const char *const entityName, + const float *const morphData, + int numWeights); + FLUTTER_PLUGIN_EXPORT bool set_morph_animation( + void *assetManager, + EntityId asset, + const char *const entityName, + const float *const morphData, + const int *const morphIndices, + int numMorphTargets, + int numFrames, + float frameLengthInMs); + FLUTTER_PLUGIN_EXPORT void add_bone_animation( + void *assetManager, + EntityId asset, + const float *const frameData, + int numFrames, + const char *const boneName, + const char **const meshNames, + int numMeshTargets, + float frameLengthInMs); + FLUTTER_PLUGIN_EXPORT bool set_bone_transform( + void *assetManager, + EntityId asset, + const char *entityName, + const float *const transform, + int boneIndex); + FLUTTER_PLUGIN_EXPORT void play_animation(void *assetManager, EntityId asset, int index, bool loop, bool reverse, bool replaceActive, float crossfade); + FLUTTER_PLUGIN_EXPORT void set_animation_frame(void *assetManager, EntityId asset, int animationIndex, int animationFrame); + FLUTTER_PLUGIN_EXPORT void stop_animation(void *assetManager, EntityId asset, int index); + FLUTTER_PLUGIN_EXPORT int get_animation_count(void *assetManager, EntityId asset); + FLUTTER_PLUGIN_EXPORT void get_animation_name(void *assetManager, EntityId asset, char *const outPtr, int index); + FLUTTER_PLUGIN_EXPORT float get_animation_duration(void *assetManager, EntityId asset, int index); + FLUTTER_PLUGIN_EXPORT void get_morph_target_name(void *assetManager, EntityId asset, const char *meshName, char *const outPtr, int index); + FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count(void *assetManager, EntityId asset, const char *meshName); + FLUTTER_PLUGIN_EXPORT void remove_asset(const void *const viewer, EntityId asset); + FLUTTER_PLUGIN_EXPORT void clear_assets(const void *const viewer); + FLUTTER_PLUGIN_EXPORT bool set_material_color(void *assetManager, EntityId asset, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a); + FLUTTER_PLUGIN_EXPORT void transform_to_unit_cube(void *assetManager, EntityId asset); + FLUTTER_PLUGIN_EXPORT void set_position(void *assetManager, EntityId asset, float x, float y, float z); + FLUTTER_PLUGIN_EXPORT void set_rotation(void *assetManager, EntityId asset, float rads, float x, float y, float z); + FLUTTER_PLUGIN_EXPORT void set_scale(void *assetManager, EntityId asset, float scale); -// Camera methods -FLUTTER_PLUGIN_EXPORT void move_camera_to_asset(const void* const viewer, EntityId asset); -FLUTTER_PLUGIN_EXPORT void set_view_frustum_culling(const void* const viewer, bool enabled); -FLUTTER_PLUGIN_EXPORT void set_camera_exposure(const void* const viewer, float aperture, float shutterSpeed, float sensitivity); -FLUTTER_PLUGIN_EXPORT void set_camera_position(const void* const viewer, float x, float y, float z); -FLUTTER_PLUGIN_EXPORT void get_camera_position(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void set_camera_rotation(const void* const viewer, float rads, float x, float y, float z); -FLUTTER_PLUGIN_EXPORT void set_camera_model_matrix(const void* const viewer, const float *const matrix); -FLUTTER_PLUGIN_EXPORT const double* const get_camera_model_matrix(const void* const viewer); -FLUTTER_PLUGIN_EXPORT const double* const get_camera_view_matrix(const void* const viewer); -FLUTTER_PLUGIN_EXPORT const double* const get_camera_projection_matrix(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void set_camera_projection_matrix(const void* const viewer, const double *const matrix, double near, double far); -FLUTTER_PLUGIN_EXPORT void set_camera_culling(const void* const viewer, double near, double far); -FLUTTER_PLUGIN_EXPORT const double* const get_camera_culling_projection_matrix(const void* const viewer); -FLUTTER_PLUGIN_EXPORT const double* const get_camera_frustum(const void* const viewer); -FLUTTER_PLUGIN_EXPORT void set_camera_focal_length(const void* const viewer, float focalLength); -FLUTTER_PLUGIN_EXPORT void set_camera_focus_distance(const void* const viewer, float focusDistance); -FLUTTER_PLUGIN_EXPORT void set_camera_manipulator_options(const void* const viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed); + // Camera methods + FLUTTER_PLUGIN_EXPORT void move_camera_to_asset(const void *const viewer, EntityId asset); + FLUTTER_PLUGIN_EXPORT void set_view_frustum_culling(const void *const viewer, bool enabled); + FLUTTER_PLUGIN_EXPORT void set_camera_exposure(const void *const viewer, float aperture, float shutterSpeed, float sensitivity); + FLUTTER_PLUGIN_EXPORT void set_camera_position(const void *const viewer, float x, float y, float z); + FLUTTER_PLUGIN_EXPORT void get_camera_position(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void set_camera_rotation(const void *const viewer, float rads, float x, float y, float z); + FLUTTER_PLUGIN_EXPORT void set_camera_model_matrix(const void *const viewer, const float *const matrix); + FLUTTER_PLUGIN_EXPORT const double *const get_camera_model_matrix(const void *const viewer); + FLUTTER_PLUGIN_EXPORT const double *const get_camera_view_matrix(const void *const viewer); + FLUTTER_PLUGIN_EXPORT const double *const get_camera_projection_matrix(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void set_camera_projection_matrix(const void *const viewer, const double *const matrix, double near, double far); + FLUTTER_PLUGIN_EXPORT void set_camera_culling(const void *const viewer, double near, double far); + FLUTTER_PLUGIN_EXPORT const double *const get_camera_culling_projection_matrix(const void *const viewer); + FLUTTER_PLUGIN_EXPORT const double *const get_camera_frustum(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void set_camera_focal_length(const void *const viewer, float focalLength); + FLUTTER_PLUGIN_EXPORT void set_camera_focus_distance(const void *const viewer, float focusDistance); + FLUTTER_PLUGIN_EXPORT void set_camera_manipulator_options(const void *const viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed); - -FLUTTER_PLUGIN_EXPORT int hide_mesh(void* assetManager, EntityId asset, const char* meshName); -FLUTTER_PLUGIN_EXPORT int reveal_mesh(void* assetManager, EntityId asset, const char* meshName); -FLUTTER_PLUGIN_EXPORT void set_post_processing(void* const viewer, bool enabled); -FLUTTER_PLUGIN_EXPORT void pick(void* const viewer, int x, int y, EntityId* entityId); -FLUTTER_PLUGIN_EXPORT const char* get_name_for_entity(void* const assetManager, const EntityId entityId); -FLUTTER_PLUGIN_EXPORT void ios_dummy(); -FLUTTER_PLUGIN_EXPORT void flutter_filament_free(void* ptr); + FLUTTER_PLUGIN_EXPORT int hide_mesh(void *assetManager, EntityId asset, const char *meshName); + FLUTTER_PLUGIN_EXPORT int reveal_mesh(void *assetManager, EntityId asset, const char *meshName); + FLUTTER_PLUGIN_EXPORT void set_post_processing(void *const viewer, bool enabled); + FLUTTER_PLUGIN_EXPORT void pick(void *const viewer, int x, int y, EntityId *entityId); + FLUTTER_PLUGIN_EXPORT const char *get_name_for_entity(void *const assetManager, const EntityId entityId); + FLUTTER_PLUGIN_EXPORT void ios_dummy(); + FLUTTER_PLUGIN_EXPORT void flutter_filament_free(void *ptr); #ifdef __cplusplus } #endif diff --git a/ios/include/FlutterFilamentFFIApi.h b/ios/include/FlutterFilamentFFIApi.h index befbbcf1..a8d634f1 100644 --- a/ios/include/FlutterFilamentFFIApi.h +++ b/ios/include/FlutterFilamentFFIApi.h @@ -66,17 +66,6 @@ FLUTTER_PLUGIN_EXPORT bool set_morph_animation_ffi( int numMorphTargets, int numFrames, float frameLengthInMs); -FLUTTER_PLUGIN_EXPORT -FLUTTER_PLUGIN_EXPORT void set_bone_animation_ffi( - void* const assetManager, - EntityId asset, - const float* const frameData, - int numFrames, - int numBones, - const char** const boneNames, - const char** const meshName, - int numMeshTargets, - float frameLengthInMs); FLUTTER_PLUGIN_EXPORT void play_animation_ffi(void* const assetManager, EntityId asset, int index, bool loop, bool reverse, bool replaceActive, float crossfade); FLUTTER_PLUGIN_EXPORT void set_animation_frame_ffi(void* const assetManager, EntityId asset, int animationIndex, int animationFrame); FLUTTER_PLUGIN_EXPORT void stop_animation_ffi(void* const assetManager, EntityId asset, int index); diff --git a/ios/include/SceneAsset.hpp b/ios/include/SceneAsset.hpp index da5038f4..0a2e23d3 100644 --- a/ios/include/SceneAsset.hpp +++ b/ios/include/SceneAsset.hpp @@ -36,50 +36,46 @@ namespace polyvox { }; struct AnimationStatus { - time_point_t mStart = time_point_t::max(); - bool mLoop = false; - bool mReverse = false; - float mDuration = 0; - AnimationType type; - int gltfIndex = -1; + time_point_t start = time_point_t::max(); + bool loop = false; + bool reverse = false; + float durationInSecs = 0; + }; + + struct GltfAnimation : AnimationStatus { + int index = -1; }; // - // Use this to manually construct a buffer of frame data for morph animations. + // Use this to construct a dynamic (i.e. non-glTF embedded) morph target animation. // - struct MorphAnimationBuffer { - utils::Entity mMeshTarget; - int mNumFrames = -1; - float mFrameLengthInMs = 0; - vector mFrameData; - vector mMorphIndices; + struct MorphAnimation : AnimationStatus { + utils::Entity meshTarget; + int numFrames = -1; + float frameLengthInMs = 0; + vector frameData; + vector morphIndices; + int lengthInFrames; }; // - // Use this to construct a dynamic (i.e. non-glTF embedded) bone animation. - // Only a single animation is supported at any time (i.e you can't blend animations). - // Multiple bones are supported but these must be skinned to a single mesh target. + // Use this to construct a dynamic (i.e. non-glTF embedded) bone/joint animation. // - struct BoneAnimationBuffer { - vector mMeshTargets; - vector mBones; - vector mBaseTransforms; - // vector mBaseTranslations; // these are the base transforms for the bones we will animate; the translations/rotations in mFrameData will be relative to this. - // vector mBaseRotations; // these are the base transforms for the bones we will animate; the translations/rotations in mFrameData will be relative to this. - // vector mBaseScales; // these are the base transforms for the bones we will animate; the translations/rotations in mFrameData will be relative to this. + struct BoneAnimation : AnimationStatus { + uint8_t boneIndex; + vector meshTargets; size_t skinIndex = 0; - int mNumFrames = -1; - float mFrameLengthInMs = 0; - vector mFrameData; + int lengthInFrames; + float frameLengthInMs = 0; + vector frameData; }; struct SceneAsset { - bool mAnimating = false; - FilamentAsset* mAsset = nullptr; - Animator* mAnimator = nullptr; - - // vector containing AnimationStatus structs for the morph, bone and/or glTF animations. - vector mAnimations; + FilamentAsset* asset = nullptr; + + vector gltfAnimations; + vector morphAnimations; + vector boneAnimations; // the index of the last active glTF animation, // used to cross-fade @@ -87,24 +83,19 @@ namespace polyvox { float fadeDuration = 0.0f; float fadeOutAnimationStart = 0.0f; - MorphAnimationBuffer mMorphAnimationBuffer; - BoneAnimationBuffer mBoneAnimationBuffer; - // a slot to preload textures - filament::Texture* mTexture = nullptr; + filament::Texture* texture = nullptr; // initialized to identity - math::mat4f mPosition; + math::mat4f position; // initialized to identity - math::mat4f mRotation; + math::mat4f rotation; float mScale = 1; SceneAsset( FilamentAsset* asset - ) : mAsset(asset) { - mAnimator = mAsset->getInstance()->getAnimator(); - } + ) : asset(asset) {} }; } diff --git a/ios/src/AssetManager.cpp b/ios/src/AssetManager.cpp index 3db9c65d..06766ac7 100644 --- a/ios/src/AssetManager.cpp +++ b/ios/src/AssetManager.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include @@ -25,1013 +25,1055 @@ #include "material/FileMaterialProvider.hpp" #include "gltfio/materials/uberarchive.h" -extern "C" { +extern "C" +{ #include "material/image.h" } -namespace polyvox { +namespace polyvox +{ -using namespace std; -using namespace std::chrono; -using namespace image; -using namespace utils; -using namespace filament; -using namespace filament::gltfio; + using namespace std; + using namespace std::chrono; + using namespace image; + using namespace utils; + using namespace filament; + using namespace filament::gltfio; -AssetManager::AssetManager(const ResourceLoaderWrapper* const resourceLoaderWrapper, - NameComponentManager* ncm, - Engine* engine, - Scene* scene, - const char* uberArchivePath) -: _resourceLoaderWrapper(resourceLoaderWrapper), -_ncm(ncm), -_engine(engine), -_scene(scene) { - - _stbDecoder = createStbProvider(_engine); - _ktxDecoder = createKtx2Provider(_engine); - - _gltfResourceLoader = new ResourceLoader({.engine = _engine, - .normalizeSkinningWeights = true }); + AssetManager::AssetManager(const ResourceLoaderWrapper *const resourceLoaderWrapper, + NameComponentManager *ncm, + Engine *engine, + Scene *scene, + const char *uberArchivePath) + : _resourceLoaderWrapper(resourceLoaderWrapper), + _ncm(ncm), + _engine(engine), + _scene(scene) + { - if(uberArchivePath) { - auto uberdata = resourceLoaderWrapper->load(uberArchivePath); - if (!uberdata.data) { - Log("Failed to load ubershader material. This is fatal."); + _stbDecoder = createStbProvider(_engine); + _ktxDecoder = createKtx2Provider(_engine); + + _gltfResourceLoader = new ResourceLoader({.engine = _engine, + .normalizeSkinningWeights = true}); + + if (uberArchivePath) + { + auto uberdata = resourceLoaderWrapper->load(uberArchivePath); + if (!uberdata.data) + { + Log("Failed to load ubershader material. This is fatal."); + } + _ubershaderProvider = gltfio::createUbershaderProvider(_engine, uberdata.data, uberdata.size); + resourceLoaderWrapper->free(uberdata); } - _ubershaderProvider = gltfio::createUbershaderProvider(_engine, uberdata.data, uberdata.size); - resourceLoaderWrapper->free(uberdata); - } else { - _ubershaderProvider = gltfio::createUbershaderProvider( - _engine, UBERARCHIVE_DEFAULT_DATA, UBERARCHIVE_DEFAULT_SIZE); + else + { + _ubershaderProvider = gltfio::createUbershaderProvider( + _engine, UBERARCHIVE_DEFAULT_DATA, UBERARCHIVE_DEFAULT_SIZE); + } + Log("Created ubershader provider."); + + EntityManager &em = EntityManager::get(); + + _assetLoader = AssetLoader::create({_engine, _ubershaderProvider, _ncm, &em}); + _gltfResourceLoader->addTextureProvider("image/ktx2", _ktxDecoder); + _gltfResourceLoader->addTextureProvider("image/png", _stbDecoder); + _gltfResourceLoader->addTextureProvider("image/jpeg", _stbDecoder); } - Log("Created ubershader provider."); - EntityManager &em = EntityManager::get(); - - _assetLoader = AssetLoader::create({_engine, _ubershaderProvider, _ncm, &em }); - _gltfResourceLoader->addTextureProvider("image/ktx2", _ktxDecoder); - _gltfResourceLoader->addTextureProvider("image/png", _stbDecoder); - _gltfResourceLoader->addTextureProvider("image/jpeg", _stbDecoder); -} - -AssetManager::~AssetManager() { - _gltfResourceLoader->asyncCancelLoad(); - _ubershaderProvider->destroyMaterials(); - destroyAll(); - AssetLoader::destroy(&_assetLoader); - -} - -EntityId AssetManager::loadGltf(const char *uri, - const char *relativeResourcePath) { - ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); - - // Parse the glTF file and create Filament entities. - FilamentAsset *asset = _assetLoader->createAsset((uint8_t *)rbuf.data, rbuf.size); - - if (!asset) { - Log("Unable to parse asset"); - return 0; + AssetManager::~AssetManager() + { + _gltfResourceLoader->asyncCancelLoad(); + _ubershaderProvider->destroyMaterials(); + destroyAll(); + AssetLoader::destroy(&_assetLoader); } - - const char *const *const resourceUris = asset->getResourceUris(); - const size_t resourceUriCount = asset->getResourceUriCount(); - std::vector resourceBuffers; - - for (size_t i = 0; i < resourceUriCount; i++) { - string uri = string(relativeResourcePath) + string("/") + string(resourceUris[i]); - Log("Loading resource URI from relative path %s", resourceUris[i], uri.c_str()); - ResourceBuffer buf = _resourceLoaderWrapper->load(uri.c_str()); - - resourceBuffers.push_back(buf); - - ResourceLoader::BufferDescriptor b(buf.data, buf.size); - _gltfResourceLoader->addResourceData(resourceUris[i], std::move(b)); - } - - // load resources synchronously - if (!_gltfResourceLoader->loadResources(asset)) { - Log("Unknown error loading glTF asset"); - _resourceLoaderWrapper->free(rbuf); - for(auto& rb : resourceBuffers) { + EntityId AssetManager::loadGltf(const char *uri, + const char *relativeResourcePath) + { + ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); + + // Parse the glTF file and create Filament entities. + FilamentAsset *asset = _assetLoader->createAsset((uint8_t *)rbuf.data, rbuf.size); + + if (!asset) + { + Log("Unable to parse asset"); + return 0; + } + + const char *const *const resourceUris = asset->getResourceUris(); + const size_t resourceUriCount = asset->getResourceUriCount(); + + std::vector resourceBuffers; + + for (size_t i = 0; i < resourceUriCount; i++) + { + string uri = string(relativeResourcePath) + string("/") + string(resourceUris[i]); + Log("Loading resource URI from relative path %s", resourceUris[i], uri.c_str()); + ResourceBuffer buf = _resourceLoaderWrapper->load(uri.c_str()); + + resourceBuffers.push_back(buf); + + ResourceLoader::BufferDescriptor b(buf.data, buf.size); + _gltfResourceLoader->addResourceData(resourceUris[i], std::move(b)); + } + + // load resources synchronously + if (!_gltfResourceLoader->loadResources(asset)) + { + Log("Unknown error loading glTF asset"); + _resourceLoaderWrapper->free(rbuf); + for (auto &rb : resourceBuffers) + { + _resourceLoaderWrapper->free(rb); + } + return 0; + } + const utils::Entity *entities = asset->getEntities(); + + _scene->addEntities(asset->getEntities(), asset->getEntityCount()); + + FilamentInstance *inst = asset->getInstance(); + inst->getAnimator()->updateBoneMatrices(); + inst->recomputeBoundingBoxes(); + + asset->releaseSourceData(); + + SceneAsset sceneAsset(asset); + + utils::Entity e = EntityManager::get().create(); + + EntityId eid = Entity::smuggle(e); + + _entityIdLookup.emplace(eid, _assets.size()); + _assets.push_back(sceneAsset); + + for (auto &rb : resourceBuffers) + { _resourceLoaderWrapper->free(rb); } - return 0; - } - const utils::Entity *entities = asset->getEntities(); - - _scene->addEntities(asset->getEntities(), asset->getEntityCount()); - - FilamentInstance* inst = asset->getInstance(); - inst->getAnimator()->updateBoneMatrices(); - inst->recomputeBoundingBoxes(); - - asset->releaseSourceData(); - - SceneAsset sceneAsset(asset); - - utils::Entity e = EntityManager::get().create(); - - EntityId eid = Entity::smuggle(e); - - _entityIdLookup.emplace(eid, _assets.size()); - _assets.push_back(sceneAsset); - - for(auto& rb : resourceBuffers) { - _resourceLoaderWrapper->free(rb); - } - _resourceLoaderWrapper->free(rbuf); - - Log("Finished loading glTF from %s", uri); - - return eid; -} - -EntityId AssetManager::loadGlb(const char *uri, bool unlit) { - - ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); - - Log("Loaded GLB of size %d at URI %s", rbuf.size, uri); - - FilamentAsset *asset = _assetLoader->createAsset( - (const uint8_t *)rbuf.data, rbuf.size); - - if (!asset) { - Log("Unknown error loading GLB asset."); - return 0; - } - - int entityCount = asset->getEntityCount(); - - _scene->addEntities(asset->getEntities(), entityCount); - - if (!_gltfResourceLoader->loadResources(asset)) { - Log("Unknown error loading glb asset"); _resourceLoaderWrapper->free(rbuf); - return 0; + + Log("Finished loading glTF from %s", uri); + + return eid; } - - const Entity *entities = asset->getEntities(); - - auto lights = asset->getLightEntities(); - _scene->addEntities(lights, asset->getLightEntityCount()); - - FilamentInstance* inst = asset->getInstance(); - - inst->getAnimator()->updateBoneMatrices(); - - inst->recomputeBoundingBoxes(); - - asset->releaseSourceData(); - - _resourceLoaderWrapper->free(rbuf); - - SceneAsset sceneAsset(asset); - - utils::Entity e = EntityManager::get().create(); - EntityId eid = Entity::smuggle(e); - - _entityIdLookup.emplace(eid, _assets.size()); - _assets.push_back(sceneAsset); - - return eid; -} -bool AssetManager::hide(EntityId entityId, const char* meshName) { - - auto asset = getAssetByEntityId(entityId); - if(!asset) { - return false; + EntityId AssetManager::loadGlb(const char *uri, bool unlit) + { + + ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); + + Log("Loaded GLB of size %d at URI %s", rbuf.size, uri); + + FilamentAsset *asset = _assetLoader->createAsset( + (const uint8_t *)rbuf.data, rbuf.size); + + if (!asset) + { + Log("Unknown error loading GLB asset."); + return 0; + } + + int entityCount = asset->getEntityCount(); + + _scene->addEntities(asset->getEntities(), entityCount); + + if (!_gltfResourceLoader->loadResources(asset)) + { + Log("Unknown error loading glb asset"); + _resourceLoaderWrapper->free(rbuf); + return 0; + } + + const Entity *entities = asset->getEntities(); + + auto lights = asset->getLightEntities(); + _scene->addEntities(lights, asset->getLightEntityCount()); + + FilamentInstance *inst = asset->getInstance(); + + inst->getAnimator()->updateBoneMatrices(); + + inst->recomputeBoundingBoxes(); + + asset->releaseSourceData(); + + _resourceLoaderWrapper->free(rbuf); + + SceneAsset sceneAsset(asset); + + utils::Entity e = EntityManager::get().create(); + EntityId eid = Entity::smuggle(e); + + _entityIdLookup.emplace(eid, _assets.size()); + _assets.push_back(sceneAsset); + + return eid; } - - auto entity = findEntityByName(asset, meshName); - - if(entity.isNull()) { - Log("Mesh %s could not be found", meshName); - return false; + + bool AssetManager::hide(EntityId entityId, const char *meshName) + { + + auto asset = getAssetByEntityId(entityId); + if (!asset) + { + return false; + } + + auto entity = findEntityByName(asset, meshName); + + if (entity.isNull()) + { + Log("Mesh %s could not be found", meshName); + return false; + } + _scene->remove(entity); + return true; } - _scene->remove(entity); - return true; -} -bool AssetManager::reveal(EntityId entityId, const char* meshName) { - auto asset = getAssetByEntityId(entityId); - if(!asset) { - Log("No asset found under entity ID"); - return false; + bool AssetManager::reveal(EntityId entityId, const char *meshName) + { + auto asset = getAssetByEntityId(entityId); + if (!asset) + { + Log("No asset found under entity ID"); + return false; + } + + auto entity = findEntityByName(asset, meshName); + + RenderableManager &rm = _engine->getRenderableManager(); + + if (entity.isNull()) + { + Log("Mesh %s could not be found", meshName); + return false; + } + _scene->addEntity(entity); + return true; } - - auto entity = findEntityByName(asset, meshName); - - RenderableManager &rm = _engine->getRenderableManager(); - - if(entity.isNull()) { - Log("Mesh %s could not be found", meshName); - return false; + + void AssetManager::destroyAll() + { + for (auto &asset : _assets) + { + _scene->removeEntities(asset.asset->getEntities(), + asset.asset->getEntityCount()); + _scene->removeEntities(asset.asset->getLightEntities(), + asset.asset->getLightEntityCount()); + _assetLoader->destroyAsset(asset.asset); + } + _assets.clear(); } - _scene->addEntity(entity); - return true; -} -void AssetManager::destroyAll() { - for (auto& asset : _assets) { - _scene->removeEntities(asset.mAsset->getEntities(), - asset.mAsset->getEntityCount()); - _scene->removeEntities(asset.mAsset->getLightEntities(), - asset.mAsset->getLightEntityCount()); - _assetLoader->destroyAsset(asset.mAsset); + FilamentAsset *AssetManager::getAssetByEntityId(EntityId entityId) + { + const auto &pos = _entityIdLookup.find(entityId); + if (pos == _entityIdLookup.end()) + { + return nullptr; + } + return _assets[pos->second].asset; } - _assets.clear(); -} -FilamentAsset* AssetManager::getAssetByEntityId(EntityId entityId) { - const auto& pos = _entityIdLookup.find(entityId); - if(pos == _entityIdLookup.end()) { - return nullptr; - } - return _assets[pos->second].mAsset; -} + // vector completedBoneAnimations; + // for (int i = completed.size() - 1; i >= 0; i--) { + // auto completedAnimationIndex = completed[i]; + // if(asset.animations.mType == AnimationType::BONE) { + // completedBoneAnimations.push_back() + // } + // (completedAnimationIndex); + // } -void AssetManager::updateAnimations() { - - std::lock_guard lock(_animationMutex); - RenderableManager &rm = _engine->getRenderableManager(); - - for (auto& asset : _assets) { + void AssetManager::updateAnimations() + { - - std::vector completed; - int index = 0; - for(auto& anim : asset.mAnimations) { + std::lock_guard lock(_animationMutex); + RenderableManager &rm = _engine->getRenderableManager(); - auto now = high_resolution_clock::now(); + auto now = high_resolution_clock::now(); + + for (auto &asset : _assets) + { - auto elapsed = float(std::chrono::duration_cast(now - anim.mStart).count()) / 1000.0f; - - if(anim.mLoop || elapsed < anim.mDuration) { + for (int i = asset.gltfAnimations.size() - 1; i >= 0; i--) { - switch(anim.type) { - case AnimationType::GLTF: { - asset.mAnimator->applyAnimation(anim.gltfIndex, elapsed); - if(asset.fadeGltfAnimationIndex != -1 && elapsed < asset.fadeDuration) { - // cross-fade - auto fadeFromTime = asset.fadeOutAnimationStart + elapsed; - auto alpha = elapsed / asset.fadeDuration; - asset.mAnimator->applyCrossFade(asset.fadeGltfAnimationIndex, fadeFromTime, alpha); - } - break; - } - case AnimationType::MORPH: { - int lengthInFrames = static_cast( - anim.mDuration * 1000.0f / - asset.mMorphAnimationBuffer.mFrameLengthInMs - ); - int frameNumber = static_cast(elapsed * 1000.0f / asset.mMorphAnimationBuffer.mFrameLengthInMs) % lengthInFrames; - // offset from the end if reverse - if(anim.mReverse) { - frameNumber = lengthInFrames - frameNumber; - } - auto baseOffset = frameNumber * asset.mMorphAnimationBuffer.mMorphIndices.size(); - for(int i = 0; i < asset.mMorphAnimationBuffer.mMorphIndices.size(); i++) { - auto morphIndex = asset.mMorphAnimationBuffer.mMorphIndices[i]; - // set the weights appropriately - rm.setMorphWeights( - rm.getInstance(asset.mMorphAnimationBuffer.mMeshTarget), - asset.mMorphAnimationBuffer.mFrameData.data() + baseOffset + i, - 1, - morphIndex - ); - } - break; - } - case AnimationType::BONE: { - int lengthInFrames = static_cast( - anim.mDuration * 1000.0f / - asset.mBoneAnimationBuffer.mFrameLengthInMs - ); - int frameNumber = static_cast(elapsed * 1000.0f / asset.mBoneAnimationBuffer.mFrameLengthInMs) % lengthInFrames; - - // offset from the end if reverse - if(anim.mReverse) { - frameNumber = lengthInFrames - frameNumber; - } - setBoneTransformFromAnimation( - asset, - frameNumber - ); - break; - } + auto animationStatus = asset.gltfAnimations[i]; + + auto elapsedInSecs = float(std::chrono::duration_cast(now - animationStatus.start).count()) / 1000.0f; + + if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs) + { + asset.gltfAnimations.erase(asset.gltfAnimations.begin() + i); + asset.fadeGltfAnimationIndex = -1; + continue; } - if(anim.mLoop && elapsed >= anim.mDuration) { - anim.mStart = now; + + asset.asset->getInstance()->getAnimator()->applyAnimation(animationStatus.index, elapsedInSecs); + if (asset.fadeGltfAnimationIndex != -1 && elapsedInSecs < asset.fadeDuration) + { + // cross-fade + auto fadeFromTime = asset.fadeOutAnimationStart + elapsedInSecs; + auto alpha = elapsedInSecs / asset.fadeDuration; + asset.asset->getInstance()->getAnimator()->applyCrossFade(asset.fadeGltfAnimationIndex, fadeFromTime, alpha); } - // animation has completed - } else { - completed.push_back(index); - asset.fadeGltfAnimationIndex = -1; + asset.asset->getInstance()->getAnimator()->updateBoneMatrices(); } - asset.mAnimator->updateBoneMatrices(); - index++; - } - for(int i = completed.size() - 1; i >= 0; i--) { - asset.mAnimations.erase(asset.mAnimations.begin() + i); - } - } -} - -bool AssetManager::setBoneTransform(EntityId entityId, const char* entityName, int32_t skinIndex, int32_t boneIndex, math::mat4f localTransform) { - - Log("Setting transform for bone %d/skin %d for mesh target %s", boneIndex, skinIndex, entityName); - - const auto& pos = _entityIdLookup.find(entityId); - if(pos == _entityIdLookup.end()) { - Log("Couldn't find asset under specified entity id."); - return false; - } - SceneAsset& sceneAsset = _assets[pos->second]; - - const auto& entity = findEntityByName(sceneAsset, entityName); - - RenderableManager& rm = _engine->getRenderableManager(); - - const auto& renderableInstance = rm.getInstance(entity); - - TransformManager &transformManager = _engine->getTransformManager(); - - const auto& filamentInstance = sceneAsset.mAsset->getInstance(); - utils::Entity joint = filamentInstance->getJointsAt(skinIndex)[boneIndex]; - - if(joint.isNull()) { - Log("ERROR : joint not found"); - return false; - } - - rm.setBones( - renderableInstance, - &localTransform, - 1, - boneIndex - ); - - return true; - - // auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[boneIndex]; - - // auto jointInstance = transformManager.getInstance(joint); - - // auto globalJointTransform = transformManager.getWorldTransform(jointInstance); + for (int i = asset.morphAnimations.size() - 1; i >= 0; i--) { - // transformManager.setTransform(jointInstance, xform * localTransform); + auto animationStatus = asset.morphAnimations[i]; - // auto inverseGlobalTransform = inverse( - // transformManager.getWorldTransform( - // transformManager.getInstance(target) - // ) - // ); + auto elapsedInSecs = float(std::chrono::duration_cast(now - animationStatus.start).count()) / 1000.0f; - // auto boneTransform = inverseGlobalTransform * globalJointTransform * localTransform * inverseBindMatrix; - // auto renderable = rm.getInstance(target); + if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs) + { + asset.morphAnimations.erase(asset.morphAnimations.begin() + i); + continue; + } - // 1.0f, 0.0f, 0.0f, 0.0f, - // 0.0f, 0.0f, 1.0f, 0.0f, - // 0.0f, -1.0f, 0.0f, 0.0f, - // 0.0f, 0.0f, 0.0f, 1.0f - // }; - // Log("TRANSFORM"); - // Log("%f %f %f %f", localTransform[0][0], localTransform[1][0], localTransform[2][0], localTransform[3][0] ) ; - // Log("%f %f %f %f", localTransform[0][1], localTransform[1][1], localTransform[2][1], localTransform[3][1] ) ; - // Log("%f %f %f %f", localTransform[0][2], localTransform[1][2], localTransform[2][2], localTransform[3][2] ) ; - // Log("%f %f %f %f", localTransform[0][3], localTransform[1][3], localTransform[2][3], localTransform[3][3] ) ; - // } -} + + int frameNumber = static_cast(elapsedInSecs * 1000.0f / animationStatus.frameLengthInMs) % animationStatus.lengthInFrames; + // offset from the end if reverse + if (animationStatus.reverse) + { + frameNumber = animationStatus.lengthInFrames - frameNumber; + } + auto baseOffset = frameNumber * animationStatus.morphIndices.size(); + for (int i = 0; i < animationStatus.morphIndices.size(); i++) + { + auto morphIndex = animationStatus.morphIndices[i]; + // set the weights appropriately + rm.setMorphWeights( + rm.getInstance(animationStatus.meshTarget), + animationStatus.frameData.data() + baseOffset + i, + 1, + morphIndex); + } + } -void AssetManager::setBoneTransformFromAnimation(SceneAsset& asset, int frameNumber) { - - RenderableManager& rm = _engine->getRenderableManager(); - - const auto& filamentInstance = asset.mAsset->getInstance(); - - TransformManager &transformManager = _engine->getTransformManager(); - - int skinIndex = 0; - - for(int i = 0; i < asset.mBoneAnimationBuffer.mBones.size(); i++) { - auto mBoneIndex = asset.mBoneAnimationBuffer.mBones[i]; - auto frameDataOffset = (frameNumber * asset.mBoneAnimationBuffer.mBones.size() * 7) + (i * 7); - - utils::Entity joint = filamentInstance->getJointsAt(skinIndex)[mBoneIndex]; - if(joint.isNull()) { + for (int i = asset.boneAnimations.size() - 1; i >= 0; i--) { + auto animationStatus = asset.boneAnimations[i]; + + auto elapsedInSecs = float(std::chrono::duration_cast(now - animationStatus.start).count()) / 1000.0f; + + if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs) + { + asset.boneAnimations.erase(asset.boneAnimations.begin() + i); + continue; + } + + float frameLengthInMs = animationStatus.frameLengthInMs; + + int frameNumber = static_cast(elapsedInSecs * 1000.0f / frameLengthInMs) % animationStatus.lengthInFrames; + + // offset from the end if reverse + if (animationStatus.reverse) + { + frameNumber = animationStatus.lengthInFrames - frameNumber; + } + updateBoneTransformFromAnimationBuffer( + animationStatus, + frameNumber); + + if (animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs) + { + animationStatus.start = now; + } + } + } + } + + bool AssetManager::setBoneTransform(EntityId entityId, const char *entityName, int32_t skinIndex, int32_t boneIndex, math::mat4f localTransform) + { + + Log("Setting transform for bone %d/skin %d for mesh target %s", boneIndex, skinIndex, entityName); + + const auto &pos = _entityIdLookup.find(entityId); + if (pos == _entityIdLookup.end()) + { + Log("Couldn't find asset under specified entity id."); + return false; + } + SceneAsset &sceneAsset = _assets[pos->second]; + + const auto &entity = findEntityByName(sceneAsset, entityName); + + RenderableManager &rm = _engine->getRenderableManager(); + + const auto &renderableInstance = rm.getInstance(entity); + + TransformManager &transformManager = _engine->getTransformManager(); + + const auto &filamentInstance = sceneAsset.asset->getInstance(); + utils::Entity joint = filamentInstance->getJointsAt(skinIndex)[boneIndex]; + + if (joint.isNull()) + { Log("ERROR : joint not found"); - continue; + return false; + } + + rm.setBones( + renderableInstance, + &localTransform, + 1, + boneIndex); + return true; + } + + void AssetManager::updateBoneTransformFromAnimationBuffer(const BoneAnimation& animation, int frameNumber) + { + + RenderableManager &rm = _engine->getRenderableManager(); + + auto boneIndex = animation.boneIndex; + math::mat4f transform(animation.frameData[frameNumber]); + + for(const auto& meshTarget : animation.meshTargets) { + const auto &renderableInstance = rm.getInstance(meshTarget); + rm.setBones( + renderableInstance, + &transform, + 1, + boneIndex + ); } - vector& fd = asset.mBoneAnimationBuffer.mFrameData; - - math::mat4f localTransform(math::quatf { - fd[frameDataOffset+3], - fd[frameDataOffset+4], - fd[frameDataOffset+5], - fd[frameDataOffset+6], - }); - - auto jointInstance = transformManager.getInstance(joint); - - auto xform = asset.mBoneAnimationBuffer.mBaseTransforms[i]; - - transformManager.setTransform(jointInstance, xform * localTransform); - } -} -void AssetManager::remove(EntityId entityId) { - const auto& pos = _entityIdLookup.find(entityId); - if(pos == _entityIdLookup.end()) { - Log("Couldn't find asset under specified entity id."); - return; - } - SceneAsset& sceneAsset = _assets[pos->second]; - - _assets.erase(std::remove_if(_assets.begin(), _assets.end(), - [=](SceneAsset& asset) { return asset.mAsset == sceneAsset.mAsset; }), - _assets.end()); - - _scene->removeEntities(sceneAsset.mAsset->getEntities(), - sceneAsset.mAsset->getEntityCount()); - - _scene->removeEntities(sceneAsset.mAsset->getLightEntities(), - sceneAsset.mAsset->getLightEntityCount()); - - _assetLoader->destroyAsset(sceneAsset.mAsset); - - if(sceneAsset.mTexture) { - _engine->destroy(sceneAsset.mTexture); - } - EntityManager& em = EntityManager::get(); - em.destroy(Entity::import(entityId)); - - -} - -void AssetManager::setMorphTargetWeights(EntityId entityId, const char* const entityName, const float* const weights, const int count) { - const auto& pos = _entityIdLookup.find(entityId); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return; - } - auto& asset = _assets[pos->second]; - - auto entity = findEntityByName(asset, entityName); - if(!entity) { - Log("Warning: failed to find entity %s", entityName); - return; - } - - RenderableManager &rm = _engine->getRenderableManager(); - - auto renderableInstance = rm.getInstance(entity); - - if(!renderableInstance.isValid()) { - Log("Warning: failed to find renderable instance for entity %s", entityName); - return; - } - - rm.setMorphWeights( - renderableInstance, - weights, - count - ); -} - -utils::Entity AssetManager::findEntityByName(SceneAsset asset, const char* entityName) { - utils::Entity entity; - for (size_t i = 0, c = asset.mAsset->getEntityCount(); i != c; ++i) { - auto entity = asset.mAsset->getEntities()[i]; - auto nameInstance = _ncm->getInstance(entity); - if(!nameInstance.isValid()) { - continue; + void AssetManager::remove(EntityId entityId) + { + const auto &pos = _entityIdLookup.find(entityId); + if (pos == _entityIdLookup.end()) + { + Log("Couldn't find asset under specified entity id."); + return; } - auto name = _ncm->getName(nameInstance); - if(!name) { - continue; + SceneAsset &sceneAsset = _assets[pos->second]; + + _assets.erase(std::remove_if(_assets.begin(), _assets.end(), + [=](SceneAsset &asset) + { return asset.asset == sceneAsset.asset; }), + _assets.end()); + + _scene->removeEntities(sceneAsset.asset->getEntities(), + sceneAsset.asset->getEntityCount()); + + _scene->removeEntities(sceneAsset.asset->getLightEntities(), + sceneAsset.asset->getLightEntityCount()); + + _assetLoader->destroyAsset(sceneAsset.asset); + + if (sceneAsset.texture) + { + _engine->destroy(sceneAsset.texture); } - if(strcmp(entityName,name)==0) { - return entity; + EntityManager &em = EntityManager::get(); + em.destroy(Entity::import(entityId)); + } + + void AssetManager::setMorphTargetWeights(EntityId entityId, const char *const entityName, const float *const weights, const int count) + { + const auto &pos = _entityIdLookup.find(entityId); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return; } - } - return entity; -} + auto &asset = _assets[pos->second]; -bool AssetManager::setMorphAnimationBuffer( - EntityId entityId, - const char* entityName, - const float* const morphData, - const int* const morphIndices, - int numMorphTargets, - int numFrames, - float frameLengthInMs) { - std::lock_guard lock(_animationMutex); + auto entity = findEntityByName(asset, entityName); + if (!entity) + { + Log("Warning: failed to find entity %s", entityName); + return; + } - const auto& pos = _entityIdLookup.find(entityId); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return false; - } - auto& asset = _assets[pos->second]; - - auto entity = findEntityByName(asset, entityName); - if(!entity) { - Log("Warning: failed to find entity %s", entityName); - return false; - } - - asset.mMorphAnimationBuffer.mMeshTarget = entity; - asset.mMorphAnimationBuffer.mFrameData.clear(); - asset.mMorphAnimationBuffer.mFrameData.insert( - asset.mMorphAnimationBuffer.mFrameData.begin(), - morphData, - morphData + (numFrames * numMorphTargets) - ); - asset.mMorphAnimationBuffer.mFrameLengthInMs = frameLengthInMs; - asset.mMorphAnimationBuffer.mMorphIndices.resize(numMorphTargets); - for(int i =0; i< numMorphTargets; i++) { - asset.mMorphAnimationBuffer.mMorphIndices[i] = morphIndices[i]; - } - - AnimationStatus animation; - animation.mDuration = (frameLengthInMs * numFrames) / 1000.0f; - animation.mStart = high_resolution_clock::now(); - animation.type = AnimationType::MORPH; - asset.mAnimations.push_back(animation); - return true; -} + RenderableManager &rm = _engine->getRenderableManager(); -bool AssetManager::setMaterialColor(EntityId entityId, const char* meshName, int materialIndex, const float r, const float g, const float b, const float a) { - - const auto& pos = _entityIdLookup.find(entityId); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return false; - } - auto& asset = _assets[pos->second]; - auto entity = findEntityByName(asset, meshName); - - RenderableManager& rm = _engine->getRenderableManager(); - - auto renderable = rm.getInstance(entity); - - if(!renderable.isValid()) { - Log("Renderable not valid, was the entity id correct?"); + auto renderableInstance = rm.getInstance(entity); - return false; - } - - MaterialInstance* mi = rm.getMaterialInstanceAt(renderable, materialIndex); - - if(!mi) { - Log("ERROR: material index must be less than number of material instances"); - return false; - } - mi->setParameter("baseColorFactor", RgbaType::sRGB, math::float4(r, g, b, a)); - Log("Set baseColorFactor for entity %d to %f %f %f %f",entityId, r,g,b,a); - return true; -} + if (!renderableInstance.isValid()) + { + Log("Warning: failed to find renderable instance for entity %s", entityName); + return; + } + rm.setMorphWeights( + renderableInstance, + weights, + count); + } -bool AssetManager::setBoneAnimationBuffer( - EntityId entityId, - const float* const frameData, - int numFrames, - int numBones, - const char** const boneNames, - const char** const meshNames, - int numMeshTargets, - float frameLengthInMs) { - std::lock_guard lock(_animationMutex); + utils::Entity AssetManager::findEntityByName(SceneAsset asset, const char *entityName) + { + utils::Entity entity; + for (size_t i = 0, c = asset.asset->getEntityCount(); i != c; ++i) + { + auto entity = asset.asset->getEntities()[i]; + auto nameInstance = _ncm->getInstance(entity); + if (!nameInstance.isValid()) + { + continue; + } + auto name = _ncm->getName(nameInstance); + if (!name) + { + continue; + } + if (strcmp(entityName, name) == 0) + { + return entity; + } + } + return entity; + } - const auto& pos = _entityIdLookup.find(entityId); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return false; + bool AssetManager::setMorphAnimationBuffer( + EntityId entityId, + const char *entityName, + const float *const morphData, + const int *const morphIndices, + int numMorphTargets, + int numFrames, + float frameLengthInMs) + { + std::lock_guard lock(_animationMutex); + + const auto &pos = _entityIdLookup.find(entityId); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return false; + } + auto &asset = _assets[pos->second]; + + auto entity = findEntityByName(asset, entityName); + if (!entity) + { + Log("Warning: failed to find entity %s", entityName); + return false; + } + + MorphAnimation morphAnimation; + + morphAnimation.meshTarget = entity; + morphAnimation.frameData.clear(); + morphAnimation.frameData.insert( + morphAnimation.frameData.begin(), + morphData, + morphData + (numFrames * numMorphTargets)); + morphAnimation.frameLengthInMs = frameLengthInMs; + morphAnimation.morphIndices.resize(numMorphTargets); + for (int i = 0; i < numMorphTargets; i++) + { + morphAnimation.morphIndices[i] = morphIndices[i]; + } + morphAnimation.durationInSecs = (frameLengthInMs * numFrames) / 1000.0f; + morphAnimation.start = high_resolution_clock::now(); + morphAnimation.lengthInFrames = static_cast( + morphAnimation.durationInSecs * 1000.0f / + frameLengthInMs + ); + asset.morphAnimations.emplace_back(morphAnimation); + return true; } - auto& asset = _assets[pos->second]; - auto filamentInstance = asset.mAsset->getInstance(); - - size_t skinCount = filamentInstance->getSkinCount(); - - if(skinCount > 1) { - Log("WARNING - skin count > 1 not currently implemented. This will probably not work"); + + bool AssetManager::setMaterialColor(EntityId entityId, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a) + { + + const auto &pos = _entityIdLookup.find(entityId); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return false; + } + auto &asset = _assets[pos->second]; + auto entity = findEntityByName(asset, meshName); + + RenderableManager &rm = _engine->getRenderableManager(); + + auto renderable = rm.getInstance(entity); + + if (!renderable.isValid()) + { + Log("Renderable not valid, was the entity id correct?"); + + return false; + } + + MaterialInstance *mi = rm.getMaterialInstanceAt(renderable, materialIndex); + + if (!mi) + { + Log("ERROR: material index must be less than number of material instances"); + return false; + } + mi->setParameter("baseColorFactor", RgbaType::sRGB, math::float4(r, g, b, a)); + Log("Set baseColorFactor for entity %d to %f %f %f %f", entityId, r, g, b, a); + return true; } - - TransformManager &transformManager = _engine->getTransformManager(); - - int skinIndex = 0; - const utils::Entity* joints = filamentInstance->getJointsAt(skinIndex); - size_t numJoints = filamentInstance->getJointCountAt(skinIndex); - - BoneAnimationBuffer& animationBuffer = asset.mBoneAnimationBuffer; - - // if an animation has already been set, reset the transform for the respective bones - for(int i = 0; i < animationBuffer.mBones.size(); i++) { - auto boneIndex = animationBuffer.mBones[i]; - auto jointInstance = transformManager.getInstance(joints[boneIndex]); - transformManager.setTransform(jointInstance, animationBuffer.mBaseTransforms[i]); - } - - asset.mAnimator->resetBoneMatrices(); - - animationBuffer.mBones.resize(numBones); - animationBuffer.mBaseTransforms.resize(numBones); - - for(int i = 0; i < numBones; i++) { - for(int j = 0; j < numJoints; j++) { - const char* jointName = _ncm->getName(_ncm->getInstance(joints[j])); - if(strcmp(jointName, boneNames[i]) == 0) { - auto jointInstance = transformManager.getInstance(joints[j]); - // auto currentXform = ; - auto baseTransform = transformManager.getTransform(jointInstance); // inverse(filamentInstance->getInverseBindMatricesAt(skinIndex)[j]); - animationBuffer.mBaseTransforms[i] = baseTransform; - animationBuffer.mBones[i] = j; + + bool AssetManager::addBoneAnimation(EntityId entityId, + const float *const frameData, + int numFrames, + const char *const boneName, + const char **const meshNames, + int numMeshTargets, + float frameLengthInMs) + { + std::lock_guard lock(_animationMutex); + + const auto &pos = _entityIdLookup.find(entityId); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return false; + } + auto &asset = _assets[pos->second]; + + asset.asset->getInstance()->getAnimator()->resetBoneMatrices(); + + auto filamentInstance = asset.asset->getInstance(); + + size_t skinCount = filamentInstance->getSkinCount(); + + if (skinCount > 1) + { + Log("WARNING - skin count > 1 not currently implemented. This will probably not work"); + } + + int skinIndex = 0; + const utils::Entity *joints = filamentInstance->getJointsAt(skinIndex); + size_t numJoints = filamentInstance->getJointCountAt(skinIndex); + + BoneAnimation animation; + bool found = false; + + for (int i = 0; i < numJoints; i++) + { + const char *jointName = _ncm->getName(_ncm->getInstance(joints[i])); + if (strcmp(jointName, boneName) == 0) + { + animation.boneIndex = i; + found = true; break; } } - } - - if(animationBuffer.mBones.size() != numBones) { - Log("Failed to find one or more bone indices"); - return false; - } - - animationBuffer.mFrameData.clear(); - // 7 == locX, locY, locZ, rotW, rotX, rotY, rotZ - animationBuffer.mFrameData.resize(numFrames * numBones * 7); - animationBuffer.mFrameData.insert( - animationBuffer.mFrameData.begin(), - frameData, - frameData + numFrames * numBones * 7 - ); - - animationBuffer.mFrameLengthInMs = frameLengthInMs; - animationBuffer.mNumFrames = numFrames; - - animationBuffer.mMeshTargets.clear(); - for(int i = 0; i < numMeshTargets; i++) { - auto entity = findEntityByName(asset, meshNames[i]); - if(!entity) { - Log("Mesh target %s for bone animation could not be found", meshNames[i]); + if(!found) { + Log("Failed to find bone %s", boneName); return false; } - Log("Added mesh target %s", meshNames[i]); - animationBuffer.mMeshTargets.push_back(entity); - } - - AnimationStatus animation; - animation.mStart = std::chrono::high_resolution_clock::now(); - animation.mReverse = false; - animation.mDuration = (frameLengthInMs * numFrames) / 1000.0f; - animation.type = AnimationType::BONE; - asset.mAnimations.push_back(animation); - - return true; -} + + animation.frameData.clear(); + for(int i = 0; i < numFrames; i++) { + animation.frameData.push_back(math::quatf( + frameData[i*4], + frameData[(i*4)+1], + frameData[(i*4)+2], + frameData[(i*4)+3] + )); + } -void AssetManager::playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade) { - std::lock_guard lock(_animationMutex); + animation.frameLengthInMs = frameLengthInMs; - if(index < 0) { - Log("ERROR: glTF animation index must be greater than zero."); - return; + animation.meshTargets.clear(); + for (int i = 0; i < numMeshTargets; i++) + { + auto entity = findEntityByName(asset, meshNames[i]); + if (!entity) + { + Log("Mesh target %s for bone animation could not be found", meshNames[i]); + return false; + } + Log("Added mesh target %s", meshNames[i]); + animation.meshTargets.push_back(entity); + } + + animation.start = std::chrono::high_resolution_clock::now(); + animation.reverse = false; + animation.durationInSecs = (frameLengthInMs * numFrames) / 1000.0f; + animation.lengthInFrames = numFrames; + animation.frameLengthInMs = frameLengthInMs; + asset.boneAnimations.push_back(animation); + + return true; } - const auto& pos = _entityIdLookup.find(e); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return; - } - auto& asset = _assets[pos->second]; - - if(replaceActive) { - vector active; - for(int i = 0; i < asset.mAnimations.size(); i++) { - if(asset.mAnimations[i].type == AnimationType::GLTF) { - active.push_back(i); + + void AssetManager::playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade) + { + std::lock_guard lock(_animationMutex); + + if (index < 0) + { + Log("ERROR: glTF animation index must be greater than zero."); + return; + } + const auto &pos = _entityIdLookup.find(e); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return; + } + auto &asset = _assets[pos->second]; + + if (replaceActive) + { + if (asset.gltfAnimations.size() > 0) + { + auto &last = asset.gltfAnimations.back(); + asset.fadeGltfAnimationIndex = last.index; + asset.fadeDuration = crossfade; + auto now = high_resolution_clock::now(); + auto elapsedInSecs = float(std::chrono::duration_cast(now - last.start).count()) / 1000.0f; + asset.fadeOutAnimationStart = elapsedInSecs; + asset.gltfAnimations.clear(); + } + else + { + asset.fadeGltfAnimationIndex = -1; + asset.fadeDuration = 0.0f; } } - if(active.size() > 0) { - auto& last = asset.mAnimations[active.back()]; - asset.fadeGltfAnimationIndex = last.gltfIndex; - asset.fadeDuration = crossfade; - auto now = high_resolution_clock::now(); - auto elapsed = float(std::chrono::duration_cast(now - last.mStart).count()) / 1000.0f; - asset.fadeOutAnimationStart = elapsed; - for(int j = active.size() - 1; j >= 0; j--) { - asset.mAnimations.erase(asset.mAnimations.begin() + active[j]); - } - } else { + else if (crossfade > 0) + { + Log("ERROR: crossfade only supported when replaceActive is true."); + return; + } + else + { asset.fadeGltfAnimationIndex = -1; asset.fadeDuration = 0.0f; } - } else if(crossfade > 0) { - Log("ERROR: crossfade only supported when replaceActive is true."); - return; - } else { - asset.fadeGltfAnimationIndex = -1; - asset.fadeDuration = 0.0f; - } - - AnimationStatus animation; - animation.gltfIndex = index; - animation.mStart = std::chrono::high_resolution_clock::now(); - animation.mLoop = loop; - animation.mReverse = reverse; - animation.type = AnimationType::GLTF; - animation.mDuration = asset.mAnimator->getAnimationDuration(index); - - asset.mAnimations.push_back(animation); - Log("Current animation count %d ", asset.mAnimations.size()); -} + GltfAnimation animation; + animation.index = index; + animation.start = std::chrono::high_resolution_clock::now(); + animation.loop = loop; + animation.reverse = reverse; + animation.durationInSecs = asset.asset->getInstance()->getAnimator()->getAnimationDuration(index); -void AssetManager::stopAnimation(EntityId entityId, int index) { - std::lock_guard lock(_animationMutex); + asset.gltfAnimations.push_back(animation); - const auto& pos = _entityIdLookup.find(entityId); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return; } - auto& asset = _assets[pos->second]; - - asset.mAnimations.erase(std::remove_if(asset.mAnimations.begin(), - asset.mAnimations.end(), - [=](AnimationStatus& anim) { return anim.gltfIndex == index; }), - asset.mAnimations.end()); - -} -void AssetManager::loadTexture(EntityId entity, const char* resourcePath, int renderableIndex) { - - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return; - } - auto& asset = _assets[pos->second]; - - Log("Loading texture at %s for renderableIndex %d", resourcePath, renderableIndex); - - string rp(resourcePath); - - if(asset.mTexture) { - _engine->destroy(asset.mTexture); - asset.mTexture = nullptr; - } - - ResourceBuffer imageResource = _resourceLoaderWrapper->load(rp.c_str()); - - StreamBufferAdapter sb((char *)imageResource.data, (char *)imageResource.data + imageResource.size); - - istream *inputStream = new std::istream(&sb); - - LinearImage *image = new LinearImage(ImageDecoder::decode( - *inputStream, rp.c_str(), ImageDecoder::ColorSpace::SRGB)); - - if (!image->isValid()) { - Log("Invalid image : %s", rp.c_str()); - delete inputStream; - _resourceLoaderWrapper->free(imageResource); - return; - } - - uint32_t channels = image->getChannels(); - uint32_t w = image->getWidth(); - uint32_t h = image->getHeight(); - asset.mTexture = Texture::Builder() - .width(w) - .height(h) - .levels(0xff) - .format(channels == 3 ? Texture::InternalFormat::RGB16F - : Texture::InternalFormat::RGBA16F) - .sampler(Texture::Sampler::SAMPLER_2D) - .build(*_engine); - - Texture::PixelBufferDescriptor::Callback freeCallback = [](void *buf, size_t, - void *data) { - delete reinterpret_cast(data); - }; - - Texture::PixelBufferDescriptor buffer( - image->getPixelRef(), size_t(w * h * channels * sizeof(float)), - channels == 3 ? Texture::Format::RGB : Texture::Format::RGBA, - Texture::Type::FLOAT, freeCallback); - - asset.mTexture->setImage(*_engine, 0, std::move(buffer)); - MaterialInstance* const* inst = asset.mAsset->getInstance()->getMaterialInstances(); - size_t mic = asset.mAsset->getInstance()->getMaterialInstanceCount(); - Log("Material instance count : %d", mic); - - auto sampler = TextureSampler(); - inst[0]->setParameter("baseColorIndex",0); - inst[0]->setParameter("baseColorMap",asset.mTexture,sampler); - delete inputStream; - - _resourceLoaderWrapper->free(imageResource); - -} + void AssetManager::stopAnimation(EntityId entityId, int index) + { + std::lock_guard lock(_animationMutex); - -void AssetManager::setAnimationFrame(EntityId entity, int animationIndex, int animationFrame) { - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return; - } - auto& asset = _assets[pos->second]; - auto offset = 60 * animationFrame * 1000; // TODO - don't hardcore 60fps framerate - asset.mAnimator->applyAnimation(animationIndex, offset); - asset.mAnimator->updateBoneMatrices(); -} - -float AssetManager::getAnimationDuration(EntityId entity, int animationIndex) { - const auto& pos = _entityIdLookup.find(entity); - - unique_ptr> names = make_unique>(); - - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity id."); - return -1.0f; - } - - auto& asset = _assets[pos->second]; - return asset.mAnimator->getAnimationDuration(animationIndex); -} - -unique_ptr> AssetManager::getAnimationNames(EntityId entity) { - - const auto& pos = _entityIdLookup.find(entity); - - unique_ptr> names = make_unique>(); - - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity id."); - return names; - } - auto& asset = _assets[pos->second]; - - size_t count = asset.mAnimator->getAnimationCount(); - - - for (size_t i = 0; i < count; i++) { - names->push_back(asset.mAnimator->getAnimationName(i)); - } - - return names; -} - -unique_ptr> AssetManager::getMorphTargetNames(EntityId entity, const char *meshName) { - - unique_ptr> names = make_unique>(); - - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return names; - } - auto& asset = _assets[pos->second]; - - const utils::Entity *entities = asset.mAsset->getEntities(); - - for (int i = 0; i < asset.mAsset->getEntityCount(); i++) { - utils::Entity e = entities[i]; - auto inst = _ncm->getInstance(e); - const char *name = _ncm->getName(inst); - - if (name && strcmp(name, meshName) == 0) { - size_t count = asset.mAsset->getMorphTargetCountAt(e); - for (int j = 0; j < count; j++) { - const char *morphName = asset.mAsset->getMorphTargetNameAt(e, j); - names->push_back(morphName); - } - break; + const auto &pos = _entityIdLookup.find(entityId); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return; } + auto &asset = _assets[pos->second]; + + asset.gltfAnimations.erase(std::remove_if(asset.gltfAnimations.begin(), + asset.gltfAnimations.end(), + [=](GltfAnimation &anim) + { return anim.index == index; }), + asset.gltfAnimations.end()); } - return names; -} -void AssetManager::transformToUnitCube(EntityId entity) { - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return; + void AssetManager::loadTexture(EntityId entity, const char *resourcePath, int renderableIndex) + { + + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return; + } + auto &asset = _assets[pos->second]; + + Log("Loading texture at %s for renderableIndex %d", resourcePath, renderableIndex); + + string rp(resourcePath); + + if (asset.texture) + { + _engine->destroy(asset.texture); + asset.texture = nullptr; + } + + ResourceBuffer imageResource = _resourceLoaderWrapper->load(rp.c_str()); + + StreamBufferAdapter sb((char *)imageResource.data, (char *)imageResource.data + imageResource.size); + + istream *inputStream = new std::istream(&sb); + + LinearImage *image = new LinearImage(ImageDecoder::decode( + *inputStream, rp.c_str(), ImageDecoder::ColorSpace::SRGB)); + + if (!image->isValid()) + { + Log("Invalid image : %s", rp.c_str()); + delete inputStream; + _resourceLoaderWrapper->free(imageResource); + return; + } + + uint32_t channels = image->getChannels(); + uint32_t w = image->getWidth(); + uint32_t h = image->getHeight(); + asset.texture = Texture::Builder() + .width(w) + .height(h) + .levels(0xff) + .format(channels == 3 ? Texture::InternalFormat::RGB16F + : Texture::InternalFormat::RGBA16F) + .sampler(Texture::Sampler::SAMPLER_2D) + .build(*_engine); + + Texture::PixelBufferDescriptor::Callback freeCallback = [](void *buf, size_t, + void *data) + { + delete reinterpret_cast(data); + }; + + Texture::PixelBufferDescriptor buffer( + image->getPixelRef(), size_t(w * h * channels * sizeof(float)), + channels == 3 ? Texture::Format::RGB : Texture::Format::RGBA, + Texture::Type::FLOAT, freeCallback); + + asset.texture->setImage(*_engine, 0, std::move(buffer)); + MaterialInstance *const *inst = asset.asset->getInstance()->getMaterialInstances(); + size_t mic = asset.asset->getInstance()->getMaterialInstanceCount(); + Log("Material instance count : %d", mic); + + auto sampler = TextureSampler(); + inst[0]->setParameter("baseColorIndex", 0); + inst[0]->setParameter("baseColorMap", asset.texture, sampler); + delete inputStream; + + _resourceLoaderWrapper->free(imageResource); } - auto& asset = _assets[pos->second]; - - Log("Transforming asset to unit cube."); - auto &tm = _engine->getTransformManager(); - FilamentInstance* inst = asset.mAsset->getInstance(); - auto aabb = inst->getBoundingBox(); - auto center = aabb.center(); - auto halfExtent = aabb.extent(); - auto maxExtent = max(halfExtent) * 2; - auto scaleFactor = 2.0f / maxExtent; - auto transform = - math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center); - tm.setTransform(tm.getInstance(inst->getRoot()), transform); -} -void AssetManager::updateTransform(SceneAsset& asset) { - auto &tm = _engine->getTransformManager(); - auto transform = - asset.mPosition * asset.mRotation * math::mat4f::scaling(asset.mScale); - tm.setTransform(tm.getInstance(asset.mAsset->getRoot()), transform); -} - -void AssetManager::setScale(EntityId entity, float scale) { - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return; + void AssetManager::setAnimationFrame(EntityId entity, int animationIndex, int animationFrame) + { + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return; + } + auto &asset = _assets[pos->second]; + auto offset = 60 * animationFrame * 1000; // TODO - don't hardcore 60fps framerate + asset.asset->getInstance()->getAnimator()->applyAnimation(animationIndex, offset); + asset.asset->getInstance()->getAnimator()->updateBoneMatrices(); } - auto& asset = _assets[pos->second]; - asset.mScale = scale; - updateTransform(asset); -} -void AssetManager::setPosition(EntityId entity, float x, float y, float z) { - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return; + float AssetManager::getAnimationDuration(EntityId entity, int animationIndex) + { + const auto &pos = _entityIdLookup.find(entity); + + unique_ptr> names = make_unique>(); + + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity id."); + return -1.0f; + } + + auto &asset = _assets[pos->second]; + return asset.asset->getInstance()->getAnimator()->getAnimationDuration(animationIndex); } - auto& asset = _assets[pos->second]; - asset.mPosition = math::mat4f::translation(math::float3(x,y,z)); - updateTransform(asset); -} -void AssetManager::setRotation(EntityId entity, float rads, float x, float y, float z) { - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return; + unique_ptr> AssetManager::getAnimationNames(EntityId entity) + { + + const auto &pos = _entityIdLookup.find(entity); + + unique_ptr> names = make_unique>(); + + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity id."); + return names; + } + auto &asset = _assets[pos->second]; + + size_t count = asset.asset->getInstance()->getAnimator()->getAnimationCount(); + + for (size_t i = 0; i < count; i++) + { + names->push_back(asset.asset->getInstance()->getAnimator()->getAnimationName(i)); + } + + return names; } - auto& asset = _assets[pos->second]; - asset.mRotation = math::mat4f::rotation(rads, math::float3(x,y,z)); - updateTransform(asset); -} -const utils::Entity *AssetManager::getCameraEntities(EntityId entity) { - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return nullptr; + unique_ptr> AssetManager::getMorphTargetNames(EntityId entity, const char *meshName) + { + + unique_ptr> names = make_unique>(); + + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return names; + } + auto &asset = _assets[pos->second]; + + const utils::Entity *entities = asset.asset->getEntities(); + + for (int i = 0; i < asset.asset->getEntityCount(); i++) + { + utils::Entity e = entities[i]; + auto inst = _ncm->getInstance(e); + const char *name = _ncm->getName(inst); + + if (name && strcmp(name, meshName) == 0) + { + size_t count = asset.asset->getMorphTargetCountAt(e); + for (int j = 0; j < count; j++) + { + const char *morphName = asset.asset->getMorphTargetNameAt(e, j); + names->push_back(morphName); + } + break; + } + } + return names; } - auto& asset = _assets[pos->second]; - return asset.mAsset->getCameraEntities(); -} -size_t AssetManager::getCameraEntityCount(EntityId entity) { - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return 0; + void AssetManager::transformToUnitCube(EntityId entity) + { + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return; + } + auto &asset = _assets[pos->second]; + + Log("Transforming asset to unit cube."); + auto &tm = _engine->getTransformManager(); + FilamentInstance *inst = asset.asset->getInstance(); + auto aabb = inst->getBoundingBox(); + auto center = aabb.center(); + auto halfExtent = aabb.extent(); + auto maxExtent = max(halfExtent) * 2; + auto scaleFactor = 2.0f / maxExtent; + auto transform = + math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center); + tm.setTransform(tm.getInstance(inst->getRoot()), transform); } - auto& asset = _assets[pos->second]; - return asset.mAsset->getCameraEntityCount(); -} -const utils::Entity* AssetManager::getLightEntities(EntityId entity) const noexcept { - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return nullptr; + void AssetManager::updateTransform(SceneAsset &asset) + { + auto &tm = _engine->getTransformManager(); + auto transform = + asset.position * asset.rotation * math::mat4f::scaling(asset.mScale); + tm.setTransform(tm.getInstance(asset.asset->getRoot()), transform); } - auto& asset = _assets[pos->second]; - return asset.mAsset->getLightEntities(); -} -size_t AssetManager::getLightEntityCount(EntityId entity) const noexcept { - const auto& pos = _entityIdLookup.find(entity); - if(pos == _entityIdLookup.end()) { - Log("ERROR: asset not found for entity."); - return 0; + void AssetManager::setScale(EntityId entity, float scale) + { + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return; + } + auto &asset = _assets[pos->second]; + asset.mScale = scale; + updateTransform(asset); } - auto& asset = _assets[pos->second]; - return asset.mAsset->getLightEntityCount(); -} -const char* AssetManager::getNameForEntity(EntityId entityId) { - const auto& entity = Entity::import(entityId); - auto nameInstance = _ncm->getInstance(entity); - if(!nameInstance.isValid()) { - Log("Failed to find name instance for entity ID %d", entityId); - return nullptr; - } - return _ncm->getName(nameInstance); -} + void AssetManager::setPosition(EntityId entity, float x, float y, float z) + { + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return; + } + auto &asset = _assets[pos->second]; + asset.position = math::mat4f::translation(math::float3(x, y, z)); + updateTransform(asset); + } + void AssetManager::setRotation(EntityId entity, float rads, float x, float y, float z) + { + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return; + } + auto &asset = _assets[pos->second]; + asset.rotation = math::mat4f::rotation(rads, math::float3(x, y, z)); + updateTransform(asset); + } + + const utils::Entity *AssetManager::getCameraEntities(EntityId entity) + { + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return nullptr; + } + auto &asset = _assets[pos->second]; + return asset.asset->getCameraEntities(); + } + + size_t AssetManager::getCameraEntityCount(EntityId entity) + { + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return 0; + } + auto &asset = _assets[pos->second]; + return asset.asset->getCameraEntityCount(); + } + + const utils::Entity *AssetManager::getLightEntities(EntityId entity) const noexcept + { + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return nullptr; + } + auto &asset = _assets[pos->second]; + return asset.asset->getLightEntities(); + } + + size_t AssetManager::getLightEntityCount(EntityId entity) const noexcept + { + const auto &pos = _entityIdLookup.find(entity); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + return 0; + } + auto &asset = _assets[pos->second]; + return asset.asset->getLightEntityCount(); + } + + const char *AssetManager::getNameForEntity(EntityId entityId) + { + const auto &entity = Entity::import(entityId); + auto nameInstance = _ncm->getInstance(entity); + if (!nameInstance.isValid()) + { + Log("Failed to find name instance for entity ID %d", entityId); + return nullptr; + } + return _ncm->getName(nameInstance); + } } // namespace polyvox - diff --git a/ios/src/FlutterFilamentApi.cpp b/ios/src/FlutterFilamentApi.cpp index 47f0244e..375c4693 100644 --- a/ios/src/FlutterFilamentApi.cpp +++ b/ios/src/FlutterFilamentApi.cpp @@ -321,18 +321,17 @@ extern "C" return ((AssetManager *)assetManager)->setMorphAnimationBuffer(asset, entityName, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs); } - FLUTTER_PLUGIN_EXPORT void set_bone_animation( + FLUTTER_PLUGIN_EXPORT void add_bone_animation( void *assetManager, EntityId asset, const float *const frameData, int numFrames, - int numBones, - const char **const boneNames, + const char *const boneName, const char **const meshNames, int numMeshTargets, float frameLengthInMs) { - ((AssetManager *)assetManager)->setBoneAnimationBuffer(asset, frameData, numFrames, numBones, boneNames, meshNames, numMeshTargets, frameLengthInMs); + ((AssetManager *)assetManager)->addBoneAnimation(asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs); } FLUTTER_PLUGIN_EXPORT void set_post_processing(void *const viewer, bool enabled) @@ -366,33 +365,6 @@ extern "C" return ((AssetManager *)assetManager)->setBoneTransform(entityId, entityName, 0, boneIndex, matrix); } - // void set_bone_transform( - // EntityId asset, - // const char* boneName, - // const char* entityName, - // float transX, - // float transY, - // float transZ, - // float quatX, - // float quatY, - // float quatZ, - // float quatW - // ) { - // ((AssetManager*)assetManager)->setBoneTransform( - // boneName, - // entityName, - // transX, - // transY, - // transZ, - // quatX, - // quatY, - // quatZ, - // quatW, - // false - // ); - - // } - FLUTTER_PLUGIN_EXPORT void play_animation( void *assetManager, EntityId asset, diff --git a/ios/src/FlutterFilamentFFIApi.cpp b/ios/src/FlutterFilamentFFIApi.cpp index 1795d9ba..b875deb7 100644 --- a/ios/src/FlutterFilamentFFIApi.cpp +++ b/ios/src/FlutterFilamentFFIApi.cpp @@ -331,18 +331,6 @@ FLUTTER_PLUGIN_EXPORT bool set_camera_ffi(void *const viewer, EntityId asset, return fut.get(); } -FLUTTER_PLUGIN_EXPORT void set_bone_animation_ffi( - void *assetManager, EntityId asset, const float *const frameData, - int numFrames, int numBones, const char **const boneNames, - const char **const meshName, int numMeshTargets, float frameLengthInMs) { - std::packaged_task lambda([&] { - set_bone_animation(assetManager, asset, frameData, numFrames, numBones, - boneNames, meshName, numMeshTargets, frameLengthInMs); - }); - auto fut = _rl->add_task(lambda); - fut.wait(); -} - FLUTTER_PLUGIN_EXPORT void get_morph_target_name_ffi(void *assetManager, EntityId asset, const char *meshName, char *const outPtr, int index) { diff --git a/lib/animations/animation_data.dart b/lib/animations/animation_data.dart index b0e4f109..879f04d1 100644 --- a/lib/animations/animation_data.dart +++ b/lib/animations/animation_data.dart @@ -1,5 +1,7 @@ import 'dart:typed_data'; +import 'package:vector_math/vector_math_64.dart'; + /// /// Specifies frame data (i.e. weights) to animate the morph targets contained in [morphTargets] under a mesh named [mesh]. /// [data] is laid out as numFrames x numMorphTargets. @@ -40,7 +42,7 @@ class MorphAnimationData { class BoneAnimationData { final String boneName; final List meshNames; - final Float32List frameData; + final List frameData; double frameLengthInMs; BoneAnimationData( this.boneName, this.meshNames, this.frameData, this.frameLengthInMs); diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 1f9dc4ea..08be8c63 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -272,12 +272,9 @@ abstract class FilamentController { FilamentEntity entity, MorphAnimationData animation); /// - /// Animates morph target weights/bone transforms (where each frame requires a duration of [frameLengthInMs]. - /// [morphWeights] is a list of doubles in frame-major format. - /// Each frame is [numWeights] in length, and each entry is the weight to be applied to the morph target located at that index in the mesh primitive at that frame. - /// for now we only allow animating a single bone (though multiple skinned targets are supported) + /// Starts animating a bone (joint) according to the specified [animation]. /// - Future setBoneAnimation(FilamentEntity entity, BoneAnimationData animation); + Future addBoneAnimation(FilamentEntity entity, BoneAnimationData animation); /// /// Sets the local joint transform for the bone at the given index in [entity] for the mesh under [meshName]. diff --git a/lib/filament_controller_ffi.dart b/lib/filament_controller_ffi.dart index 5d8ffd22..6028f3b4 100644 --- a/lib/filament_controller_ffi.dart +++ b/lib/filament_controller_ffi.dart @@ -691,41 +691,40 @@ class FilamentControllerFFI extends FilamentController { } @override - Future setBoneAnimation( + Future addBoneAnimation( FilamentEntity entity, BoneAnimationData animation) async { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - // var data = calloc(animation.frameData.length); - // int offset = 0; - // var numFrames = animation.frameData.length ~/ 7; - // var boneNames = calloc>(1); - // boneNames.elementAt(0).value = - // animation.boneName.toNativeUtf8().cast(); - // var meshNames = calloc>(animation.meshNames.length); - // for (int i = 0; i < animation.meshNames.length; i++) { - // meshNames.elementAt(i).value = - // animation.meshNames[i].toNativeUtf8().cast(); - // } + var numFrames = animation.frameData.length; - // for (int i = 0; i < animation.frameData.length; i++) { - // data.elementAt(offset).value = animation.frameData[i]; - // offset += 1; - // } + var meshNames = calloc>(animation.meshNames.length); + for (int i = 0; i < animation.meshNames.length; i++) { + meshNames.elementAt(i).value = + animation.meshNames[i].toNativeUtf8().cast(); + } - // await _channel.invokeMethod("setBoneAnimation", [ - // _assetManager!, - // asset, - // data, - // numFrames, - // 1, - // boneNames, - // meshNames, - // animation.meshNames.length, - // animation.frameLengthInMs - // ]); - // calloc.free(data); + var data = calloc(numFrames * 4); + + for (int i = 0; i < numFrames; i++) { + data.elementAt(i * 4).value = animation.frameData[i].w; + data.elementAt((i * 4) + 1).value = animation.frameData[i].x; + data.elementAt((i * 4) + 2).value = animation.frameData[i].y; + data.elementAt((i * 4) + 3).value = animation.frameData[i].z; + } + + add_bone_animation( + _assetManager!, + entity, + data, + numFrames, + animation.boneName.toNativeUtf8().cast(), + meshNames, + animation.meshNames.length, + animation.frameLengthInMs); + calloc.free(data); + calloc.free(meshNames); } @override diff --git a/lib/generated_bindings.dart b/lib/generated_bindings.dart index f1ea54da..01828110 100644 --- a/lib/generated_bindings.dart +++ b/lib/generated_bindings.dart @@ -370,20 +370,18 @@ external bool set_morph_animation( EntityId, ffi.Pointer, ffi.Int, - ffi.Int, - ffi.Pointer>, + ffi.Pointer, ffi.Pointer>, ffi.Int, ffi.Float)>( - symbol: 'set_bone_animation', assetId: 'flutter_filament_plugin') -external void set_bone_animation( + symbol: 'add_bone_animation', assetId: 'flutter_filament_plugin') +external void add_bone_animation( ffi.Pointer assetManager, int asset, ffi.Pointer frameData, int numFrames, - int numBones, - ffi.Pointer> boneNames, - ffi.Pointer> meshName, + ffi.Pointer boneName, + ffi.Pointer> meshNames, int numMeshTargets, double frameLengthInMs, );