From af543f46b26720875692429e00f46886e56d0756 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 8 Nov 2023 17:47:11 +0800 Subject: [PATCH] add onLoad/onUnload streams --- lib/filament_controller.dart | 14 ++++++++- lib/filament_controller_ffi.dart | 51 +++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 4b5825b7..5356dd04 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -27,6 +27,17 @@ class TextureDetails { } abstract class FilamentController { + /// + /// A Stream containing every FilamentEntity added to the scene (i.e. via [loadGlb], [loadGltf] or [addLight]). + /// This is provided for convenience so you can set listeners in front-end widgets that can respond to entity loads without manually passing around the FilamentEntity returned from those methods. + /// + Stream get onLoad; + + /// + /// A Stream containing every FilamentEntity removed from the scene (i.e. via [removeAsset], [clearAssets], [removeLight] or [clearLights]). + + Stream get onUnload; + /// /// A [ValueNotifier] that holds the current dimensions (in physical pixels, after multiplying by pixel ratio) of the FilamentWidget. /// If you need to perform work as early as possible, add a listener to this property before a [FilamentWidget] has been inserted into the widget hierarchy. @@ -201,7 +212,8 @@ abstract class FilamentController { /// [relativeResourcePath] is the folder path where the glTF resources are stored; /// this is usually the parent directory of the .gltf file itself. /// - Future loadGltf(String path, String relativeResourcePath); + Future loadGltf(String path, String relativeResourcePath, + {bool force = false}); /// /// Called by `FilamentGestureDetector`. You probably don't want to call this yourself. diff --git a/lib/filament_controller_ffi.dart b/lib/filament_controller_ffi.dart index 9176d6f5..305b3182 100644 --- a/lib/filament_controller_ffi.dart +++ b/lib/filament_controller_ffi.dart @@ -20,7 +20,14 @@ const FilamentEntity _FILAMENT_ASSET_ERROR = 0; class FilamentControllerFFI extends FilamentController { final _channel = const MethodChannel("app.polyvox.filament/event"); + /// + /// This will be set on constructor invocation. + /// On Windows, this will be set to the value returned by the [usesBackingWindow] method call. + /// On Web, this will always be true; + /// On other platforms, this will always be false. + /// bool _usesBackingWindow = false; + @override bool get requiresTextureWidget => !_usesBackingWindow; @@ -49,6 +56,15 @@ class FilamentControllerFFI extends FilamentController { Timer? _resizeTimer; + final _lights = {}; + final _entities = {}; + + final _onLoadController = StreamController.broadcast(); + Stream get onLoad => _onLoadController.stream; + + final _onUnloadController = StreamController.broadcast(); + Stream get onUnload => _onUnloadController.stream; + /// /// This controller uses platform channels to bridge Dart with the C/C++ code for the Filament API. /// Setting up the context/texture (since this is platform-specific) and the render ticker are platform-specific; all other methods are passed through by the platform channel to the methods specified in FlutterFilamentApi.h. @@ -450,15 +466,19 @@ class FilamentControllerFFI extends FilamentController { } var entity = add_light_ffi(_viewer!, type, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, castShadows); + _onLoadController.sink.add(entity); + _lights.add(entity); return entity; } @override - Future removeLight(FilamentEntity light) async { + Future removeLight(FilamentEntity entity) async { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - remove_light_ffi(_viewer!, light); + _lights.remove(entity); + remove_light_ffi(_viewer!, entity); + _onUnloadController.add(entity); } @override @@ -467,6 +487,10 @@ class FilamentControllerFFI extends FilamentController { throw Exception("No viewer available, ignoring"); } clear_lights_ffi(_viewer!); + for (final entity in _lights) { + _onUnloadController.add(entity); + } + _lights.clear(); } @override @@ -477,12 +501,14 @@ class FilamentControllerFFI extends FilamentController { if (unlit) { throw Exception("Not yet implemented"); } - var asset = + var entity = load_glb_ffi(_assetManager!, path.toNativeUtf8().cast(), unlit); - if (asset == _FILAMENT_ASSET_ERROR) { + if (entity == _FILAMENT_ASSET_ERROR) { throw Exception("An error occurred loading the asset at $path"); } - return asset; + _entities.add(entity); + _onLoadController.sink.add(entity); + return entity; } @override @@ -495,12 +521,14 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - var asset = load_gltf_ffi(_assetManager!, path.toNativeUtf8().cast(), + var entity = load_gltf_ffi(_assetManager!, path.toNativeUtf8().cast(), relativeResourcePath.toNativeUtf8().cast()); - if (asset == _FILAMENT_ASSET_ERROR) { + if (entity == _FILAMENT_ASSET_ERROR) { throw Exception("An error occurred loading the asset at $path"); } - return asset; + _entities.add(entity); + _onLoadController.sink.add(entity); + return entity; } @override @@ -700,7 +728,9 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } + _entities.remove(entity); remove_asset_ffi(_viewer!, entity); + _onUnloadController.add(entity); } @override @@ -709,6 +739,11 @@ class FilamentControllerFFI extends FilamentController { throw Exception("No viewer available, ignoring"); } clear_assets_ffi(_viewer!); + + for (final entity in _entities) { + _onUnloadController.add(entity); + } + _entities.clear(); } @override