gizmo & picking improvements
This commit is contained in:
@@ -6,10 +6,14 @@ class _Gizmo {
|
|||||||
bool isVisible = false;
|
bool isVisible = false;
|
||||||
|
|
||||||
final ThermionViewer viewer;
|
final ThermionViewer viewer;
|
||||||
final nonPickable = <ThermionEntity>{};
|
final GizmoAsset _gizmo;
|
||||||
final GizmoAsset _asset;
|
|
||||||
|
|
||||||
_Gizmo(this._asset, this.viewer);
|
ThermionEntity? _attachedTo;
|
||||||
|
|
||||||
|
_Gizmo(this._gizmo, this.viewer);
|
||||||
|
|
||||||
|
final _onEntityTransformUpdated = StreamController<
|
||||||
|
({ThermionEntity entity, Matrix4 transform})>.broadcast();
|
||||||
|
|
||||||
Axis? _active;
|
Axis? _active;
|
||||||
Axis? get active => _active;
|
Axis? get active => _active;
|
||||||
@@ -17,10 +21,10 @@ class _Gizmo {
|
|||||||
Vector3? _activeCords;
|
Vector3? _activeCords;
|
||||||
|
|
||||||
void checkHover(int x, int y) async {
|
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) {
|
switch (result) {
|
||||||
case GizmoPickResultType.None:
|
case GizmoPickResultType.None:
|
||||||
await _asset.unhighlight();
|
await _gizmo.unhighlight();
|
||||||
_active = null;
|
_active = null;
|
||||||
break;
|
break;
|
||||||
case GizmoPickResultType.AxisX:
|
case GizmoPickResultType.AxisX:
|
||||||
@@ -43,29 +47,35 @@ class _Gizmo {
|
|||||||
Matrix4? gizmoTransform;
|
Matrix4? gizmoTransform;
|
||||||
|
|
||||||
Future attach(ThermionEntity entity) async {
|
Future attach(ThermionEntity entity) async {
|
||||||
if (_asset.nonPickableEntities.contains(entity)) {
|
print("Attached to ${entity}");
|
||||||
return;
|
|
||||||
|
if (_attachedTo != null && entity != _attachedTo) {
|
||||||
|
await viewer.setParent(_attachedTo!, 0);
|
||||||
}
|
}
|
||||||
final transform = await viewer.getWorldTransform(entity);
|
|
||||||
transform.setRotation(Matrix3.identity());
|
_attachedTo = entity;
|
||||||
transform.setDiagonal(Vector4.all(1.0));
|
|
||||||
await viewer.setTransform(_asset.entity, transform);
|
await viewer.setParent(_gizmo.entity, entity);
|
||||||
await viewer.setParent(entity, _asset.entity);
|
await viewer.setTransform(_gizmo.entity, Matrix4.identity());
|
||||||
|
|
||||||
if (!isVisible) {
|
if (!isVisible) {
|
||||||
await _asset.addToScene();
|
await _gizmo.addToScene();
|
||||||
isVisible = true;
|
isVisible = true;
|
||||||
}
|
}
|
||||||
gizmoTransform = await viewer.getWorldTransform(_asset.entity);
|
gizmoTransform = await viewer.getWorldTransform(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future detach() async {
|
Future detach() async {
|
||||||
await _asset.removeFromScene();
|
await _gizmo.removeFromScene();
|
||||||
|
if (_attachedTo != null) {
|
||||||
|
await viewer.setParent(_attachedTo!, 0);
|
||||||
|
}
|
||||||
_active = null;
|
_active = null;
|
||||||
isVisible = false;
|
isVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateTransform(Vector2 currentPosition, Vector2 delta) async {
|
void _updateTransform(Vector2 currentPosition, Vector2 delta) async {
|
||||||
if (gizmoTransform == null) {
|
if (_attachedTo == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,9 +114,13 @@ class _Gizmo {
|
|||||||
Vector3 worldSpaceDelta = newPosition - gizmoTransform!.getTranslation();
|
Vector3 worldSpaceDelta = newPosition - gizmoTransform!.getTranslation();
|
||||||
worldSpaceDelta.multiply(_active!.asVector());
|
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;
|
final ThermionViewer viewer;
|
||||||
late final _Gizmo translationGizmo;
|
late final _Gizmo translationGizmo;
|
||||||
|
|
||||||
|
Stream<({ThermionEntity entity, Matrix4 transform})>
|
||||||
|
get onEntityTransformUpdated =>
|
||||||
|
translationGizmo._onEntityTransformUpdated.stream;
|
||||||
|
|
||||||
GizmoInputHandler({required this.wrapped, required this.viewer}) {
|
GizmoInputHandler({required this.wrapped, required this.viewer}) {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
final _initialized = Completer<bool>();
|
final _initialized = Completer<bool>();
|
||||||
|
|
||||||
Future initialize() async {
|
Future initialize() async {
|
||||||
if (_initialized.isCompleted) {
|
if (_initialized.isCompleted) {
|
||||||
throw Exception("Already initialized");
|
throw Exception("Already initialized");
|
||||||
@@ -137,7 +156,7 @@ class GizmoInputHandler extends InputHandler {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future dispose() async {
|
Future dispose() async {
|
||||||
await viewer.removeEntity(translationGizmo._asset);
|
await viewer.removeEntity(translationGizmo._gizmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -166,9 +185,21 @@ class GizmoInputHandler extends InputHandler {
|
|||||||
if (!_initialized.isCompleted) {
|
if (!_initialized.isCompleted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isMiddle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await viewer.pick(localPosition.x.toInt(), localPosition.y.toInt(),
|
await viewer.pick(localPosition.x.toInt(), localPosition.y.toInt(),
|
||||||
(result) {
|
(result) async {
|
||||||
translationGizmo.attach(result.entity);
|
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) {
|
void setActionForType(InputType gestureType, InputAction gestureAction) {
|
||||||
throw UnimplementedError();
|
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);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:thermion_dart/thermion_dart.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
|
||||||
enum InputType {
|
enum InputType {
|
||||||
@@ -37,8 +38,17 @@ abstract class InputHandler {
|
|||||||
Future<void> onPointerMove(
|
Future<void> onPointerMove(
|
||||||
Vector2 localPosition, Vector2 delta, bool isMiddle);
|
Vector2 localPosition, Vector2 delta, bool isMiddle);
|
||||||
Future<void> onPointerUp(bool isMiddle);
|
Future<void> onPointerUp(bool isMiddle);
|
||||||
Future<void> onScaleStart(Vector2 focalPoint, int pointerCount, Duration? sourceTimestamp);
|
Future<void> onScaleStart(
|
||||||
Future<void> onScaleUpdate(Vector2 focalPoint, Vector2 focalPointDelta, double horizontalScale, double verticalScale, double scale, int pointerCount, double rotation, Duration? sourceTimestamp);
|
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<void> onScaleEnd(int pointerCount, double velocity);
|
||||||
Future<bool> get initialized;
|
Future<bool> get initialized;
|
||||||
Future dispose();
|
Future dispose();
|
||||||
@@ -48,4 +58,6 @@ abstract class InputHandler {
|
|||||||
|
|
||||||
void keyDown(PhysicalKey key);
|
void keyDown(PhysicalKey key);
|
||||||
void keyUp(PhysicalKey key);
|
void keyUp(PhysicalKey key);
|
||||||
|
|
||||||
|
// Future setCamera(Camera camera);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'ffi_view.dart';
|
|||||||
|
|
||||||
class FFIGizmo extends FFIAsset implements GizmoAsset {
|
class FFIGizmo extends FFIAsset implements GizmoAsset {
|
||||||
final Set<ThermionEntity> nonPickableEntities;
|
final Set<ThermionEntity> nonPickableEntities;
|
||||||
|
final Set<ThermionEntity> gizmoEntities;
|
||||||
late NativeCallable<GizmoPickCallbackFunction> _nativeCallback;
|
late NativeCallable<GizmoPickCallbackFunction> _nativeCallback;
|
||||||
|
|
||||||
void Function(GizmoPickResultType axis, Vector3 coords)? _callback;
|
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));
|
_callback?.call(GizmoPickResultType.values[resultType], Vector3(x, y, z));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isNonPickable(ThermionEntity entity) =>
|
||||||
|
nonPickableEntities.contains(entity);
|
||||||
|
bool isGizmoEntity(ThermionEntity entity) => gizmoEntities.contains(entity);
|
||||||
|
|
||||||
FFIGizmo(
|
FFIGizmo(
|
||||||
this._view,
|
this._view,
|
||||||
super.pointer,
|
super.pointer,
|
||||||
super.sceneManager,
|
super.sceneManager,
|
||||||
super.renderableManager,
|
super.renderableManager,
|
||||||
super.unlitMaterialProvider,
|
super.unlitMaterialProvider,
|
||||||
this.nonPickableEntities
|
this.nonPickableEntities,
|
||||||
) {
|
this.gizmoEntities) {
|
||||||
_nativeCallback =
|
_nativeCallback =
|
||||||
NativeCallable<GizmoPickCallbackFunction>.listener(_onPickResult);
|
NativeCallable<GizmoPickCallbackFunction>.listener(_onPickResult);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,5 +81,6 @@ abstract class GizmoAsset extends ThermionAsset {
|
|||||||
{Future Function(GizmoPickResultType axis, Vector3 coords)? handler});
|
{Future Function(GizmoPickResultType axis, Vector3 coords)? handler});
|
||||||
Future highlight(Axis axis);
|
Future highlight(Axis axis);
|
||||||
Future unhighlight();
|
Future unhighlight();
|
||||||
Set<ThermionEntity> get nonPickableEntities;
|
bool isNonPickable(ThermionEntity entity);
|
||||||
|
bool isGizmoEntity(ThermionEntity entity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,12 @@ namespace thermion
|
|||||||
|
|
||||||
auto parent = entityManager.create();
|
auto parent = entityManager.create();
|
||||||
|
|
||||||
auto *parentMaterialInstance = _material->createInstance();
|
// auto *parentMaterialInstance = _material->createInstance();
|
||||||
parentMaterialInstance->setParameter("baseColorFactor", math::float4{0.0f, 1.0f, 1.0f, 1.0f});
|
// parentMaterialInstance->setParameter("baseColorFactor", math::float4{1.0f, 1.0f, 1.0f, 0.0f});
|
||||||
parentMaterialInstance->setParameter("scale", 4.0f);
|
// parentMaterialInstance->setParameter("scale", 4.0f);
|
||||||
|
// parentMaterialInstance->setDoubleSided(false);
|
||||||
|
|
||||||
_materialInstances.push_back(parentMaterialInstance);
|
// _materialInstances.push_back(parentMaterialInstance);
|
||||||
|
|
||||||
// Create center cube vertices
|
// Create center cube vertices
|
||||||
float centerCubeSize = 0.1f;
|
float centerCubeSize = 0.1f;
|
||||||
@@ -73,11 +74,11 @@ namespace thermion
|
|||||||
RenderableManager::Builder(1)
|
RenderableManager::Builder(1)
|
||||||
.boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
|
.boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
|
||||||
{centerCubeSize, centerCubeSize, centerCubeSize}})
|
{centerCubeSize, centerCubeSize, centerCubeSize}})
|
||||||
.material(0, parentMaterialInstance)
|
// .material(0, parentMaterialInstance)
|
||||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||||
.priority(7)
|
.priority(0)
|
||||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
|
||||||
.culling(false)
|
.culling(true)
|
||||||
.build(*_engine, parent);
|
.build(*_engine, parent);
|
||||||
|
|
||||||
auto parentTransformInstance = transformManager.getInstance(parent);
|
auto parentTransformInstance = transformManager.getInstance(parent);
|
||||||
@@ -265,6 +266,7 @@ namespace thermion
|
|||||||
_materialInstances.push_back(materialInstance);
|
_materialInstances.push_back(materialInstance);
|
||||||
materialInstance->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
|
materialInstance->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
|
||||||
materialInstance->setParameter("scale", 4.0f);
|
materialInstance->setParameter("scale", 4.0f);
|
||||||
|
materialInstance->setDepthFunc(MaterialInstance::DepthFunc::A);
|
||||||
|
|
||||||
RenderableManager::Builder(1)
|
RenderableManager::Builder(1)
|
||||||
.boundingBox({{-volumeWidth / 2, -volumeDepth / 2, 0}, {volumeWidth / 2, volumeDepth / 2, volumeLength}})
|
.boundingBox({{-volumeWidth / 2, -volumeDepth / 2, 0}, {volumeWidth / 2, volumeDepth / 2, volumeLength}})
|
||||||
|
|||||||
Reference in New Issue
Block a user