feat: add rotation gizmo

This commit is contained in:
Nick Fisher
2024-12-12 16:28:55 +08:00
parent 0ad73d06e0
commit def85614d8
17 changed files with 4056 additions and 7790 deletions

View File

@@ -128,6 +128,10 @@ class GizmoInputHandler extends InputHandler {
final InputHandler wrapped;
final ThermionViewer viewer;
late final _Gizmo translationGizmo;
late final _Gizmo rotationGizmo;
_Gizmo get active =>
type == GizmoType.translation ? translationGizmo : rotationGizmo;
GizmoType type = GizmoType.translation;
Stream<({ThermionEntity entity, Matrix4 transform})>
get onEntityTransformUpdated =>
@@ -145,9 +149,12 @@ class GizmoInputHandler extends InputHandler {
}
await viewer.initialized;
final view = await viewer.getViewAt(0);
var translationGizmoAsset =
await viewer.createGizmo(view, GizmoType.translation);
this.translationGizmo = _Gizmo(translationGizmoAsset, viewer);
var tg = await viewer.createGizmo(view, GizmoType.translation);
this.translationGizmo = _Gizmo(tg, viewer);
var rg = await viewer.createGizmo(view, GizmoType.rotation);
this.rotationGizmo = _Gizmo(rg, viewer);
_initialized.complete(true);
}
@@ -156,6 +163,7 @@ class GizmoInputHandler extends InputHandler {
@override
Future dispose() async {
await viewer.removeEntity(rotationGizmo._gizmo);
await viewer.removeEntity(translationGizmo._gizmo);
}
@@ -192,13 +200,13 @@ class GizmoInputHandler extends InputHandler {
await viewer.pick(localPosition.x.toInt(), localPosition.y.toInt(),
(result) async {
if (translationGizmo._gizmo.isNonPickable(result.entity) ||
if (active._gizmo.isNonPickable(result.entity) ||
result.entity == FILAMENT_ENTITY_NULL) {
await translationGizmo.detach();
await active.detach();
return;
}
if (!translationGizmo._gizmo.isGizmoEntity(result.entity)) {
translationGizmo.attach(result.entity);
if (!active._gizmo.isGizmoEntity(result.entity)) {
active.attach(result.entity);
}
});
}
@@ -208,19 +216,19 @@ class GizmoInputHandler extends InputHandler {
if (!_initialized.isCompleted) {
return;
}
translationGizmo.checkHover(
active.checkHover(
localPosition.x.floor(), localPosition.y.floor());
}
@override
Future<void> onPointerMove(
Vector2 localPosition, Vector2 delta, bool isMiddle) async {
if (!isMiddle && translationGizmo._active != null) {
if (!isMiddle && active._active != null) {
final scaledDelta = Vector2(
delta.x,
delta.y,
);
translationGizmo._updateTransform(localPosition, scaledDelta);
active._updateTransform(localPosition, scaledDelta);
return;
}
return wrapped.onPointerMove(localPosition, delta, isMiddle);
@@ -268,21 +276,19 @@ class GizmoInputHandler extends InputHandler {
}
Future detach(ThermionAsset asset) async {
if (translationGizmo._attachedTo == asset.entity) {
await translationGizmo.detach();
if (active._attachedTo == asset.entity) {
await active.detach();
return;
}
final childEntities = await asset.getChildEntities();
for(final childEntity in childEntities) {
if(translationGizmo._attachedTo == childEntity) {
await translationGizmo.detach();
return;
for (final childEntity in childEntities) {
if (active._attachedTo == childEntity) {
await active.detach();
return;
}
}
}
// @override
// Future setCamera(Camera camera) async {
// await wrapped.setCamera(camera);

View File

@@ -1388,17 +1388,35 @@ external void remove_skybox_render_thread(
ffi.Pointer<TSceneManager>,
ffi.Pointer<TView>,
ffi.Pointer<TScene>,
ffi.UnsignedInt,
ffi.Pointer<
ffi.NativeFunction<ffi.Void Function(ffi.Pointer<TGizmo>)>>)>(
isLeaf: true)
external ffi.Pointer<TGizmo> SceneManager_createGizmoRenderThread(
symbol: "SceneManager_createGizmoRenderThread", isLeaf: true)
external ffi.Pointer<TGizmo> _SceneManager_createGizmoRenderThread(
ffi.Pointer<TSceneManager> tSceneManager,
ffi.Pointer<TView> tView,
ffi.Pointer<TScene> tScene,
int tGizmoType,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<TGizmo>)>>
onComplete,
);
ffi.Pointer<TGizmo> SceneManager_createGizmoRenderThread(
ffi.Pointer<TSceneManager> tSceneManager,
ffi.Pointer<TView> tView,
ffi.Pointer<TScene> tScene,
TGizmoType tGizmoType,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<TGizmo>)>>
onComplete,
) =>
_SceneManager_createGizmoRenderThread(
tSceneManager,
tView,
tScene,
tGizmoType.value,
onComplete,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TSceneManager>,
@@ -1688,14 +1706,31 @@ external void unproject_texture_render_thread(
);
@ffi.Native<
ffi.Pointer<TGizmo> Function(ffi.Pointer<TSceneManager>, ffi.Pointer<TView>,
ffi.Pointer<TScene>)>(isLeaf: true)
external ffi.Pointer<TGizmo> SceneManager_createGizmo(
ffi.Pointer<TGizmo> Function(
ffi.Pointer<TSceneManager>,
ffi.Pointer<TView>,
ffi.Pointer<TScene>,
ffi.UnsignedInt)>(symbol: "SceneManager_createGizmo", isLeaf: true)
external ffi.Pointer<TGizmo> _SceneManager_createGizmo(
ffi.Pointer<TSceneManager> tSceneManager,
ffi.Pointer<TView> tView,
ffi.Pointer<TScene> tScene,
int tGizmoType,
);
ffi.Pointer<TGizmo> SceneManager_createGizmo(
ffi.Pointer<TSceneManager> tSceneManager,
ffi.Pointer<TView> tView,
ffi.Pointer<TScene> tScene,
TGizmoType tGizmoType,
) =>
_SceneManager_createGizmo(
tSceneManager,
tView,
tScene,
tGizmoType.value,
);
@ffi.Native<
ffi.Pointer<TSceneAsset> Function(
ffi.Pointer<TSceneManager>,
@@ -2487,6 +2522,20 @@ final class Aabb3 extends ffi.Struct {
external double halfExtentZ;
}
enum TGizmoType {
TRANSLATION(0),
ROTATION(1);
final int value;
const TGizmoType(this.value);
static TGizmoType fromValue(int value) => switch (value) {
0 => TRANSLATION,
1 => ROTATION,
_ => throw ArgumentError("Unknown value for TGizmoType: $value"),
};
}
enum TSamplerCompareFunc {
/// !< Less or equal
LE(0),

View File

@@ -2066,7 +2066,7 @@ class ThermionViewerFFI extends ThermionViewer {
var scene = View_getScene(view.view);
final gizmo = await withPointerCallback<TGizmo>((cb) {
SceneManager_createGizmoRenderThread(
_sceneManager!, view.view, scene, cb);
_sceneManager!, view.view, scene, TGizmoType.values[gizmoType.index], cb);
});
if (gizmo == nullptr) {
throw Exception("Failed to create gizmo");