gizmo & picking improvements

This commit is contained in:
Nick Fisher
2024-11-30 13:57:31 +08:00
parent c2077cb6b1
commit aa7350c419
5 changed files with 110 additions and 38 deletions

View File

@@ -6,10 +6,14 @@ class _Gizmo {
bool isVisible = false;
final ThermionViewer viewer;
final nonPickable = <ThermionEntity>{};
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<bool>();
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);
// }
}

View File

@@ -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<void> onPointerMove(
Vector2 localPosition, Vector2 delta, bool isMiddle);
Future<void> onPointerUp(bool isMiddle);
Future<void> onScaleStart(Vector2 focalPoint, int pointerCount, Duration? sourceTimestamp);
Future<void> onScaleUpdate(Vector2 focalPoint, Vector2 focalPointDelta, double horizontalScale, double verticalScale, double scale, int pointerCount, double rotation, Duration? sourceTimestamp);
Future<void> onScaleStart(
Vector2 focalPoint, int pointerCount, Duration? sourceTimestamp);
Future<void> onScaleUpdate(
Vector2 focalPoint,
Vector2 focalPointDelta,
double horizontalScale,
double verticalScale,
double scale,
int pointerCount,
double rotation,
Duration? sourceTimestamp);
Future<void> onScaleEnd(int pointerCount, double velocity);
Future<bool> get initialized;
Future dispose();
@@ -48,4 +58,6 @@ abstract class InputHandler {
void keyDown(PhysicalKey key);
void keyUp(PhysicalKey key);
// Future setCamera(Camera camera);
}

View File

@@ -9,6 +9,7 @@ import 'ffi_view.dart';
class FFIGizmo extends FFIAsset implements GizmoAsset {
final Set<ThermionEntity> nonPickableEntities;
final Set<ThermionEntity> gizmoEntities;
late NativeCallable<GizmoPickCallbackFunction> _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<GizmoPickCallbackFunction>.listener(_onPickResult);
}

View File

@@ -81,5 +81,6 @@ abstract class GizmoAsset extends ThermionAsset {
{Future Function(GizmoPickResultType axis, Vector3 coords)? handler});
Future highlight(Axis axis);
Future unhighlight();
Set<ThermionEntity> get nonPickableEntities;
bool isNonPickable(ThermionEntity entity);
bool isGizmoEntity(ThermionEntity entity);
}

View File

@@ -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}})