diff --git a/thermion_dart/lib/thermion_dart/thermion_viewer.dart b/thermion_dart/lib/thermion_dart/thermion_viewer.dart index d268ba16..5ef344df 100644 --- a/thermion_dart/lib/thermion_dart/thermion_viewer.dart +++ b/thermion_dart/lib/thermion_dart/thermion_viewer.dart @@ -72,6 +72,11 @@ abstract class ThermionViewer { /// Stream get pickResult; + /// + /// The result(s) of calling [pickGizmo] (see below). + /// + Stream get gizmoPickResult; + /// /// Whether the controller is currently rendering at [framerate]. /// @@ -137,11 +142,17 @@ abstract class ThermionViewer { Future removeSkybox(); /// - /// Loads an image-based light from the specified path at the given intensity. - /// Only one IBL can be active at any given time; if an IBL has already been loaded, it will be replaced. + /// Creates an indirect light by loading the reflections/irradiance from the KTX file. + /// Only one indirect light can be active at any given time; if an indirect light has already been loaded, it will be replaced. /// Future loadIbl(String lightingPath, {double intensity = 30000}); + /// + /// Creates a indirect light with the given color. + /// Only one indirect light can be active at any given time; if an indirect light has already been loaded, it will be replaced. + /// + Future createIbl(double r, double g, double b, double intensity); + /// /// Rotates the IBL & skybox. /// @@ -648,6 +659,14 @@ abstract class ThermionViewer { /// void pick(int x, int y); + /// + /// Used to test whether a Gizmo is at the given viewport coordinates. + /// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself. + /// This is asynchronous and will require 2-3 frames to complete - subscribe to the [gizmoPickResult] stream to receive the results of this method. + /// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget). + /// + void pickGizmo(int x, int y); + /// /// Retrieves the name assigned to the given ThermionEntity (usually corresponds to the glTF mesh name). /// @@ -773,4 +792,9 @@ abstract class ThermionViewer { /// Use this method to toggle visibility of the respective layer. /// Future setLayerEnabled(int layer, bool enabled); + + /// + /// Show/hide the translation gizmo. + /// + Future setGizmoVisibility(bool visible); } diff --git a/thermion_dart/lib/thermion_dart/thermion_viewer_ffi.dart b/thermion_dart/lib/thermion_dart/thermion_viewer_ffi.dart index 12a0b9a3..8d7fad1b 100644 --- a/thermion_dart/lib/thermion_dart/thermion_viewer_ffi.dart +++ b/thermion_dart/lib/thermion_dart/thermion_viewer_ffi.dart @@ -43,6 +43,12 @@ class ThermionViewerFFI extends ThermionViewer { final _pickResultController = StreamController.broadcast(); + @override + Stream get gizmoPickResult => + _gizmoPickResultController.stream; + final _gizmoPickResultController = + StreamController.broadcast(); + final Pointer resourceLoader; var _driver = nullptr.cast(); @@ -67,14 +73,15 @@ class ThermionViewerFFI extends ThermionViewer { this._renderCallback = renderCallback ?? nullptr; this._driver = driver ?? nullptr; this._sharedContext = sharedContext ?? nullptr; - try { - _onPickResultCallable = NativeCallable< - Void Function( - EntityId entityId, Int x, Int y)>.listener(_onPickResult); - } catch (err) { - _logger.severe( - "Failed to set pick result callback. This is expected if running on web/wasm"); - } + + _onPickResultCallable = + NativeCallable.listener( + _onPickResult); + + _onGizmoPickResultCallable = + NativeCallable.listener( + _onGizmoPickResult); + _initialize(); } @@ -277,6 +284,14 @@ class ThermionViewerFFI extends ThermionViewer { allocator.free(pathPtr); } + /// + /// + /// + @override + Future createIbl(double r, double g, double b, double intensity) async { + create_ibl(_viewer!, r, g, b, intensity); + } + /// /// /// @@ -1379,8 +1394,18 @@ class ThermionViewerFFI extends ThermionViewer { _scene!.registerSelected(entityId); } + void _onGizmoPickResult(ThermionEntity entityId, int x, int y) { + _gizmoPickResultController.add(( + entity: entityId, + x: (x / pixelRatio).toDouble(), + y: (viewportDimensions.$2 - y) / pixelRatio + )); + } + late NativeCallable _onPickResultCallable; + late NativeCallable + _onGizmoPickResultCallable; /// /// @@ -1395,6 +1420,16 @@ class ThermionViewerFFI extends ThermionViewer { filament_pick(_viewer!, x, y, _onPickResultCallable.nativeFunction); } + /// + /// + /// + @override + void pickGizmo(int x, int y) async { + x = (x * pixelRatio).ceil(); + y = (viewportDimensions.$2 - (y * pixelRatio)).ceil(); + pick_gizmo(_sceneManager!, x, y, _onGizmoPickResultCallable.nativeFunction); + } + /// /// /// @@ -1768,4 +1803,11 @@ class ThermionViewerFFI extends ThermionViewer { Future setLayerEnabled(int layer, bool enabled) async { set_layer_enabled(_sceneManager!, layer, enabled); } + + /// + /// + /// + Future setGizmoVisibility(bool visible) async { + set_gizmo_visibility(_sceneManager!, visible); + } }