diff --git a/example/assets/shapes/shapes.blend b/example/assets/shapes/shapes.blend index 27743c63..31aa068a 100644 --- a/example/assets/shapes/shapes.blend +++ b/example/assets/shapes/shapes.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ab0cada556723be0d138d7b1cadb5e315a273524db0468e0c4255d8d2b0c1c2d -size 1222992 +oid sha256:983af4eb524f24b17bf081ae40a7217b60415122ab02cbf02c0186fbf069d52a +size 1251408 diff --git a/example/assets/shapes/shapes.glb b/example/assets/shapes/shapes.glb index 7be024c3..015701e5 100644 --- a/example/assets/shapes/shapes.glb +++ b/example/assets/shapes/shapes.glb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b728c8fe0ce9eb06290dc37034404a952df8ea360b014b76c82fe8b9d695e85a -size 113124 +oid sha256:715793a3cf36ccf5608c347b961d0f2549e54edb4ba5227a5a008dc1d3445e83 +size 116948 diff --git a/example/lib/main.dart b/example/lib/main.dart index ed9431fe..2de07159 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -73,8 +73,6 @@ class ExampleWidgetState extends State { static FilamentEntity? flightHelmet; static FilamentEntity? buster; - static List? animations; - static FilamentEntity? directionalLight; static bool loop = false; @@ -90,8 +88,6 @@ class ExampleWidgetState extends State { setState(() { _filamentController = FilamentControllerFFI(); }); - await Future.delayed(const Duration(milliseconds: 100)); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { await _filamentController!.createViewer(); _createEntityLoadListener(); @@ -101,8 +97,7 @@ class ExampleWidgetState extends State { await _filamentController!.setRendering(true); assets.add( await _filamentController!.loadGlb("assets/shapes/shapes.glb")); - ExampleWidgetState.animations = - await _filamentController!.getAnimationNames(assets.first); + await _filamentController! .setCameraManipulatorOptions(zoomSpeed: 1.0); @@ -123,7 +118,6 @@ class ExampleWidgetState extends State { _listener = _filamentController!.onLoad.listen((FilamentEntity entity) async { assets.add(entity); - animations = await _filamentController!.getAnimationNames(entity); if (mounted) { setState(() {}); } @@ -136,37 +130,65 @@ class ExampleWidgetState extends State { final _sharedFocusNode = FocusNode(); Widget _assetEntry(FilamentEntity entity) { - return Row(children: [ - Text("Asset ${entity}"), - IconButton( - tooltip: "Transform to unit cube", - onPressed: () async { - await _filamentController!.transformToUnitCube(entity); - }, - icon: const Icon(Icons.settings_overscan_outlined)), - IconButton( - onPressed: () async { - _transformController?.dispose(); - if (_controlled == entity) { - _controlled = null; - } else { - _controlled = entity; - _transformController?.dispose(); - _transformController = - EntityTransformController(_filamentController!, entity); - } - setState(() {}); - }, - icon: Icon(Icons.control_camera, - color: _controlled == entity ? Colors.green : Colors.black)), - IconButton( - onPressed: () async { - await _filamentController!.removeEntity(entity); - assets.remove(entity); - setState(() {}); - }, - icon: const Icon(Icons.cancel_sharp)), - ]); + return FutureBuilder( + future: _filamentController!.getAnimationNames(entity), + builder: (_, animations) { + if (animations.data == null) { + return Container(); + } + return Row(children: [ + Text("Asset ${entity}"), + IconButton( + iconSize: 14, + tooltip: "Transform to unit cube", + onPressed: () async { + await _filamentController!.transformToUnitCube(entity); + }, + icon: const Icon(Icons.settings_overscan_outlined)), + IconButton( + iconSize: 14, + tooltip: "Attach mouse control", + onPressed: () async { + _transformController?.dispose(); + if (_controlled == entity) { + _controlled = null; + } else { + _controlled = entity; + _transformController?.dispose(); + _transformController = + EntityTransformController(_filamentController!, entity); + } + setState(() {}); + }, + icon: Icon(Icons.control_camera, + color: + _controlled == entity ? Colors.green : Colors.black)), + IconButton( + iconSize: 14, + tooltip: "Remove", + onPressed: () async { + await _filamentController!.removeEntity(entity); + assets.remove(entity); + setState(() {}); + }, + icon: const Icon(Icons.cancel_sharp)), + if (animations.data!.isNotEmpty) + PopupMenuButton( + tooltip: "Animations", + itemBuilder: (_) => animations.data! + .map((a) => PopupMenuItem( + value: a, + child: Text(a), + )) + .toList(), + onSelected: (value) async { + print("Playing animation $value"); + await _filamentController! + .playAnimation(entity, animations.data!.indexOf(value!)); + }, + ) + ]); + }); } @override @@ -222,8 +244,9 @@ class ExampleWidgetState extends State { ), GestureDetector( onTap: () async { - await _filamentController! - .loadGlb('assets/shapes/shapes.glb'); + await _filamentController!.loadGlb( + 'assets/shapes/shapes.glb', + numInstances: 10); }, child: Container( color: Colors.transparent, diff --git a/example/lib/menus/asset_submenu.dart b/example/lib/menus/asset_submenu.dart index 7aa1d052..358cfebb 100644 --- a/example/lib/menus/asset_submenu.dart +++ b/example/lib/menus/asset_submenu.dart @@ -43,16 +43,25 @@ class _AssetSubmenuState extends State { child: const Text('Find Cylinder entity by name')), MenuItemButton( onPressed: () async { - Timer.periodic(const Duration(milliseconds: 50), (_) async { - await widget.controller.setBoneTransform( - ExampleWidgetState.assets.last, - "Cylinder", - "Bone", - Matrix4.rotationX(pi / 2)); - }); + await widget.controller.addBoneAnimation( + ExampleWidgetState.assets.last, + BoneAnimationData([ + "Bone" + ], [ + "Cylinder" + ], [ + [v.Quaternion.axisAngle(v.Vector3(1, 1, 1), pi / 2)] + ], [ + [v.Vector3.zero()] + ], 16)); }, child: const Text('Set bone transform for Cylinder (pi/2 rotation X)')), + MenuItemButton( + onPressed: () async { + await widget.controller.resetBones(ExampleWidgetState.assets.last); + }, + child: const Text('Reset bones for Cylinder')), MenuItemButton( onPressed: () async { await widget.controller.addBoneAnimation( @@ -72,9 +81,11 @@ class _AssetSubmenuState extends State { }, child: const Text('Set bone transform animation for Cylinder')), MenuItemButton( + closeOnActivate: false, onPressed: () async { var names = await widget.controller.getMorphTargetNames( ExampleWidgetState.assets.last, "Cylinder"); + print("NAMES : $names"); await showDialog( context: context, builder: (ctx) { @@ -134,26 +145,6 @@ class _AssetSubmenuState extends State { child: Text( "Toggle animation looping ${ExampleWidgetState.loop ? "OFF" : "ON"}")) ]; - if (ExampleWidgetState.animations != null) { - children.addAll(ExampleWidgetState.animations!.map((a) => MenuItemButton( - onPressed: () { - widget.controller.playAnimation(ExampleWidgetState.assets.last, - ExampleWidgetState.animations!.indexOf(a), - replaceActive: true, - crossfade: 0.5, - loop: ExampleWidgetState.loop); - }, - child: Text( - "play animation ${ExampleWidgetState.animations!.indexOf(a)} (replace/fade)")))); - children.addAll(ExampleWidgetState.animations!.map((a) => MenuItemButton( - onPressed: () { - widget.controller.playAnimation(ExampleWidgetState.assets.last, - ExampleWidgetState.animations!.indexOf(a), - replaceActive: false, loop: ExampleWidgetState.loop); - }, - child: Text( - "Play animation ${ExampleWidgetState.animations!.indexOf(a)} (noreplace)")))); - } return SubmenuButton(menuChildren: children, child: const Text("Shapes")); } @@ -213,8 +204,6 @@ class _AssetSubmenuState extends State { force: true); await widget.controller .playAnimation(ExampleWidgetState.buster!, 0, loop: true); - ExampleWidgetState.animations = await widget.controller - .getAnimationNames(ExampleWidgetState.assets.last); } else { await widget.controller .removeEntity(ExampleWidgetState.buster!); @@ -242,7 +231,7 @@ class _AssetSubmenuState extends State { : 'Remove flight helmet')), MenuItemButton( onPressed: () { - widget.controller.setBackgroundColor(const Color(0xFF73C9FA)); + widget.controller.setBackgroundColor(const Color(0xAA73C9FA)); }, child: const Text("Set background color")), MenuItemButton( diff --git a/example/lib/menus/camera_submenu.dart b/example/lib/menus/camera_submenu.dart index 9ab4464c..ba424e6e 100644 --- a/example/lib/menus/camera_submenu.dart +++ b/example/lib/menus/camera_submenu.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; - +import 'package:vector_math/vector_math_64.dart' as v; import 'package:flutter_filament/filament_controller.dart'; import 'package:flutter_filament_example/main.dart'; @@ -99,7 +99,8 @@ class _CameraSubmenuState extends State { MenuItemButton( onPressed: () async { widget.controller.setCameraPosition(0.0, 0.0, 0.0); - widget.controller.setCameraRotation(0, 0.0, 1.0, 0.0); + widget.controller.setCameraRotation( + v.Quaternion.axisAngle(v.Vector3(0, 0.0, 1.0), 0.0)); }, child: const Text('Move to 0,0,0, facing towards 0,0,-1'), ), @@ -119,7 +120,8 @@ class _CameraSubmenuState extends State { ), MenuItemButton( onPressed: () { - widget.controller.setCameraRotation(pi / 4, 0.0, 1.0, 0.0); + widget.controller.setCameraRotation( + v.Quaternion.axisAngle(v.Vector3(0, 1, 0), pi / 4)); }, child: const Text("Rotate camera 45 degrees around y axis"), ), diff --git a/example/lib/picker_result_widget.dart b/example/lib/picker_result_widget.dart index 01544d46..dca58d90 100644 --- a/example/lib/picker_result_widget.dart +++ b/example/lib/picker_result_widget.dart @@ -9,11 +9,8 @@ class PickerResultWidget extends StatelessWidget { @override Widget build(BuildContext context) { return StreamBuilder( - stream: controller.pickResult.map((FilamentEntity? entityId) { - if (entityId == null) { - return null; - } - return controller.getNameForEntity(entityId); + stream: controller.pickResult.map((result) { + return controller.getNameForEntity(result.entity); }), builder: (ctx, snapshot) => snapshot.data == null ? Container() diff --git a/ios/include/FlutterFilamentApi.h b/ios/include/FlutterFilamentApi.h index fed53bc2..a1474b43 100644 --- a/ios/include/FlutterFilamentApi.h +++ b/ios/include/FlutterFilamentApi.h @@ -73,9 +73,14 @@ extern "C" 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 *sceneManager, const char *assetPath, bool unlit); + FLUTTER_PLUGIN_EXPORT EntityId load_glb(void *sceneManager, const char *assetPath, int numInstances); + FLUTTER_PLUGIN_EXPORT EntityId load_glb_from_buffer(void *sceneManager, const void* const data, size_t length); FLUTTER_PLUGIN_EXPORT EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath); + FLUTTER_PLUGIN_EXPORT EntityId create_instance(void *sceneManager, EntityId id); + FLUTTER_PLUGIN_EXPORT int get_instance_count(void *sceneManager, EntityId entityId); + FLUTTER_PLUGIN_EXPORT void get_instances(void *sceneManager, EntityId entityId, EntityId *out); FLUTTER_PLUGIN_EXPORT void set_main_camera(const void *const viewer); + FLUTTER_PLUGIN_EXPORT EntityId get_main_camera(const void *const viewer); 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( @@ -159,7 +164,7 @@ extern "C" 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_rotation(const void *const viewer, float w, 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); diff --git a/ios/include/FlutterFilamentFFIApi.h b/ios/include/FlutterFilamentFFIApi.h index 006db42a..097f369a 100644 --- a/ios/include/FlutterFilamentFFIApi.h +++ b/ios/include/FlutterFilamentFFIApi.h @@ -38,34 +38,36 @@ FLUTTER_PLUGIN_EXPORT void remove_ibl_ffi(void* const viewer); FLUTTER_PLUGIN_EXPORT EntityId add_light_ffi(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_ffi(void* const viewer, EntityId entityId); FLUTTER_PLUGIN_EXPORT void clear_lights_ffi(void* const viewer); -FLUTTER_PLUGIN_EXPORT EntityId load_glb_ffi(void* const assetManager, const char *assetPath, bool unlit); -FLUTTER_PLUGIN_EXPORT EntityId load_gltf_ffi(void* const assetManager, const char *assetPath, const char *relativePath); +FLUTTER_PLUGIN_EXPORT EntityId load_glb_ffi(void* const sceneManager, const char *assetPath, int numInstances); +FLUTTER_PLUGIN_EXPORT EntityId load_glb_from_buffer_ffi(void* const sceneManager, const void* const data, size_t length, int numInstances); +FLUTTER_PLUGIN_EXPORT EntityId load_gltf_ffi(void* const sceneManager, const char *assetPath, const char *relativePath); +FLUTTER_PLUGIN_EXPORT EntityId create_instance_ffi(void* const sceneManager, EntityId entityId); FLUTTER_PLUGIN_EXPORT void remove_entity_ffi(void* const viewer, EntityId asset); FLUTTER_PLUGIN_EXPORT void clear_entities_ffi(void* const viewer); FLUTTER_PLUGIN_EXPORT bool set_camera_ffi(void* const viewer, EntityId asset, const char *nodeName); FLUTTER_PLUGIN_EXPORT void apply_weights_ffi( - void* const assetManager, + void* const sceneManager, EntityId asset, const char *const entityName, float *const weights, int count ); -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); -FLUTTER_PLUGIN_EXPORT int get_animation_count_ffi(void* const assetManager, EntityId asset); -FLUTTER_PLUGIN_EXPORT void get_animation_name_ffi(void* const assetManager, EntityId asset, char *const outPtr, int index); -FLUTTER_PLUGIN_EXPORT void get_morph_target_name_ffi(void* const assetManager, EntityId asset, const char *meshName, char *const outPtr, int index); -FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count_ffi(void* const assetManager, EntityId asset, const char *meshName); -FLUTTER_PLUGIN_EXPORT void set_morph_target_weights_ffi(void* const assetManager, +FLUTTER_PLUGIN_EXPORT void play_animation_ffi(void* const sceneManager, EntityId asset, int index, bool loop, bool reverse, bool replaceActive, float crossfade); +FLUTTER_PLUGIN_EXPORT void set_animation_frame_ffi(void* const sceneManager, EntityId asset, int animationIndex, int animationFrame); +FLUTTER_PLUGIN_EXPORT void stop_animation_ffi(void* const sceneManager, EntityId asset, int index); +FLUTTER_PLUGIN_EXPORT int get_animation_count_ffi(void* const sceneManager, EntityId asset); +FLUTTER_PLUGIN_EXPORT void get_animation_name_ffi(void* const sceneManager, EntityId asset, char *const outPtr, int index); +FLUTTER_PLUGIN_EXPORT void get_morph_target_name_ffi(void* const sceneManager, EntityId asset, const char *meshName, char *const outPtr, int index); +FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count_ffi(void* const sceneManager, EntityId asset, const char *meshName); +FLUTTER_PLUGIN_EXPORT void set_morph_target_weights_ffi(void* const sceneManager, EntityId asset, const char *const entityName, const float *const morphData, int numWeights ); FLUTTER_PLUGIN_EXPORT bool set_morph_animation_ffi( - void *assetManager, + void *sceneManager, EntityId asset, const char *const entityName, const float *const morphData, @@ -74,13 +76,13 @@ FLUTTER_PLUGIN_EXPORT bool set_morph_animation_ffi( int numFrames, float frameLengthInMs); FLUTTER_PLUGIN_EXPORT bool set_bone_transform_ffi( - void *assetManager, + void *sceneManager, EntityId asset, const char *entityName, const float *const transform, const char *boneName); FLUTTER_PLUGIN_EXPORT void add_bone_animation_ffi( - void *assetManager, + void *sceneManager, EntityId asset, const float *const frameData, int numFrames, @@ -91,7 +93,7 @@ FLUTTER_PLUGIN_EXPORT void add_bone_animation_ffi( bool isModelSpace); FLUTTER_PLUGIN_EXPORT void set_post_processing_ffi(void* const viewer, bool enabled); FLUTTER_PLUGIN_EXPORT void pick_ffi(void* const viewer, int x, int y, EntityId* entityId); -FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose_ffi(void* const assetManager, EntityId entityId); +FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose_ffi(void* const sceneManager, EntityId entityId); FLUTTER_PLUGIN_EXPORT void ios_dummy_ffi(); FLUTTER_PLUGIN_EXPORT EntityId create_geometry_ffi(void* const viewer, float* vertices, int numVertices, uint16_t* indices, int numIndices, const char* materialPath); diff --git a/ios/include/SceneAsset.hpp b/ios/include/SceneAsset.hpp deleted file mode 100644 index 3b34940e..00000000 --- a/ios/include/SceneAsset.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include "Log.hpp" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -extern "C" { - #include "FlutterFilamentApi.h" -} -template class std::vector; -namespace polyvox { - using namespace filament; - using namespace filament::gltfio; - using namespace utils; - using namespace std; - - typedef std::chrono::time_point time_point_t; - - enum AnimationType { - MORPH, BONE, GLTF - }; - - struct AnimationStatus { - 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 construct a dynamic (i.e. non-glTF embedded) morph target animation. - // - 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/joint animation. - // - struct BoneAnimation : AnimationStatus { - size_t boneIndex; - vector meshTargets; - size_t skinIndex = 0; - int lengthInFrames; - float frameLengthInMs = 0; - vector frameData; - }; - - struct SceneAsset { - FilamentAsset* asset = nullptr; - vector initialJointTransforms; - vector gltfAnimations; - vector morphAnimations; - vector boneAnimations; - - // the index of the last active glTF animation, - // used to cross-fade - int fadeGltfAnimationIndex = -1; - float fadeDuration = 0.0f; - float fadeOutAnimationStart = 0.0f; - - // a slot to preload textures - filament::Texture* texture = nullptr; - - SceneAsset( - FilamentAsset* asset - ) : asset(asset) {} - }; -} diff --git a/ios/include/SceneManager.hpp b/ios/include/SceneManager.hpp index cbac0282..b89e23b2 100644 --- a/ios/include/SceneManager.hpp +++ b/ios/include/SceneManager.hpp @@ -1,41 +1,64 @@ #pragma once #include +#include +#include +#include #include #include #include +#include #include -#include "SceneAsset.hpp" +#include "utils/NameComponentManager.h" #include "ResourceBuffer.hpp" -#include "components/StandardComponents.h" +#include "components/CollisionComponentManager.hpp" +#include "components/AnimationComponentManager.hpp" -typedef int32_t EntityId; +#include "tsl/robin_map.h" -namespace polyvox +namespace flutter_filament { + typedef int32_t EntityId; + using namespace filament; using namespace filament::gltfio; + using namespace utils; + using std::vector; + using std::unique_ptr; + using std::string; + class SceneManager { public: SceneManager(const ResourceLoaderWrapper *const loader, - NameComponentManager *ncm, Engine *engine, Scene *scene, const char *uberArchivePath); ~SceneManager(); + + EntityId loadGltf(const char *uri, const char *relativeResourcePath); - EntityId loadGlb(const char *uri, bool unlit); - FilamentAsset *getAssetByEntityId(EntityId entityId); + + //// + /// @brief + /// @param uri + /// @param numInstances + /// @return an Entity representing the FilamentAsset associated with the loaded FilamentAsset. + /// + EntityId loadGlb(const char *uri, int numInstances); + EntityId loadGlbFromBuffer(const uint8_t* data, size_t length, int numInstances=1); + EntityId createInstance(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); + + unique_ptr> getMorphTargetNames(EntityId entity, const char *name); void transformToUnitCube(EntityId e); inline void updateTransform(EntityId e); void setScale(EntityId e, float scale); @@ -45,8 +68,8 @@ namespace polyvox void queueRotationUpdate(EntityId e, float rads, float x, float y, float z, float w, bool relative); 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; + const utils::Entity *getLightEntities(EntityId e) noexcept; + size_t getLightEntityCount(EntityId e) noexcept; void updateAnimations(); void updateTransforms(); void testCollisions(EntityId entity); @@ -107,29 +130,48 @@ namespace polyvox void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform); void removeCollisionComponent(EntityId entityId); void setParent(EntityId child, EntityId parent); + void addAnimatableComponent(EntityId entity); + + /// @brief returns the number of instances of the FilamentAsset represented by the given entity. + /// @param entityId + /// @return + int getInstanceCount(EntityId entityId); + + /// @brief returns an array containing all instances of the FilamentAsset represented by the given entity. + /// @param entityId + /// @return + void getInstances(EntityId entityId, EntityId* out); + + friend class FilamentViewer; private: - AssetLoader *_assetLoader = nullptr; + gltfio::AssetLoader *_assetLoader = nullptr; const ResourceLoaderWrapper *const _resourceLoaderWrapper; - NameComponentManager *_ncm = nullptr; Engine *_engine; Scene *_scene; - MaterialProvider *_ubershaderProvider = nullptr; + gltfio::MaterialProvider *_ubershaderProvider = nullptr; gltfio::ResourceLoader *_gltfResourceLoader = nullptr; gltfio::TextureProvider *_stbDecoder = nullptr; gltfio::TextureProvider *_ktxDecoder = nullptr; std::mutex _mutex; - vector _assets; - tsl::robin_map _entityIdLookup; - tsl::robin_map> _transformUpdates; - std::vector _nonTransformableCollidableEntities; + utils::NameComponentManager* _ncm; + tsl::robin_map< + EntityId, + gltfio::FilamentInstance*> _instances; + tsl::robin_map _assets; + tsl::robin_map> _transformUpdates; + + AnimationComponentManager* _animationComponentManager = nullptr; CollisionComponentManager* _collisionComponentManager = nullptr; + gltfio::FilamentInstance* getInstanceByEntityId(EntityId entityId); + gltfio::FilamentAsset* getAssetByEntityId(EntityId entityId); + utils::Entity findEntityByName( - SceneAsset asset, + const gltfio::FilamentInstance* instance, const char *entityName); }; diff --git a/ios/include/StreamBufferAdapter.hpp b/ios/include/StreamBufferAdapter.hpp index f1931bc8..8e1cca43 100644 --- a/ios/include/StreamBufferAdapter.hpp +++ b/ios/include/StreamBufferAdapter.hpp @@ -5,9 +5,8 @@ #include #include -namespace polyvox { +namespace flutter_filament { - using namespace std; // // A generic adapter to expose any contiguous section of memory as a std::streambuf. @@ -20,15 +19,15 @@ namespace polyvox { ~StreamBufferAdapter() { } - streamsize size(); + std::streamsize size(); private: int_type uflow() override; int_type underflow() override; int_type pbackfail(int_type ch) override; - streampos seekoff(streamoff off, ios_base::seekdir way, ios_base::openmode which) override; - streampos seekpos(streampos sp, ios_base::openmode which) override; - streamsize showmanyc() override; + std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which) override; + std::streampos seekpos(std::streampos sp, std::ios_base::openmode which) override; + std::streamsize showmanyc() override; }; diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index 4eb6a6c8..3ffcc394 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -91,11 +91,6 @@ #include "TimeIt.hpp" #include "ThreadPool.hpp" -using namespace filament; -using namespace filament::math; -using namespace gltfio; -using namespace utils; -using namespace image; namespace filament { @@ -103,9 +98,18 @@ namespace filament class LightManager; } // namespace filament -namespace polyvox +namespace flutter_filament { + using namespace filament; + using namespace filament::math; + using namespace gltfio; + using namespace utils; + using namespace image; + using namespace std::chrono; + + using std::string; + // const float kAperture = 1.0f; // const float kShutterSpeed = 1.0f; // const float kSensitivity = 50.0f; @@ -135,6 +139,8 @@ namespace polyvox _engine = Engine::create(Engine::Backend::OPENGL, (backend::Platform *)platform, (void *)sharedContext, nullptr); #endif + _engine->setAutomaticInstancingEnabled(true); + _renderer = _engine->createRenderer(); _frameInterval = 1000.0f / 60.0f; @@ -151,6 +157,7 @@ namespace polyvox Log("Main camera created"); _view = _engine->createView(); + Log("View created"); setToneMapping(ToneMapping::ACES); @@ -200,15 +207,11 @@ namespace polyvox _view->setDynamicResolutionOptions(options); setAntiAliasing(false, true, false); - EntityManager &em = EntityManager::get(); - _ncm = new NameComponentManager(em); - _sceneManager = new SceneManager( _resourceLoaderWrapper, - _ncm, _engine, _scene, uberArchivePath); @@ -339,7 +342,7 @@ namespace polyvox int32_t FilamentViewer::addLight(LightManager::Type t, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows) { auto light = EntityManager::get().create(); - LightManager::Builder(t) + auto builder = LightManager::Builder(t) .color(Color::cct(colour)) .intensity(intensity) .position(math::float3(posX, posY, posZ)) @@ -377,7 +380,7 @@ namespace polyvox _lights.clear(); } - static bool endsWith(string path, string ending) + static bool endsWith(std::string path, std::string ending) { return path.compare(path.length() - ending.length(), ending.length(), ending) == 0; } @@ -435,7 +438,7 @@ namespace polyvox void FilamentViewer::loadPngTexture(string path, ResourceBuffer rb) { - polyvox::StreamBufferAdapter sb((char *)rb.data, (char *)rb.data + rb.size); + flutter_filament::StreamBufferAdapter sb((char *)rb.data, (char *)rb.data + rb.size); std::istream inputStream(&sb); @@ -480,7 +483,7 @@ namespace polyvox void FilamentViewer::loadTextureFromPath(string path) { - string ktxExt(".ktx"); + std::string ktxExt(".ktx"); string ktx2Ext(".ktx2"); string pngExt(".png"); @@ -802,10 +805,22 @@ namespace polyvox cam.setFocusDistance(_cameraFocusDistance); } + /// + /// + /// void FilamentViewer::setMainCamera() { _view->setCamera(_mainCamera); } + /// + /// + /// + EntityId FilamentViewer::getMainCamera() { + return Entity::smuggle(_mainCamera->getEntity()); + } + + + /// /// Sets the active camera to the GLTF camera node specified by [name] (or if null, the first camera found under that node). /// N.B. Blender will generally export a three-node hierarchy - @@ -832,18 +847,16 @@ namespace polyvox utils::Entity target; if (!cameraName) - { - auto inst = _ncm->getInstance(cameras[0]); - const char *name = _ncm->getName(inst); + { target = cameras[0]; + const char *name = asset->getName(target); Log("No camera specified, using first camera node found (%s)", name); } else { for (int j = 0; j < count; j++) { - auto inst = _ncm->getInstance(cameras[j]); - const char *name = _ncm->getName(inst); + const char *name = asset->getName(cameras[j]); if (strcmp(name, cameraName) == 0) { target = cameras[j]; @@ -1138,7 +1151,7 @@ namespace polyvox std::string filename = stringStream.str(); - ofstream wf(filename, ios::out | ios::binary); + std::ofstream wf(filename, std::ios::out | std::ios::binary); LinearImage image(toLinearWithAlpha(vp.width, vp.height, vp.width * 4, static_cast(buf))); @@ -1228,7 +1241,7 @@ namespace polyvox Camera &cam = _view->getCamera(); _cameraPosition = math::mat4f::translation(math::float3(x, y, z)); - cam.setModelMatrix(_cameraPosition * _cameraRotation); + cam.setModelMatrix(_cameraRotation * _cameraPosition); } void FilamentViewer::moveCameraToAsset(EntityId entityId) @@ -1249,11 +1262,11 @@ namespace polyvox Log("Moved camera to %f %f %f, lookAt %f %f %f, near %f far %f", eye[0], eye[1], eye[2], lookAt[0], lookAt[1], lookAt[2], cam.getNear(), cam.getCullingFar()); } - void FilamentViewer::setCameraRotation(float rads, float x, float y, float z) + void FilamentViewer::setCameraRotation(float w, float x, float y, float z) { Camera &cam = _view->getCamera(); - _cameraRotation = math::mat4f::rotation(rads, math::float3(x, y, z)); - cam.setModelMatrix(_cameraPosition * _cameraRotation); + _cameraRotation = math::mat4f(math::quatf(w, x, y, z)); + cam.setModelMatrix(_cameraRotation * _cameraPosition); } void FilamentViewer::setCameraModelMatrix(const float *const matrix) @@ -1455,7 +1468,10 @@ namespace polyvox void FilamentViewer::pick(uint32_t x, uint32_t y, EntityId *entityId) { _view->pick(x, y, [=](filament::View::PickingQueryResult const &result) - { *entityId = Entity::smuggle(result.renderable); }); + { + + *entityId = Entity::smuggle(result.renderable); + }); } EntityId FilamentViewer::createGeometry(float *vertices, uint32_t numVertices, uint16_t *indices, uint32_t numIndices, const char* materialPath) @@ -1523,4 +1539,4 @@ namespace polyvox return Entity::smuggle(renderable); } -} // namespace polyvox +} // namespace flutter_filament diff --git a/ios/src/FlutterFilamentApi.cpp b/ios/src/FlutterFilamentApi.cpp index cd8c9ac9..175f7448 100644 --- a/ios/src/FlutterFilamentApi.cpp +++ b/ios/src/FlutterFilamentApi.cpp @@ -8,7 +8,7 @@ #include #include -using namespace polyvox; +using namespace flutter_filament; extern "C" { @@ -114,9 +114,26 @@ extern "C" ((FilamentViewer *)viewer)->clearLights(); } - FLUTTER_PLUGIN_EXPORT EntityId load_glb(void *sceneManager, const char *assetPath, bool unlit) + FLUTTER_PLUGIN_EXPORT EntityId load_glb(void *sceneManager, const char *assetPath, int numInstances) { - return ((SceneManager *)sceneManager)->loadGlb(assetPath, unlit); + return ((SceneManager *)sceneManager)->loadGlb(assetPath, numInstances); + } + + FLUTTER_PLUGIN_EXPORT EntityId load_glb_from_buffer(void *sceneManager, const void* const data, size_t length) + { + return ((SceneManager *)sceneManager)->loadGlbFromBuffer((const uint8_t*)data, length); + } + + FLUTTER_PLUGIN_EXPORT EntityId create_instance(void *sceneManager, EntityId entityId) { + return ((SceneManager *)sceneManager)->createInstance(entityId); + } + + FLUTTER_PLUGIN_EXPORT int get_instance_count(void *sceneManager, EntityId entityId) { + return ((SceneManager*)sceneManager)->getInstanceCount(entityId); + } + + FLUTTER_PLUGIN_EXPORT void get_instances(void *sceneManager, EntityId entityId, EntityId *out) { + return ((SceneManager*)sceneManager)->getInstances(entityId, out); } FLUTTER_PLUGIN_EXPORT EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath) @@ -129,6 +146,12 @@ extern "C" return ((FilamentViewer *)viewer)->setMainCamera(); } + + FLUTTER_PLUGIN_EXPORT EntityId get_main_camera(const void *const viewer) + { + return ((FilamentViewer *)viewer)->getMainCamera(); + } + FLUTTER_PLUGIN_EXPORT bool set_camera(const void *const viewer, EntityId asset, const char *nodeName) { return ((FilamentViewer *)viewer)->setCamera(asset, nodeName); @@ -236,9 +259,9 @@ extern "C" ((FilamentViewer *)viewer)->setCameraPosition(x, y, z); } - 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_rotation(const void *const viewer, float w, float x, float y, float z) { - ((FilamentViewer *)viewer)->setCameraRotation(rads, x, y, z); + ((FilamentViewer *)viewer)->setCameraRotation(w, x, y, z); } FLUTTER_PLUGIN_EXPORT void set_camera_model_matrix(const void *const viewer, const float *const matrix) @@ -448,20 +471,20 @@ extern "C" int index) { auto names = ((SceneManager *)sceneManager)->getAnimationNames(asset); - string name = names->at(index); + std::string name = names->at(index); strcpy(outPtr, name.c_str()); } FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count(void *sceneManager, EntityId asset, const char *meshName) { - unique_ptr> names = ((SceneManager *)sceneManager)->getMorphTargetNames(asset, meshName); + std::unique_ptr> names = ((SceneManager *)sceneManager)->getMorphTargetNames(asset, meshName); return (int)names->size(); } FLUTTER_PLUGIN_EXPORT void get_morph_target_name(void *sceneManager, EntityId asset, const char *meshName, char *const outPtr, int index) { - unique_ptr> names = ((SceneManager *)sceneManager)->getMorphTargetNames(asset, meshName); - string name = names->at(index); + std::unique_ptr> names = ((SceneManager *)sceneManager)->getMorphTargetNames(asset, meshName); + std::string name = names->at(index); strcpy(outPtr, name.c_str()); } @@ -572,7 +595,7 @@ extern "C" FLUTTER_PLUGIN_EXPORT EntityId find_child_entity_by_name(void *const sceneManager, const EntityId parent, const char* name) { auto entity = ((SceneManager*)sceneManager)->findChildEntityByName(parent, name); - return Entity::smuggle(entity); + return utils::Entity::smuggle(entity); } FLUTTER_PLUGIN_EXPORT void set_parent(void *const sceneManager, EntityId child, EntityId parent) { diff --git a/ios/src/FlutterFilamentFFIApi.cpp b/ios/src/FlutterFilamentFFIApi.cpp index bae93f73..1ee2dcc3 100644 --- a/ios/src/FlutterFilamentFFIApi.cpp +++ b/ios/src/FlutterFilamentFFIApi.cpp @@ -31,7 +31,7 @@ extern "C" #include #endif -using namespace polyvox; +using namespace flutter_filament; using namespace std::chrono_literals; class RenderLoop { @@ -262,21 +262,30 @@ set_background_color_ffi(void *const viewer, const float r, const float g, fut.wait(); } -FLUTTER_PLUGIN_EXPORT EntityId load_gltf_ffi(void *const assetManager, +FLUTTER_PLUGIN_EXPORT EntityId load_gltf_ffi(void *const sceneManager, const char *path, const char *relativeResourcePath) { std::packaged_task lambda([&]() mutable { - return load_gltf(assetManager, path, relativeResourcePath); + return load_gltf(sceneManager, path, relativeResourcePath); }); auto fut = _rl->add_task(lambda); fut.wait(); return fut.get(); } -FLUTTER_PLUGIN_EXPORT EntityId load_glb_ffi(void *const assetManager, - const char *path, bool unlit) { +FLUTTER_PLUGIN_EXPORT EntityId load_glb_ffi(void *const sceneManager, + const char *path, int numInstances) { std::packaged_task lambda( - [&]() mutable { return load_glb(assetManager, path, unlit); }); + [&]() mutable { return load_glb(sceneManager, path, numInstances); }); + auto fut = _rl->add_task(lambda); + fut.wait(); + return fut.get(); +} + +FLUTTER_PLUGIN_EXPORT EntityId load_glb_from_buffer_ffi(void *const sceneManager, + const void *const data, size_t length, int numInstances) { + std::packaged_task lambda( + [&]() mutable { return load_glb_from_buffer(sceneManager, data, length); }); auto fut = _rl->add_task(lambda); fut.wait(); return fut.get(); @@ -388,20 +397,20 @@ FLUTTER_PLUGIN_EXPORT bool set_camera_ffi(void *const viewer, EntityId asset, } FLUTTER_PLUGIN_EXPORT void -get_morph_target_name_ffi(void *assetManager, EntityId asset, +get_morph_target_name_ffi(void *sceneManager, EntityId asset, const char *meshName, char *const outPtr, int index) { std::packaged_task lambda([&] { - get_morph_target_name(assetManager, asset, meshName, outPtr, index); + get_morph_target_name(sceneManager, asset, meshName, outPtr, index); }); auto fut = _rl->add_task(lambda); fut.wait(); } FLUTTER_PLUGIN_EXPORT int -get_morph_target_name_count_ffi(void *assetManager, EntityId asset, +get_morph_target_name_count_ffi(void *sceneManager, EntityId asset, const char *meshName) { std::packaged_task lambda([&] { - return get_morph_target_name_count(assetManager, asset, meshName); + return get_morph_target_name_count(sceneManager, asset, meshName); }); auto fut = _rl->add_task(lambda); fut.wait(); @@ -410,52 +419,52 @@ get_morph_target_name_count_ffi(void *assetManager, EntityId asset, -FLUTTER_PLUGIN_EXPORT void play_animation_ffi(void *const assetManager, +FLUTTER_PLUGIN_EXPORT void play_animation_ffi(void *const sceneManager, EntityId asset, int index, bool loop, bool reverse, bool replaceActive, float crossfade) { std::packaged_task lambda([&] { - play_animation(assetManager, asset, index, loop, reverse, replaceActive, + play_animation(sceneManager, asset, index, loop, reverse, replaceActive, crossfade); }); auto fut = _rl->add_task(lambda); fut.wait(); } -FLUTTER_PLUGIN_EXPORT void set_animation_frame_ffi(void *const assetManager, +FLUTTER_PLUGIN_EXPORT void set_animation_frame_ffi(void *const sceneManager, EntityId asset, int animationIndex, int animationFrame) { std::packaged_task lambda([&] { - set_animation_frame(assetManager, asset, animationIndex, animationFrame); + set_animation_frame(sceneManager, asset, animationIndex, animationFrame); }); auto fut = _rl->add_task(lambda); fut.wait(); } -FLUTTER_PLUGIN_EXPORT void stop_animation_ffi(void *const assetManager, +FLUTTER_PLUGIN_EXPORT void stop_animation_ffi(void *const sceneManager, EntityId asset, int index) { std::packaged_task lambda( - [&] { stop_animation(assetManager, asset, index); }); + [&] { stop_animation(sceneManager, asset, index); }); auto fut = _rl->add_task(lambda); fut.wait(); } -FLUTTER_PLUGIN_EXPORT int get_animation_count_ffi(void *const assetManager, +FLUTTER_PLUGIN_EXPORT int get_animation_count_ffi(void *const sceneManager, EntityId asset) { std::packaged_task lambda( - [&] { return get_animation_count(assetManager, asset); }); + [&] { return get_animation_count(sceneManager, asset); }); auto fut = _rl->add_task(lambda); fut.wait(); return fut.get(); } -FLUTTER_PLUGIN_EXPORT void get_animation_name_ffi(void *const assetManager, +FLUTTER_PLUGIN_EXPORT void get_animation_name_ffi(void *const sceneManager, EntityId asset, char *const outPtr, int index) { std::packaged_task lambda( - [&] { get_animation_name(assetManager, asset, outPtr, index); }); + [&] { get_animation_name(sceneManager, asset, outPtr, index); }); auto fut = _rl->add_task(lambda); fut.wait(); } @@ -476,27 +485,27 @@ FLUTTER_PLUGIN_EXPORT void pick_ffi(void *const viewer, int x, int y, } FLUTTER_PLUGIN_EXPORT const char * -get_name_for_entity_ffi(void *const assetManager, const EntityId entityId) { +get_name_for_entity_ffi(void *const sceneManager, const EntityId entityId) { std::packaged_task lambda( - [&] { return get_name_for_entity(assetManager, entityId); }); + [&] { return get_name_for_entity(sceneManager, entityId); }); auto fut = _rl->add_task(lambda); fut.wait(); return fut.get(); } -void set_morph_target_weights_ffi(void *const assetManager, +void set_morph_target_weights_ffi(void *const sceneManager, EntityId asset, const char *const entityName, const float *const morphData, int numWeights) { std::packaged_task lambda( - [&] { return set_morph_target_weights(assetManager, asset, entityName, morphData, numWeights); }); + [&] { return set_morph_target_weights(sceneManager, asset, entityName, morphData, numWeights); }); auto fut = _rl->add_task(lambda); fut.wait(); } bool set_morph_animation_ffi( - void *assetManager, + void *sceneManager, EntityId asset, const char *const entityName, const float *const morphData, @@ -506,7 +515,7 @@ bool set_morph_animation_ffi( float frameLengthInMs) { std::packaged_task lambda( [&] { - return set_morph_animation(assetManager, asset, entityName, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs); + return set_morph_animation(sceneManager, asset, entityName, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs); }); auto fut = _rl->add_task(lambda); fut.wait(); @@ -515,27 +524,27 @@ bool set_morph_animation_ffi( FLUTTER_PLUGIN_EXPORT bool set_bone_transform_ffi( - void *assetManager, + void *sceneManager, EntityId asset, const char *entityName, const float *const transform, const char *boneName) { std::packaged_task lambda( - [&] { return set_bone_transform(assetManager, asset, entityName, transform, boneName); }); + [&] { return set_bone_transform(sceneManager, asset, entityName, transform, boneName); }); auto fut = _rl->add_task(lambda); fut.wait(); return fut.get(); } -FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose_ffi(void* const assetManager, EntityId entityId) { +FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose_ffi(void* const sceneManager, EntityId entityId) { std::packaged_task lambda( - [&] { return reset_to_rest_pose(assetManager, entityId); }); + [&] { return reset_to_rest_pose(sceneManager, entityId); }); auto fut = _rl->add_task(lambda); fut.wait(); } FLUTTER_PLUGIN_EXPORT void add_bone_animation_ffi( - void *assetManager, + void *sceneManager, EntityId asset, const float *const frameData, int numFrames, @@ -547,7 +556,7 @@ FLUTTER_PLUGIN_EXPORT void add_bone_animation_ffi( std::packaged_task lambda( [=] { - add_bone_animation(assetManager, asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs, isModelSpace); + add_bone_animation(sceneManager, asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs, isModelSpace); }); auto fut = _rl->add_task(lambda); fut.wait(); diff --git a/ios/src/SceneManager.cpp b/ios/src/SceneManager.cpp index 1f9e5b1f..bb358ca9 100644 --- a/ios/src/SceneManager.cpp +++ b/ios/src/SceneManager.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include #include @@ -18,7 +20,6 @@ #include #include "StreamBufferAdapter.hpp" -#include "SceneAsset.hpp" #include "Log.hpp" #include "SceneManager.hpp" @@ -30,23 +31,22 @@ extern "C" #include "material/image.h" } -namespace polyvox + +namespace flutter_filament { - using namespace std; using namespace std::chrono; using namespace image; using namespace utils; using namespace filament; using namespace filament::gltfio; + using std::unique_ptr; SceneManager::SceneManager(const ResourceLoaderWrapper *const resourceLoaderWrapper, - NameComponentManager *ncm, Engine *engine, Scene *scene, const char *uberArchivePath) : _resourceLoaderWrapper(resourceLoaderWrapper), - _ncm(ncm), _engine(engine), _scene(scene) { @@ -74,16 +74,20 @@ namespace polyvox } Log("Created ubershader provider."); - EntityManager &em = EntityManager::get(); + utils::EntityManager &em = utils::EntityManager::get(); + + _ncm = new NameComponentManager(em); _assetLoader = AssetLoader::create({_engine, _ubershaderProvider, _ncm, &em}); _gltfResourceLoader->addTextureProvider ("image/ktx2", _ktxDecoder); _gltfResourceLoader->addTextureProvider("image/png", _stbDecoder); _gltfResourceLoader->addTextureProvider("image/jpeg", _stbDecoder); - const auto& tm = _engine->getTransformManager(); + auto& tm = _engine->getTransformManager(); _collisionComponentManager = new CollisionComponentManager(tm); + _animationComponentManager = new AnimationComponentManager(tm, _engine->getRenderableManager()); + } SceneManager::~SceneManager() @@ -94,12 +98,32 @@ namespace polyvox AssetLoader::destroy(&_assetLoader); } + int SceneManager::getInstanceCount(EntityId entityId) { + auto* asset = getAssetByEntityId(entityId); + if(!asset) { + return -1; + } + + return asset->getAssetInstanceCount(); + } + + void SceneManager::getInstances(EntityId entityId, EntityId* out) { + auto* asset = getAssetByEntityId(entityId); + if(!asset) { + return; + } + auto* instances = asset->getAssetInstances(); + for(int i=0; i < asset->getAssetInstanceCount(); i++) { + auto instanceEntity = instances[i]->getRoot(); + out[i] = Entity::smuggle(instanceEntity); + } + } + EntityId SceneManager::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) @@ -115,7 +139,7 @@ namespace polyvox for (size_t i = 0; i < resourceUriCount; i++) { - string uri = string(relativeResourcePath) + string("/") + string(resourceUris[i]); + std::string uri = std::string(relativeResourcePath) + std::string("/") + std::string(resourceUris[i]); Log("Loading resource URI from relative path %s", resourceUris[i], uri.c_str()); ResourceBuffer buf = _resourceLoaderWrapper->load(uri.c_str()); @@ -157,25 +181,13 @@ namespace polyvox inst->getAnimator()->updateBoneMatrices(); inst->recomputeBoundingBoxes(); + _animationComponentManager->addAnimationComponent(inst); + asset->releaseSourceData(); - - SceneAsset sceneAsset(asset); - - const auto joints = inst->getJointsAt(0); - - TransformManager &transformManager = _engine->getTransformManager(); - - for(int i = 0; i < inst->getJointCountAt(0); i++) { - const auto joint = joints[i]; - const auto& jointTransformInstance = transformManager.getInstance(joint); - const auto& jointTransform = transformManager.getTransform(jointTransformInstance); - sceneAsset.initialJointTransforms.push_back(jointTransform); - } - + EntityId eid = Entity::smuggle(asset->getRoot()); - _entityIdLookup.emplace(eid, _assets.size()); - _assets.push_back(sceneAsset); + _assets.emplace(eid, asset); for (auto &rb : resourceBuffers) { @@ -188,15 +200,18 @@ namespace polyvox return eid; } - EntityId SceneManager::loadGlb(const char *uri, bool unlit) - { + EntityId SceneManager::loadGlbFromBuffer(const uint8_t* data, size_t length, int numInstances) { - ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); + Log("Loading GLB from buffer of length %d", length); - Log("Loaded GLB data (%d bytes) from URI %s", rbuf.size, uri); - - FilamentAsset *asset = _assetLoader->createAsset( - (const uint8_t *)rbuf.data, rbuf.size); + FilamentAsset *asset = nullptr; + if(numInstances > 1) { + FilamentInstance* instances[numInstances]; + asset = _assetLoader->createInstancedAsset((const uint8_t *)data, length, instances, numInstances); + } else { + asset = _assetLoader->createAsset( + (const uint8_t *)data, length); + } if (!asset) { @@ -221,7 +236,6 @@ namespace polyvox if (!_gltfResourceLoader->loadResources(asset)) { Log("Unknown error loading glb asset"); - _resourceLoaderWrapper->free(rbuf); return 0; } #endif @@ -229,53 +243,79 @@ namespace polyvox auto lights = asset->getLightEntities(); _scene->addEntities(lights, asset->getLightEntityCount()); - FilamentInstance *inst = asset->getInstance(); - - inst->getAnimator()->updateBoneMatrices(); - - inst->recomputeBoundingBoxes(); - auto box = inst->getBoundingBox(); - auto verts = box.extent(); - Log("AABB extent for %s is %f %f %f", uri, verts.x, verts.y, verts.z); - - asset->releaseSourceData(); - - _resourceLoaderWrapper->free(rbuf); - - SceneAsset sceneAsset(asset); - - const auto joints = inst->getJointsAt(0); - - TransformManager &transformManager = _engine->getTransformManager(); - - for(int i = 0; i < inst->getJointCountAt(0); i++) { - const auto joint = joints[i]; - const auto& jointTransformInstance = transformManager.getInstance(joint); - const auto& jointTransform = transformManager.getTransform(jointTransformInstance); - sceneAsset.initialJointTransforms.push_back(jointTransform); + for(int i =0; i < asset->getAssetInstanceCount(); i++) { + FilamentInstance *inst = asset->getAssetInstances()[i]; + inst->getAnimator()->updateBoneMatrices(); + inst->recomputeBoundingBoxes(); + auto instanceEntity = inst->getRoot(); + auto instanceEntityId = Entity::smuggle(instanceEntity); + _instances.emplace(instanceEntityId, inst); + addAnimatableComponent(instanceEntityId); } + asset->releaseSourceData(); + EntityId eid = Entity::smuggle(asset->getRoot()); - - _entityIdLookup.emplace(eid, _assets.size()); - _assets.push_back(sceneAsset); - + _assets.emplace(eid, asset); return eid; } + void SceneManager::addAnimatableComponent(EntityId entityId) { + + auto* instance = getInstanceByEntityId(entityId); + if (!instance) + { + auto* asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return; + } + } + + _animationComponentManager->addAnimationComponent(instance); + } + + EntityId SceneManager::createInstance(EntityId entityId) { + std::lock_guard lock(_mutex); + + const auto &pos = _assets.find(entityId); + if (pos == _assets.end()) + { + Log("Couldn't find asset under specified entity id."); + return false; + } + const auto asset = pos->second; + auto instance = _assetLoader->createInstance(asset); + + return Entity::smuggle(instance->getRoot()); + } + + EntityId SceneManager::loadGlb(const char *uri, int numInstances) + { + ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); + auto entity = loadGlbFromBuffer((const uint8_t*)rbuf.data, rbuf.size, numInstances); + _resourceLoaderWrapper->free(rbuf); + return entity; + } + bool SceneManager::hide(EntityId entityId, const char *meshName) { - - auto asset = getAssetByEntityId(entityId); - if (!asset) + auto* instance = getInstanceByEntityId(entityId); + if (!instance) { - return false; + auto* asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return false; + } } utils::Entity entity; if(meshName) { - entity = findEntityByName(asset, meshName); + entity = findEntityByName(instance, meshName); Log("Hiding child entity under name %s ", meshName); if (entity.isNull()) { Log("Failed to hide entity; specified mesh name does not exist under the target entity, or the target entity itself is no longer valid."); @@ -284,8 +324,8 @@ namespace polyvox _scene->remove(entity); } else { Log("Hiding all child entities"); - auto* entities = asset->getEntities(); - for(int i =0; i < asset->getEntityCount(); i++) { + auto* entities = instance->getEntities(); + for(int i =0; i < instance->getEntityCount(); i++) { auto entity = entities[i]; _scene->remove(entity); } @@ -296,17 +336,21 @@ namespace polyvox bool SceneManager::reveal(EntityId entityId, const char *meshName) { - auto asset = getAssetByEntityId(entityId); - if (!asset) + auto* instance = getInstanceByEntityId(entityId); + if (!instance) { - Log("No asset found under entity ID"); - return false; + auto* asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return false; + } } utils::Entity entity; if(meshName) { - entity = findEntityByName(asset, meshName); + entity = findEntityByName(instance, meshName); if (entity.isNull()) { Log("Failed to reveal entity; specified mesh name does not exist under the target entity, or the target entity itself is no longer valid."); @@ -315,14 +359,13 @@ namespace polyvox _scene->addEntity(entity); } else { Log("Revealing all child entities"); - auto* entities = asset->getEntities(); - for(int i =0; i < asset->getEntityCount(); i++) { + auto* entities = instance->getEntities(); + for(int i =0; i < instance->getEntityCount(); i++) { auto entity = entities[i]; _scene->addEntity(entity); } } - return true; } @@ -330,154 +373,38 @@ namespace polyvox { for (auto &asset : _assets) { - _scene->removeEntities(asset.asset->getEntities(), - asset.asset->getEntityCount()); - _scene->removeEntities(asset.asset->getLightEntities(), - asset.asset->getLightEntityCount()); - _assetLoader->destroyAsset(asset.asset); + _scene->removeEntities(asset.second->getEntities(), + asset.second->getEntityCount()); + _scene->removeEntities(asset.second->getLightEntities(), + asset.second->getLightEntityCount()); + _assetLoader->destroyAsset(asset.second); } _assets.clear(); } - FilamentAsset *SceneManager::getAssetByEntityId(EntityId entityId) + FilamentInstance *SceneManager::getInstanceByEntityId(EntityId entityId) { - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) + const auto &pos = _instances.find(entityId); + if (pos == _instances.end()) { + Log("Failed to find FilamentInstance for entity %d", entityId); return nullptr; } - return _assets[pos->second].asset; + return pos->second; } - void SceneManager::updateAnimations() + FilamentAsset *SceneManager::getAssetByEntityId(EntityId entityId) { - std::lock_guard lock(_mutex); - RenderableManager &rm = _engine->getRenderableManager(); - - auto now = high_resolution_clock::now(); - - for (auto &asset : _assets) + const auto &pos = _assets.find(entityId); + if (pos == _assets.end()) { - - for (int i = ((int)asset.gltfAnimations.size()) - 1; i >= 0; i--) { - - 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.asset->getInstance()->getAnimator()->applyAnimation(animationStatus.index, animationStatus.durationInSecs - 0.001); - asset.asset->getInstance()->getAnimator()->updateBoneMatrices(); - asset.gltfAnimations.erase(asset.gltfAnimations.begin() + i); - asset.fadeGltfAnimationIndex = -1; - continue; - } - 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); - } - } - - asset.asset->getInstance()->getAnimator()->updateBoneMatrices(); - - - for (int i = (int)asset.morphAnimations.size() - 1; i >= 0; i--) { - - auto animationStatus = asset.morphAnimations[i]; - - auto elapsedInSecs = float(std::chrono::duration_cast(now - animationStatus.start).count()) / 1000.0f; - - if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs) - { - asset.morphAnimations.erase(asset.morphAnimations.begin() + i); - continue; - } - - - 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); - } - } - - for (int i = (int)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 elapsedFrames = elapsedInSecs * 1000.0f / animationStatus.frameLengthInMs; - - int currFrame = static_cast(elapsedFrames) % animationStatus.lengthInFrames; - float delta = elapsedFrames - currFrame; - int nextFrame = currFrame; - auto restLocalTransform = asset.initialJointTransforms[animationStatus.boneIndex]; - - // offset from the end if reverse - if (animationStatus.reverse) - { - currFrame = animationStatus.lengthInFrames - currFrame; - if(currFrame > 0) { - nextFrame = currFrame - 1; - } else { - nextFrame = 0; - } - } else { - if(currFrame < animationStatus.lengthInFrames - 1) { - nextFrame = currFrame + 1; - } else { - nextFrame = currFrame; - } - } - - // simple linear interpolation - math::mat4f curr = (1 - delta) * (restLocalTransform * animationStatus.frameData[currFrame]); - math::mat4f next = delta * (restLocalTransform * animationStatus.frameData[nextFrame]); - math::mat4f localTransform = curr + next; - - auto filamentInstance = asset.asset->getInstance(); - TransformManager &transformManager = _engine->getTransformManager(); - - const Entity joint = filamentInstance->getJointsAt(animationStatus.skinIndex)[animationStatus.boneIndex]; - - auto jointTransform = transformManager.getInstance(joint); - - transformManager.setTransform(jointTransform, localTransform); - - asset.asset->getInstance()->getAnimator()->updateBoneMatrices(); - - if (animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs) - { - animationStatus.start = now; - } - } + Log("Failed to find FilamentAsset for entity %d", entityId); + return nullptr; } + return pos->second; } + // TODO - we really don't want to be looking up the bone index/entity by name every single frame // - could use findChildEntityByName // - or is it better to add an option for "streaming" mode where we can just return a reference to a mat4 and then update the values directly? @@ -485,15 +412,18 @@ namespace polyvox { std::lock_guard lock(_mutex); - 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]; + auto* instance = getInstanceByEntityId(entityId); - const auto &entity = findEntityByName(sceneAsset, entityName); + if(!instance) { + auto* asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return false; + } + } + + const auto &entity = findEntityByName(instance, entityName); if(entity.isNull()) { Log("Failed to find entity %s.", entityName); @@ -511,17 +441,15 @@ namespace polyvox TransformManager &transformManager = _engine->getTransformManager(); - const auto &filamentInstance = sceneAsset.asset->getInstance(); - - size_t skinCount = filamentInstance->getSkinCount(); + size_t skinCount = instance->getSkinCount(); if (skinCount > 1) { Log("WARNING - skin count > 1 not currently implemented. This will probably not work"); } - size_t numJoints = filamentInstance->getJointCountAt(skinIndex); - auto joints = filamentInstance->getJointsAt(skinIndex); + size_t numJoints = instance->getJointCountAt(skinIndex); + auto joints = instance->getJointsAt(skinIndex); int boneIndex = -1; for (int i = 0; i < numJoints; i++) { @@ -537,7 +465,7 @@ namespace polyvox return false; } - utils::Entity joint = filamentInstance->getJointsAt(skinIndex)[boneIndex]; + utils::Entity joint = instance->getJointsAt(skinIndex)[boneIndex]; if (joint.isNull()) { @@ -545,7 +473,7 @@ namespace polyvox return false; } - const auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[boneIndex]; + const auto& inverseBindMatrix = instance->getInverseBindMatricesAt(skinIndex)[boneIndex]; auto jointTransform = transformManager.getInstance(joint); auto globalJointTransform = transformManager.getWorldTransform(jointTransform); @@ -570,83 +498,87 @@ namespace polyvox void SceneManager::remove(EntityId entityId) { std::lock_guard lock(_mutex); - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) - { - Log("Couldn't find asset under specified entity id."); - return; - } - auto assetIndex = pos->second; - SceneAsset &sceneAsset = _assets[assetIndex]; - - Log("Removing entity %d at asset index %d", entityId, assetIndex); - - for(auto entityPos : _entityIdLookup) { - if(entityPos.second > pos->second) { - _entityIdLookup[entityPos.first] = entityPos.second-1; - } - } - - _entityIdLookup.erase(entityId); - - auto entityCount = sceneAsset.asset->getEntityCount(); - const auto* entities = sceneAsset.asset->getEntities(); auto entity = Entity::import(entityId); + if(_animationComponentManager->hasComponent(entity)) { + _animationComponentManager->removeComponent(entity); + } + if(_collisionComponentManager->hasComponent(entity)) { _collisionComponentManager->removeComponent(entity); } - - for(int i = 0; i < entityCount; i++) { - auto entity = entities[i]; - if(_collisionComponentManager->hasComponent(entity)) { - _collisionComponentManager->removeComponent(entity); - } - } - auto root = sceneAsset.asset->getRoot(); - if(_collisionComponentManager->hasComponent(root)) { - _collisionComponentManager->removeComponent(root); - } - _nonTransformableCollidableEntities.erase(std::remove_if(_nonTransformableCollidableEntities.begin(), _nonTransformableCollidableEntities.end(), - [=](EntityId entityId2) - { return entityId == entityId2; }), - _nonTransformableCollidableEntities.end()); - - _scene->removeEntities(entities, entityCount); - - auto lightCount =sceneAsset.asset->getLightEntityCount(); - if(lightCount > 0) { - _scene->removeEntities(sceneAsset.asset->getLightEntities(), - sceneAsset.asset->getLightEntityCount()); - } + _scene->remove(entity); - _assetLoader->destroyAsset(sceneAsset.asset); + const auto* instance = getInstanceByEntityId(entityId); + + if(instance) { + _instances.erase(entityId); + _scene->removeEntities(instance->getEntities(), instance->getEntityCount()); + for(int i = 0; i < instance->getEntityCount(); i++) { + auto childEntity = instance->getEntities()[i]; + if(_collisionComponentManager->hasComponent(childEntity)) { + _collisionComponentManager->removeComponent(childEntity); + } + if(_animationComponentManager->hasComponent(childEntity)) { + _animationComponentManager->removeComponent(childEntity); + } + } + // if this a FilamentAsset Entity + } else { + auto* asset = getAssetByEntityId(entityId); - if (sceneAsset.texture) - { - _engine->destroy(sceneAsset.texture); + if(!asset) { + Log("ERROR: could not find FilamentInstance or FilamentAsset associated with the given entity id"); + return; + } + _assets.erase(entityId); + + _scene->removeEntities(asset->getEntities(), asset->getEntityCount()); + + _animationComponentManager->removeComponent(asset->getInstance()->getRoot()); + + for(int i = 0; i < asset->getEntityCount(); i++) { + auto childEntity = asset->getEntities()[i]; + if(_collisionComponentManager->hasComponent(childEntity)) { + _collisionComponentManager->removeComponent(childEntity); + } + if(_animationComponentManager->hasComponent(childEntity)) { + _animationComponentManager->removeComponent(childEntity); + } + } + + auto lightCount = asset->getLightEntityCount(); + if(lightCount > 0) { + _scene->removeEntities(asset->getLightEntities(), + asset->getLightEntityCount()); + } + _assetLoader->destroyAsset(asset); } - EntityManager &em = EntityManager::get(); + + // if (sceneAsset.texture) + // { + // _engine->destroy(sceneAsset.texture); + // } + + utils::EntityManager &em = utils::EntityManager::get(); em.destroy(entity); - _assets.erase(std::remove_if(_assets.begin(), _assets.end(), - [=](SceneAsset &asset) - { return asset.asset == sceneAsset.asset; }), - _assets.end()); } void SceneManager::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* instance = getInstanceByEntityId(entityId); - auto entity = findEntityByName(asset, entityName); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + return; + } + instance = asset->getInstance(); + } + + auto entity = findEntityByName(instance, entityName); if (!entity) { Log("Warning: failed to find entity %s", entityName); @@ -672,15 +604,15 @@ namespace polyvox utils::Entity SceneManager::findChildEntityByName(EntityId entityId, const char *entityName) { std::lock_guard lock(_mutex); - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) + const auto &pos = _instances.find(entityId); + if (pos == _instances.end()) { Log("Couldn't find asset under specified entity id."); return utils::Entity(); } - SceneAsset &sceneAsset = _assets[pos->second]; + const auto* instance = pos->second; - const auto entity = findEntityByName(sceneAsset, entityName); + const auto entity = findEntityByName(instance, entityName); if(entity.isNull()) { Log("Failed to find entity %s.", entityName); @@ -691,12 +623,12 @@ namespace polyvox } - utils::Entity SceneManager::findEntityByName(SceneAsset asset, const char *entityName) - { + utils::Entity SceneManager::findEntityByName(const FilamentInstance *instance, const char *entityName) + { utils::Entity entity; - for (size_t i = 0, c = asset.asset->getEntityCount(); i != c; ++i) + for (size_t i = 0, c = instance->getEntityCount(); i != c; ++i) { - auto entity = asset.asset->getEntities()[i]; + auto entity = instance->getEntities()[i]; auto nameInstance = _ncm->getInstance(entity); if (!nameInstance.isValid()) { @@ -726,18 +658,21 @@ namespace polyvox { std::lock_guard lock(_mutex); - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) + auto* instance = getInstanceByEntityId(entityId); + if (!instance) { - Log("ERROR: asset not found for entity."); - return false; + auto* asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return false; + } } - auto &asset = _assets[pos->second]; - auto entity = findEntityByName(asset, entityName); + auto entity = findEntityByName(instance, entityName); if (!entity) { - Log("Warning: failed to find entity %s", entityName); + Log("ERROR: failed to find entity %s", entityName); return false; } @@ -761,21 +696,30 @@ namespace polyvox morphAnimation.durationInSecs * 1000.0f / frameLengthInMs ); - asset.morphAnimations.emplace_back(morphAnimation); + + auto animationComponentInstance = _animationComponentManager->getInstance(instance->getRoot()); + auto& animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance); + auto& morphAnimations = animationComponent.morphAnimations; + + morphAnimations.emplace_back(morphAnimation); return true; } bool SceneManager::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()) + auto* instance = getInstanceByEntityId(entityId); + if (!instance) { - Log("ERROR: asset not found for entity."); - return false; + auto* asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return false; + } } - auto &asset = _assets[pos->second]; - auto entity = findEntityByName(asset, meshName); + + auto entity = findEntityByName(instance, meshName); RenderableManager &rm = _engine->getRenderableManager(); @@ -803,31 +747,36 @@ namespace polyvox void SceneManager::resetBones(EntityId entityId) { std::lock_guard lock(_mutex); - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) + auto* instance = getInstanceByEntityId(entityId); + if (!instance) { - Log("ERROR: asset not found for entity."); - return; + auto* asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return; + } } - auto &asset = _assets[pos->second]; - auto filamentInstance = asset.asset->getInstance(); - filamentInstance->getAnimator()->resetBoneMatrices(); + instance->getAnimator()->resetBoneMatrices(); - auto skinCount = filamentInstance->getSkinCount(); + auto skinCount = instance->getSkinCount(); TransformManager &transformManager = _engine->getTransformManager(); - + + auto animationComponentInstance = _animationComponentManager->getInstance(instance->getRoot()); + auto& animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance); + for(int skinIndex = 0; skinIndex < skinCount; skinIndex++) { - for(int i =0; i < filamentInstance->getJointCountAt(skinIndex);i++) { - const Entity joint = filamentInstance->getJointsAt(skinIndex)[i]; - auto restLocalTransform = asset.initialJointTransforms[i]; + for(int i =0; i < instance->getJointCountAt(skinIndex);i++) { + const Entity joint = instance->getJointsAt(skinIndex)[i]; + auto restLocalTransform = animationComponent.initialJointTransforms[i]; auto jointTransform = transformManager.getInstance(joint); transformManager.setTransform(jointTransform, restLocalTransform); } } - filamentInstance->getAnimator()->updateBoneMatrices(); - filamentInstance->getAnimator()->resetBoneMatrices(); + instance->getAnimator()->updateBoneMatrices(); + instance->getAnimator()->resetBoneMatrices(); } @@ -842,17 +791,18 @@ namespace polyvox { std::lock_guard lock(_mutex); - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) + auto* instance = getInstanceByEntityId(entityId); + if (!instance) { - Log("ERROR: asset not found for entity."); - return false; + auto* asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return false; + } } - auto &asset = _assets[pos->second]; - - auto filamentInstance = asset.asset->getInstance(); - size_t skinCount = filamentInstance->getSkinCount(); + size_t skinCount = instance->getSkinCount(); if (skinCount > 1) { @@ -860,8 +810,8 @@ namespace polyvox } int skinIndex = 0; - const utils::Entity *joints = filamentInstance->getJointsAt(skinIndex); - size_t numJoints = filamentInstance->getJointCountAt(skinIndex); + const utils::Entity *joints = instance->getJointsAt(skinIndex); + size_t numJoints = instance->getJointCountAt(skinIndex); BoneAnimation animation; bool found = false; @@ -883,7 +833,7 @@ namespace polyvox animation.frameData.clear(); - const auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[animation.boneIndex]; + const auto& inverseBindMatrix = instance->getInverseBindMatricesAt(skinIndex)[animation.boneIndex]; const auto& bindMatrix = inverse(inverseBindMatrix); math::float3 trans; math::quatf rot; @@ -912,13 +862,7 @@ namespace polyvox frameData[(i*16)+13], frameData[(i*16)+14], frameData[(i*16)+15]); - // if(i == numFrames - 1) { Log("Model transform for bone %s is \n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", boneName, - // frame[0][0],frame[1][0],frame[2][0],frame[3][0], - // frame[0][1],frame[1][1],frame[2][1],frame[3][1], - // frame[0][2],frame[1][2],frame[2][2],frame[3][2], - // frame[0][3],frame[1][3],frame[2][3],frame[3][3]); - // } - + if(isModelSpace) { frame = (math::mat4f(rot) * frame) * math::mat4f(brot); } @@ -930,7 +874,7 @@ namespace polyvox animation.meshTargets.clear(); for (int i = 0; i < numMeshTargets; i++) { - auto entity = findEntityByName(asset, meshNames[i]); + auto entity = findEntityByName(instance, meshNames[i]); if (!entity) { Log("Mesh target %s for bone animation could not be found", meshNames[i]); @@ -945,12 +889,18 @@ namespace polyvox animation.lengthInFrames = numFrames; animation.frameLengthInMs = frameLengthInMs; animation.skinIndex = 0; - asset.boneAnimations.push_back(animation); + + + auto animationComponentInstance = _animationComponentManager->getInstance(instance->getRoot()); + auto& animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance); + auto& boneAnimations = animationComponent.boneAnimations; + + boneAnimations.emplace_back(animation); return true; } - void SceneManager::playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade) + void SceneManager::playAnimation(EntityId entityId, int index, bool loop, bool reverse, bool replaceActive, float crossfade) { std::lock_guard lock(_mutex); @@ -959,30 +909,44 @@ namespace polyvox Log("ERROR: glTF animation index must be greater than zero."); return; } - const auto &pos = _entityIdLookup.find(e); - if (pos == _entityIdLookup.end()) + + auto* instance = getInstanceByEntityId(entityId); + if (!instance) { - Log("ERROR: asset not found for entity."); + auto* asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return; + } + } + + if(!_animationComponentManager->hasComponent(instance->getRoot())) { + Log("ERROR: specified entity is not animatable (has no animation component attached)."); return; } - auto &asset = _assets[pos->second]; + + auto animationComponentInstance = _animationComponentManager->getInstance(instance->getRoot()); + + + auto& animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance); if (replaceActive) { - if (asset.gltfAnimations.size() > 0) + if (animationComponent.gltfAnimations.size() > 0) { - auto &last = asset.gltfAnimations.back(); - asset.fadeGltfAnimationIndex = last.index; - asset.fadeDuration = crossfade; + auto &last = animationComponent.gltfAnimations.back(); + animationComponent.fadeGltfAnimationIndex = last.index; + animationComponent.fadeDuration = crossfade; auto now = high_resolution_clock::now(); auto elapsedInSecs = float(std::chrono::duration_cast(now - last.start).count()) / 1000.0f; - asset.fadeOutAnimationStart = elapsedInSecs; - asset.gltfAnimations.clear(); + animationComponent.fadeOutAnimationStart = elapsedInSecs; + animationComponent.gltfAnimations.clear(); } else { - asset.fadeGltfAnimationIndex = -1; - asset.fadeDuration = 0.0f; + animationComponent.fadeGltfAnimationIndex = -1; + animationComponent.fadeDuration = 0.0f; } } else if (crossfade > 0) @@ -992,8 +956,8 @@ namespace polyvox } else { - asset.fadeGltfAnimationIndex = -1; - asset.fadeDuration = 0.0f; + animationComponent.fadeGltfAnimationIndex = -1; + animationComponent.fadeDuration = 0.0f; } GltfAnimation animation; @@ -1001,186 +965,189 @@ namespace polyvox animation.start = std::chrono::high_resolution_clock::now(); animation.loop = loop; animation.reverse = reverse; - animation.durationInSecs = asset.asset->getInstance()->getAnimator()->getAnimationDuration(index); + animation.durationInSecs = instance->getAnimator()->getAnimationDuration(index); - asset.gltfAnimations.push_back(animation); + animationComponent.gltfAnimations.push_back(animation); } - void SceneManager::stopAnimation(EntityId entityId, int index) - { + void SceneManager::stopAnimation(EntityId entityId, int index) { std::lock_guard lock(_mutex); - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { return; } - auto &asset = _assets[pos->second]; - asset.gltfAnimations.erase(std::remove_if(asset.gltfAnimations.begin(), - asset.gltfAnimations.end(), + auto animationComponentInstance = _animationComponentManager->getInstance(instance->getRoot()); + auto& animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance); + + animationComponent.gltfAnimations.erase(std::remove_if(animationComponent.gltfAnimations.begin(), + animationComponent.gltfAnimations.end(), [=](GltfAnimation &anim) { return anim.index == index; }), - asset.gltfAnimations.end()); + animationComponent.gltfAnimations.end()); } void SceneManager::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]; + // const auto &pos = _instances.find(entity); + // if (pos == _instances.end()) + // { + // Log("ERROR: asset not found for entity."); + // return; + // } + // const auto *instance = pos->second; - Log("Loading texture at %s for renderableIndex %d", resourcePath, renderableIndex); + // Log("Loading texture at %s for renderableIndex %d", resourcePath, renderableIndex); - string rp(resourcePath); + // string rp(resourcePath); - if (asset.texture) - { - _engine->destroy(asset.texture); - asset.texture = nullptr; - } + // if (asset.texture) + // { + // _engine->destroy(asset.texture); + // asset.texture = nullptr; + // } - ResourceBuffer imageResource = _resourceLoaderWrapper->load(rp.c_str()); + // ResourceBuffer imageResource = _resourceLoaderWrapper->load(rp.c_str()); - StreamBufferAdapter sb((char *)imageResource.data, (char *)imageResource.data + imageResource.size); + // StreamBufferAdapter sb((char *)imageResource.data, (char *)imageResource.data + imageResource.size); - istream *inputStream = new std::istream(&sb); + // istream *inputStream = new std::istream(&sb); - LinearImage *image = new LinearImage(ImageDecoder::decode( - *inputStream, rp.c_str(), ImageDecoder::ColorSpace::SRGB)); + // 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; - } + // 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); + // 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::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); + // 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); + // asset.texture->setImage(*_engine, 0, std::move(buffer)); + // MaterialInstance *const *inst = instance->getMaterialInstances(); + // size_t mic = instance->getMaterialInstanceCount(); + // Log("Material instance count : %d", mic); - auto sampler = TextureSampler(); - inst[0]->setParameter("baseColorIndex", 0); - inst[0]->setParameter("baseColorMap", asset.texture, sampler); - delete inputStream; + // auto sampler = TextureSampler(); + // inst[0]->setParameter("baseColorIndex", 0); + // inst[0]->setParameter("baseColorMap", asset.texture, sampler); + // delete inputStream; - _resourceLoaderWrapper->free(imageResource); + // _resourceLoaderWrapper->free(imageResource); } - void SceneManager::setAnimationFrame(EntityId entity, int animationIndex, int animationFrame) + void SceneManager::setAnimationFrame(EntityId entityId, 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* instance = getInstanceByEntityId(entityId); auto offset = 60 * animationFrame * 1000; // TODO - don't hardcore 60fps framerate - asset.asset->getInstance()->getAnimator()->applyAnimation(animationIndex, offset); - asset.asset->getInstance()->getAnimator()->updateBoneMatrices(); + instance->getAnimator()->applyAnimation(animationIndex, offset); + instance->getAnimator()->updateBoneMatrices(); } float SceneManager::getAnimationDuration(EntityId entity, int animationIndex) { - const auto &pos = _entityIdLookup.find(entity); + const auto &pos = _instances.find(entity); - unique_ptr> names = make_unique>(); + unique_ptr> names = std::make_unique>(); - if (pos == _entityIdLookup.end()) + if (pos == _instances.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 *instance = pos->second; + return instance->getAnimator()->getAnimationDuration(animationIndex); } - unique_ptr> SceneManager::getAnimationNames(EntityId entity) + unique_ptr> SceneManager::getAnimationNames(EntityId entity) { - const auto &pos = _entityIdLookup.find(entity); + const auto &pos = _instances.find(entity); - unique_ptr> names = make_unique>(); + unique_ptr> names = std::make_unique>(); - if (pos == _entityIdLookup.end()) + FilamentInstance* instance; + + if (pos != _instances.end()) { - Log("ERROR: asset not found for entity id."); - return names; + instance = pos->second; + } else { + const auto& assetPos = _assets.find(entity); + if(assetPos != _assets.end()) { + instance = assetPos->second->getInstance(); + } else { + Log("Could not resolve entity ID %d to FilamentInstance or FilamentAsset"); + return names; + } } - auto &asset = _assets[pos->second]; - size_t count = asset.asset->getInstance()->getAnimator()->getAnimationCount(); + size_t count = instance->getAnimator()->getAnimationCount(); for (size_t i = 0; i < count; i++) { - names->push_back(asset.asset->getInstance()->getAnimator()->getAnimationName(i)); + names->push_back(instance->getAnimator()->getAnimationName(i)); } return names; } - unique_ptr> SceneManager::getMorphTargetNames(EntityId entity, const char *meshName) + unique_ptr> SceneManager::getMorphTargetNames(EntityId entityId, const char *meshName) { - unique_ptr> names = make_unique>(); + unique_ptr> names = std::make_unique>(); - const auto &pos = _entityIdLookup.find(entity); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return names; + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + return names; + } + instance = asset->getInstance(); } - auto &asset = _assets[pos->second]; - const utils::Entity *entities = asset.asset->getEntities(); + const auto *asset = instance->getAsset(); - for (int i = 0; i < asset.asset->getEntityCount(); i++) + const utils::Entity *entities = asset->getEntities(); + + for (int i = 0; i < asset->getEntityCount(); i++) { utils::Entity e = entities[i]; - auto inst = _ncm->getInstance(e); - const char *name = _ncm->getName(inst); + const char *name = asset->getName(e); if (name && strcmp(name, meshName) == 0) { - size_t count = asset.asset->getMorphTargetCountAt(e); + size_t count = asset->getMorphTargetCountAt(e); for (int j = 0; j < count; j++) { - const char *morphName = asset.asset->getMorphTargetNameAt(e, j); + const char *morphName = asset->getMorphTargetNameAt(e, j); names->push_back(morphName); } break; @@ -1189,25 +1156,27 @@ namespace polyvox return names; } - void SceneManager::transformToUnitCube(EntityId entity) + void SceneManager::transformToUnitCube(EntityId entityId) { - const auto &pos = _entityIdLookup.find(entity); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return; + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return; + } } - auto &asset = _assets[pos->second]; auto &tm = _engine->getTransformManager(); - FilamentInstance *inst = asset.asset->getInstance(); - auto aabb = inst->getBoundingBox(); + + auto aabb = instance->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); + tm.setTransform(tm.getInstance(instance->getRoot()), transform); } void SceneManager::setParent(EntityId childEntityId, EntityId parentEntityId) { @@ -1219,44 +1188,50 @@ namespace polyvox const auto& parentInstance = tm.getInstance(parent); const auto& childInstance = tm.getInstance(child); tm.setParent(childInstance, parentInstance); - - } void SceneManager::addCollisionComponent(EntityId entityId, void(*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsTransform) { std::lock_guard lock(_mutex); - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return; - } - auto &asset = _assets[pos->second]; - asset.asset->getAssetInstances(); - auto collisionInstance = _collisionComponentManager->addComponent(asset.asset->getRoot()); - _collisionComponentManager->elementAt<0>(collisionInstance) = asset.asset->getInstance()->getBoundingBox(); + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + return; + } else { + instance = asset->getInstance(); + + } + } + auto collisionInstance = _collisionComponentManager->addComponent(instance->getRoot()); + _collisionComponentManager->elementAt<0>(collisionInstance) = instance->getBoundingBox(); _collisionComponentManager->elementAt<1>(collisionInstance) = onCollisionCallback; _collisionComponentManager->elementAt<2>(collisionInstance) = affectsTransform; } void SceneManager::testCollisions(EntityId entityId) { - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return; + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + instance = asset->getInstance(); + } } - auto &asset = _assets[pos->second]; + const auto entity = Entity::import(entityId); const auto& tm = _engine->getTransformManager(); - auto transformInstance = tm.getInstance(asset.asset->getRoot()); + auto transformInstance = tm.getInstance(instance->getRoot()); auto worldTransform = tm.getWorldTransform(transformInstance); - auto aabb = asset.asset->getInstance()->getBoundingBox(); + // Log("World transform for %d is %f %f %f", entityId, worldTransform[3][0], worldTransform[3][1], worldTransform[3][2]); + auto aabb = instance->getBoundingBox(); aabb = aabb.transform(worldTransform); - _collisionComponentManager->collides(entityId, aabb); + _collisionComponentManager->collides(entity, aabb); } + void SceneManager::updateAnimations() { + std::lock_guard lock(_mutex); + _animationComponentManager->update(); + } void SceneManager::updateTransforms() { std::lock_guard lock(_mutex); @@ -1264,15 +1239,26 @@ namespace polyvox auto &tm = _engine->getTransformManager(); for ( const auto &[entityId, transformUpdate]: _transformUpdates ) { - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) + const auto &pos = _instances.find(entityId); + + bool isCollidable = true; + Entity entity; + filament::TransformManager::Instance transformInstance; + filament::math::mat4f transform; + Aabb boundingBox; + if (pos == _instances.end()) { - Log("ERROR: asset not found for entity."); - continue; + Log("WARNING: SceneAsset not found for entity."); + isCollidable = false; + entity = Entity::import(entityId); + } else { + const auto *instance = pos->second; + entity = instance->getRoot(); + boundingBox = instance->getBoundingBox(); } - auto &asset = _assets[pos->second]; - auto transformInstance = tm.getInstance(asset.asset->getRoot()); - auto transform = tm.getTransform(transformInstance); + + transformInstance = tm.getInstance(entity); + transform = tm.getTransform(transformInstance); math::float3 newTranslation = std::get<0>(transformUpdate); bool newTranslationRelative = std::get<1>(transformUpdate); @@ -1304,21 +1290,23 @@ namespace polyvox } transform = composeMatrix(translation, rotation, scale); - auto bb = asset.asset->getBoundingBox(); - auto transformedBB = bb.transform(transform); - - auto collisionAxes = _collisionComponentManager->collides(entityId, transformedBB); - if(collisionAxes.size() == 1) { - auto globalAxis = collisionAxes[0]; - globalAxis *= norm(relativeTranslation); - auto newRelativeTranslation = relativeTranslation + globalAxis; - translation -= relativeTranslation; - translation += newRelativeTranslation; - transform = composeMatrix(translation, rotation, scale); - } else if(collisionAxes.size() > 1) { - translation -= relativeTranslation; - transform = composeMatrix(translation, rotation, scale); + if(isCollidable) { + auto transformedBB = boundingBox.transform(transform); + + auto collisionAxes = _collisionComponentManager->collides(entity, transformedBB); + + if(collisionAxes.size() == 1) { + auto globalAxis = collisionAxes[0]; + globalAxis *= norm(relativeTranslation); + auto newRelativeTranslation = relativeTranslation + globalAxis; + translation -= relativeTranslation; + translation += newRelativeTranslation; + transform = composeMatrix(translation, rotation, scale); + } else if(collisionAxes.size() > 1) { + translation -= relativeTranslation; + transform = composeMatrix(translation, rotation, scale); + } } tm.setTransform(transformInstance, transform); } @@ -1400,15 +1388,15 @@ namespace polyvox const auto &pos = _transformUpdates.find(entity); if (pos == _transformUpdates.end()) { - _transformUpdates.emplace(entity, make_tuple(math::float3(), true, math::quatf(1.0f), true, 1.0f)); + _transformUpdates.emplace(entity, std::make_tuple(math::float3(), true, math::quatf(1.0f), true, 1.0f)); } auto curr = _transformUpdates[entity]; - auto& trans = get<0>(curr); + auto& trans = std::get<0>(curr); trans.x = x; trans.y = y; trans.z = z; - auto& isRelative = get<1>(curr); + auto& isRelative = std::get<1>(curr); isRelative = relative; _transformUpdates[entity] = curr; } @@ -1419,7 +1407,7 @@ namespace polyvox const auto &pos = _transformUpdates.find(entity); if (pos == _transformUpdates.end()) { - _transformUpdates.emplace(entity, make_tuple(math::float3(), true, math::quatf(1.0f), true, 1.0f)); + _transformUpdates.emplace(entity, std::make_tuple(math::float3(), true, math::quatf(1.0f), true, 1.0f)); } auto curr = _transformUpdates[entity]; auto& rot = std::get<2>(curr); @@ -1427,57 +1415,57 @@ namespace polyvox rot.x = x; rot.y = y; rot.z = z; - auto& isRelative = get<3>(curr); + auto& isRelative = std::get<3>(curr); isRelative = relative; _transformUpdates[entity] = curr; } - const utils::Entity *SceneManager::getCameraEntities(EntityId entity) + const utils::Entity *SceneManager::getCameraEntities(EntityId entityId) { - const auto &pos = _entityIdLookup.find(entity); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return nullptr; + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + instance = asset->getInstance(); + } } - auto &asset = _assets[pos->second]; - return asset.asset->getCameraEntities(); + return instance->getAsset()->getCameraEntities(); } - size_t SceneManager::getCameraEntityCount(EntityId entity) + size_t SceneManager::getCameraEntityCount(EntityId entityId) { - const auto &pos = _entityIdLookup.find(entity); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return 0; + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + instance = asset->getInstance(); + } } - auto &asset = _assets[pos->second]; - return asset.asset->getCameraEntityCount(); + return instance->getAsset()->getCameraEntityCount(); } - const utils::Entity *SceneManager::getLightEntities(EntityId entity) const noexcept + const utils::Entity *SceneManager::getLightEntities(EntityId entityId) noexcept { - const auto &pos = _entityIdLookup.find(entity); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return nullptr; + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + instance = asset->getInstance(); + } } - auto &asset = _assets[pos->second]; - return asset.asset->getLightEntities(); + return instance->getAsset()->getLightEntities(); } - size_t SceneManager::getLightEntityCount(EntityId entity) const noexcept + size_t SceneManager::getLightEntityCount(EntityId entityId) noexcept { - const auto &pos = _entityIdLookup.find(entity); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return 0; + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + instance = asset->getInstance(); + } } - auto &asset = _assets[pos->second]; - return asset.asset->getLightEntityCount(); + return instance->getAsset()->getLightEntityCount(); } const char *SceneManager::getNameForEntity(EntityId entityId) @@ -1493,42 +1481,46 @@ namespace polyvox } int SceneManager::getEntityCount(EntityId entityId, bool renderableOnly) { - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return 0; + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + instance = asset->getInstance(); + } else { + return 0; + } } - auto &asset = _assets[pos->second]; if(renderableOnly) { int count = 0; const auto& rm = _engine->getRenderableManager(); - const Entity *entities = asset.asset->getEntities(); - for(int i=0; i < asset.asset->getEntityCount(); i++) { + const Entity *entities = instance->getEntities(); + for(int i=0; i < instance->getEntityCount(); i++) { if(rm.hasComponent(entities[i])) { count++; } } return count; } - return asset.asset->getEntityCount(); + return instance->getEntityCount(); } const char* SceneManager::getEntityNameAt(EntityId entityId, int index, bool renderableOnly) { - const auto &pos = _entityIdLookup.find(entityId); - if (pos == _entityIdLookup.end()) - { - Log("ERROR: asset not found for entity."); - return nullptr; + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(!asset) { + instance = asset->getInstance(); + } else { + return nullptr; + } } - auto &asset = _assets[pos->second]; int found = -1; if(renderableOnly) { int count = 0; const auto& rm = _engine->getRenderableManager(); - const Entity *entities = asset.asset->getEntities(); - for(int i=0; i < asset.asset->getEntityCount(); i++) { + const Entity *entities = instance->getEntities(); + for(int i=0; i < instance->getEntityCount(); i++) { if(rm.hasComponent(entities[i])) { if(count == index) { found = i; @@ -1541,14 +1533,14 @@ namespace polyvox found = index; } - if(found >= asset.asset->getEntityCount()) { + if(found >= instance->getEntityCount()) { Log("ERROR: index %d greater than number of child entities.", found); return nullptr; } - const utils::Entity entity = asset.asset->getEntities()[found]; + const utils::Entity entity = instance->getEntities()[found]; auto inst = _ncm->getInstance(entity); return _ncm->getName(inst); } -} // namespace polyvox +} // namespace flutter_filament diff --git a/ios/src/StreamBufferAdapter.cpp b/ios/src/StreamBufferAdapter.cpp index 76bfeb71..fcbc6cd7 100644 --- a/ios/src/StreamBufferAdapter.cpp +++ b/ios/src/StreamBufferAdapter.cpp @@ -3,9 +3,7 @@ #include #include -using namespace std; - -namespace polyvox { +namespace flutter_filament { class StreamBufferAdapter : public std::streambuf { @@ -14,14 +12,14 @@ class StreamBufferAdapter : public std::streambuf ~StreamBufferAdapter() { } - streamsize size(); + std::streamsize size(); private: int_type uflow() override; int_type underflow() override; int_type pbackfail(int_type ch) override; - streampos seekoff(streamoff off, ios_base::seekdir way, ios_base::openmode which) override; - streampos seekpos(streampos sp, ios_base::openmode which) override; + std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which) override; + std::streampos seekpos(std::streampos sp, std::ios_base::openmode which) override; std::streamsize showmanyc() override; }; @@ -31,11 +29,11 @@ StreamBufferAdapter::StreamBufferAdapter(const char *begin, const char *end) setg((char*)begin, (char*)begin, (char*)end); } -streamsize StreamBufferAdapter::size() { +std::streamsize StreamBufferAdapter::size() { return egptr() - eback(); } -streambuf::int_type StreamBufferAdapter::underflow() +std::streambuf::int_type StreamBufferAdapter::underflow() { if (gptr() == egptr()) { return traits_type::eof(); @@ -43,7 +41,7 @@ streambuf::int_type StreamBufferAdapter::underflow() return *(gptr()); } -streambuf::int_type StreamBufferAdapter::uflow() +std::streambuf::int_type StreamBufferAdapter::uflow() { if (gptr() == egptr()) { return traits_type::eof(); @@ -53,7 +51,7 @@ streambuf::int_type StreamBufferAdapter::uflow() return *(gptr()); } -streambuf::int_type StreamBufferAdapter::pbackfail(int_type ch) +std::streambuf::int_type StreamBufferAdapter::pbackfail(int_type ch) { if (gptr() == eback() || (ch != traits_type::eof() && ch != gptr()[-1])) return traits_type::eof(); @@ -61,15 +59,15 @@ streambuf::int_type StreamBufferAdapter::pbackfail(int_type ch) return *(gptr()); } -streamsize StreamBufferAdapter::showmanyc() +std::streamsize StreamBufferAdapter::showmanyc() { return egptr() - gptr(); } -streampos StreamBufferAdapter::seekoff(streamoff off, ios_base::seekdir way, ios_base::openmode which = ios_base::in) { - if(way == ios_base::beg) { +std::streampos StreamBufferAdapter::seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in) { + if(way == std::ios_base::beg) { setg(eback(), eback()+off, egptr()); - } else if(way == ios_base::cur) { + } else if(way == std::ios_base::cur) { gbump(off); } else { setg(eback(), egptr()-off, egptr()); @@ -77,7 +75,7 @@ streampos StreamBufferAdapter::seekoff(streamoff off, ios_base::seekdir way, ios return gptr() - eback(); } -streampos StreamBufferAdapter::seekpos(streampos sp, ios_base::openmode which = ios_base::in) { +std::streampos StreamBufferAdapter::seekpos(std::streampos sp, std::ios_base::openmode which = std::ios_base::in) { return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which); } } \ No newline at end of file diff --git a/lib/camera/camera_orientation.dart b/lib/camera/camera_orientation.dart new file mode 100644 index 00000000..3e800836 --- /dev/null +++ b/lib/camera/camera_orientation.dart @@ -0,0 +1,15 @@ +import 'package:vector_math/vector_math_64.dart' as v; + +class CameraOrientation { + v.Vector3 position = v.Vector3(0, 0, 0); + + var rotationX = 0.0; + var rotationY = 0.0; + var rotationZ = 0.0; + + v.Quaternion compose() { + return v.Quaternion.axisAngle(v.Vector3(0, 0, 1), rotationZ) * + v.Quaternion.axisAngle(v.Vector3(0, 1, 0), rotationY) * + v.Quaternion.axisAngle(v.Vector3(1, 0, 0), rotationX); + } +} diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index aecfa87b..445cf0c1 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -1,6 +1,7 @@ // ignore_for_file: constant_identifier_names import 'dart:async'; +import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/widgets.dart'; @@ -12,6 +13,9 @@ import 'package:vector_math/vector_math_64.dart'; // a handle that can be safely passed back to the rendering layer to manipulate an Entity typedef FilamentEntity = int; +// "picking" means clicking/tapping on the viewport, and unprojecting the X/Y coordinate to determine whether any renderable entities were present at those coordinates. +typedef FilamentPickResult = ({FilamentEntity entity, double x, double y}); + enum ToneMapper { ACES, FILMIC, LINEAR } // see filament Manipulator.h for more details @@ -65,7 +69,7 @@ abstract class FilamentController { /// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick]. /// If [pick] is called without an active subscription to this stream, the results will be silently discarded. /// - Stream get pickResult; + Stream get pickResult; /// /// Whether the controller is currently rendering at [framerate]. @@ -206,7 +210,35 @@ abstract class FilamentController { /// /// Load the .glb asset at the given path and insert into the scene. /// - Future loadGlb(String path, {bool unlit = false}); + Future loadGlb(String path, {int numInstances = 1}); + + /// + /// Load the .glb asset from the specified path (either Flutter asset URI or filepath) and insert into the scene. + /// If [cache] is true, the contents of the path will be cached locally and re-used for any future calls to load that asset. + /// See also [evictCache]. + /// + Future loadGlbFromBuffer(String path, + {bool cache = false, int numInstances = 1}); + + /// + /// Create a new instance of [entity]. + /// + Future createInstance(FilamentEntity entity); + + /// + /// Returns the number of instances of the asset associated with [entity]. + /// + Future getInstanceCount(FilamentEntity entity); + + /// + /// Returns all instances of [entity]. + /// + Future> getInstances(FilamentEntity entity); + + /// + /// Frees all cached resources loaded via [loadGlbFromBuffer]. + /// + Future evictCache(); /// /// Load the .gltf asset at the given path and insert into the scene. @@ -281,16 +313,11 @@ abstract class FilamentController { Future resetBones(FilamentEntity entity); /// - /// Starts animating a bone (joint) according to the specified [animation]. + /// Transforms the bone(s)/joint(s) according [animation]. + /// To set the instantaneous transform, just use a single frame. /// 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]. - /// - Future setBoneTransform( - FilamentEntity entity, String meshName, String boneName, Matrix4 data); - /// /// Removes/destroys the specified entity from the scene. /// [entity] will no longer be a valid handle after this method is called; ensure you immediately discard all references once this method is complete. @@ -350,6 +377,11 @@ abstract class FilamentController { /// Future setMainCamera(); + /// + /// Returns the entity associated with the main camera. + /// + Future getMainCamera(); + /// /// Sets the current scene camera to the glTF camera under [name] in [entity]. /// @@ -450,7 +482,7 @@ abstract class FilamentController { /// /// Rotate the camera by [rads] around the given axis. Note this is not persistent - any viewport navigation will reset the camera transform. /// - Future setCameraRotation(double rads, double x, double y, double z); + Future setCameraRotation(Quaternion quaternion); /// /// Sets the camera model matrix. diff --git a/lib/filament_controller_ffi.dart b/lib/filament_controller_ffi.dart index 5218e30f..44e8799a 100644 --- a/lib/filament_controller_ffi.dart +++ b/lib/filament_controller_ffi.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:ffi'; import 'dart:io'; +import 'dart:typed_data'; import 'dart:ui' as ui; import 'dart:developer' as dev; import 'package:flutter/services.dart'; @@ -52,8 +53,9 @@ class FilamentControllerFFI extends FilamentController { final hasViewer = ValueNotifier(false); @override - Stream get pickResult => _pickResultController.stream; - final _pickResultController = StreamController.broadcast(); + Stream get pickResult => _pickResultController.stream; + final _pickResultController = + StreamController.broadcast(); int? _resizingWidth; int? _resizingHeight; @@ -545,8 +547,82 @@ class FilamentControllerFFI extends FilamentController { _lights.clear(); } + final _assetCache = , int)>{}; + @override - Future loadGlb(String path, {bool unlit = false}) async { + Future loadGlbFromBuffer(String path, + {bool cache = false, int numInstances = 1}) async { + late (Pointer, int) data; + + if (cache && _assetCache.containsKey(path)) { + data = _assetCache[path]!; + } else { + late ByteData asset; + if (path.startsWith("file://")) { + var raw = File(path.replaceAll("file://", "")).readAsBytesSync(); + asset = raw.buffer.asByteData(raw.offsetInBytes); + } else { + asset = await rootBundle.load(path.replaceAll("asset://", "")); + } + + var ptr = allocator(asset.lengthInBytes); + for (int i = 0; i < asset.lengthInBytes; i++) { + ptr[i] = asset.getUint8(i); + } + + data = (ptr.cast(), asset.lengthInBytes); + } + var entity = load_glb_from_buffer_ffi( + _sceneManager!, data.$1, data.$2, numInstances); + if (!cache) { + allocator.free(data.$1); + } else { + _assetCache[path] = data; + } + if (entity == _FILAMENT_ASSET_ERROR) { + throw Exception("Failed to load GLB from path $path"); + } + return entity; + } + + @override + Future createInstance(FilamentEntity entity) async { + var created = create_instance(_sceneManager!, entity); + if (created == _FILAMENT_ASSET_ERROR) { + throw Exception("Failed to create instance"); + } + return created; + } + + @override + Future getInstanceCount(FilamentEntity entity) async { + return get_instance_count(_sceneManager!, entity); + } + + @override + Future> getInstances(FilamentEntity entity) async { + var count = await getInstanceCount(entity); + var out = allocator(count); + get_instances(_sceneManager!, entity, out); + var instances = []; + for (int i = 0; i < count; i++) { + instances.add(out[i]); + } + allocator.free(out); + return instances; + } + + @override + Future evictCache() async { + for (final value in _assetCache.values) { + allocator.free(value.$1); + } + _assetCache.clear(); + } + + @override + Future loadGlb(String path, + {bool unlit = false, int numInstances = 1}) async { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } @@ -554,7 +630,7 @@ class FilamentControllerFFI extends FilamentController { throw Exception("Not yet implemented"); } final pathPtr = path.toNativeUtf8().cast(); - var entity = load_glb_ffi(_sceneManager!, pathPtr, unlit); + var entity = load_glb_ffi(_sceneManager!, pathPtr, numInstances); allocator.free(pathPtr); if (entity == _FILAMENT_ASSET_ERROR) { throw Exception("An error occurred loading the asset at $path"); @@ -910,6 +986,10 @@ class FilamentControllerFFI extends FilamentController { set_main_camera(_viewer!); } + Future getMainCamera() async { + return get_main_camera(_viewer!); + } + @override Future setCamera(FilamentEntity entity, String? name) async { if (_viewer == null) { @@ -1027,11 +1107,12 @@ class FilamentControllerFFI extends FilamentController { } @override - Future setCameraRotation(double rads, double x, double y, double z) async { + Future setCameraRotation(Quaternion quaternion) async { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - set_camera_rotation(_viewer!, rads, x, y, z); + set_camera_rotation( + _viewer!, quaternion.w, quaternion.x, quaternion.y, quaternion.z); } @override @@ -1158,13 +1239,13 @@ class FilamentControllerFFI extends FilamentController { } @override - Future reveal(FilamentEntity entity, String meshName) async { + Future reveal(FilamentEntity entity, String? meshName) async { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - final meshNamePtr = meshName.toNativeUtf8().cast(); - final result = reveal_mesh(_sceneManager!, entity, meshNamePtr) != 1; + final meshNamePtr = meshName?.toNativeUtf8().cast() ?? nullptr; + final result = reveal_mesh(_sceneManager!, entity, meshNamePtr) == 1; allocator.free(meshNamePtr); if (!result) { throw Exception("Failed to reveal mesh $meshName"); @@ -1199,7 +1280,8 @@ class FilamentControllerFFI extends FilamentController { } } var entityId = outPtr.value; - _pickResultController.add(entityId); + _pickResultController + .add((entity: entityId, x: x.toDouble(), y: y.toDouble())); allocator.free(outPtr); } @@ -1331,28 +1413,6 @@ class FilamentControllerFFI extends FilamentController { return frustum; } - @override - Future setBoneTransform(FilamentEntity entity, String meshName, - String boneName, Matrix4 data) async { - var ptr = allocator(16); - for (int i = 0; i < 16; i++) { - ptr.elementAt(i).value = data.storage[i]; - } - - var meshNamePtr = meshName.toNativeUtf8(allocator: allocator).cast(); - var boneNamePtr = boneName.toNativeUtf8(allocator: allocator).cast(); - - var result = set_bone_transform_ffi( - _sceneManager!, entity, meshNamePtr, ptr, boneNamePtr); - - allocator.free(ptr); - allocator.free(meshNamePtr); - allocator.free(boneNamePtr); - if (!result) { - throw Exception("Failed to set bone transform. See logs for details"); - } - } - @override Future getChildEntity( FilamentEntity parent, String childName) async { diff --git a/lib/generated_bindings.dart b/lib/generated_bindings.dart index 2a33add6..d1c86dda 100644 --- a/lib/generated_bindings.dart +++ b/lib/generated_bindings.dart @@ -183,11 +183,21 @@ external void clear_lights( @ffi.Native< EntityId Function(ffi.Pointer, ffi.Pointer, - ffi.Bool)>(symbol: 'load_glb', assetId: 'flutter_filament_plugin') + ffi.Int)>(symbol: 'load_glb', assetId: 'flutter_filament_plugin') external int load_glb( ffi.Pointer sceneManager, ffi.Pointer assetPath, - bool unlit, + int numInstances, +); + +@ffi.Native< + EntityId Function( + ffi.Pointer, ffi.Pointer, ffi.Size)>( + symbol: 'load_glb_from_buffer', assetId: 'flutter_filament_plugin') +external int load_glb_from_buffer( + ffi.Pointer sceneManager, + ffi.Pointer data, + int length, ); @ffi.Native< @@ -200,12 +210,42 @@ external int load_gltf( ffi.Pointer relativePath, ); +@ffi.Native, EntityId)>( + symbol: 'create_instance', assetId: 'flutter_filament_plugin') +external int create_instance( + ffi.Pointer sceneManager, + int id, +); + +@ffi.Native, EntityId)>( + symbol: 'get_instance_count', assetId: 'flutter_filament_plugin') +external int get_instance_count( + ffi.Pointer sceneManager, + int entityId, +); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, EntityId, ffi.Pointer)>( + symbol: 'get_instances', assetId: 'flutter_filament_plugin') +external int get_instances( + ffi.Pointer sceneManager, + int entityId, + ffi.Pointer out, +); + @ffi.Native)>( symbol: 'set_main_camera', assetId: 'flutter_filament_plugin') external void set_main_camera( ffi.Pointer viewer, ); +@ffi.Native)>( + symbol: 'get_main_camera', assetId: 'flutter_filament_plugin') +external int get_main_camera( + ffi.Pointer viewer, +); + @ffi.Native< ffi.Bool Function( ffi.Pointer, EntityId, ffi.Pointer)>( @@ -653,7 +693,7 @@ external void get_camera_position( symbol: 'set_camera_rotation', assetId: 'flutter_filament_plugin') external void set_camera_rotation( ffi.Pointer viewer, - double rads, + double w, double x, double y, double z, @@ -1140,11 +1180,22 @@ external void clear_lights_ffi( @ffi.Native< EntityId Function(ffi.Pointer, ffi.Pointer, - ffi.Bool)>(symbol: 'load_glb_ffi', assetId: 'flutter_filament_plugin') + ffi.Int)>(symbol: 'load_glb_ffi', assetId: 'flutter_filament_plugin') external int load_glb_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, ffi.Pointer assetPath, - bool unlit, + int numInstances, +); + +@ffi.Native< + EntityId Function( + ffi.Pointer, ffi.Pointer, ffi.Size, ffi.Int)>( + symbol: 'load_glb_from_buffer_ffi', assetId: 'flutter_filament_plugin') +external int load_glb_from_buffer_ffi( + ffi.Pointer sceneManager, + ffi.Pointer data, + int length, + int numInstances, ); @ffi.Native< @@ -1152,11 +1203,18 @@ external int load_glb_ffi( ffi.Pointer)>( symbol: 'load_gltf_ffi', assetId: 'flutter_filament_plugin') external int load_gltf_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, ffi.Pointer assetPath, ffi.Pointer relativePath, ); +@ffi.Native, EntityId)>( + symbol: 'create_instance_ffi', assetId: 'flutter_filament_plugin') +external int create_instance_ffi( + ffi.Pointer sceneManager, + int entityId, +); + @ffi.Native, EntityId)>( symbol: 'remove_entity_ffi', assetId: 'flutter_filament_plugin') external void remove_entity_ffi( @@ -1185,7 +1243,7 @@ external bool set_camera_ffi( ffi.Pointer, ffi.Pointer, ffi.Int)>( symbol: 'apply_weights_ffi', assetId: 'flutter_filament_plugin') external void apply_weights_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, ffi.Pointer entityName, ffi.Pointer weights, @@ -1197,7 +1255,7 @@ external void apply_weights_ffi( ffi.Bool, ffi.Bool, ffi.Float)>( symbol: 'play_animation_ffi', assetId: 'flutter_filament_plugin') external void play_animation_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, int index, bool loop, @@ -1210,7 +1268,7 @@ external void play_animation_ffi( ffi.Void Function(ffi.Pointer, EntityId, ffi.Int, ffi.Int)>( symbol: 'set_animation_frame_ffi', assetId: 'flutter_filament_plugin') external void set_animation_frame_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, int animationIndex, int animationFrame, @@ -1219,7 +1277,7 @@ external void set_animation_frame_ffi( @ffi.Native, EntityId, ffi.Int)>( symbol: 'stop_animation_ffi', assetId: 'flutter_filament_plugin') external void stop_animation_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, int index, ); @@ -1227,7 +1285,7 @@ external void stop_animation_ffi( @ffi.Native, EntityId)>( symbol: 'get_animation_count_ffi', assetId: 'flutter_filament_plugin') external int get_animation_count_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, ); @@ -1236,7 +1294,7 @@ external int get_animation_count_ffi( ffi.Pointer, EntityId, ffi.Pointer, ffi.Int)>( symbol: 'get_animation_name_ffi', assetId: 'flutter_filament_plugin') external void get_animation_name_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, ffi.Pointer outPtr, int index, @@ -1247,7 +1305,7 @@ external void get_animation_name_ffi( ffi.Pointer, ffi.Pointer, ffi.Int)>( symbol: 'get_morph_target_name_ffi', assetId: 'flutter_filament_plugin') external void get_morph_target_name_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, ffi.Pointer meshName, ffi.Pointer outPtr, @@ -1260,7 +1318,7 @@ external void get_morph_target_name_ffi( symbol: 'get_morph_target_name_count_ffi', assetId: 'flutter_filament_plugin') external int get_morph_target_name_count_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, ffi.Pointer meshName, ); @@ -1270,7 +1328,7 @@ external int get_morph_target_name_count_ffi( ffi.Pointer, ffi.Pointer, ffi.Int)>( symbol: 'set_morph_target_weights_ffi', assetId: 'flutter_filament_plugin') external void set_morph_target_weights_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, ffi.Pointer entityName, ffi.Pointer morphData, @@ -1289,7 +1347,7 @@ external void set_morph_target_weights_ffi( ffi.Float)>( symbol: 'set_morph_animation_ffi', assetId: 'flutter_filament_plugin') external bool set_morph_animation_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, ffi.Pointer entityName, ffi.Pointer morphData, @@ -1308,7 +1366,7 @@ external bool set_morph_animation_ffi( ffi.Pointer)>( symbol: 'set_bone_transform_ffi', assetId: 'flutter_filament_plugin') external bool set_bone_transform_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, ffi.Pointer entityName, ffi.Pointer transform, @@ -1328,7 +1386,7 @@ external bool set_bone_transform_ffi( ffi.Bool)>( symbol: 'add_bone_animation_ffi', assetId: 'flutter_filament_plugin') external void add_bone_animation_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int asset, ffi.Pointer frameData, int numFrames, @@ -1360,7 +1418,7 @@ external void pick_ffi( @ffi.Native, EntityId)>( symbol: 'reset_to_rest_pose_ffi', assetId: 'flutter_filament_plugin') external void reset_to_rest_pose_ffi( - ffi.Pointer assetManager, + ffi.Pointer sceneManager, int entityId, ); diff --git a/lib/hardware/hardware_keyboard_poll.dart b/lib/hardware/hardware_keyboard_poll.dart new file mode 100644 index 00000000..c5473627 --- /dev/null +++ b/lib/hardware/hardware_keyboard_poll.dart @@ -0,0 +1,42 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter_filament/entities/entity_transform_controller.dart'; +import 'package:flutter_filament/filament_controller.dart'; + +class HardwareKeyboardPoll { + final EntityTransformController _controller; + late Timer _timer; + HardwareKeyboardPoll(this._controller) { + _timer = Timer.periodic(const Duration(milliseconds: 16), (_) { + print(RawKeyboard.instance.keysPressed); + if (RawKeyboard.instance.keysPressed.contains(LogicalKeyboardKey.keyW)) { + _controller.forwardPressed(); + } else { + _controller.forwardReleased(); + } + + if (RawKeyboard.instance.keysPressed.contains(LogicalKeyboardKey.keyS)) { + _controller.backPressed(); + } else { + _controller.backReleased(); + } + + if (RawKeyboard.instance.keysPressed.contains(LogicalKeyboardKey.keyA)) { + _controller.strafeLeftPressed(); + } else { + _controller.strafeLeftReleased(); + } + + if (RawKeyboard.instance.keysPressed.contains(LogicalKeyboardKey.keyD)) { + _controller.strafeRightPressed(); + } else { + _controller.strafeRightReleased(); + } + }); + } + + void dispose() { + _timer.cancel(); + } +} diff --git a/lib/lights/light_options.dart b/lib/lights/light_options.dart new file mode 100644 index 00000000..76f7b187 --- /dev/null +++ b/lib/lights/light_options.dart @@ -0,0 +1,29 @@ +import 'package:vector_math/vector_math_64.dart' as v; + +class LightOptions { + String? iblPath; + double iblIntensity; + int directionalType; + double directionalColor; + double directionalIntensity; + bool directionalCastShadows; + late v.Vector3 directionalPosition; + late v.Vector3 directionalDirection; + + LightOptions( + {required this.iblPath, + required this.iblIntensity, + required this.directionalType, + required this.directionalColor, + required this.directionalIntensity, + required this.directionalCastShadows, + v.Vector3? directionalDirection, + v.Vector3? directionalPosition}) { + this.directionalDirection = directionalDirection == null + ? v.Vector3(0, -1, 0) + : directionalDirection; + this.directionalPosition = directionalPosition == null + ? v.Vector3(0, 100, 0) + : directionalPosition; + } +} diff --git a/lib/widgets/camera_options_widget.dart b/lib/widgets/camera_options_widget.dart index a0fe7fa4..c2273fa4 100644 --- a/lib/widgets/camera_options_widget.dart +++ b/lib/widgets/camera_options_widget.dart @@ -1,16 +1,20 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; +import 'package:flutter_filament/camera/camera_orientation.dart'; import 'package:flutter_filament/filament_controller.dart'; -import 'package:vector_math/vector_math_64.dart' as v; +import 'dart:math'; +import 'package:vector_math/vector_math_64.dart' as v64; class CameraOptionsWidget extends StatefulWidget { final FilamentController controller; + final CameraOrientation cameraOrientation; final List<({FilamentEntity entity, String name})> cameras; CameraOptionsWidget( - {super.key, required this.controller, required this.cameras}) {} + {super.key, + required this.controller, + required this.cameras, + required this.cameraOrientation}) {} @override State createState() => _CameraOptionsWidgetState(); @@ -45,6 +49,7 @@ class _CameraOptionsWidgetState extends State { @override void didUpdateWidget(CameraOptionsWidget oldWidget) { + super.didUpdateWidget(oldWidget); if (oldWidget.cameras.length != widget.cameras.length) { setState(() {}); } @@ -55,9 +60,20 @@ class _CameraOptionsWidgetState extends State { double.parse(_apertureController.text), double.parse(_speedController.text), double.parse(_sensitivityController.text)); + await widget.controller.setCameraPosition( + widget.cameraOrientation.position.x, + widget.cameraOrientation.position.y, + widget.cameraOrientation.position.z); + var rotation = widget.cameraOrientation.compose(); + await widget.controller.setCameraRotation(rotation); + print( + "Camera : ${widget.cameraOrientation.position} ${widget.cameraOrientation.rotationX} ${widget.cameraOrientation.rotationY} ${widget.cameraOrientation.rotationZ}"); setState(() {}); } + double _bloom = 0.0; + + double _focalLength = 26.0; @override Widget build(BuildContext context) { return Theme( @@ -81,6 +97,118 @@ class _CameraOptionsWidgetState extends State { Expanded( child: TextField(controller: _sensitivityController)), ]), + Row(children: [ + Text("Bloom: ${_bloom.toStringAsFixed(2)}"), + Slider( + value: _bloom, + min: 0.0, + max: 1.0, + onChanged: (v) async { + setState(() { + _bloom = v; + }); + await widget.controller.setBloom(_bloom); + }) + ]), + Row(children: [ + Text("Focal length"), + Slider( + label: _focalLength.toString(), + value: _focalLength, + min: 1.0, + max: 100.0, + onChanged: (v) async { + setState(() { + _focalLength = v; + }); + await widget.controller + .setCameraFocalLength(_focalLength); + }) + ]), + Row(children: [ + Text("X"), + Slider( + label: widget.cameraOrientation.position.x.toString(), + value: widget.cameraOrientation.position.x, + min: -100.0, + max: 100.0, + onChanged: (v) async { + setState(() { + widget.cameraOrientation.position.x = v; + }); + _set(); + }) + ]), + Row(children: [ + Text("Y"), + Slider( + label: widget.cameraOrientation.position.y.toString(), + value: widget.cameraOrientation.position.y, + min: -100.0, + max: 100.0, + onChanged: (v) async { + setState(() { + widget.cameraOrientation.position.y = v; + }); + _set(); + }) + ]), + Row(children: [ + Text("Z"), + Slider( + label: widget.cameraOrientation.position.z.toString(), + value: widget.cameraOrientation.position.z, + min: -100.0, + max: 100.0, + onChanged: (v) async { + setState(() { + widget.cameraOrientation.position.z = v; + }); + _set(); + }) + ]), + Row(children: [ + Text("ROTX"), + Slider( + label: widget.cameraOrientation.rotationX.toString(), + value: widget.cameraOrientation.rotationX, + min: -pi, + max: pi, + onChanged: (value) async { + setState(() { + widget.cameraOrientation.rotationX = value; + }); + _set(); + }) + ]), + Row(children: [ + Text("ROTY"), + Slider( + label: widget.cameraOrientation.rotationY.toString(), + value: widget.cameraOrientation.rotationY, + min: -pi, + max: pi, + onChanged: (v) async { + setState(() { + widget.cameraOrientation.rotationY = v; + }); + _set(); + }), + ]), + Row(children: [ + Text("ROTZ"), + Slider( + label: widget.cameraOrientation.rotationZ.toString(), + value: widget.cameraOrientation.rotationZ, + min: -pi, + max: pi, + onChanged: (v) async { + setState(() { + widget.cameraOrientation.rotationZ = v; + }); + _set(); + }) + ]), Wrap( children: [ GestureDetector( diff --git a/lib/widgets/filament_gesture_detector.dart b/lib/widgets/filament_gesture_detector.dart index 10f54e52..978cd7dc 100644 --- a/lib/widgets/filament_gesture_detector.dart +++ b/lib/widgets/filament_gesture_detector.dart @@ -32,16 +32,22 @@ class FilamentGestureDetector extends StatelessWidget { final bool showControlOverlay; /// - /// If false, all gestures will be ignored. + /// If false, gestures will not manipulate the active camera. /// - final bool enabled; + final bool enableCamera; + + /// + /// If false, pointer down events will not trigger hit-testing (picking). + /// + final bool enablePicking; const FilamentGestureDetector( {Key? key, required this.controller, this.child, this.showControlOverlay = false, - this.enabled = true}) + this.enableCamera = true, + this.enablePicking = true}) : super(key: key); @override @@ -53,14 +59,16 @@ class FilamentGestureDetector extends StatelessWidget { controller: controller, child: child, showControlOverlay: showControlOverlay, - listenerEnabled: enabled, + enableCamera: enableCamera, + enablePicking: enablePicking, ); } else { return FilamentGestureDetectorMobile( controller: controller, child: child, showControlOverlay: showControlOverlay, - listenerEnabled: enabled, + enableCamera: enableCamera, + enablePicking: enablePicking, ); } } diff --git a/lib/widgets/filament_gesture_detector_desktop.dart b/lib/widgets/filament_gesture_detector_desktop.dart index 40157e32..6265bc0c 100644 --- a/lib/widgets/filament_gesture_detector_desktop.dart +++ b/lib/widgets/filament_gesture_detector_desktop.dart @@ -28,16 +28,22 @@ class FilamentGestureDetectorDesktop extends StatefulWidget { final bool showControlOverlay; /// - /// If false, all gestures will be ignored. + /// If false, gestures will not manipulate the active camera. /// - final bool listenerEnabled; + final bool enableCamera; + + /// + /// If false, pointer down events will not trigger hit-testing (picking). + /// + final bool enablePicking; const FilamentGestureDetectorDesktop( {Key? key, required this.controller, this.child, this.showControlOverlay = false, - this.listenerEnabled = true}) + this.enableCamera = true, + this.enablePicking = true}) : super(key: key); @override @@ -57,7 +63,8 @@ class _FilamentGestureDetectorDesktopState @override void didUpdateWidget(FilamentGestureDetectorDesktop oldWidget) { if (widget.showControlOverlay != oldWidget.showControlOverlay || - widget.listenerEnabled != oldWidget.listenerEnabled) { + widget.enableCamera != oldWidget.enableCamera || + widget.enablePicking != oldWidget.enablePicking) { setState(() {}); } @@ -86,12 +93,9 @@ class _FilamentGestureDetectorDesktopState @override Widget build(BuildContext context) { - if (!widget.listenerEnabled) { - return widget.child ?? Container(); - } return Listener( onPointerSignal: (PointerSignalEvent pointerSignal) async { - if (pointerSignal is PointerScrollEvent) { + if (pointerSignal is PointerScrollEvent && widget.enableCamera) { _zoom(pointerSignal); } else { throw Exception("TODO"); @@ -108,20 +112,20 @@ class _FilamentGestureDetectorDesktopState onPointerMove: (PointerMoveEvent d) async { // if this is the first move event, we need to call rotateStart/panStart to set the first coordinates if (!_pointerMoving) { - if (d.buttons == kTertiaryButton) { + if (d.buttons == kTertiaryButton && widget.enableCamera) { widget.controller .rotateStart(d.localPosition.dx, d.localPosition.dy); - } else { + } else if (widget.enableCamera) { widget.controller .panStart(d.localPosition.dx, d.localPosition.dy); } } // set the _pointerMoving flag so we don't call rotateStart/panStart on future move events _pointerMoving = true; - if (d.buttons == kTertiaryButton) { + if (d.buttons == kTertiaryButton && widget.enableCamera) { widget.controller .rotateUpdate(d.localPosition.dx, d.localPosition.dy); - } else { + } else if (widget.enableCamera) { widget.controller.panUpdate(d.localPosition.dx, d.localPosition.dy); } }, @@ -130,12 +134,12 @@ class _FilamentGestureDetectorDesktopState // 2) if _pointerMoving is false, this is interpreted as a pick // same applies to middle mouse button, but this is ignored as a pick onPointerUp: (PointerUpEvent d) async { - if (d.buttons == kTertiaryButton) { + if (d.buttons == kTertiaryButton && widget.enableCamera) { widget.controller.rotateEnd(); } else { - if (_pointerMoving) { + if (_pointerMoving && widget.enableCamera) { widget.controller.panEnd(); - } else { + } else if (widget.enablePicking) { widget.controller .pick(d.localPosition.dx.toInt(), d.localPosition.dy.toInt()); } diff --git a/lib/widgets/filament_gesture_detector_mobile.dart b/lib/widgets/filament_gesture_detector_mobile.dart index 117bdc9f..3645a082 100644 --- a/lib/widgets/filament_gesture_detector_mobile.dart +++ b/lib/widgets/filament_gesture_detector_mobile.dart @@ -28,9 +28,14 @@ class FilamentGestureDetectorMobile extends StatefulWidget { final bool showControlOverlay; /// - /// If false, all gestures will be ignored. + /// If false, gestures will not manipulate the active camera. /// - final bool listenerEnabled; + final bool enableCamera; + + /// + /// If false, pointer down events will not trigger hit-testing (picking). + /// + final bool enablePicking; final double zoomDelta; @@ -39,7 +44,8 @@ class FilamentGestureDetectorMobile extends StatefulWidget { required this.controller, this.child, this.showControlOverlay = false, - this.listenerEnabled = true, + this.enableCamera = true, + this.enablePicking = true, this.zoomDelta = 1}) : super(key: key); @@ -105,7 +111,8 @@ class _FilamentGestureDetectorMobileState @override void didUpdateWidget(FilamentGestureDetectorMobile oldWidget) { if (widget.showControlOverlay != oldWidget.showControlOverlay || - widget.listenerEnabled != oldWidget.listenerEnabled) { + widget.enableCamera != oldWidget.enableCamera || + widget.enablePicking != oldWidget.enablePicking) { setState(() {}); } @@ -122,10 +129,6 @@ class _FilamentGestureDetectorMobileState // - inner is a Listener for all other gestures (including scroll zoom on desktop) @override Widget build(BuildContext context) { - if (!widget.listenerEnabled) { - return widget.child ?? Container(); - } - return Stack(children: [ Positioned.fill( child: GestureDetector( @@ -136,10 +139,10 @@ class _FilamentGestureDetectorMobileState }); }, onScaleStart: (d) async { - if (d.pointerCount == 2) { + if (d.pointerCount == 2 && widget.enableCamera) { _scaling = true; await widget.controller.zoomBegin(); - } else if (!_scaling) { + } else if (!_scaling && widget.enableCamera) { if (_rotateOnPointerMove) { widget.controller.rotateStart( d.localFocalPoint.dx, d.localFocalPoint.dy); @@ -150,7 +153,7 @@ class _FilamentGestureDetectorMobileState } }, onScaleUpdate: (ScaleUpdateDetails d) async { - if (d.pointerCount == 2) { + if (d.pointerCount == 2 && widget.enableCamera) { if (d.horizontalScale != _lastScale) { widget.controller.zoomUpdate( d.localFocalPoint.dx, @@ -158,7 +161,7 @@ class _FilamentGestureDetectorMobileState d.horizontalScale > _lastScale ? 0.1 : -0.1); _lastScale = d.horizontalScale; } - } else if (!_scaling) { + } else if (!_scaling && widget.enableCamera) { if (_rotateOnPointerMove) { widget.controller .rotateUpdate(d.focalPoint.dx, d.focalPoint.dy); @@ -169,9 +172,9 @@ class _FilamentGestureDetectorMobileState } }, onScaleEnd: (d) async { - if (d.pointerCount == 2) { + if (d.pointerCount == 2 && widget.enableCamera) { widget.controller.zoomEnd(); - } else if (!_scaling) { + } else if (!_scaling && widget.enableCamera) { if (_rotateOnPointerMove) { widget.controller.rotateEnd(); } else { diff --git a/lib/widgets/light_slider.dart b/lib/widgets/light_slider.dart index 564c7565..56e25b24 100644 --- a/lib/widgets/light_slider.dart +++ b/lib/widgets/light_slider.dart @@ -3,72 +3,52 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_filament/filament_controller.dart'; +import 'package:flutter_filament/lights/light_options.dart'; import 'package:vector_math/vector_math_64.dart' as v; class LightSliderWidget extends StatefulWidget { final FilamentController controller; - late final v.Vector3 initialPosition; - late final v.Vector3 initialDirection; - final int initialType; - final double initialColor; - final double initialIntensity; - final bool initialCastShadows; + final LightOptions options; final bool showControls; LightSliderWidget( {super.key, required this.controller, - this.initialType = 0, - this.initialColor = 6500, - this.initialIntensity = 100000, - this.initialCastShadows = true, this.showControls = false, - v.Vector3? initialDirection, - v.Vector3? initialPosition}) { - this.initialDirection = initialDirection ?? v.Vector3(0, 0.5, -1); - this.initialPosition = initialPosition ?? v.Vector3(0, 0.5, 1); - } - + required this.options}); @override - State createState() => _IblRotationSliderWidgetState(); + State createState() => _LightSliderWidgetState(); } -class _IblRotationSliderWidgetState extends State { - v.Vector3 lightPos = v.Vector3(1, 0.1, 1); - v.Vector3 lightDir = v.Vector3(-1, 0.1, 0); - bool castShadows = true; - int type = 0; - double color = 6500; - double intensity = 100000; +class _LightSliderWidgetState extends State { FilamentEntity? _light; @override void initState() { - type = widget.initialType; - castShadows = widget.initialCastShadows; - color = widget.initialColor; - lightPos = widget.initialPosition; - lightDir = widget.initialDirection; - intensity = widget.initialIntensity; _set(); super.initState(); } Future _set() async { - if (_light != null) await widget.controller.removeLight(_light!); + await widget.controller.clearLights(); + + if (widget.options.iblPath != null) { + _light = await widget.controller.loadIbl(widget.options.iblPath!, + intensity: widget.options.iblIntensity); + } _light = await widget.controller.addLight( - type, - color, - intensity, - lightPos.x, - lightPos.y, - lightPos.z, - lightDir.x, - lightDir.y, - lightDir.z, - castShadows); + widget.options.directionalType, + widget.options.directionalColor, + widget.options.directionalIntensity, + widget.options.directionalPosition.x, + widget.options.directionalPosition.y, + widget.options.directionalPosition.z, + widget.options.directionalDirection.x, + widget.options.directionalDirection.y, + widget.options.directionalDirection.z, + widget.options.directionalCastShadows); setState(() {}); } @@ -87,35 +67,39 @@ class _IblRotationSliderWidgetState extends State { showValueIndicator: ShowValueIndicator.always, valueIndicatorTextStyle: TextStyle(color: Colors.black)), child: Column(mainAxisSize: MainAxisSize.min, children: [ + Text("Directional"), Row(children: [ Expanded( child: Slider( - label: "POSX", - value: lightPos.x, + label: + "POSX ${widget.options.directionalPosition.x}", + value: widget.options.directionalPosition.x, min: -10.0, max: 10.0, onChanged: (value) { - lightPos.x = value; + widget.options.directionalPosition.x = value; _set(); })), Expanded( child: Slider( - label: "POSY", - value: lightPos.y, - min: -10.0, - max: 10.0, + label: + "POSY ${widget.options.directionalPosition.y}", + value: widget.options.directionalPosition.y, + min: -100.0, + max: 100.0, onChanged: (value) { - lightPos.y = value; + widget.options.directionalPosition.y = value; _set(); })), Expanded( child: Slider( - label: "POSZ", - value: lightPos.z, - min: -10.0, - max: 10.0, + label: + "POSZ ${widget.options.directionalPosition.z}", + value: widget.options.directionalPosition.z, + min: -100.0, + max: 100.0, onChanged: (value) { - lightPos.z = value; + widget.options.directionalPosition.z = value; _set(); })) ]), @@ -123,58 +107,58 @@ class _IblRotationSliderWidgetState extends State { Expanded( child: Slider( label: "DIRX", - value: lightDir.x, - min: -10.0, - max: 10.0, + value: widget.options.directionalDirection.x, + min: -1.0, + max: 1.0, onChanged: (value) { - lightDir.x = value; + widget.options.directionalDirection.x = value; _set(); })), Expanded( child: Slider( label: "DIRY", - value: lightDir.y, - min: -10.0, - max: 10.0, + value: widget.options.directionalDirection.y, + min: -1.0, + max: 1.0, onChanged: (value) { - lightDir.y = value; + widget.options.directionalDirection.y = value; _set(); })), Expanded( child: Slider( label: "DIRZ", - value: lightDir.z, - min: -10.0, - max: 10.0, + value: widget.options.directionalDirection.z, + min: -1.0, + max: 1.0, onChanged: (value) { - lightDir.z = value; + widget.options.directionalDirection.z = value; _set(); })) ]), Slider( label: "Color", - value: color, + value: widget.options.directionalColor, min: 0, max: 16000, onChanged: (value) { - color = value; + widget.options.directionalColor = value; _set(); }), Slider( - label: "Intensity", - value: intensity, + label: "Intensity ${widget.options.directionalIntensity}", + value: widget.options.directionalIntensity, min: 0, max: 1000000, onChanged: (value) { - intensity = value; + widget.options.directionalIntensity = value; _set(); }), DropdownButton( onChanged: (v) { - this.type = v; + this.widget.options.directionalType = v; _set(); }, - value: type, + value: this.widget.options.directionalType, items: List.generate( 5, (idx) => DropdownMenuItem( @@ -182,13 +166,27 @@ class _IblRotationSliderWidgetState extends State { child: Text("$idx"), ))), Row(children: [ - Text("Shadows: $castShadows"), + Text( + "Shadows: ${this.widget.options.directionalCastShadows}"), Checkbox( - value: castShadows, + value: widget.options.directionalCastShadows, onChanged: (v) { - this.castShadows = v!; + this.widget.options.directionalCastShadows = v!; _set(); }) + ]), + Text("Indirect"), + Row(children: [ + Expanded( + child: Slider( + label: "Intensity ${widget.options.iblIntensity}", + value: widget.options.iblIntensity, + min: 0.0, + max: 200000, + onChanged: (value) { + widget.options.iblIntensity = value; + _set(); + })), ]) ])))); } diff --git a/linux/flutter_filament_plugin.cc b/linux/flutter_filament_plugin.cc index 33f3ed9a..69055014 100644 --- a/linux/flutter_filament_plugin.cc +++ b/linux/flutter_filament_plugin.cc @@ -43,7 +43,7 @@ struct _FlutterFilamentPlugin { double width = 0; double height = 0; bool rendering = false; - polyvox::FilamentViewer* viewer; + flutter_filament::FilamentViewer* viewer; }; G_DEFINE_TYPE(FlutterFilamentPlugin, flutter_filament_plugin, g_object_get_type()) @@ -71,7 +71,7 @@ static FlMethodResponse* _create_filament_viewer(FlutterFilamentPlugin* self, Fl self->height = height; auto context = glXGetCurrentContext(); - self->viewer = (polyvox::FilamentViewer*)create_filament_viewer( + self->viewer = (flutter_filament::FilamentViewer*)create_filament_viewer( (void*)context, callback ); @@ -698,7 +698,7 @@ static FlMethodResponse* _get_morph_target_names(FlutterFilamentPlugin* self, Fl static FlMethodResponse* _set_tone_mapping(FlutterFilamentPlugin* self, FlMethodCall* method_call) { FlValue* args = fl_method_call_get_args(method_call); - polyvox::ToneMapping toneMapping = static_cast(fl_value_get_int(args)); + flutter_filament::ToneMapping toneMapping = static_cast(fl_value_get_int(args)); set_tone_mapping(self->viewer, toneMapping); return FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); } diff --git a/linux/include/flutter_filament/resource_loader.hpp b/linux/include/flutter_filament/resource_loader.hpp index 9bac451c..2ba1af5e 100644 --- a/linux/include/flutter_filament/resource_loader.hpp +++ b/linux/include/flutter_filament/resource_loader.hpp @@ -12,14 +12,13 @@ #include "ResourceBuffer.hpp" -using namespace std; -static map _file_assets; +static std::map _file_assets; static uint32_t _i = 0; ResourceBuffer loadResource(const char* name) { - std::cout << "LOADING RESOURCE" << std::endl; + std::cout << "LOADING RESOURCE" << std::endl; char cwd[PATH_MAX]; if (getcwd(cwd, sizeof(cwd)) != NULL) { diff --git a/macos/flutter_filament.podspec b/macos/flutter_filament.podspec index 0134458b..7853340f 100644 --- a/macos/flutter_filament.podspec +++ b/macos/flutter_filament.podspec @@ -14,7 +14,7 @@ A new Flutter plugin project. s.author = { 'Your Company' => 'email@example.com' } s.source = { :path => '.' } - s.source_files = 'Classes/*', 'src/*', "src/camutils/*", 'include/filament/*', 'include/*', 'include/material/*.c' + s.source_files = 'Classes/*', 'src/*', "src/camutils/*", 'include/filament/*', 'include/*', 'include/components/*', 'include/material/*.c' s.public_header_files = 'include/SwiftFlutterFilamentPlugin-Bridging-Header.h', 'include/FlutterFilamentApi.h', 'include/FlutterFilamentFFIApi.h', 'include/ResourceBuffer.hpp' #, 'include/filament/*' s.dependency 'FlutterMacOS'