diff --git a/thermion_dart/lib/src/filament/src/filament_app.dart b/thermion_dart/lib/src/filament/src/filament_app.dart index bb6270cc..1437dc08 100644 --- a/thermion_dart/lib/src/filament/src/filament_app.dart +++ b/thermion_dart/lib/src/filament/src/filament_app.dart @@ -247,7 +247,8 @@ abstract class FilamentApp { /// /// /// - Future setClearColor(double r, double g, double b, double a); + Future setClearOptions(double r, double g, double b, double a, + {int clearStencil = 0, bool discard = false, bool clear = true}); /// /// @@ -264,4 +265,9 @@ abstract class FilamentApp { /// /// Future createColorGrading(ToneMapper mapper); + + /// + /// + /// + Future createGizmo(covariant View view, T animationManager, GizmoType type); } 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 098eae36..89096ccf 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 @@ -1,371 +1,371 @@ -import 'dart:async'; -import 'dart:math'; -import 'package:thermion_dart/thermion_dart.dart'; - -class _Gizmo { - final ThermionViewer viewer; - - final GizmoAsset _gizmo; - - final transformUpdates = StreamController<({Matrix4 transform})>.broadcast(); - - Axis? _active; - final GizmoType type; - - _Gizmo(this._gizmo, this.viewer, this.type); - - static Future<_Gizmo> forType(ThermionViewer viewer, GizmoType type) async { - final view = await viewer.view; - return _Gizmo(await viewer.createGizmo(view, type), viewer, type); - } - - Future dispose() async { - await transformUpdates.close(); - await viewer.destroyAsset(_gizmo); - } - - Future hide() async { - final scene = await viewer.view.getScene(); - await scene.remove(_gizmo); - } - - Future reveal() async { - final scene = await viewer.view.getScene(); - await scene.add(_gizmo); - gizmoTransform = await _gizmo.getWorldTransform(); - } - - double _getAngleBetweenVectors(Vector2 v1, Vector2 v2) { - // Normalize vectors to ensure consistent rotation regardless of distance from center - v1.normalize(); - v2.normalize(); - - // Calculate angle using atan2 - double angle = atan2(v2.y, v2.x) - atan2(v1.y, v1.x); - - // Ensure angle is between -π and π - if (angle > pi) angle -= 2 * pi; - if (angle < -pi) angle += 2 * pi; - - return angle; - } - - void checkHover(int x, int y) async { - _gizmo.pick(x, y, handler: (result, coords) async { - switch (result) { - case GizmoPickResultType.None: - await _gizmo.unhighlight(); - _active = null; - break; - case GizmoPickResultType.AxisX: - _active = Axis.X; - case GizmoPickResultType.AxisY: - _active = Axis.Y; - case GizmoPickResultType.AxisZ: - _active = Axis.Z; - default: - } - }); - } - - Matrix4? gizmoTransform; - - void _updateTransform(Vector2 currentPosition, Vector2 delta) async { - if (type == GizmoType.translation) { - await _updateTranslation(currentPosition, delta); - } else if (type == GizmoType.rotation) { - await _updateRotation(currentPosition, delta); - } - - await _gizmo.setTransform(gizmoTransform!); - - transformUpdates.add((transform: gizmoTransform!)); - } - - Future? _updateTranslation( - Vector2 currentPosition, Vector2 delta) async { - var view = await viewer.view; - var camera = await viewer.getActiveCamera(); - var viewport = await view.getViewport(); - var projectionMatrix = await camera.getProjectionMatrix(); - var viewMatrix = await camera.getViewMatrix(); - var inverseViewMatrix = await camera.getModelMatrix(); - var inverseProjectionMatrix = projectionMatrix.clone()..invert(); - - // get gizmo position in screenspace - var gizmoPositionWorldSpace = gizmoTransform!.getTranslation(); - Vector4 gizmoClipSpace = projectionMatrix * - viewMatrix * - Vector4(gizmoPositionWorldSpace.x, gizmoPositionWorldSpace.y, - gizmoPositionWorldSpace.z, 1.0); - - var gizmoNdc = gizmoClipSpace / gizmoClipSpace.w; - - var gizmoScreenSpace = Vector2(((gizmoNdc.x / 2) + 0.5) * viewport.width, - viewport.height - (((gizmoNdc.y / 2) + 0.5) * viewport.height)); - - gizmoScreenSpace += delta; - - gizmoNdc = Vector4(((gizmoScreenSpace.x / viewport.width) - 0.5) * 2, - (((gizmoScreenSpace.y / viewport.height)) - 0.5) * -2, gizmoNdc.z, 1.0); - - var gizmoViewSpace = inverseProjectionMatrix * gizmoNdc; - gizmoViewSpace /= gizmoViewSpace.w; - - var newPosition = (inverseViewMatrix * gizmoViewSpace).xyz; - - Vector3 worldSpaceDelta = newPosition - gizmoTransform!.getTranslation(); - worldSpaceDelta.multiply(_active!.asVector()); - - gizmoTransform! - .setTranslation(gizmoTransform!.getTranslation() + worldSpaceDelta); - } - - Future? _updateRotation(Vector2 currentPosition, Vector2 delta) async { - var camera = await viewer.view.getCamera(); - var viewport = await viewer.view.getViewport(); - var projectionMatrix = await camera.getProjectionMatrix(); - var viewMatrix = await camera.getViewMatrix(); - - // Get gizmo center in screen space - var gizmoPositionWorldSpace = gizmoTransform!.getTranslation(); - Vector4 gizmoClipSpace = projectionMatrix * - viewMatrix * - Vector4(gizmoPositionWorldSpace.x, gizmoPositionWorldSpace.y, - gizmoPositionWorldSpace.z, 1.0); - - var gizmoNdc = gizmoClipSpace / gizmoClipSpace.w; - var gizmoScreenSpace = Vector2(((gizmoNdc.x / 2) + 0.5) * viewport.width, - viewport.height - (((gizmoNdc.y / 2) + 0.5) * viewport.height)); - - // Calculate vectors from gizmo center to previous and current mouse positions - var prevVector = (currentPosition - delta) - gizmoScreenSpace; - var currentVector = currentPosition - gizmoScreenSpace; - - // Calculate rotation angle based on the active axis - double rotationAngle = 0.0; - switch (_active) { - case Axis.X: - // For X axis, project onto YZ plane - var prev = Vector2(prevVector.y, -prevVector.x); - var curr = Vector2(currentVector.y, -currentVector.x); - rotationAngle = _getAngleBetweenVectors(prev, curr); - break; - case Axis.Y: - // For Y axis, project onto XZ plane - var prev = Vector2(prevVector.x, -prevVector.y); - var curr = Vector2(currentVector.x, -currentVector.y); - rotationAngle = _getAngleBetweenVectors(prev, curr); - break; - case Axis.Z: - // For Z axis, use screen plane directly - rotationAngle = -1 * _getAngleBetweenVectors(prevVector, currentVector); - break; - default: - return; - } - - // Create rotation matrix based on the active axis - var rotationMatrix = Matrix4.identity(); - switch (_active) { - case Axis.X: - rotationMatrix.setRotationX(rotationAngle); - break; - case Axis.Y: - rotationMatrix.setRotationY(rotationAngle); - break; - case Axis.Z: - rotationMatrix.setRotationZ(rotationAngle); - break; - default: - return; - } - - // Apply rotation to the current transform - gizmoTransform = gizmoTransform! * rotationMatrix; - } -} - -class GizmoInputHandler extends InputHandler { - final ThermionViewer viewer; - - late final _gizmos = {}; - - _Gizmo? _active; - - ThermionEntity? _attached; - - Future attach(ThermionEntity entity) async { - if (_attached != null) { - await detach(); - } - _attached = entity; - if (_active != null) { - await FilamentApp.instance!.setParent(_attached!, _active!._gizmo.entity); - await _active!.reveal(); - } - } - - Future getGizmoTransform() async { - return _active?.gizmoTransform; - } - - Future detach() async { - if (_attached == null) { - return; - } - await FilamentApp.instance!.setParent(_attached!, null); - await _active?.hide(); - _attached = null; - } - - final _initialized = Completer(); - - final _transformController = StreamController.broadcast(); - Stream get transformUpdated => _transformController.stream; - - final _pickResultController = StreamController.broadcast(); - Stream get onPickResult => _pickResultController.stream; - - GizmoInputHandler({required this.viewer, required GizmoType initialType}) { - initialize().then((_) { - setGizmoType(initialType); - }); - } - - GizmoType? getGizmoType() { - return _active?.type; - } - - Future setGizmoType(GizmoType? type) async { - if (type == null) { - await detach(); - _active?.hide(); - _active = null; - } else { - _active?.hide(); - _active = _gizmos[type]!; - _active!.reveal(); - if (_attached != null) { - await attach(_attached!); - } - } - } - - Future initialize() async { - if (_initialized.isCompleted) { - throw Exception("Already initialized"); - } - await viewer.initialized; - - _gizmos[GizmoType.translation] = - await _Gizmo.forType(viewer, GizmoType.translation); - _gizmos[GizmoType.rotation] = - await _Gizmo.forType(viewer, GizmoType.rotation); - await setGizmoType(GizmoType.translation); - for (final gizmo in _gizmos.values) { - gizmo.transformUpdates.stream.listen((update) { - _transformController.add(update.transform); - }); - } - _initialized.complete(true); - } - - @override - Future dispose() async { - _gizmos[GizmoType.rotation]!.dispose(); - _gizmos[GizmoType.translation]!.dispose(); - _gizmos.clear(); - } - - @override - InputAction? getActionForType(InputType gestureType) { - if (gestureType == InputType.LMB_DOWN) { - return InputAction.PICK; - } - throw UnimplementedError(); - } - - @override - Future get initialized => _initialized.future; - - @override - void keyDown(PhysicalKey key) {} - - @override - void keyUp(PhysicalKey key) {} - - @override - Future? onPointerDown(Vector2 localPosition, bool isMiddle) async { - if (!_initialized.isCompleted) { - return; - } - - if (isMiddle) { - return; - } - - await viewer.pick(localPosition.x.toInt(), localPosition.y.toInt(), - (result) async { - if (_active?._gizmo.isNonPickable(result.entity) == true || - result.entity == FILAMENT_ENTITY_NULL) { - _pickResultController.add(null); - return; - } - if (_active?._gizmo.isGizmoEntity(result.entity) != true) { - _pickResultController.add(result.entity); - } - }); - } - - @override - Future? onPointerHover(Vector2 localPosition, Vector2 delta) async { - if (!_initialized.isCompleted) { - return; - } - _active?.checkHover(localPosition.x.floor(), localPosition.y.floor()); - } - - @override - Future? onPointerMove( - Vector2 localPosition, Vector2 delta, bool isMiddle) async { - if (!isMiddle && _active?._active != null) { - final scaledDelta = Vector2( - delta.x, - delta.y, - ); - _active!._updateTransform(localPosition, scaledDelta); - return; - } - } - - @override - Future? onPointerScroll( - Vector2 localPosition, double scrollDelta) async {} - - @override - Future? onPointerUp(bool isMiddle) async {} - - @override - Future? onScaleEnd(int pointerCount, double velocity) {} - - @override - Future? onScaleStart( - Vector2 focalPoint, int pointerCount, Duration? sourceTimestamp) {} - - @override - Future? onScaleUpdate( - Vector2 focalPoint, - Vector2 focalPointDelta, - double horizontalScale, - double verticalScale, - double scale, - int pointerCount, - double rotation, - Duration? sourceTimestamp) {} - - @override - void setActionForType(InputType gestureType, InputAction gestureAction) { - throw UnimplementedError(); - } -} +// import 'dart:async'; +// import 'dart:math'; +// import 'package:thermion_dart/thermion_dart.dart'; + +// class _Gizmo { +// final ThermionViewer viewer; + +// final GizmoAsset _gizmo; + +// final transformUpdates = StreamController<({Matrix4 transform})>.broadcast(); + +// Axis? _active; +// final GizmoType type; + +// _Gizmo(this._gizmo, this.viewer, this.type); + +// static Future<_Gizmo> forType(ThermionViewer viewer, GizmoType type) async { +// final view = await viewer.view; +// return _Gizmo(await viewer.createGizmo(view, type), viewer, type); +// } + +// Future dispose() async { +// await transformUpdates.close(); +// await viewer.destroyAsset(_gizmo); +// } + +// Future hide() async { +// final scene = await viewer.view.getScene(); +// await scene.remove(_gizmo); +// } + +// Future reveal() async { +// final scene = await viewer.view.getScene(); +// await scene.add(_gizmo); +// gizmoTransform = await _gizmo.getWorldTransform(); +// } + +// double _getAngleBetweenVectors(Vector2 v1, Vector2 v2) { +// // Normalize vectors to ensure consistent rotation regardless of distance from center +// v1.normalize(); +// v2.normalize(); + +// // Calculate angle using atan2 +// double angle = atan2(v2.y, v2.x) - atan2(v1.y, v1.x); + +// // Ensure angle is between -π and π +// if (angle > pi) angle -= 2 * pi; +// if (angle < -pi) angle += 2 * pi; + +// return angle; +// } + +// void checkHover(int x, int y) async { +// _gizmo.pick(x, y, handler: (result, coords) async { +// switch (result) { +// case GizmoPickResultType.None: +// await _gizmo.unhighlight(); +// _active = null; +// break; +// case GizmoPickResultType.AxisX: +// _active = Axis.X; +// case GizmoPickResultType.AxisY: +// _active = Axis.Y; +// case GizmoPickResultType.AxisZ: +// _active = Axis.Z; +// default: +// } +// }); +// } + +// Matrix4? gizmoTransform; + +// void _updateTransform(Vector2 currentPosition, Vector2 delta) async { +// if (type == GizmoType.translation) { +// await _updateTranslation(currentPosition, delta); +// } else if (type == GizmoType.rotation) { +// await _updateRotation(currentPosition, delta); +// } + +// await _gizmo.setTransform(gizmoTransform!); + +// transformUpdates.add((transform: gizmoTransform!)); +// } + +// Future? _updateTranslation( +// Vector2 currentPosition, Vector2 delta) async { +// var view = await viewer.view; +// var camera = await viewer.getActiveCamera(); +// var viewport = await view.getViewport(); +// var projectionMatrix = await camera.getProjectionMatrix(); +// var viewMatrix = await camera.getViewMatrix(); +// var inverseViewMatrix = await camera.getModelMatrix(); +// var inverseProjectionMatrix = projectionMatrix.clone()..invert(); + +// // get gizmo position in screenspace +// var gizmoPositionWorldSpace = gizmoTransform!.getTranslation(); +// Vector4 gizmoClipSpace = projectionMatrix * +// viewMatrix * +// Vector4(gizmoPositionWorldSpace.x, gizmoPositionWorldSpace.y, +// gizmoPositionWorldSpace.z, 1.0); + +// var gizmoNdc = gizmoClipSpace / gizmoClipSpace.w; + +// var gizmoScreenSpace = Vector2(((gizmoNdc.x / 2) + 0.5) * viewport.width, +// viewport.height - (((gizmoNdc.y / 2) + 0.5) * viewport.height)); + +// gizmoScreenSpace += delta; + +// gizmoNdc = Vector4(((gizmoScreenSpace.x / viewport.width) - 0.5) * 2, +// (((gizmoScreenSpace.y / viewport.height)) - 0.5) * -2, gizmoNdc.z, 1.0); + +// var gizmoViewSpace = inverseProjectionMatrix * gizmoNdc; +// gizmoViewSpace /= gizmoViewSpace.w; + +// var newPosition = (inverseViewMatrix * gizmoViewSpace).xyz; + +// Vector3 worldSpaceDelta = newPosition - gizmoTransform!.getTranslation(); +// worldSpaceDelta.multiply(_active!.asVector()); + +// gizmoTransform! +// .setTranslation(gizmoTransform!.getTranslation() + worldSpaceDelta); +// } + +// Future? _updateRotation(Vector2 currentPosition, Vector2 delta) async { +// var camera = await viewer.view.getCamera(); +// var viewport = await viewer.view.getViewport(); +// var projectionMatrix = await camera.getProjectionMatrix(); +// var viewMatrix = await camera.getViewMatrix(); + +// // Get gizmo center in screen space +// var gizmoPositionWorldSpace = gizmoTransform!.getTranslation(); +// Vector4 gizmoClipSpace = projectionMatrix * +// viewMatrix * +// Vector4(gizmoPositionWorldSpace.x, gizmoPositionWorldSpace.y, +// gizmoPositionWorldSpace.z, 1.0); + +// var gizmoNdc = gizmoClipSpace / gizmoClipSpace.w; +// var gizmoScreenSpace = Vector2(((gizmoNdc.x / 2) + 0.5) * viewport.width, +// viewport.height - (((gizmoNdc.y / 2) + 0.5) * viewport.height)); + +// // Calculate vectors from gizmo center to previous and current mouse positions +// var prevVector = (currentPosition - delta) - gizmoScreenSpace; +// var currentVector = currentPosition - gizmoScreenSpace; + +// // Calculate rotation angle based on the active axis +// double rotationAngle = 0.0; +// switch (_active) { +// case Axis.X: +// // For X axis, project onto YZ plane +// var prev = Vector2(prevVector.y, -prevVector.x); +// var curr = Vector2(currentVector.y, -currentVector.x); +// rotationAngle = _getAngleBetweenVectors(prev, curr); +// break; +// case Axis.Y: +// // For Y axis, project onto XZ plane +// var prev = Vector2(prevVector.x, -prevVector.y); +// var curr = Vector2(currentVector.x, -currentVector.y); +// rotationAngle = _getAngleBetweenVectors(prev, curr); +// break; +// case Axis.Z: +// // For Z axis, use screen plane directly +// rotationAngle = -1 * _getAngleBetweenVectors(prevVector, currentVector); +// break; +// default: +// return; +// } + +// // Create rotation matrix based on the active axis +// var rotationMatrix = Matrix4.identity(); +// switch (_active) { +// case Axis.X: +// rotationMatrix.setRotationX(rotationAngle); +// break; +// case Axis.Y: +// rotationMatrix.setRotationY(rotationAngle); +// break; +// case Axis.Z: +// rotationMatrix.setRotationZ(rotationAngle); +// break; +// default: +// return; +// } + +// // Apply rotation to the current transform +// gizmoTransform = gizmoTransform! * rotationMatrix; +// } +// } + +// class GizmoInputHandler extends InputHandler { +// final ThermionViewer viewer; + +// late final _gizmos = {}; + +// _Gizmo? _active; + +// ThermionEntity? _attached; + +// Future attach(ThermionEntity entity) async { +// if (_attached != null) { +// await detach(); +// } +// _attached = entity; +// if (_active != null) { +// await FilamentApp.instance!.setParent(_attached!, _active!._gizmo.entity); +// await _active!.reveal(); +// } +// } + +// Future getGizmoTransform() async { +// return _active?.gizmoTransform; +// } + +// Future detach() async { +// if (_attached == null) { +// return; +// } +// await FilamentApp.instance!.setParent(_attached!, null); +// await _active?.hide(); +// _attached = null; +// } + +// final _initialized = Completer(); + +// final _transformController = StreamController.broadcast(); +// Stream get transformUpdated => _transformController.stream; + +// final _pickResultController = StreamController.broadcast(); +// Stream get onPickResult => _pickResultController.stream; + +// GizmoInputHandler({required this.viewer, required GizmoType initialType}) { +// initialize().then((_) { +// setGizmoType(initialType); +// }); +// } + +// GizmoType? getGizmoType() { +// return _active?.type; +// } + +// Future setGizmoType(GizmoType? type) async { +// if (type == null) { +// await detach(); +// _active?.hide(); +// _active = null; +// } else { +// _active?.hide(); +// _active = _gizmos[type]!; +// _active!.reveal(); +// if (_attached != null) { +// await attach(_attached!); +// } +// } +// } + +// Future initialize() async { +// if (_initialized.isCompleted) { +// throw Exception("Already initialized"); +// } +// await viewer.initialized; + +// _gizmos[GizmoType.translation] = +// await _Gizmo.forType(viewer, GizmoType.translation); +// _gizmos[GizmoType.rotation] = +// await _Gizmo.forType(viewer, GizmoType.rotation); +// await setGizmoType(GizmoType.translation); +// for (final gizmo in _gizmos.values) { +// gizmo.transformUpdates.stream.listen((update) { +// _transformController.add(update.transform); +// }); +// } +// _initialized.complete(true); +// } + +// @override +// Future dispose() async { +// _gizmos[GizmoType.rotation]!.dispose(); +// _gizmos[GizmoType.translation]!.dispose(); +// _gizmos.clear(); +// } + +// @override +// InputAction? getActionForType(InputType gestureType) { +// if (gestureType == InputType.LMB_DOWN) { +// return InputAction.PICK; +// } +// throw UnimplementedError(); +// } + +// @override +// Future get initialized => _initialized.future; + +// @override +// void keyDown(PhysicalKey key) {} + +// @override +// void keyUp(PhysicalKey key) {} + +// @override +// Future? onPointerDown(Vector2 localPosition, bool isMiddle) async { +// if (!_initialized.isCompleted) { +// return; +// } + +// if (isMiddle) { +// return; +// } + +// await viewer.pick(localPosition.x.toInt(), localPosition.y.toInt(), +// (result) async { +// if (_active?._gizmo.isNonPickable(result.entity) == true || +// result.entity == FILAMENT_ENTITY_NULL) { +// _pickResultController.add(null); +// return; +// } +// if (_active?._gizmo.isGizmoEntity(result.entity) != true) { +// _pickResultController.add(result.entity); +// } +// }); +// } + +// @override +// Future? onPointerHover(Vector2 localPosition, Vector2 delta) async { +// if (!_initialized.isCompleted) { +// return; +// } +// _active?.checkHover(localPosition.x.floor(), localPosition.y.floor()); +// } + +// @override +// Future? onPointerMove( +// Vector2 localPosition, Vector2 delta, bool isMiddle) async { +// if (!isMiddle && _active?._active != null) { +// final scaledDelta = Vector2( +// delta.x, +// delta.y, +// ); +// _active!._updateTransform(localPosition, scaledDelta); +// return; +// } +// } + +// @override +// Future? onPointerScroll( +// Vector2 localPosition, double scrollDelta) async {} + +// @override +// Future? onPointerUp(bool isMiddle) async {} + +// @override +// Future? onScaleEnd(int pointerCount, double velocity) {} + +// @override +// Future? onScaleStart( +// Vector2 focalPoint, int pointerCount, Duration? sourceTimestamp) {} + +// @override +// Future? onScaleUpdate( +// Vector2 focalPoint, +// Vector2 focalPointDelta, +// double horizontalScale, +// double verticalScale, +// double scale, +// int pointerCount, +// double rotation, +// Duration? sourceTimestamp) {} + +// @override +// void setActionForType(InputType gestureType, InputAction gestureAction) { +// throw UnimplementedError(); +// } +// } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart index 8ecccd3c..e568bd93 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart @@ -6,6 +6,7 @@ import 'package:thermion_dart/src/filament/src/engine.dart'; import 'package:thermion_dart/src/filament/src/scene.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_gizmo.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart'; @@ -609,14 +610,6 @@ class FFIFilamentApp extends FilamentApp { .firstWhere((x) => _swapChains[x]?.contains(view) == true); final out = Uint8List(viewport.width * viewport.height * 4); - await withVoidCallback((cb) { - Engine_flushAndWaitRenderThead(engine, cb); - }); - - var fence = await withPointerCallback((cb) { - Engine_createFenceRenderThread(engine, cb); - }); - await withBoolCallback((cb) { Renderer_beginFrameRenderThread(renderer, swapChain.swapChain, 0, cb); }); @@ -647,20 +640,18 @@ class FFIFilamentApp extends FilamentApp { }); await withVoidCallback((cb) { - Engine_destroyFenceRenderThread(engine, fence, cb); + Engine_flushAndWaitRenderThead(engine, cb); }); - - // await withVoidCallback((cb) { - // Engine_flushAndWaitRenderThead(engine, cb); - // }); return out; } /// /// /// - Future setClearColor(double r, double g, double b, double a) async { - Renderer_setClearOptions(renderer, r, g, b, a, 0, true, false); + Future setClearOptions(double r, double g, double b, double a, + {int clearStencil = 0, bool discard = false, bool clear = true}) async { + Renderer_setClearOptions( + renderer, r, g, b, a, clearStencil, clear, discard); } /// @@ -735,7 +726,7 @@ class FFIFilamentApp extends FilamentApp { View_setColorGrading(view.view, nullptr); for (final cg in view.colorGrading.entries) { await withVoidCallback( - (cb) => Engine_destroyColorGradingRenderThread(engine, cg.value, cb)); + (cb) => Engine_destroyColorGradingRenderThread(engine, cg.value, cb)); } await withVoidCallback( (cb) => Engine_destroyViewRenderThread(engine, view.view, cb)); @@ -751,6 +742,43 @@ class FFIFilamentApp extends FilamentApp { ColorGrading_createRenderThread( engine, TToneMapping.values[mapper.index], cb)); } + + FFIMaterial? _gizmoMaterial; + + /// + /// + /// + Future createGizmo(covariant FFIView view, + Pointer animationManager, GizmoType gizmoType) async { + if (_gizmoMaterial == null) { + final materialPtr = await withPointerCallback((cb) { + Material_createGizmoMaterialRenderThread(engine, cb); + }); + _gizmoMaterial ??= FFIMaterial(materialPtr, this); + } + + var gltfResourceLoader = await withPointerCallback( + (cb) => GltfResourceLoader_createRenderThread(engine, nullptr, cb)); + + final gizmo = await withPointerCallback((cb) { + Gizmo_createRenderThread(engine, gltfAssetLoader, gltfResourceLoader, nameComponentManager, + view.view, _gizmoMaterial!.pointer, TGizmoType.values[gizmoType.index], cb); + }); + if (gizmo == nullptr) { + throw Exception("Failed to create gizmo"); + } + final gizmoEntityCount = + SceneAsset_getChildEntityCount(gizmo.cast()); + final gizmoEntities = Int32List(gizmoEntityCount); + SceneAsset_getChildEntities( + gizmo.cast(), gizmoEntities.address); + + return FFIGizmo(gizmo.cast(), this, + animationManager.cast(), + view: view, + entities: gizmoEntities.toSet() + ..add(SceneAsset_getEntity(gizmo.cast()))); + } } class FinalizableUint8List implements Finalizable { 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 32c23821..ec87f5e5 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 @@ -25,9 +25,9 @@ class FFIGizmo extends FFIAsset implements GizmoAsset { bool isGizmoEntity(ThermionEntity entity) => entities.contains(entity); FFIGizmo( - super.asset, - super.app, - super.animationManager, + super.asset, + super.app, + super.animationManager, { required this.view, required this.entities, diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart index fca3b8c7..0ea2cf2e 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart @@ -35,6 +35,11 @@ external ffi.Pointer Material_createGridMaterial( ffi.Pointer tEngine, ); +@ffi.Native Function(ffi.Pointer)>(isLeaf: true) +external ffi.Pointer Material_createGizmoMaterial( + ffi.Pointer tEngine, +); + @ffi.Native, ffi.Pointer)>( isLeaf: true) external bool Material_hasParameter( @@ -1057,22 +1062,40 @@ external void TextureSampler_destroy( ); @ffi.Native< - ffi.Pointer Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, ffi.UnsignedInt)>(symbol: "Gizmo_create", isLeaf: true) external ffi.Pointer _Gizmo_create( ffi.Pointer tEngine, + ffi.Pointer assetLoader, + ffi.Pointer tGltfResourceLoader, + ffi.Pointer tNameComponentManager, ffi.Pointer tView, + ffi.Pointer tMaterial, int tGizmoType, ); ffi.Pointer Gizmo_create( ffi.Pointer tEngine, + ffi.Pointer assetLoader, + ffi.Pointer tGltfResourceLoader, + ffi.Pointer tNameComponentManager, ffi.Pointer tView, + ffi.Pointer tMaterial, TGizmoType tGizmoType, ) => _Gizmo_create( tEngine, + assetLoader, + tGltfResourceLoader, + tNameComponentManager, tView, + tMaterial, tGizmoType.value, ); @@ -1991,6 +2014,19 @@ external void Material_createImageMaterialRenderThread( onComplete, ); +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer< + ffi + .NativeFunction)>>)>( + isLeaf: true) +external void Material_createGizmoMaterialRenderThread( + ffi.Pointer tEngine, + ffi.Pointer)>> + onComplete, +); + @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -2151,17 +2187,6 @@ external void MaterialProvider_createMaterialInstanceRenderThread( callback, ); -@ffi.Native< - ffi.Void Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>)>(isLeaf: true) -external void SceneManager_destroyMaterialInstanceRenderThread( - ffi.Pointer tSceneManager, - ffi.Pointer tMaterialInstance, - ffi.Pointer> callback, -); - @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -2741,6 +2766,52 @@ external void Scene_addFilamentAssetRenderThread( ffi.Pointer> callback, ); +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.UnsignedInt, + ffi.Pointer< + ffi.NativeFunction)>>)>( + symbol: "Gizmo_createRenderThread", isLeaf: true) +external void _Gizmo_createRenderThread( + ffi.Pointer tEngine, + ffi.Pointer tAssetLoader, + ffi.Pointer tGltfResourceLoader, + ffi.Pointer tNameComponentManager, + ffi.Pointer tView, + ffi.Pointer tMaterial, + int tGizmoType, + ffi.Pointer)>> + callback, +); + +void Gizmo_createRenderThread( + ffi.Pointer tEngine, + ffi.Pointer tAssetLoader, + ffi.Pointer tGltfResourceLoader, + ffi.Pointer tNameComponentManager, + ffi.Pointer tView, + ffi.Pointer tMaterial, + TGizmoType tGizmoType, + ffi.Pointer)>> + callback, +) => + _Gizmo_createRenderThread( + tEngine, + tAssetLoader, + tGltfResourceLoader, + tNameComponentManager, + tView, + tMaterial, + tGizmoType.value, + callback, + ); + @ffi.Native< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(isLeaf: true) @@ -3824,15 +3895,15 @@ final class Aabb3 extends ffi.Struct { } enum TGizmoType { - TRANSLATION(0), - ROTATION(1); + GIZMO_TYPE_TRANSLATION(0), + GIZMO_TYPE_ROTATION(1); final int value; const TGizmoType(this.value); static TGizmoType fromValue(int value) => switch (value) { - 0 => TRANSLATION, - 1 => ROTATION, + 0 => GIZMO_TYPE_TRANSLATION, + 1 => GIZMO_TYPE_ROTATION, _ => throw ArgumentError("Unknown value for TGizmoType: $value"), }; } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart index a58bf824..88d52e66 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart @@ -90,9 +90,8 @@ class ThermionViewerFFI extends ThermionViewer { View_setAntiAliasing(view.view, false, false, false); View_setDitheringEnabled(view.view, false); View_setRenderQuality(view.view, TQualityLevel.MEDIUM); - - - await FilamentApp.instance!.setClearColor(1.0, 0.0, 0.0, 1.0); + + await FilamentApp.instance!.setClearOptions(0.0, 0.0, 0.0, 0.0); scene = FFIScene(Engine_createScene(app.engine)); await view.setScene(scene); final camera = FFICamera( @@ -431,8 +430,6 @@ class ThermionViewerFFI extends ThermionViewer { } } - - /// /// /// @@ -602,10 +599,15 @@ class ThermionViewerFFI extends ThermionViewer { /// /// /// - Future showGridOverlay() async { + Future setGridOverlayVisibility(bool visible) async { _grid ??= _grid = await GridOverlay.create(app, animationManager); - await scene.add(_grid!); - await view.setLayerVisibility(VisibilityLayers.OVERLAY, true); + if (visible) { + await scene.add(_grid!); + await view.setLayerVisibility(VisibilityLayers.OVERLAY, true); + } else { + await scene.remove(_grid!); + await view.setLayerVisibility(VisibilityLayers.OVERLAY, true); + } } /// @@ -720,36 +722,18 @@ class ThermionViewerFFI extends ThermionViewer { return asset; } - //// + final _gizmos = {}; + + /// + /// /// - // @override - Future createGizmo(FFIView view, GizmoType gizmoType) async { - throw UnimplementedError(); - // var scene = View_getScene(view.view); - // final gizmo = await withPointerCallback((cb) { - // SceneManager_createGizmoRenderThread(_sceneManager!, view.view, scene, - // TGizmoType.values[gizmoType.index], cb); - // }); - // if (gizmo == nullptr) { - // throw Exception("Failed to create gizmo"); - // } - - // final gizmoEntityCount = - // SceneAsset_getChildEntityCount(gizmo.cast()); - // final gizmoEntities = Int32List(gizmoEntityCount); - // SceneAsset_getChildEntities( - // gizmo.cast(), gizmoEntities.address); - - // return FFIGizmo( - // view, - // gizmo.cast(), - // _sceneManager!, - // app.engine!, - // nullptr, - // this, - // gizmoEntities.toSet() - // ..add(SceneAsset_getEntity(gizmo.cast()))); + Future getGizmo(GizmoType gizmoType) async { + if (_gizmos[gizmoType] == null) { + _gizmos[gizmoType] = + await FilamentApp.instance!.createGizmo(view, animationManager, gizmoType); + } + return _gizmos[gizmoType]!; } Future addToScene(covariant FFIAsset asset) async { diff --git a/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart b/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart index 38c6cd3c..c77d0c87 100644 --- a/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart +++ b/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart @@ -239,9 +239,10 @@ abstract class ThermionViewer { {List? materialInstances, bool keepData = false, bool addToScene=true}); /// - /// The gizmo for translating/rotating objects. Only one gizmo can be active for a given view. + /// Returns a gizmo for translating/rotating objects. + /// Only one gizmo can be visible at any given time for this viewer. /// - Future createGizmo(covariant View view, GizmoType type); + Future getGizmo(GizmoType type); /// /// Register a callback to be invoked when this viewer is disposed. @@ -261,12 +262,7 @@ abstract class ThermionViewer { /// /// /// - Future showGridOverlay(); - - /// - /// - /// - Future removeGridOverlay(); + Future setGridOverlayVisibility(bool visible); /// /// @@ -293,6 +289,14 @@ abstract class ThermionViewer { /// int getCameraCount(); + /// + /// Adds the asset to the scene, meaning the asset will be rendered/visible. + /// Future addToScene(covariant ThermionAsset asset); + + /// + /// Removes the asset from the scene, meaning the asset will not be rendered/visible. + /// The asset itself will remain valid. + /// Future removeFromScene(covariant ThermionAsset asset); } diff --git a/thermion_dart/native/CMakeLists.txt b/thermion_dart/native/CMakeLists.txt index e7db0f40..6d206a54 100644 --- a/thermion_dart/native/CMakeLists.txt +++ b/thermion_dart/native/CMakeLists.txt @@ -36,6 +36,7 @@ set(MATERIAL_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/include/material/image.c" "${CMAKE_CURRENT_SOURCE_DIR}/include/material/grid.c" "${CMAKE_CURRENT_SOURCE_DIR}/include/material/unlit.c" + "${CMAKE_CURRENT_SOURCE_DIR}/include/material/unlit_fixed_size.c" "${CMAKE_CURRENT_SOURCE_DIR}/include/material/gizmo.c" ) diff --git a/thermion_dart/native/include/c_api/APIBoundaryTypes.h b/thermion_dart/native/include/c_api/APIBoundaryTypes.h index 0153d991..764e49aa 100644 --- a/thermion_dart/native/include/c_api/APIBoundaryTypes.h +++ b/thermion_dart/native/include/c_api/APIBoundaryTypes.h @@ -153,8 +153,8 @@ extern "C" typedef struct Aabb3 Aabb3; enum TGizmoType { - TRANSLATION, - ROTATION + GIZMO_TYPE_TRANSLATION, + GIZMO_TYPE_ROTATION }; enum TPrimitiveType { diff --git a/thermion_dart/native/include/c_api/TGizmo.h b/thermion_dart/native/include/c_api/TGizmo.h index c1b70fcb..c71789f5 100644 --- a/thermion_dart/native/include/c_api/TGizmo.h +++ b/thermion_dart/native/include/c_api/TGizmo.h @@ -16,7 +16,15 @@ enum TGizmoPickResultType { AxisX, AxisY, AxisZ, Parent, None }; typedef void (*GizmoPickCallback)(TGizmoPickResultType resultType, float x, float y, float z); -EMSCRIPTEN_KEEPALIVE TGizmo *Gizmo_create(TEngine *tEngine, TView *tView, TGizmoType tGizmoType); +EMSCRIPTEN_KEEPALIVE TGizmo *Gizmo_create( + TEngine *tEngine, + TGltfAssetLoader *assetLoader, + TGltfResourceLoader *tGltfResourceLoader, + TNameComponentManager *tNameComponentManager, + TView *tView, + TMaterial *tMaterial, + TGizmoType tGizmoType +); EMSCRIPTEN_KEEPALIVE void Gizmo_pick(TGizmo *tGizmo, uint32_t x, uint32_t y, GizmoPickCallback callback); EMSCRIPTEN_KEEPALIVE void Gizmo_highlight(TGizmo *tGizmo, TGizmoAxis axis); EMSCRIPTEN_KEEPALIVE void Gizmo_unhighlight(TGizmo *tGizmo); diff --git a/thermion_dart/native/include/c_api/TGltfAssetLoader.h b/thermion_dart/native/include/c_api/TGltfAssetLoader.h index 810f21c1..f2e645b9 100644 --- a/thermion_dart/native/include/c_api/TGltfAssetLoader.h +++ b/thermion_dart/native/include/c_api/TGltfAssetLoader.h @@ -13,7 +13,7 @@ EMSCRIPTEN_KEEPALIVE TGltfAssetLoader *GltfAssetLoader_create(TEngine *tEngine, EMSCRIPTEN_KEEPALIVE TFilamentAsset *GltfAssetLoader_load( TEngine *tEngine, TGltfAssetLoader *tAssetLoader, - uint8_t *data, + const uint8_t *data, size_t length, uint8_t numInstances ); diff --git a/thermion_dart/native/include/c_api/TMaterialInstance.h b/thermion_dart/native/include/c_api/TMaterialInstance.h index f1351d7e..c9364cba 100644 --- a/thermion_dart/native/include/c_api/TMaterialInstance.h +++ b/thermion_dart/native/include/c_api/TMaterialInstance.h @@ -70,6 +70,7 @@ extern "C" EMSCRIPTEN_KEEPALIVE TMaterialInstance *Material_createInstance(TMaterial *tMaterial); EMSCRIPTEN_KEEPALIVE TMaterial *Material_createImageMaterial(TEngine *tEngine); EMSCRIPTEN_KEEPALIVE TMaterial *Material_createGridMaterial(TEngine *tEngine); + EMSCRIPTEN_KEEPALIVE TMaterial *Material_createGizmoMaterial(TEngine *tEngine); EMSCRIPTEN_KEEPALIVE bool Material_hasParameter(TMaterial *tMaterial, const char *propertyName); EMSCRIPTEN_KEEPALIVE bool MaterialInstance_isStencilWriteEnabled(TMaterialInstance *materialInstance); EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilWrite(TMaterialInstance *materialInstance, bool enabled); diff --git a/thermion_dart/native/include/c_api/TSceneAsset.h b/thermion_dart/native/include/c_api/TSceneAsset.h index 45b8aa6c..c8aabb99 100644 --- a/thermion_dart/native/include/c_api/TSceneAsset.h +++ b/thermion_dart/native/include/c_api/TSceneAsset.h @@ -27,7 +27,7 @@ extern "C" TEngine *tEngine, TGltfAssetLoader *tAssetLoader, TNameComponentManager *tNameComponentManager, - uint8_t *data, + const uint8_t *data, size_t length, size_t numInstances ); @@ -37,7 +37,7 @@ extern "C" TGltfResourceLoader *tResourceLoader, TEngine *tEngine, TNameComponentManager *tNameComponentManager, - uint8_t *data, + const uint8_t *data, size_t length, size_t numInstances ); diff --git a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h index cac219a0..9dd6a82b 100644 --- a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h +++ b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h @@ -81,6 +81,7 @@ namespace thermion EMSCRIPTEN_KEEPALIVE void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance *)); EMSCRIPTEN_KEEPALIVE void Material_createImageMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *)); + EMSCRIPTEN_KEEPALIVE void Material_createGizmoMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *)); EMSCRIPTEN_KEEPALIVE void ColorGrading_createRenderThread(TEngine *tEngine, TToneMapping toneMapping, void (*callback)(TColorGrading *)); EMSCRIPTEN_KEEPALIVE void View_setColorGradingRenderThread(TView *tView, TColorGrading *tColorGrading, void (*callback)()); @@ -116,7 +117,6 @@ namespace thermion void (*callback)(TSceneAsset *) ); EMSCRIPTEN_KEEPALIVE void MaterialProvider_createMaterialInstanceRenderThread(TMaterialProvider *tMaterialProvider, TMaterialKey *tKey, void (*callback)(TMaterialInstance *)); - EMSCRIPTEN_KEEPALIVE void SceneManager_destroyMaterialInstanceRenderThread(TSceneManager *tSceneManager, TMaterialInstance *tMaterialInstance, void (*callback)()); EMSCRIPTEN_KEEPALIVE void AnimationManager_updateBoneMatricesRenderThread( TAnimationManager *tAnimationManager, @@ -269,6 +269,16 @@ namespace thermion void (*callback)(TFilamentAsset *) ); EMSCRIPTEN_KEEPALIVE void Scene_addFilamentAssetRenderThread(TScene* tScene, TFilamentAsset *tAsset, void (*callback)()); + EMSCRIPTEN_KEEPALIVE void Gizmo_createRenderThread( + TEngine *tEngine, + TGltfAssetLoader *tAssetLoader, + TGltfResourceLoader *tGltfResourceLoader, + TNameComponentManager *tNameComponentManager, + TView *tView, + TMaterial *tMaterial, + TGizmoType tGizmoType, + void (*callback)(TGizmo *) + ); diff --git a/thermion_dart/native/include/scene/Gizmo.hpp b/thermion_dart/native/include/scene/Gizmo.hpp index 9ad8b8d2..ed634552 100644 --- a/thermion_dart/native/include/scene/Gizmo.hpp +++ b/thermion_dart/native/include/scene/Gizmo.hpp @@ -37,7 +37,6 @@ namespace thermion SceneAsset *sceneAsset, Engine *engine, View *view, - Scene *scene, Material *material) noexcept; Gizmo(Gizmo &&other) noexcept; diff --git a/thermion_dart/native/include/scene/GltfSceneAsset.hpp b/thermion_dart/native/include/scene/GltfSceneAsset.hpp index eea3a5bc..cb8943e5 100644 --- a/thermion_dart/native/include/scene/GltfSceneAsset.hpp +++ b/thermion_dart/native/include/scene/GltfSceneAsset.hpp @@ -137,7 +137,7 @@ namespace thermion Entity findEntityByName(const char* name) override { TRACE("Searching for entity with name %s", name); Entity entities[1]; - auto found = _asset->getEntitiesByName(name, entities, 1); + auto found = _asset->getEntitiesByName(name, entities, 1); return entities[0]; } diff --git a/thermion_dart/native/include/scene/GltfSceneAssetInstance.hpp b/thermion_dart/native/include/scene/GltfSceneAssetInstance.hpp index d99de6f8..cc5ea84e 100644 --- a/thermion_dart/native/include/scene/GltfSceneAssetInstance.hpp +++ b/thermion_dart/native/include/scene/GltfSceneAssetInstance.hpp @@ -117,6 +117,9 @@ namespace thermion for(int i = 0; i < getChildEntityCount(); i++) { auto entity = getChildEntities()[i]; auto nameInstance = _ncm->getInstance(entity); + if(!nameInstance.isValid()) { + continue; + } auto entityName = _ncm->getName(nameInstance); if (strcmp(entityName, name) == 0) { diff --git a/thermion_dart/native/src/c_api/TGizmo.cpp b/thermion_dart/native/src/c_api/TGizmo.cpp index ecc5ec51..951069ce 100644 --- a/thermion_dart/native/src/c_api/TGizmo.cpp +++ b/thermion_dart/native/src/c_api/TGizmo.cpp @@ -3,7 +3,11 @@ #include #include "c_api/TGizmo.h" +#include "c_api/TSceneAsset.h" #include "scene/Gizmo.hpp" +#include "scene/GltfSceneAsset.hpp" +#include "resources/translation_gizmo_glb.h" +#include "resources/rotation_gizmo_glb.h" #include "Log.hpp" #ifdef __cplusplus @@ -14,6 +18,61 @@ namespace thermion using namespace filament; #endif + EMSCRIPTEN_KEEPALIVE TGizmo *Gizmo_create( + TEngine *tEngine, + TGltfAssetLoader *assetLoader, + TGltfResourceLoader *tGltfResourceLoader, + TNameComponentManager *tNameComponentManager, + TView *tView, + TMaterial *tMaterial, + TGizmoType tGizmoType) { + + auto *engine = reinterpret_cast(tEngine); + auto *view = reinterpret_cast(tView); + auto *material = reinterpret_cast(tMaterial); + auto *gltfResourceLoader = reinterpret_cast(tGltfResourceLoader); + TSceneAsset *sceneAsset; + switch (tGizmoType) + { + case GIZMO_TYPE_TRANSLATION: + { + TRACE("Building translation gizmo"); + sceneAsset = SceneAsset_loadGlb( + tEngine, + assetLoader, + tNameComponentManager, + TRANSLATION_GIZMO_GLB_TRANSLATION_GIZMO_DATA, + TRANSLATION_GIZMO_GLB_TRANSLATION_GIZMO_SIZE, + 3 + ); + break; + } + case GIZMO_TYPE_ROTATION: + { + TRACE("Building rotation gizmo"); + sceneAsset = SceneAsset_loadGlb( + tEngine, + assetLoader, + tNameComponentManager, + ROTATION_GIZMO_GLB_ROTATION_GIZMO_DATA, + ROTATION_GIZMO_GLB_ROTATION_GIZMO_SIZE, + 3 + ); + break; + } + } + auto *gltfSceneAsset = reinterpret_cast(sceneAsset); + auto *filamentAsset = gltfSceneAsset->getAsset(); + gltfResourceLoader->loadResources(filamentAsset); + auto *gizmo = new Gizmo( + gltfSceneAsset, + engine, + view, + material + ); + return reinterpret_cast(gizmo); + } + EMSCRIPTEN_KEEPALIVE void Gizmo_pick(TGizmo *tGizmo, uint32_t x, uint32_t y, GizmoPickCallback callback) { auto *gizmo = reinterpret_cast(tGizmo); diff --git a/thermion_dart/native/src/c_api/TGltfAssetLoader.cpp b/thermion_dart/native/src/c_api/TGltfAssetLoader.cpp index 57e8cbd3..8a455c62 100644 --- a/thermion_dart/native/src/c_api/TGltfAssetLoader.cpp +++ b/thermion_dart/native/src/c_api/TGltfAssetLoader.cpp @@ -56,7 +56,7 @@ EMSCRIPTEN_KEEPALIVE TGltfAssetLoader *GltfAssetLoader_create(TEngine *tEngine, EMSCRIPTEN_KEEPALIVE TFilamentAsset *GltfAssetLoader_load( TEngine *tEngine, TGltfAssetLoader *tAssetLoader, - uint8_t *data, + const uint8_t *data, size_t length, uint8_t numInstances) { diff --git a/thermion_dart/native/src/c_api/TMaterialInstance.cpp b/thermion_dart/native/src/c_api/TMaterialInstance.cpp index 96689e36..25028be8 100644 --- a/thermion_dart/native/src/c_api/TMaterialInstance.cpp +++ b/thermion_dart/native/src/c_api/TMaterialInstance.cpp @@ -11,6 +11,7 @@ #include "MathUtils.hpp" #include "material/image.h" #include "material/grid.h" +#include "material/unlit_fixed_size.h" #include "c_api/TMaterialInstance.h" @@ -45,7 +46,13 @@ namespace thermion return reinterpret_cast(material); } - + EMSCRIPTEN_KEEPALIVE TMaterial *Material_createGizmoMaterial(TEngine *tEngine) { + auto *engine = reinterpret_cast(tEngine); + auto *material = filament::Material::Builder() + .package(UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_DATA, UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE) + .build(*engine); + return reinterpret_cast(material); + } EMSCRIPTEN_KEEPALIVE bool Material_hasParameter(TMaterial *tMaterial, const char *propertyName) { auto *material = reinterpret_cast(tMaterial); diff --git a/thermion_dart/native/src/c_api/TSceneAsset.cpp b/thermion_dart/native/src/c_api/TSceneAsset.cpp index 9926989d..b2e09d14 100644 --- a/thermion_dart/native/src/c_api/TSceneAsset.cpp +++ b/thermion_dart/native/src/c_api/TSceneAsset.cpp @@ -70,7 +70,7 @@ extern "C" TEngine *tEngine, TGltfAssetLoader *tAssetLoader, TNameComponentManager *tNameComponentManager, - uint8_t *data, + const uint8_t *data, size_t length, size_t numInstances ) { diff --git a/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp b/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp index 8fc77ff9..0e6b1ffe 100644 --- a/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp +++ b/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp @@ -8,6 +8,7 @@ #include "c_api/APIBoundaryTypes.h" #include "c_api/TAnimationManager.h" #include "c_api/TEngine.h" +#include "c_api/TGizmo.h" #include "c_api/TGltfAssetLoader.h" #include "c_api/TGltfResourceLoader.h" #include "c_api/TRenderer.h" @@ -380,6 +381,17 @@ extern "C" }); auto fut = _renderThread->add_task(lambda); } + + EMSCRIPTEN_KEEPALIVE void Material_createGizmoMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *)) { + std::packaged_task lambda( + [=]() mutable + { + auto *instance = Material_createGizmoMaterial(tEngine); + onComplete(instance); + }); + auto fut = _renderThread->add_task(lambda); + } + EMSCRIPTEN_KEEPALIVE void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance *)) { @@ -1010,4 +1022,23 @@ extern "C" }); auto fut = _renderThread->add_task(lambda); } + + EMSCRIPTEN_KEEPALIVE void Gizmo_createRenderThread( + TEngine *tEngine, + TGltfAssetLoader *tAssetLoader, + TGltfResourceLoader *tGltfResourceLoader, + TNameComponentManager *tNameComponentManager, + TView *tView, + TMaterial *tMaterial, + TGizmoType tGizmoType, + void (*callback)(TGizmo *) + ) { + std::packaged_task lambda( + [=]() mutable + { + auto *gizmo = Gizmo_create(tEngine, tAssetLoader,tGltfResourceLoader, tNameComponentManager, tView, tMaterial, tGizmoType); + callback(gizmo); + }); + auto fut = _renderThread->add_task(lambda); + } }