From b357144a792d4f2981068ad08a52b9d5e10ac663 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Tue, 26 Mar 2024 00:24:21 +0800 Subject: [PATCH] expose method for retrieving all child entities --- example/lib/main.dart | 8 +++---- example/lib/menus/asset_submenu.dart | 7 ++++++ ios/include/FilamentViewer.hpp | 2 +- ios/include/FlutterFilamentApi.h | 1 + ios/include/SceneManager.hpp | 1 + ios/src/FilamentViewer.cpp | 18 +++++++++------ ios/src/FlutterFilamentApi.cpp | 4 ++++ ios/src/SceneManager.cpp | 28 +++++++++++++++++++++++ lib/filament/entities/gizmo.dart | 3 +++ lib/filament/filament_controller.dart | 10 ++++++-- lib/filament/filament_controller_ffi.dart | 15 ++++++++++-- lib/filament/generated_bindings.dart | 11 +++++++++ lib/filament/scene.dart | 14 ++++++++---- 13 files changed, 101 insertions(+), 21 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ec022a18..e909d9ec 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:flutter/material.dart'; @@ -129,7 +130,7 @@ class ExampleWidgetState extends State { ), EntityListWidget(controller: _filamentController), Positioned( - bottom: 0, + bottom: Platform.isIOS ? 30 : 0, left: 0, right: 10, height: 30, @@ -164,9 +165,8 @@ class ExampleWidgetState extends State { ), GestureDetector( onTap: () async { - await _filamentController!.loadGlb( - 'assets/shapes/shapes.glb', - numInstances: 10); + await _filamentController! + .loadGlb('assets/shapes/shapes.glb', numInstances: 1); }, child: Container( color: Colors.transparent, diff --git a/example/lib/menus/asset_submenu.dart b/example/lib/menus/asset_submenu.dart index 9355d64c..7afd8f35 100644 --- a/example/lib/menus/asset_submenu.dart +++ b/example/lib/menus/asset_submenu.dart @@ -215,6 +215,13 @@ class _AssetSubmenuState extends State { }, child: const Text("Add point light"), ), + MenuItemButton( + onPressed: () async { + await widget.controller + .addLight(3, 6500, 15000000, 0, 1, 0, 0, -1, 0, true); + }, + child: const Text("Add spot light"), + ), MenuItemButton( onPressed: () async { await widget.controller.clearLights(); diff --git a/ios/include/FilamentViewer.hpp b/ios/include/FilamentViewer.hpp index 8aa757b5..394a4242 100644 --- a/ios/include/FilamentViewer.hpp +++ b/ios/include/FilamentViewer.hpp @@ -195,7 +195,7 @@ namespace flutter_filament uint32_t _imageWidth = 0; mat4f _imageScale; Texture *_imageTexture = nullptr; - utils::Entity *_imageEntity = nullptr; + utils::Entity _imageEntity; VertexBuffer *_imageVb = nullptr; IndexBuffer *_imageIb = nullptr; Material *_imageMaterial = nullptr; diff --git a/ios/include/FlutterFilamentApi.h b/ios/include/FlutterFilamentApi.h index 1d27b29a..5854f4fa 100644 --- a/ios/include/FlutterFilamentApi.h +++ b/ios/include/FlutterFilamentApi.h @@ -188,6 +188,7 @@ extern "C" FLUTTER_PLUGIN_EXPORT const char *get_name_for_entity(void *const sceneManager, const EntityId entityId); FLUTTER_PLUGIN_EXPORT EntityId find_child_entity_by_name(void *const sceneManager, const EntityId parent, const char* name); FLUTTER_PLUGIN_EXPORT int get_entity_count(void *const sceneManager, const EntityId target, bool renderableOnly); + FLUTTER_PLUGIN_EXPORT void get_entities(void *const sceneManager, const EntityId target, bool renderableOnly, EntityId* out); FLUTTER_PLUGIN_EXPORT const char* get_entity_name_at(void *const sceneManager, const EntityId target, int index, bool renderableOnly); FLUTTER_PLUGIN_EXPORT void set_recording(void *const viewer, bool recording); FLUTTER_PLUGIN_EXPORT void set_recording_output_directory(void *const viewer, const char* outputDirectory); diff --git a/ios/include/SceneManager.hpp b/ios/include/SceneManager.hpp index 96b685e3..98479cd8 100644 --- a/ios/include/SceneManager.hpp +++ b/ios/include/SceneManager.hpp @@ -130,6 +130,7 @@ namespace flutter_filament EntityId entityId, const char *entityName); int getEntityCount(EntityId entity, bool renderableOnly); + void getEntities(EntityId entity, bool renderableOnly, EntityId *out); const char* getEntityNameAt(EntityId entity, int index, bool renderableOnly); void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform); void removeCollisionComponent(EntityId entityId); diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index 81e5484e..92ac6882 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -238,17 +238,16 @@ namespace flutter_filament _imageIb->setBuffer(*_engine, {sFullScreenTriangleIndices, sizeof(sFullScreenTriangleIndices)}); - utils::Entity imageEntity = em.create(); + _imageEntity = em.create(); RenderableManager::Builder(1) .boundingBox({{}, {1.0f, 1.0f, 1.0f}}) .material(0, _imageMaterial->getDefaultInstance()) .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, _imageVb, _imageIb, 0, 3) .culling(false) - .build(*_engine, imageEntity); - _imageEntity = &imageEntity; - _scene->addEntity(imageEntity); - Log("Added imageEntity %d", imageEntity); + .build(*_engine, _imageEntity); + _scene->addEntity(_imageEntity); + Log("Added imageEntity %d", _imageEntity); } void FilamentViewer::setAntiAliasing(bool msaa, bool fxaa, bool taa) { @@ -335,6 +334,8 @@ namespace flutter_filament _lights.push_back(light); auto entityId = Entity::smuggle(light); + auto transformInstance = transformManager.getInstance(light); + transformManager.setTransform(transformInstance, math::mat4::translation(math::float3 { posX, posY, posZ})); Log("Added light under entity ID %d of type %d with colour %f intensity %f at (%f, %f, %f) with direction (%f, %f, %f) with shadows %d", entityId, t, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, shadows); return entityId; } @@ -885,7 +886,7 @@ namespace flutter_filament ResourceBuffer skyboxBuffer = _resourceLoaderWrapper->load(skyboxPath); - // because this will go out of scope before the texture callback is invoked, we need to make a copy to the heap + // because this will go out of scope before the texture callback is invoked, we need to make a copy of the variable itself (not its contents) ResourceBuffer *skyboxBufferCopy = new ResourceBuffer(skyboxBuffer); if (skyboxBuffer.size <= 0) @@ -1449,9 +1450,12 @@ namespace flutter_filament void FilamentViewer::pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y)) { + _view->pick(x, y, [=](filament::View::PickingQueryResult const &result) { - callback(Entity::smuggle(result.renderable), x, y); + if(result.renderable != _imageEntity) { + callback(Entity::smuggle(result.renderable), x, y); + } }); } diff --git a/ios/src/FlutterFilamentApi.cpp b/ios/src/FlutterFilamentApi.cpp index 9b310060..22429b46 100644 --- a/ios/src/FlutterFilamentApi.cpp +++ b/ios/src/FlutterFilamentApi.cpp @@ -562,6 +562,10 @@ extern "C" return ((SceneManager *)sceneManager)->getEntityCount(target, renderableOnly); } + FLUTTER_PLUGIN_EXPORT void get_entities(void *const sceneManager, const EntityId target, bool renderableOnly, EntityId* out) { + ((SceneManager *)sceneManager)->getEntities(target, renderableOnly, out); + } + FLUTTER_PLUGIN_EXPORT const char* get_entity_name_at(void *const sceneManager, const EntityId target, int index, bool renderableOnly) { return ((SceneManager *)sceneManager)->getEntityNameAt(target, index, renderableOnly); } diff --git a/ios/src/SceneManager.cpp b/ios/src/SceneManager.cpp index 24cee25f..015c26d0 100644 --- a/ios/src/SceneManager.cpp +++ b/ios/src/SceneManager.cpp @@ -1529,6 +1529,34 @@ namespace flutter_filament return instance->getEntityCount(); } + void SceneManager::getEntities(EntityId entityId, bool renderableOnly, EntityId* out) { + const auto *instance = getInstanceByEntityId(entityId); + if(!instance) { + auto asset = getAssetByEntityId(entityId); + if(asset) { + instance = asset->getInstance(); + } else { + return; + } + } + + if(renderableOnly) { + int count = 0; + const auto& rm = _engine->getRenderableManager(); + const Entity *entities = instance->getEntities(); + int offset = 0; + for(int i=0; i < instance->getEntityCount(); i++) { + if(rm.hasComponent(entities[i])) { + out[offset] = Entity::smuggle(entities[i]); + } + } + } else { + for(int i=0;i < instance->getEntityCount(); i++) { + out[i] = Entity::smuggle(instance->getEntities()[i]); + } + } + } + const char* SceneManager::getEntityNameAt(EntityId entityId, int index, bool renderableOnly) { const auto *instance = getInstanceByEntityId(entityId); if(!instance) { diff --git a/lib/filament/entities/gizmo.dart b/lib/filament/entities/gizmo.dart index 5cf348ed..71a4b554 100644 --- a/lib/filament/entities/gizmo.dart +++ b/lib/filament/entities/gizmo.dart @@ -65,6 +65,9 @@ class Gizmo { } void detach() async { + await controller.setParent(x, 0); + await controller.setParent(y, 0); + await controller.setParent(z, 0); await controller.hide(x, null); await controller.hide(y, null); await controller.hide(z, null); diff --git a/lib/filament/filament_controller.dart b/lib/filament/filament_controller.dart index 60da124d..93fff6b7 100644 --- a/lib/filament/filament_controller.dart +++ b/lib/filament/filament_controller.dart @@ -576,6 +576,12 @@ abstract class FilamentController { double orbitSpeedY = 0.01, double zoomSpeed = 0.01}); + /// + /// Returns all child entities under [parent]. + /// + Future> getChildEntities( + FilamentEntity parent, bool renderableOnly); + /// /// Finds the child entity named [childName] associated with the given parent. /// Usually, [parent] will be the return value from [loadGlb]/[loadGltf] and [childName] will be the name of a node/mesh. @@ -584,9 +590,9 @@ abstract class FilamentController { FilamentEntity parent, String childName); /// - /// List all child entities under the given entity. + /// List the name of all child entities under the given entity. /// - Future> getChildEntities(FilamentEntity entity, + Future> getChildEntityNames(FilamentEntity entity, {bool renderableOnly = true}); /// diff --git a/lib/filament/filament_controller_ffi.dart b/lib/filament/filament_controller_ffi.dart index 6f330e8e..2e9f946b 100644 --- a/lib/filament/filament_controller_ffi.dart +++ b/lib/filament/filament_controller_ffi.dart @@ -358,7 +358,7 @@ class FilamentControllerFFI extends FilamentController { get_gizmo(_sceneManager!, out); var gizmo = Gizmo(out[0], out[1], out[2], this); allocator.free(out); - _scene = SceneImpl(gizmo); + _scene = SceneImpl(gizmo, this); hasViewer.value = true; _creating = false; @@ -1504,8 +1504,19 @@ class FilamentControllerFFI extends FilamentController { return childEntity; } + Future> getChildEntities( + FilamentEntity parent, bool renderableOnly) async { + var count = get_entity_count(_sceneManager!, parent, renderableOnly); + var out = allocator(count); + get_entities(_sceneManager!, parent, renderableOnly, out); + var outList = + List.generate(count, (index) => out[index]).cast(); + allocator.free(out); + return outList; + } + @override - Future> getChildEntities(FilamentEntity entity, + Future> getChildEntityNames(FilamentEntity entity, {bool renderableOnly = false}) async { var count = get_entity_count(_sceneManager!, entity, renderableOnly); var names = []; diff --git a/lib/filament/generated_bindings.dart b/lib/filament/generated_bindings.dart index 8ed8e408..306478a9 100644 --- a/lib/filament/generated_bindings.dart +++ b/lib/filament/generated_bindings.dart @@ -885,6 +885,17 @@ external int get_entity_count( bool renderableOnly, ); +@ffi.Native< + ffi.Void Function( + ffi.Pointer, EntityId, ffi.Bool, ffi.Pointer)>( + symbol: 'get_entities', assetId: 'flutter_filament_plugin') +external void get_entities( + ffi.Pointer sceneManager, + int target, + bool renderableOnly, + ffi.Pointer out, +); + @ffi.Native< ffi.Pointer Function( ffi.Pointer, EntityId, ffi.Int, ffi.Bool)>( diff --git a/lib/filament/scene.dart b/lib/filament/scene.dart index 28469e85..bd47434f 100644 --- a/lib/filament/scene.dart +++ b/lib/filament/scene.dart @@ -9,7 +9,9 @@ class SceneImpl extends Scene { final Gizmo _gizmo; Gizmo get gizmo => _gizmo; - SceneImpl(this._gizmo); + FilamentController controller; + + SceneImpl(this._gizmo, this.controller); @override FilamentEntity? selected; @@ -35,8 +37,9 @@ class SceneImpl extends Scene { _onUpdatedController.add(true); } - void unregisterLight(FilamentEntity entity) { - if (selected == entity) { + void unregisterLight(FilamentEntity entity) async { + var children = await controller.getChildEntities(entity, true); + if (selected == entity || children.contains(selected)) { selected = null; _gizmo.detach(); } @@ -45,8 +48,9 @@ class SceneImpl extends Scene { _onUpdatedController.add(true); } - void unregisterEntity(FilamentEntity entity) { - if (selected == entity) { + void unregisterEntity(FilamentEntity entity) async { + var children = await controller.getChildEntities(entity, true); + if (selected == entity || children.contains(selected)) { selected = null; _gizmo.detach(); }