From aa7350c419aef635dc0e9606d097de3476c9b189 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Sat, 30 Nov 2024 13:57:31 +0800 Subject: [PATCH] gizmo & picking improvements --- .../implementations/gizmo_input_handler.dart | 94 ++++++++++++++----- .../lib/src/input/src/input_handler.dart | 16 +++- .../lib/src/viewer/src/ffi/src/ffi_gizmo.dart | 19 ++-- .../src/viewer/src/shared_types/entities.dart | 3 +- thermion_dart/native/src/scene/Gizmo.cpp | 16 ++-- 5 files changed, 110 insertions(+), 38 deletions(-) diff --git a/thermion_dart/lib/src/input/src/implementations/gizmo_input_handler.dart b/thermion_dart/lib/src/input/src/implementations/gizmo_input_handler.dart index 05fd0025..27cebbe5 100644 --- a/thermion_dart/lib/src/input/src/implementations/gizmo_input_handler.dart +++ b/thermion_dart/lib/src/input/src/implementations/gizmo_input_handler.dart @@ -6,10 +6,14 @@ class _Gizmo { bool isVisible = false; final ThermionViewer viewer; - final nonPickable = {}; - final GizmoAsset _asset; + final GizmoAsset _gizmo; - _Gizmo(this._asset, this.viewer); + ThermionEntity? _attachedTo; + + _Gizmo(this._gizmo, this.viewer); + + final _onEntityTransformUpdated = StreamController< + ({ThermionEntity entity, Matrix4 transform})>.broadcast(); Axis? _active; Axis? get active => _active; @@ -17,10 +21,10 @@ class _Gizmo { Vector3? _activeCords; void checkHover(int x, int y) async { - _asset.pick(x, y, handler: (result, coords) async { + _gizmo.pick(x, y, handler: (result, coords) async { switch (result) { case GizmoPickResultType.None: - await _asset.unhighlight(); + await _gizmo.unhighlight(); _active = null; break; case GizmoPickResultType.AxisX: @@ -43,29 +47,35 @@ class _Gizmo { Matrix4? gizmoTransform; Future attach(ThermionEntity entity) async { - if (_asset.nonPickableEntities.contains(entity)) { - return; + print("Attached to ${entity}"); + + if (_attachedTo != null && entity != _attachedTo) { + await viewer.setParent(_attachedTo!, 0); } - final transform = await viewer.getWorldTransform(entity); - transform.setRotation(Matrix3.identity()); - transform.setDiagonal(Vector4.all(1.0)); - await viewer.setTransform(_asset.entity, transform); - await viewer.setParent(entity, _asset.entity); + + _attachedTo = entity; + + await viewer.setParent(_gizmo.entity, entity); + await viewer.setTransform(_gizmo.entity, Matrix4.identity()); + if (!isVisible) { - await _asset.addToScene(); + await _gizmo.addToScene(); isVisible = true; } - gizmoTransform = await viewer.getWorldTransform(_asset.entity); + gizmoTransform = await viewer.getWorldTransform(entity); } Future detach() async { - await _asset.removeFromScene(); + await _gizmo.removeFromScene(); + if (_attachedTo != null) { + await viewer.setParent(_attachedTo!, 0); + } _active = null; isVisible = false; } void _updateTransform(Vector2 currentPosition, Vector2 delta) async { - if (gizmoTransform == null) { + if (_attachedTo == null) { return; } @@ -104,9 +114,13 @@ class _Gizmo { Vector3 worldSpaceDelta = newPosition - gizmoTransform!.getTranslation(); worldSpaceDelta.multiply(_active!.asVector()); - gizmoTransform!.setTranslation(gizmoTransform!.getTranslation() + worldSpaceDelta); + gizmoTransform! + .setTranslation(gizmoTransform!.getTranslation() + worldSpaceDelta); - await viewer.setTransform(_asset.entity, gizmoTransform!); + await viewer.setTransform(_attachedTo!, gizmoTransform!); + + _onEntityTransformUpdated + .add((entity: _attachedTo!, transform: gizmoTransform!)); } } @@ -115,11 +129,16 @@ class GizmoInputHandler extends InputHandler { final ThermionViewer viewer; late final _Gizmo translationGizmo; + Stream<({ThermionEntity entity, Matrix4 transform})> + get onEntityTransformUpdated => + translationGizmo._onEntityTransformUpdated.stream; + GizmoInputHandler({required this.wrapped, required this.viewer}) { initialize(); } final _initialized = Completer(); + Future initialize() async { if (_initialized.isCompleted) { throw Exception("Already initialized"); @@ -137,7 +156,7 @@ class GizmoInputHandler extends InputHandler { @override Future dispose() async { - await viewer.removeEntity(translationGizmo._asset); + await viewer.removeEntity(translationGizmo._gizmo); } @override @@ -166,9 +185,21 @@ class GizmoInputHandler extends InputHandler { if (!_initialized.isCompleted) { return; } + + if (isMiddle) { + return; + } + await viewer.pick(localPosition.x.toInt(), localPosition.y.toInt(), - (result) { - translationGizmo.attach(result.entity); + (result) async { + if (translationGizmo._gizmo.isNonPickable(result.entity) || + result.entity == FILAMENT_ENTITY_NULL) { + await translationGizmo.detach(); + return; + } + if (!translationGizmo._gizmo.isGizmoEntity(result.entity)) { + translationGizmo.attach(result.entity); + } }); } @@ -235,4 +266,25 @@ class GizmoInputHandler extends InputHandler { void setActionForType(InputType gestureType, InputAction gestureAction) { throw UnimplementedError(); } + + Future detach(ThermionAsset asset) async { + + if (translationGizmo._attachedTo == asset.entity) { + await translationGizmo.detach(); + return; + } + final childEntities = await asset.getChildEntities(); + for(final childEntity in childEntities) { + if(translationGizmo._attachedTo == childEntity) { + await translationGizmo.detach(); + return; + } + } + + } + + // @override + // Future setCamera(Camera camera) async { + // await wrapped.setCamera(camera); + // } } diff --git a/thermion_dart/lib/src/input/src/input_handler.dart b/thermion_dart/lib/src/input/src/input_handler.dart index 0e4f5968..bac17a34 100644 --- a/thermion_dart/lib/src/input/src/input_handler.dart +++ b/thermion_dart/lib/src/input/src/input_handler.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:thermion_dart/thermion_dart.dart'; import 'package:vector_math/vector_math_64.dart'; enum InputType { @@ -37,8 +38,17 @@ abstract class InputHandler { Future onPointerMove( Vector2 localPosition, Vector2 delta, bool isMiddle); Future onPointerUp(bool isMiddle); - Future onScaleStart(Vector2 focalPoint, int pointerCount, Duration? sourceTimestamp); - Future onScaleUpdate(Vector2 focalPoint, Vector2 focalPointDelta, double horizontalScale, double verticalScale, double scale, int pointerCount, double rotation, Duration? sourceTimestamp); + Future onScaleStart( + Vector2 focalPoint, int pointerCount, Duration? sourceTimestamp); + Future onScaleUpdate( + Vector2 focalPoint, + Vector2 focalPointDelta, + double horizontalScale, + double verticalScale, + double scale, + int pointerCount, + double rotation, + Duration? sourceTimestamp); Future onScaleEnd(int pointerCount, double velocity); Future get initialized; Future dispose(); @@ -48,4 +58,6 @@ abstract class InputHandler { void keyDown(PhysicalKey key); void keyUp(PhysicalKey key); + + // Future setCamera(Camera camera); } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_gizmo.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_gizmo.dart index c858e537..66473ca9 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_gizmo.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_gizmo.dart @@ -9,6 +9,7 @@ import 'ffi_view.dart'; class FFIGizmo extends FFIAsset implements GizmoAsset { final Set nonPickableEntities; + final Set gizmoEntities; late NativeCallable _nativeCallback; void Function(GizmoPickResultType axis, Vector3 coords)? _callback; @@ -19,14 +20,18 @@ class FFIGizmo extends FFIAsset implements GizmoAsset { _callback?.call(GizmoPickResultType.values[resultType], Vector3(x, y, z)); } + bool isNonPickable(ThermionEntity entity) => + nonPickableEntities.contains(entity); + bool isGizmoEntity(ThermionEntity entity) => gizmoEntities.contains(entity); + FFIGizmo( - this._view, - super.pointer, - super.sceneManager, - super.renderableManager, - super.unlitMaterialProvider, - this.nonPickableEntities - ) { + this._view, + super.pointer, + super.sceneManager, + super.renderableManager, + super.unlitMaterialProvider, + this.nonPickableEntities, + this.gizmoEntities) { _nativeCallback = NativeCallable.listener(_onPickResult); } diff --git a/thermion_dart/lib/src/viewer/src/shared_types/entities.dart b/thermion_dart/lib/src/viewer/src/shared_types/entities.dart index 71676d46..5c0c45ff 100644 --- a/thermion_dart/lib/src/viewer/src/shared_types/entities.dart +++ b/thermion_dart/lib/src/viewer/src/shared_types/entities.dart @@ -81,5 +81,6 @@ abstract class GizmoAsset extends ThermionAsset { {Future Function(GizmoPickResultType axis, Vector3 coords)? handler}); Future highlight(Axis axis); Future unhighlight(); - Set get nonPickableEntities; + bool isNonPickable(ThermionEntity entity); + bool isGizmoEntity(ThermionEntity entity); } diff --git a/thermion_dart/native/src/scene/Gizmo.cpp b/thermion_dart/native/src/scene/Gizmo.cpp index 5e091dc8..69a45371 100644 --- a/thermion_dart/native/src/scene/Gizmo.cpp +++ b/thermion_dart/native/src/scene/Gizmo.cpp @@ -28,11 +28,12 @@ namespace thermion auto parent = entityManager.create(); - auto *parentMaterialInstance = _material->createInstance(); - parentMaterialInstance->setParameter("baseColorFactor", math::float4{0.0f, 1.0f, 1.0f, 1.0f}); - parentMaterialInstance->setParameter("scale", 4.0f); + // auto *parentMaterialInstance = _material->createInstance(); + // parentMaterialInstance->setParameter("baseColorFactor", math::float4{1.0f, 1.0f, 1.0f, 0.0f}); + // parentMaterialInstance->setParameter("scale", 4.0f); + // parentMaterialInstance->setDoubleSided(false); - _materialInstances.push_back(parentMaterialInstance); + // _materialInstances.push_back(parentMaterialInstance); // Create center cube vertices float centerCubeSize = 0.1f; @@ -73,11 +74,11 @@ namespace thermion RenderableManager::Builder(1) .boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize}, {centerCubeSize, centerCubeSize, centerCubeSize}}) - .material(0, parentMaterialInstance) + // .material(0, parentMaterialInstance) .layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY) - .priority(7) + .priority(0) .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36) - .culling(false) + .culling(true) .build(*_engine, parent); auto parentTransformInstance = transformManager.getInstance(parent); @@ -265,6 +266,7 @@ namespace thermion _materialInstances.push_back(materialInstance); materialInstance->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 0.0f}); materialInstance->setParameter("scale", 4.0f); + materialInstance->setDepthFunc(MaterialInstance::DepthFunc::A); RenderableManager::Builder(1) .boundingBox({{-volumeWidth / 2, -volumeDepth / 2, 0}, {volumeWidth / 2, volumeDepth / 2, volumeLength}})