feature!:

This is a breaking change needed to fully implement instancing and stencil highlighting.

Previously, users would work directly with entities (on the Dart side, ThermionEntity), e.g.

final entity = await viewer.loadGlb("some.glb");

However, Filament "entities" are a lower-level abstraction.

Loading a glTF file, for example, inserts multiple entities into the scene.

For example, each mesh, light, and camera within a glTF asset will be assigned an entity. A top-level (non-renderable) entity will also be created for the glTF asset, which can be used to transform the entire hierarchy.

"Asset" is a better representation for loading/inserting objects into the scene; think of this as a bundle of entities.

Unless you need to work directly with transforms, instancing, materials and renderables, you can work directly with ThermionAsset.
This commit is contained in:
Nick Fisher
2024-11-21 15:04:10 +08:00
parent 9ada6aae64
commit ed444b0615
195 changed files with 18061 additions and 12628 deletions

View File

@@ -1,21 +1,11 @@
output: '../lib/src/viewer/src/ffi/src/thermion_dart.g.dart'
headers:
entry-points:
- '../native/include/ThermionDartRenderThreadApi.h'
- '../native/include/ThermionDartApi.h'
- '../native/include/TView.h'
- '../native/include/TCamera.h'
- '../native/include/TGizmo.h'
- '../native/include/c_api/*.h'
- '../native/include/ResourceBuffer.h'
include-directives:
- '../native/include/ThermionDartRenderThreadApi.h'
- '../native/include/ThermionDartApi.h'
- '../native/include/TView.h'
- '../native/include/TCamera.h'
- '../native/include/TGizmo.h'
- '../native/include/TMaterialInstance.h'
- '../native/include/c_api/*.h'
- '../native/include/ResourceBuffer.h'
- '../native/include/APIBoundaryTypes.h'
ffi-native:
assetId: package:thermion_dart/thermion_dart.dart
ignore-source-errors: true

View File

@@ -4,4 +4,6 @@ export 'src/input_handler.dart';
export 'src/delegates.dart';
export 'src/delegate_input_handler.dart';
export 'src/implementations/default_pick_delegate.dart';
export 'src/implementations/gizmo_pick_delegate.dart';
export 'src/implementations/gizmo_input_handler.dart';
export 'src/implementations/third_person_camera_delegate.dart';

View File

@@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:math';
import 'package:logging/logging.dart';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart';
@@ -54,6 +53,13 @@ class DelegateInputHandler implements InputHandler {
_actions = actions;
}
if (pickDelegate != null) {
if (_actions[InputType.LMB_DOWN] != null) {
throw Exception();
}
_actions[InputType.LMB_DOWN] = InputAction.PICK;
}
for (var gestureType in InputType.values) {
_inputDeltas[gestureType] = Vector3.zero();
}
@@ -94,7 +100,7 @@ class DelegateInputHandler implements InputHandler {
clampY: clampY,
entity: entity,
rotationSensitivity: rotateSensitivity,
zoomSensitivity:zoomSensitivity,
zoomSensitivity: zoomSensitivity,
panSensitivity: panSensitivity,
movementSensitivity: movementSensitivity),
actions: {
@@ -265,7 +271,8 @@ class DelegateInputHandler implements InputHandler {
Future<void> onScaleEnd(int pointerCount, double velocity) async {}
@override
Future<void> onScaleStart(Vector2 localPosition, int pointerCount, Duration? sourceTimestamp ) async {
Future<void> onScaleStart(Vector2 localPosition, int pointerCount,
Duration? sourceTimestamp) async {
// noop
}

View File

@@ -24,4 +24,5 @@ abstract class VelocityDelegate {
abstract class PickDelegate {
const PickDelegate();
void pick(Vector2 location);
Future dispose();
}

View File

@@ -1,13 +1,24 @@
import 'dart:async';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart';
class DefaultPickDelegate extends PickDelegate {
final ThermionViewer viewer;
const DefaultPickDelegate(this.viewer);
DefaultPickDelegate(this.viewer);
final _picked = StreamController<ThermionEntity>();
Stream<ThermionEntity> get picked => _picked.stream;
Future dispose() async {
_picked.close();
}
@override
void pick(Vector2 location) {
viewer.pick(location.x.toInt(), location.y.toInt());
viewer.pick(location.x.toInt(), location.y.toInt(), (result) {
_picked.sink.add(result.entity);
});
}
}

View File

@@ -86,13 +86,14 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
if (_queuedRotationDelta.length2 > 0.0) {
double deltaX = _queuedRotationDelta.x * rotationSensitivity;
double deltaY = _queuedRotationDelta.y * rotationSensitivity;
relativeRotation = Quaternion.axisAngle(current.up, -deltaX) * Quaternion.axisAngle(current.right, -deltaY);
relativeRotation = Quaternion.axisAngle(current.up, -deltaX) *
Quaternion.axisAngle(current.right, -deltaY);
_queuedRotationDelta = Vector2.zero();
}
// Apply (mouse) pan
if (_queuedTranslateDelta.length2 > 0.0) {
double deltaX = _queuedTranslateDelta.x * panSensitivity;
double deltaX = -_queuedTranslateDelta.x * panSensitivity;
double deltaY = _queuedTranslateDelta.y * panSensitivity;
double deltaZ = -_queuedTranslateDelta.z * panSensitivity;
@@ -104,8 +105,9 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
// Apply zoom
if (_queuedZoomDelta != 0.0) {
relativeTranslation += current.forward
..scaled(_queuedZoomDelta * zoomSensitivity);
var zoomTranslation = current.forward..scaled(zoomSensitivity);
zoomTranslation.scale(_queuedZoomDelta);
relativeTranslation += zoomTranslation;
_queuedZoomDelta = 0.0;
}
@@ -128,11 +130,10 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
await viewer.setTransform(
await entity,
Matrix4.compose(
relativeTranslation, relativeRotation, Vector3(1, 1, 1)) * current );
Matrix4.compose(
relativeTranslation, relativeRotation, Vector3(1, 1, 1)) *
current);
_executing = false;
}
}

View File

@@ -0,0 +1,238 @@
import 'dart:async';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart';
class _Gizmo {
bool isVisible = false;
final ThermionViewer viewer;
final nonPickable = <ThermionEntity>{};
final GizmoAsset _asset;
_Gizmo(this._asset, this.viewer);
Axis? _active;
Axis? get active => _active;
Vector3? _activeCords;
void checkHover(int x, int y) async {
_asset.pick(x, y, handler: (result, coords) async {
switch (result) {
case GizmoPickResultType.None:
await _asset.unhighlight();
_active = null;
break;
case GizmoPickResultType.AxisX:
_active = Axis.X;
_activeCords = coords;
case GizmoPickResultType.AxisY:
_active = Axis.Y;
_activeCords = coords;
case GizmoPickResultType.AxisZ:
_active = Axis.Z;
_activeCords = coords;
default:
}
});
}
Matrix4? gizmoTransform;
Future attach(ThermionEntity entity) async {
if (_asset.nonPickableEntities.contains(entity)) {
return;
}
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);
if (!isVisible) {
await _asset.addToScene();
isVisible = true;
}
gizmoTransform = await viewer.getWorldTransform(_asset.entity);
}
Future detach() async {
await _asset.removeFromScene();
_active = null;
isVisible = false;
}
void _updateTransform(Vector2 currentPosition, Vector2 delta) async {
if (gizmoTransform == null) {
return;
}
var view = await viewer.getViewAt(0);
var camera = await viewer.getActiveCamera();
var viewport = await view.getViewport();
var projectionMatrix = await viewer.getCameraProjectionMatrix();
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);
await viewer.setTransform(_asset.entity, gizmoTransform!);
}
}
class GizmoInputHandler extends InputHandler {
final InputHandler wrapped;
final ThermionViewer viewer;
late final _Gizmo translationGizmo;
GizmoInputHandler({required this.wrapped, required this.viewer}) {
initialize();
}
final _initialized = Completer<bool>();
Future initialize() async {
if (_initialized.isCompleted) {
throw Exception("Already initialized");
}
await viewer.initialized;
final view = await viewer.getViewAt(0);
var translationGizmoAsset =
await viewer.createGizmo(view, GizmoType.translation);
this.translationGizmo = _Gizmo(translationGizmoAsset, viewer);
_initialized.complete(true);
}
@override
Stream get cameraUpdated => throw UnimplementedError();
@override
Future dispose() async {
await viewer.removeEntity(translationGizmo._asset);
}
@override
InputAction? getActionForType(InputType gestureType) {
if (gestureType == InputType.LMB_DOWN) {
return InputAction.PICK;
}
throw UnimplementedError();
}
@override
Future<bool> get initialized => _initialized.future;
@override
void keyDown(PhysicalKey key) {
wrapped.keyDown(key);
}
@override
void keyUp(PhysicalKey key) {
wrapped.keyDown(key);
}
@override
Future<void> onPointerDown(Vector2 localPosition, bool isMiddle) async {
if (!_initialized.isCompleted) {
return;
}
await viewer.pick(localPosition.x.toInt(), localPosition.y.toInt(),
(result) {
translationGizmo.attach(result.entity);
});
}
@override
Future<void> onPointerHover(Vector2 localPosition, Vector2 delta) async {
if (!_initialized.isCompleted) {
return;
}
translationGizmo.checkHover(
localPosition.x.floor(), localPosition.y.floor());
}
@override
Future<void> onPointerMove(
Vector2 localPosition, Vector2 delta, bool isMiddle) async {
if (!isMiddle && translationGizmo._active != null) {
final scaledDelta = Vector2(
delta.x,
delta.y,
);
translationGizmo._updateTransform(localPosition, scaledDelta);
return;
}
return wrapped.onPointerMove(localPosition, delta, isMiddle);
}
@override
Future<void> onPointerScroll(
Vector2 localPosition, double scrollDelta) async {
return wrapped.onPointerScroll(localPosition, scrollDelta);
}
@override
Future<void> onPointerUp(bool isMiddle) async {
await wrapped.onPointerUp(isMiddle);
}
@override
Future<void> onScaleEnd(int pointerCount, double velocity) {
return wrapped.onScaleEnd(pointerCount, velocity);
}
@override
Future<void> onScaleStart(
Vector2 focalPoint, int pointerCount, Duration? sourceTimestamp) {
return wrapped.onScaleStart(focalPoint, pointerCount, sourceTimestamp);
}
@override
Future<void> onScaleUpdate(
Vector2 focalPoint,
Vector2 focalPointDelta,
double horizontalScale,
double verticalScale,
double scale,
int pointerCount,
double rotation,
Duration? sourceTimestamp) {
return wrapped.onScaleUpdate(focalPoint, focalPointDelta, horizontalScale,
verticalScale, scale, pointerCount, rotation, sourceTimestamp);
}
@override
void setActionForType(InputType gestureType, InputAction gestureAction) {
throw UnimplementedError();
}
}

View File

@@ -0,0 +1,41 @@
// import 'dart:async';
// import 'package:thermion_dart/thermion_dart.dart';
// import 'package:vector_math/vector_math_64.dart';
// class GizmoPickDelegate extends PickDelegate {
// final ThermionViewer viewer;
// late final GizmoAsset translationGizmo;
// GizmoPickDelegate(this.viewer) {
// initialize();
// }
// bool _initialized = false;
// Future initialize() async {
// if (_initialized) {
// throw Exception("Already initialized");
// }
// final view = await viewer.getViewAt(0);
// translationGizmo = await viewer.createGizmo(view, GizmoType.translation);
// await translationGizmo.addToScene();
// _initialized = true;
// }
// final _picked = StreamController<ThermionEntity>();
// Stream<ThermionEntity> get picked => _picked.stream;
// Future dispose() async {
// _picked.close();
// }
// @override
// void pick(Vector2 location) {
// if (!_initialized) {
// return;
// }
// viewer.pick(location.x.toInt(), location.y.toInt(), (result) {
// translationGizmo.attach(result.entity);
// });
// }
// }

View File

@@ -1,230 +1,329 @@
// import 'dart:async';
// import 'package:flutter/gestures.dart';
// import 'package:flutter/services.dart';
// import 'package:logging/logging.dart';
// import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
// import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
// import 'dart:ui';
// import 'package:thermion_dart/thermion_dart/input/input_handler.dart';
// import 'package:thermion_dart/thermion_dart.dart';
// import 'package:vector_math/vector_math_64.dart';
// // Renamed implementation
// class PickingCameraGestureHandler implements InputHandler {
// import '../input_handler.dart';
// class GizmoPickingHandler implements InputHandler {
// final ThermionViewer viewer;
// final bool enableCamera;
// final bool enablePicking;
// final Logger _logger = Logger("PickingCameraGestureHandler");
// late final GizmoAsset _translationGizmo;
// AbstractGizmo? _gizmo;
// Timer? _scrollTimer;
// ThermionEntity? _highlightedEntity;
// StreamSubscription<FilamentPickResult>? _pickResultSubscription;
// GizmoPickingHandler(this.viewer) {}
// bool _gizmoAttached = false;
// final _initialized = Completer<bool>();
// PickingCameraGestureHandler({
// required this.viewer,
// this.enableCamera = true,
// this.enablePicking = true,
// }) {
// try {
// _gizmo = viewer.gizmo;
// } catch (err) {
// _logger.warning(
// "Failed to get gizmo. If you are running on WASM, this is expected");
// Future initialize() async {
// if (_initialized.isCompleted) {
// throw Exception("Already initialized");
// }
// final view = await viewer.getViewAt(0);
// _translationGizmo = await viewer.createGizmo(view, GizmoType.translation);
// _initialized.complete(true);
// }
// _pickResultSubscription = viewer.pickResult.listen(_onPickResult);
// // Add keyboard listener
// RawKeyboard.instance.addListener(_handleKeyEvent);
// Future dispose() async {
// await viewer.removeEntity(_translationGizmo);
// }
// @override
// ThermionGestureState get currentState => _currentState;
// void _handleKeyEvent(RawKeyEvent event) {
// if (event is RawKeyDownEvent &&
// event.logicalKey == LogicalKeyboardKey.escape) {
// _resetToNullState();
// }
// }
// void _resetToNullState() async {
// _currentState = ThermionGestureState.NULL;
// if (_highlightedEntity != null) {
// await viewer.removeStencilHighlight(_highlightedEntity!);
// _highlightedEntity = null;
// }
// }
// void _onPickResult(FilamentPickResult result) async {
// var targetEntity = await viewer.getAncestor(result.entity) ?? result.entity;
// if (_highlightedEntity != targetEntity) {
// if (_highlightedEntity != null) {
// await viewer.removeStencilHighlight(_highlightedEntity!);
// }
// _highlightedEntity = targetEntity;
// if (_highlightedEntity != null) {
// await viewer.setStencilHighlight(_highlightedEntity!);
// _gizmo?.attach(_highlightedEntity!);
// }
// }
// }
// Stream get cameraUpdated => throw UnimplementedError();
// @override
// Future<void> onPointerHover(Offset localPosition, Offset delta) async {
// if (_gizmoAttached) {
// _gizmo?.checkHover(localPosition.dx, localPosition.dy);
// }
// if (_highlightedEntity != null) {
// await viewer.queuePositionUpdateFromViewportCoords(
// _highlightedEntity!,
// localPosition.dx,
// localPosition.dy,
// );
// }
// }
// @override
// Future<void> onPointerScroll(Offset localPosition, double scrollDelta) async {
// if (!enableCamera) {
// return;
// }
// if (_currentState == ThermionGestureState.NULL ||
// _currentState == ThermionGestureState.ZOOMING) {
// await _zoom(localPosition, scrollDelta);
// }
// }
// @override
// Future<void> onPointerDown(Offset localPosition, int buttons) async {
// if (_highlightedEntity != null) {
// _resetToNullState();
// return;
// }
// if (enablePicking && buttons != kMiddleMouseButton) {
// viewer.pick(localPosition.dx.toInt(), localPosition.dy.toInt());
// }
// if (buttons == kMiddleMouseButton && enableCamera) {
// await viewer.rotateStart(localPosition.dx, localPosition.dy);
// _currentState = ThermionGestureState.ROTATING;
// } else if (buttons == kPrimaryMouseButton && enableCamera) {
// await viewer.panStart(localPosition.dx, localPosition.dy);
// _currentState = ThermionGestureState.PANNING;
// }
// }
// @override
// Future<void> onPointerMove(
// Offset localPosition, Offset delta, int buttons) async {
// if (_highlightedEntity != null) {
// await _handleEntityHighlightedMove(localPosition);
// return;
// }
// switch (_currentState) {
// case ThermionGestureState.NULL:
// break;
// case ThermionGestureState.ROTATING:
// if (enableCamera) {
// await viewer.rotateUpdate(localPosition.dx, localPosition.dy);
// }
// break;
// case ThermionGestureState.PANNING:
// if (enableCamera) {
// await viewer.panUpdate(localPosition.dx, localPosition.dy);
// }
// break;
// case ThermionGestureState.ZOOMING:
// // ignore
// break;
// }
// }
// @override
// Future<void> onPointerUp(int buttons) async {
// switch (_currentState) {
// case ThermionGestureState.ROTATING:
// await viewer.rotateEnd();
// _currentState = ThermionGestureState.NULL;
// break;
// case ThermionGestureState.PANNING:
// await viewer.panEnd();
// _currentState = ThermionGestureState.NULL;
// break;
// default:
// break;
// }
// }
// Future<void> _handleEntityHighlightedMove(Offset localPosition) async {
// if (_highlightedEntity != null) {
// await viewer.queuePositionUpdateFromViewportCoords(
// _highlightedEntity!,
// localPosition.dx,
// localPosition.dy,
// );
// }
// }
// Future<void> _zoom(Offset localPosition, double scrollDelta) async {
// _scrollTimer?.cancel();
// _currentState = ThermionGestureState.ZOOMING;
// await viewer.zoomBegin();
// await viewer.zoomUpdate(
// localPosition.dx, localPosition.dy, scrollDelta > 0 ? 1 : -1);
// _scrollTimer = Timer(const Duration(milliseconds: 100), () async {
// await viewer.zoomEnd();
// _currentState = ThermionGestureState.NULL;
// });
// }
// @override
// void dispose() {
// _pickResultSubscription?.cancel();
// if (_highlightedEntity != null) {
// viewer.removeStencilHighlight(_highlightedEntity!);
// }
// RawKeyboard.instance.removeListener(_handleKeyEvent);
// }
// @override
// Future<bool> get initialized => viewer.initialized;
// @override
// InputAction getActionForType(InputType type) {
// // TODO: implement getActionForType
// InputAction? getActionForType(InputType gestureType) {
// throw UnimplementedError();
// }
// @override
// Future<void> onScaleEnd() {
// Future<bool> get initialized => _initialized.future;
// @override
// void keyDown(PhysicalKey key) {}
// @override
// void keyUp(PhysicalKey key) {}
// @override
// Future<void> onPointerDown(Vector2 localPosition, bool isMiddle) {
// viewer.pick(localPosition.x.floor(), localPosition.y.floor(), (axis) {
// })
// // _translationGizmo.pick(
// // localPosition.x.floor(), localPosition.y.floor(), (axis) {});
// }
// @override
// Future<void> onPointerHover(Vector2 localPosition, Vector2 delta) {
// // TODO: implement onPointerHover
// throw UnimplementedError();
// }
// @override
// Future<void> onPointerMove(
// Vector2 localPosition, Vector2 delta, bool isMiddle) {
// // TODO: implement onPointerMove
// throw UnimplementedError();
// }
// @override
// Future<void> onPointerScroll(Vector2 localPosition, double scrollDelta) {
// // TODO: implement onPointerScroll
// throw UnimplementedError();
// }
// @override
// Future<void> onPointerUp(bool isMiddle) {
// // TODO: implement onPointerUp
// throw UnimplementedError();
// }
// @override
// Future<void> onScaleEnd(int pointerCount, double velocity) {
// // TODO: implement onScaleEnd
// throw UnimplementedError();
// }
// @override
// Future<void> onScaleStart() {
// Future<void> onScaleStart(
// Vector2 focalPoint, int pointerCount, Duration? sourceTimestamp) {
// // TODO: implement onScaleStart
// throw UnimplementedError();
// }
// @override
// Future<void> onScaleUpdate() {
// Future<void> onScaleUpdate(
// Vector2 focalPoint,
// Vector2 focalPointDelta,
// double horizontalScale,
// double verticalScale,
// double scale,
// int pointerCount,
// double rotation,
// Duration? sourceTimestamp) {
// // TODO: implement onScaleUpdate
// throw UnimplementedError();
// }
// @override
// void setActionForType(InputType type, InputAction action) {
// void setActionForType(InputType gestureType, InputAction gestureAction) {
// // TODO: implement setActionForType
// }
// }
// // final ThermionViewer viewer;
// // final bool enableCamera;
// // final bool enablePicking;
// // final Logger _logger = Logger("PickingCameraGestureHandler");
// // AbstractGizmo? _gizmo;
// // Timer? _scrollTimer;
// // ThermionEntity? _highlightedEntity;
// // StreamSubscription<FilamentPickResult>? _pickResultSubscription;
// // bool _gizmoAttached = false;
// // PickingCameraGestureHandler({
// // required this.viewer,
// // this.enableCamera = true,
// // this.enablePicking = true,
// // }) {
// // try {
// // _gizmo = viewer.gizmo;
// // } catch (err) {
// // _logger.warning(
// // "Failed to get gizmo. If you are running on WASM, this is expected");
// // }
// // _pickResultSubscription = viewer.pickResult.listen(_onPickResult);
// // // Add keyboard listener
// // RawKeyboard.instance.addListener(_handleKeyEvent);
// // }
// // @override
// // ThermionGestureState get currentState => _currentState;
// // void _handleKeyEvent(RawKeyEvent event) {
// // if (event is RawKeyDownEvent &&
// // event.logicalKey == LogicalKeyboardKey.escape) {
// // _resetToNullState();
// // }
// // }
// // void _resetToNullState() async {
// // _currentState = ThermionGestureState.NULL;
// // if (_highlightedEntity != null) {
// // await viewer.removeStencilHighlight(_highlightedEntity!);
// // _highlightedEntity = null;
// // }
// // }
// // void _onPickResult(FilamentPickResult result) async {
// // var targetEntity = await viewer.getAncestor(result.entity) ?? result.entity;
// // if (_highlightedEntity != targetEntity) {
// // if (_highlightedEntity != null) {
// // await viewer.removeStencilHighlight(_highlightedEntity!);
// // }
// // _highlightedEntity = targetEntity;
// // if (_highlightedEntity != null) {
// // await viewer.setStencilHighlight(_highlightedEntity!);
// // _gizmo?.attach(_highlightedEntity!);
// // }
// // }
// // }
// // @override
// // Future<void> onPointerHover(Offset localPosition, Offset delta) async {
// // if (_gizmoAttached) {
// // _gizmo?.checkHover(localPosition.dx, localPosition.dy);
// // }
// // if (_highlightedEntity != null) {
// // await viewer.queuePositionUpdateFromViewportCoords(
// // _highlightedEntity!,
// // localPosition.dx,
// // localPosition.dy,
// // );
// // }
// // }
// // @override
// // Future<void> onPointerScroll(Offset localPosition, double scrollDelta) async {
// // if (!enableCamera) {
// // return;
// // }
// // if (_currentState == ThermionGestureState.NULL ||
// // _currentState == ThermionGestureState.ZOOMING) {
// // await _zoom(localPosition, scrollDelta);
// // }
// // }
// // @override
// // Future<void> onPointerDown(Offset localPosition, int buttons) async {
// // if (_highlightedEntity != null) {
// // _resetToNullState();
// // return;
// // }
// // if (enablePicking && buttons != kMiddleMouseButton) {
// // viewer.pick(localPosition.dx.toInt(), localPosition.dy.toInt());
// // }
// // if (buttons == kMiddleMouseButton && enableCamera) {
// // await viewer.rotateStart(localPosition.dx, localPosition.dy);
// // _currentState = ThermionGestureState.ROTATING;
// // } else if (buttons == kPrimaryMouseButton && enableCamera) {
// // await viewer.panStart(localPosition.dx, localPosition.dy);
// // _currentState = ThermionGestureState.PANNING;
// // }
// // }
// // @override
// // Future<void> onPointerMove(
// // Offset localPosition, Offset delta, int buttons) async {
// // if (_highlightedEntity != null) {
// // await _handleEntityHighlightedMove(localPosition);
// // return;
// // }
// // switch (_currentState) {
// // case ThermionGestureState.NULL:
// // break;
// // case ThermionGestureState.ROTATING:
// // if (enableCamera) {
// // await viewer.rotateUpdate(localPosition.dx, localPosition.dy);
// // }
// // break;
// // case ThermionGestureState.PANNING:
// // if (enableCamera) {
// // await viewer.panUpdate(localPosition.dx, localPosition.dy);
// // }
// // break;
// // case ThermionGestureState.ZOOMING:
// // // ignore
// // break;
// // }
// // }
// // @override
// // Future<void> onPointerUp(int buttons) async {
// // switch (_currentState) {
// // case ThermionGestureState.ROTATING:
// // await viewer.rotateEnd();
// // _currentState = ThermionGestureState.NULL;
// // break;
// // case ThermionGestureState.PANNING:
// // await viewer.panEnd();
// // _currentState = ThermionGestureState.NULL;
// // break;
// // default:
// // break;
// // }
// // }
// // Future<void> _handleEntityHighlightedMove(Offset localPosition) async {
// // if (_highlightedEntity != null) {
// // await viewer.queuePositionUpdateFromViewportCoords(
// // _highlightedEntity!,
// // localPosition.dx,
// // localPosition.dy,
// // );
// // }
// // }
// // Future<void> _zoom(Offset localPosition, double scrollDelta) async {
// // _scrollTimer?.cancel();
// // _currentState = ThermionGestureState.ZOOMING;
// // await viewer.zoomBegin();
// // await viewer.zoomUpdate(
// // localPosition.dx, localPosition.dy, scrollDelta > 0 ? 1 : -1);
// // _scrollTimer = Timer(const Duration(milliseconds: 100), () async {
// // await viewer.zoomEnd();
// // _currentState = ThermionGestureState.NULL;
// // });
// // }
// // @override
// // void dispose() {
// // _pickResultSubscription?.cancel();
// // if (_highlightedEntity != null) {
// // viewer.removeStencilHighlight(_highlightedEntity!);
// // }
// // RawKeyboard.instance.removeListener(_handleKeyEvent);
// // }
// // @override
// // Future<bool> get initialized => viewer.initialized;
// // @override
// // InputAction getActionForType(InputType type) {
// // // TODO: implement getActionForType
// // throw UnimplementedError();
// // }
// // @override
// // Future<void> onScaleEnd() {
// // // TODO: implement onScaleEnd
// // throw UnimplementedError();
// // }
// // @override
// // Future<void> onScaleStart() {
// // // TODO: implement onScaleStart
// // throw UnimplementedError();
// // }
// // @override
// // Future<void> onScaleUpdate() {
// // // TODO: implement onScaleUpdate
// // throw UnimplementedError();
// // }
// // @override
// // void setActionForType(InputType type, InputAction action) {
// // // TODO: implement setActionForType
// // }
// // }

View File

@@ -4,41 +4,40 @@ import 'package:vector_math/vector_math_64.dart';
import '../../viewer/viewer.dart';
class Axis {
class AxisWidget {
final ThermionViewer _viewer;
final ThermionEntity xAxis;
final ThermionEntity yAxis;
final ThermionEntity zAxis;
Axis._(this.xAxis, this.yAxis, this.zAxis, this._viewer);
AxisWidget._(this.xAxis, this.yAxis, this.zAxis, this._viewer);
static Future<Axis> create(ThermionViewer viewer) async {
final xAxis = await viewer!.createGeometry(
final xAxis = await viewer.createGeometry(
Geometry(Float32List.fromList([0, 0, 0, 10, 0, 0]), [0, 1],
primitiveType: PrimitiveType.LINES),
materialInstance: await viewer!.createUnlitMaterialInstance());
final yAxis = await viewer!.createGeometry(
materialInstances: [await viewer.createUnlitMaterialInstance()]);
final yAxis = await viewer.createGeometry(
Geometry(Float32List.fromList([0, 0, 0, 0, 10, 0]), [0, 1],
primitiveType: PrimitiveType.LINES),
materialInstance: await viewer!.createUnlitMaterialInstance());
final zAxis = await viewer!.createGeometry(
materialInstances: [await viewer.createUnlitMaterialInstance()]);
final zAxis = await viewer.createGeometry(
Geometry(Float32List.fromList([0, 0, 0, 0, 0, 10]), [0, 1],
primitiveType: PrimitiveType.LINES),
materialInstance: await viewer!.createUnlitMaterialInstance());
await viewer!.setMaterialPropertyFloat4(
xAxis, "baseColorFactor", 0, 1.0, 0.0, 0.0, 1.0);
await viewer!.setMaterialPropertyFloat4(
yAxis, "baseColorFactor", 0, 0.0, 1.0, 0.0, 1.0);
await viewer!.setMaterialPropertyFloat4(
zAxis, "baseColorFactor", 0, 0.0, 0.0, 1.0, 1.0);
return Axis._(xAxis, yAxis, zAxis, viewer);
materialInstances: [await viewer.createUnlitMaterialInstance()]);
throw Exception("TODO");
// await viewer!.setMaterialPropertyFloat4(
// xAxis, "baseColorFactor", 0, 1.0, 0.0, 0.0, 1.0);
// await viewer!.setMaterialPropertyFloat4(
// yAxis, "baseColorFactor", 0, 0.0, 1.0, 0.0, 1.0);
// await viewer!.setMaterialPropertyFloat4(
// zAxis, "baseColorFactor", 0, 0.0, 0.0, 1.0, 1.0);
// return Axis._(xAxis, yAxis, zAxis, viewer);
}
Future setTransform(Matrix4 transform) async {
await _viewer.setTransform(xAxis, transform);
await _viewer.setTransform(yAxis, transform);
await _viewer.setTransform(zAxis, transform);
}
}

View File

@@ -1,127 +1,120 @@
import 'dart:async';
import 'package:thermion_dart/src/viewer/viewer.dart';
import 'package:vector_math/vector_math_64.dart';
abstract class Gizmo {
bool get isVisible;
bool get isHovered;
void reset();
Future attach(ThermionEntity entity);
Future detach();
// abstract class BaseGizmo extends Gizmo {
// final ThermionEntity x;
// final ThermionEntity y;
// final ThermionEntity z;
// final ThermionEntity center;
Stream<Aabb2> get boundingBox;
// ThermionEntity? _activeAxis;
// ThermionEntity? _activeEntity;
// ThermionViewer viewer;
void checkHover(int x, int y);
}
// bool _visible = false;
// bool get isVisible => _visible;
abstract class BaseGizmo extends Gizmo {
final ThermionEntity x;
final ThermionEntity y;
final ThermionEntity z;
final ThermionEntity center;
// bool _isHovered = false;
// bool get isHovered => _isHovered;
ThermionEntity? _activeAxis;
ThermionEntity? _activeEntity;
ThermionViewer viewer;
// final Set<ThermionEntity> ignore;
bool _visible = false;
bool get isVisible => _visible;
// Stream<Aabb2> get boundingBox => _boundingBoxController.stream;
// final _boundingBoxController = StreamController<Aabb2>.broadcast();
bool _isHovered = false;
bool get isHovered => _isHovered;
// ThermionEntity get entity => center;
final Set<ThermionEntity> ignore;
// BaseGizmo(
// {required this.x,
// required this.y,
// required this.z,
// required this.center,
// required this.viewer,
// this.ignore = const <ThermionEntity>{}}) {
// onPick(_onGizmoPickResult);
// }
Stream<Aabb2> get boundingBox => _boundingBoxController.stream;
final _boundingBoxController = StreamController<Aabb2>.broadcast();
// final _stopwatch = Stopwatch();
BaseGizmo({required this.x, required this.y, required this.z, required this.center, required this.viewer,
this.ignore = const <ThermionEntity>{}}) {
onPick(_onGizmoPickResult);
}
// double _transX = 0.0;
// double _transY = 0.0;
final _stopwatch = Stopwatch();
// Future translate(double transX, double transY) async {
// if (!_stopwatch.isRunning) {
// _stopwatch.start();
// }
double _transX = 0.0;
double _transY = 0.0;
// _transX += transX;
// _transY += transY;
Future translate(double transX, double transY) async {
if (!_stopwatch.isRunning) {
_stopwatch.start();
}
// if (_stopwatch.elapsedMilliseconds < 16) {
// return;
// }
_transX += transX;
_transY += transY;
// final axis = Vector3(_activeAxis == x ? 1.0 : 0.0,
// _activeAxis == y ? 1.0 : 0.0, _activeAxis == z ? 1.0 : 0.0);
if (_stopwatch.elapsedMilliseconds < 16) {
return;
}
// await viewer.queueRelativePositionUpdateWorldAxis(
// _activeEntity!,
// _transX,
// -_transY, // flip the sign because "up" in NDC Y axis is positive, but negative in Flutter
// axis.x,
// axis.y,
// axis.z);
// _transX = 0;
// _transY = 0;
// _stopwatch.reset();
// }
final axis = Vector3(_activeAxis == x ? 1.0 : 0.0,
_activeAxis == y ? 1.0 : 0.0, _activeAxis == z ? 1.0 : 0.0);
// void reset() {
// _activeAxis = null;
// }
await viewer.queueRelativePositionUpdateWorldAxis(
_activeEntity!,
_transX,
-_transY, // flip the sign because "up" in NDC Y axis is positive, but negative in Flutter
axis.x,
axis.y,
axis.z);
_transX = 0;
_transY = 0;
_stopwatch.reset();
}
// void _onGizmoPickResult(FilamentPickResult result) async {
// if (result.entity == x || result.entity == y || result.entity == z) {
// _activeAxis = result.entity;
// _isHovered = true;
// } else if (result.entity == 0) {
// _activeAxis = null;
// _isHovered = false;
// } else {
// throw Exception("Unexpected gizmo pick result");
// }
// }
void reset() {
_activeAxis = null;
}
// Future attach(ThermionEntity entity) async {
// _activeAxis = null;
// if (entity == _activeEntity) {
// return;
// }
// if (entity == center) {
// _activeEntity = null;
// return;
// }
// _visible = true;
void _onGizmoPickResult(FilamentPickResult result) async {
if (result.entity == x || result.entity == y || result.entity == z) {
_activeAxis = result.entity;
_isHovered = true;
} else if (result.entity == 0) {
_activeAxis = null;
_isHovered = false;
} else {
throw Exception("Unexpected gizmo pick result");
}
}
// if (_activeEntity != null) {
// // await viewer.removeStencilHighlight(_activeEntity!);
// }
// _activeEntity = entity;
Future attach(ThermionEntity entity) async {
_activeAxis = null;
if (entity == _activeEntity) {
return;
}
if (entity == center) {
_activeEntity = null;
return;
}
_visible = true;
// await viewer.setParent(center, entity, preserveScaling: false);
// _boundingBoxController.sink.add(await viewer.getViewportBoundingBox(x));
// }
if (_activeEntity != null) {
await viewer.removeStencilHighlight(_activeEntity!);
}
_activeEntity = entity;
// Future detach() async {
// await setVisibility(false);
// }
await viewer.setParent(center, entity, preserveScaling: false);
_boundingBoxController.sink.add(await viewer.getViewportBoundingBox(x));
}
// @override
// void checkHover(int x, int y) {
// pick(x, y);
// }
Future detach() async {
await setVisibility(false);
}
// Future pick(int x, int y);
@override
void checkHover(int x, int y) {
pick(x, y);
}
Future pick(int x, int y);
Future setVisibility(bool visible);
void onPick(void Function(PickResult result) callback);
}
// Future setVisibility(bool visible);
// void onPick(void Function(PickResult result) callback);
// }

View File

@@ -1,85 +0,0 @@
import 'shared_types/shared_types.dart';
///
/// To ensure we can easily store/recreate a particular, [ThermionViewer] will raise an event whenever an
/// entity is added/removed.
///
enum EventType { EntityAdded, EntityRemoved, EntityHidden, EntityRevealed, ClearLights }
///
/// An "entity added" event must provide sufficient detail to enable that asset to be reloaded in future.
/// This requires a bit more legwork because entities may be lights (direct/indirect), geometry or gltf.
///
enum EntityType { Geometry, Gltf, DirectLight, IBL }
class SceneUpdateEvent {
late final ThermionEntity? entity;
late final EventType eventType;
EntityType get addedEntityType {
if (_directLight != null) {
return EntityType.DirectLight;
} else if (_ibl != null) {
return EntityType.IBL;
} else if (_gltf != null) {
return EntityType.Gltf;
} else if (_geometry != null) {
return EntityType.Geometry;
} else {
throw Exception("Unknown entity type");
}
}
DirectLight? _directLight;
IBL? _ibl;
GLTF? _gltf;
Geometry? _geometry;
SceneUpdateEvent.remove(this.entity) {
this.eventType = EventType.EntityRemoved;
}
SceneUpdateEvent.reveal(this.entity) {
this.eventType = EventType.EntityRevealed;
}
SceneUpdateEvent.hide(this.entity) {
this.eventType = EventType.EntityHidden;
}
SceneUpdateEvent.addDirectLight(this.entity, this._directLight) {
this.eventType = EventType.EntityAdded;
}
SceneUpdateEvent.addIbl(this.entity, this._ibl) {
this.eventType = EventType.EntityAdded;
}
SceneUpdateEvent.addGltf(this.entity, this._gltf) {
this.eventType = EventType.EntityAdded;
}
SceneUpdateEvent.addGeometry(this.entity, this._geometry) {
this.eventType = EventType.EntityAdded;
}
SceneUpdateEvent.clearLights() {
this.eventType = EventType.ClearLights;
}
DirectLight getDirectLight() {
return _directLight!;
}
IBL getAsIBL() {
return _ibl!;
}
GLTF getAsGLTF() {
return _gltf!;
}
Geometry getAsGeometry() {
return _geometry!;
}
}

View File

@@ -0,0 +1,186 @@
import 'dart:typed_data';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
import 'package:thermion_dart/thermion_dart.dart';
import 'ffi_material_instance.dart';
class FFIAsset extends ThermionAsset {
final Pointer<TSceneAsset> pointer;
final Pointer<TSceneManager> sceneManager;
Pointer<TRenderableManager> get renderableManager =>
Engine_getRenderableManager(engine);
final Pointer<TEngine> engine;
FFIAsset? _highlight;
final Pointer<TMaterialProvider> _unlitMaterialProvider;
final bool isInstance;
late final ThermionEntity entity;
FFIAsset(
this.pointer, this.sceneManager, this.engine, this._unlitMaterialProvider,
{this.isInstance = false}) {
entity = SceneAsset_getEntity(pointer);
}
@override
Future<List<ThermionEntity>> getChildEntities() async {
var count = SceneAsset_getChildEntityCount(pointer);
var children = Int32List(count);
SceneAsset_getChildEntities(pointer, children.address);
return children;
}
@override
Future<ThermionAsset> getInstance(int index) async {
if (isInstance) {
throw Exception(
"This is itself an instance. Call getInstance on the original asset that this instance was created from");
}
var instance = SceneAsset_getInstance(pointer, index);
if (instance == nullptr) {
throw Exception("No instance available at index $index");
}
return FFIAsset(instance, sceneManager, engine, _unlitMaterialProvider);
}
///
///
///
@override
Future<FFIAsset> createInstance(
{covariant List<MaterialInstance>? materialInstances = null}) async {
var created = await withPointerCallback<TSceneAsset>((cb) {
var ptrList = Int64List(materialInstances?.length ?? 0);
if (materialInstances != null && materialInstances.isNotEmpty) {
ptrList.setRange(
0,
materialInstances.length,
materialInstances
.cast<ThermionFFIMaterialInstance>()
.map((mi) => mi.pointer.address)
.toList());
}
SceneAsset_createInstanceRenderThread(
pointer,
ptrList.address.cast<Pointer<TMaterialInstance>>(),
materialInstances?.length ?? 0,
cb);
});
if (created == FILAMENT_ASSET_ERROR) {
throw Exception("Failed to create instance");
}
return FFIAsset(created, sceneManager, engine, _unlitMaterialProvider);
}
///
///
///
@override
Future<int> getInstanceCount() async {
return SceneAsset_getInstanceCount(pointer);
}
///
///
///
@override
Future<List<ThermionAsset>> getInstances() async {
var count = await getInstanceCount();
final result = List<ThermionAsset>.generate(count, (i) {
return FFIAsset(SceneAsset_getInstance(pointer, i), sceneManager, engine,
_unlitMaterialProvider);
});
return result;
}
@override
Future removeStencilHighlight() async {
if (_highlight != null) {
SceneManager_removeFromScene(sceneManager, _highlight!.entity);
final childEntities = await _highlight!.getChildEntities();
for (final child in childEntities) {
SceneManager_removeFromScene(sceneManager, child);
}
}
}
@override
Future setStencilHighlight(
{double r = 1.0,
double g = 0.0,
double b = 0.0,
int? entityIndex}) async {
if (_highlight == null) {
var targetEntity = this.entity;
if (entityIndex != null) {
final childEntities = await this.getChildEntities();
targetEntity = childEntities[entityIndex!];
}
var sourceMaterialInstance = ThermionFFIMaterialInstance(
RenderableManager_getMaterialInstanceAt(
renderableManager, targetEntity, 0));
await sourceMaterialInstance.setStencilWriteEnabled(true);
await sourceMaterialInstance.setDepthWriteEnabled(true);
await sourceMaterialInstance
.setStencilOpDepthStencilPass(StencilOperation.REPLACE);
await sourceMaterialInstance.setStencilReferenceValue(1);
final materialInstancePtr =
await withPointerCallback<TMaterialInstance>((cb) {
final key = Struct.create<TMaterialKey>();
MaterialProvider_createMaterialInstanceRenderThread(
_unlitMaterialProvider, key.address, cb);
});
final highlightMaterialInstance =
ThermionFFIMaterialInstance(materialInstancePtr);
await highlightMaterialInstance
.setStencilCompareFunction(SamplerCompareFunction.NE);
await highlightMaterialInstance.setStencilReferenceValue(1);
await highlightMaterialInstance.setDepthCullingEnabled(false);
await highlightMaterialInstance.setParameterFloat("vertexScale", 1.03);
await highlightMaterialInstance.setParameterFloat4(
"baseColorFactor", r, g, b, 1.0);
var highlightInstance = await this
.createInstance(materialInstances: [highlightMaterialInstance]);
_highlight = highlightInstance;
var targetHighlightEntity = _highlight!.entity;
if (entityIndex != null) {
var highlightChildEntities = await _highlight!.getChildEntities();
targetHighlightEntity = highlightChildEntities[entityIndex!];
}
RenderableManager_setPriority(
renderableManager, targetHighlightEntity, 7);
RenderableManager_setPriority(renderableManager, targetEntity, 0);
await highlightMaterialInstance.setStencilReferenceValue(1);
SceneManager_addToScene(sceneManager, targetHighlightEntity);
}
}
@override
Future addToScene() async {
SceneAsset_addToScene(pointer, SceneManager_getScene(sceneManager));
}
@override
Future removeFromScene() async {
SceneManager_removeFromScene(sceneManager, entity);
for (final child in await getChildEntities()) {
SceneManager_removeFromScene(sceneManager, child);
}
}
}

View File

@@ -9,9 +9,10 @@ import 'thermion_dart.g.dart' as g;
class FFICamera extends Camera {
final Pointer<g.TCamera> camera;
final Pointer<g.TEngine> engine;
final Pointer<g.TTransformManager> transformManager;
late ThermionEntity _entity;
FFICamera(this.camera, this.engine) {
FFICamera(this.camera, this.engine, this.transformManager) {
_entity = g.Camera_getEntity(camera);
}
@@ -29,7 +30,7 @@ class FFICamera extends Camera {
@override
Future setTransform(Matrix4 transform) async {
var entity = g.Camera_getEntity(camera);
g.Engine_setTransform(engine, entity, matrix4ToDouble4x4(transform));
g.TransformManager_setTransform(transformManager, entity, matrix4ToDouble4x4(transform));
}
@override

View File

@@ -1,50 +1,69 @@
import 'dart:async';
import 'dart:ffi';
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/shared_types/entities.dart';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
import '../../../../utils/src/gizmo.dart';
import '../../../viewer.dart';
class FFIGizmo extends BaseGizmo {
Pointer<TGizmo> pointer;
import 'ffi_view.dart';
class FFIGizmo extends FFIAsset implements GizmoAsset {
final Set<ThermionEntity> nonPickableEntities;
late NativeCallable<GizmoPickCallbackFunction> _nativeCallback;
void Function(GizmoPickResultType axis, Vector3 coords)? _callback;
late FFIView _view;
void _onPickResult(int resultType, double x, double y, double z) {
_callback?.call(GizmoPickResultType.values[resultType], Vector3(x, y, z));
}
FFIGizmo(
this.pointer, ThermionViewer viewer) : super(x: 0, y: 0, z: 0, center: 0, viewer: viewer) {
this._view,
super.pointer,
super.sceneManager,
super.renderableManager,
super.unlitMaterialProvider,
this.nonPickableEntities
) {
_nativeCallback =
NativeCallable<GizmoPickCallbackFunction>.listener(_onPickResult);
}
///
/// The result(s) of calling [pickGizmo] (see below).
///
// Stream<PickResult> get onPick => _pickResultController.stream;
// final _pickResultController = StreamController<PickResult>.broadcast();
void Function(PickResult)? _callback;
void onPick(void Function(PickResult) callback) {
_callback = callback;
}
void _onPickResult(DartEntityId entityId, int x, int y, Pointer<TView> view) {
_callback?.call((entity: entityId, x: x, y: y, depth: 0, fragX: 0, fragY: 0, fragZ: 0));
}
///
/// Used to test whether a Gizmo is at the given viewport coordinates.
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [gizmoPickResult] stream to receive the results of this method.
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
///
@override
Future pick(int x, int y) async {
Gizmo_pick(pointer, x.toInt(), y, _nativeCallback.nativeFunction);
Future removeStencilHighlight() async {
throw Exception("Not supported for gizmo");
}
@override
Future setVisibility(bool visible) async {
Gizmo_setVisibility(pointer, visible);
Future setStencilHighlight(
{double r = 1.0,
double g = 0.0,
double b = 0.0,
int? entityIndex}) async {
throw Exception("Not supported for gizmo");
}
@override
Future pick(int x, int y,
{Future Function(GizmoPickResultType result, Vector3 coords)?
handler}) async {
_callback = handler;
final viewport = await _view.getViewport();
y = viewport.height - y;
Gizmo_pick(pointer.cast<TGizmo>(), x, y, _nativeCallback.nativeFunction);
}
@override
Future highlight(Axis axis) async {
Gizmo_unhighlight(pointer.cast<TGizmo>());
Gizmo_highlight(pointer.cast<TGizmo>(), TGizmoAxis.values[axis.index]);
}
@override
Future unhighlight() async {
Gizmo_unhighlight(pointer.cast<TGizmo>());
}
}

View File

@@ -0,0 +1,116 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
import 'package:thermion_dart/thermion_dart.dart';
class ThermionFFIMaterialInstance extends MaterialInstance {
final Pointer<TMaterialInstance> pointer;
ThermionFFIMaterialInstance(this.pointer) {
if (pointer == nullptr) {
throw Exception("MaterialInstance not found");
}
}
@override
Future setDepthCullingEnabled(bool enabled) async {
MaterialInstance_setDepthCulling(this.pointer, enabled);
}
@override
Future setDepthWriteEnabled(bool enabled) async {
MaterialInstance_setDepthWrite(this.pointer, enabled);
}
@override
Future setParameterFloat4(
String name, double x, double y, double z, double w) async {
MaterialInstance_setParameterFloat4(
pointer, name.toNativeUtf8().cast<Char>(), x, y, z, w);
}
@override
Future setParameterFloat2(String name, double x, double y) async {
MaterialInstance_setParameterFloat2(
pointer, name.toNativeUtf8().cast<Char>(), x, y);
}
@override
Future setParameterFloat(String name, double value) async {
MaterialInstance_setParameterFloat(
pointer, name.toNativeUtf8().cast<Char>(), value);
}
@override
Future setParameterInt(String name, int value) async {
MaterialInstance_setParameterInt(
pointer, name.toNativeUtf8().cast<Char>(), value);
}
@override
Future setDepthFunc(SamplerCompareFunction depthFunc) async {
MaterialInstance_setDepthFunc(pointer, TSamplerCompareFunc.values[depthFunc.index]);
}
@override
Future setStencilCompareFunction(SamplerCompareFunction func,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilCompareFunction(
pointer, TSamplerCompareFunc.values[func.index], TStencilFace.values[face.index]);
}
@override
Future setStencilOpDepthFail(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilOpDepthFail(pointer,
TStencilOperation.values[op.index], TStencilFace.values[face.index]);
}
@override
Future setStencilOpDepthStencilPass(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilOpDepthStencilPass(pointer,
TStencilOperation.values[op.index], TStencilFace.values[face.index]);
}
@override
Future setStencilOpStencilFail(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilOpStencilFail(pointer,
TStencilOperation.values[op.index], TStencilFace.values[face.index]);
}
@override
Future setStencilReferenceValue(int value,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilReferenceValue(
pointer, value, TStencilFace.values[face.index]);
}
@override
Future setStencilWriteEnabled(bool enabled) async {
MaterialInstance_setStencilWrite(pointer, enabled);
}
@override
Future setCullingMode(CullingMode cullingMode) async {
MaterialInstance_setCullingMode(
pointer, TCullingMode.values[cullingMode.index]);
}
@override
Future<bool> isStencilWriteEnabled() async {
return MaterialInstance_isStencilWriteEnabled(pointer);
}
@override
Future setStencilReadMask(int mask) async {
MaterialInstance_setStencilReadMask(pointer, mask);
}
@override
Future setStencilWriteMask(int mask) async {
MaterialInstance_setStencilWriteMask(pointer, mask);
}
}

View File

@@ -18,7 +18,7 @@ class FFIView extends View {
@override
Future setRenderTarget(covariant FFIRenderTarget? renderTarget) async {
if(renderTarget != null) {
if (renderTarget != null) {
View_setRenderTarget(view, renderTarget.renderTarget);
} else {
View_setRenderTarget(view, nullptr);
@@ -39,8 +39,9 @@ class FFIView extends View {
@override
Future<Camera> getCamera() async {
final engine = Viewer_getEngine(viewer);
final cameraPtr = View_getCamera(view);
return FFICamera(cameraPtr, engine);
final transformManager = Engine_getTransformManager(engine);
final cameraPtr = View_getCamera(view);
return FFICamera(cameraPtr, engine, transformManager);
}
@override
@@ -72,4 +73,12 @@ class FFIView extends View {
final engine = await Viewer_getEngine(viewer);
View_setToneMappingRenderThread(view, engine, mapper.index);
}
Future setStencilBufferEnabled(bool enabled) async {
return View_setStencilBufferEnabled(view, enabled);
}
Future<bool> isStencilBufferEnabled() async {
return View_isStencilBufferEnabled(view);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,85 @@
library;
import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart';
export 'geometry.dart';
export 'gltf.dart';
export 'light_options.dart';
// a handle that can be safely passed back to the rendering layer to manipulate an Entity
// repre handle that can be safely passed back to the rendering layer to manipulate an Entity
typedef ThermionEntity = int;
abstract class ThermionAsset {
ThermionEntity get entity;
Future<List<ThermionEntity>> getChildEntities();
///
/// Renders an outline around [entity] with the given color.
///
Future setStencilHighlight(
{double r = 1.0, double g = 0.0, double b = 0.0, int? entityIndex});
///
/// Removes the outline around [entity]. Noop if there was no highlight.
///
Future removeStencilHighlight();
///
///
///
Future<ThermionAsset> getInstance(int index);
///
/// Create a new instance of [entity].
/// Instances are not automatically added to the scene; you must
/// call [addToScene].
///
Future<ThermionAsset> createInstance(
{covariant List<MaterialInstance>? materialInstances = null});
///
/// Returns the number of instances associated with this asset.
///
Future<int> getInstanceCount();
///
/// Returns all instances of associated with this asset.
///
Future<List<ThermionAsset>> getInstances();
///
/// Adds all entities (renderable, lights and cameras) under [asset] to the scene.
///
Future addToScene();
///
/// Removes all entities (renderable, lights and cameras) under [asset] from the scene.
///
Future removeFromScene();
}
enum Axis {
X(const [1.0, 0.0, 0.0]),
Y(const [0.0, 1.0, 0.0]),
Z(const [0.0, 0.0, 1.0]);
const Axis(this.vector);
final List<double> vector;
Vector3 asVector() => Vector3(vector[0], vector[1], vector[2]);
}
enum GizmoPickResultType { AxisX, AxisY, AxisZ, Parent, None }
enum GizmoType { translation, rotation }
abstract class GizmoAsset extends ThermionAsset {
Future pick(int x, int y,
{Future Function(GizmoPickResultType axis, Vector3 coords)? handler});
Future highlight(Axis axis);
Future unhighlight();
Set<ThermionEntity> get nonPickableEntities;
}

View File

@@ -1,32 +1,112 @@
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
enum SamplerCompareFunction {
enum SamplerCompareFunction {
/// !< Less or equal
LE,
/// !< Greater or equal
GE,
/// !< Strictly less than
L,
/// !< Strictly greater than
G,
/// !< Equal
E,
/// !< Not equal
NE,
/// !< Always. Depth / stencil testing is deactivated.
A,
/// !< Never. The depth / stencil test always fails.
N;
}
abstract class MaterialInstance {
Future setDepthWriteEnabled(bool enabled);
Future setDepthFunc(SamplerCompareFunction depthFunc);
Future setDepthCullingEnabled(bool enabled);
Future setParameterFloat4(String name, double x, double y, double z, double w);
Future setParameterFloat2(String name, double x, double y);
Future setParameterFloat(String name, double x);
Future setParameterInt(String name, int value);
/// Defines stencil operations
enum StencilOperation {
/// Keep the current value
KEEP,
/// Set the value to zero
ZERO,
/// Set the value to reference value
REPLACE,
/// Increment the current value with saturation
INCR,
/// Increment the current value without saturation
INCR_WRAP,
/// Decrement the current value with saturation
DECR,
/// Decrement the current value without saturation
DECR_WRAP,
/// Invert the current value
INVERT
}
enum CullingMode {
NONE, // No culling
FRONT, // Cull front faces
BACK, // Cull back faces
FRONT_AND_BACK // Cull both front and back faces
}
/// Defines which face(s) the stencil operation affects
enum StencilFace {
/// Front face only
FRONT,
/// Back face only
BACK,
/// Both front and back faces
FRONT_AND_BACK
}
enum AlphaMode { OPAQUE, MASK, BLEND }
abstract class MaterialInstance {
Future<bool> isStencilWriteEnabled();
Future setDepthWriteEnabled(bool enabled);
Future setDepthFunc(SamplerCompareFunction depthFunc);
Future setDepthCullingEnabled(bool enabled);
Future setParameterFloat4(
String name, double x, double y, double z, double w);
Future setParameterFloat2(String name, double x, double y);
Future setParameterFloat(String name, double x);
Future setParameterInt(String name, int value);
/// Sets the stencil operation to be performed when the stencil test fails
Future setStencilOpStencilFail(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]);
/// Sets the stencil operation to be performed when the depth test fails
Future setStencilOpDepthFail(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]);
/// Sets the stencil operation to be performed when both depth and stencil tests pass
Future setStencilOpDepthStencilPass(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]);
/// Sets the stencil test comparison function
Future setStencilCompareFunction(SamplerCompareFunction func,
[StencilFace face = StencilFace.FRONT_AND_BACK]);
/// Sets the reference value used for stencil testing
Future setStencilReferenceValue(int value,
[StencilFace face = StencilFace.FRONT_AND_BACK]);
Future setStencilWriteEnabled(bool enabled);
Future setCullingMode(CullingMode cullingMode);
Future setStencilReadMask(int mask);
Future setStencilWriteMask(int mask);
}

View File

@@ -1,5 +1,5 @@
import 'package:thermion_dart/thermion_dart.dart';
import 'swap_chain.dart';
///
/// The viewport currently attached to a [View].
@@ -27,4 +27,6 @@ abstract class View {
Future setFrustumCullingEnabled(bool enabled);
Future setToneMapper(ToneMapper mapper);
Future setBloom(double strength);
Future setStencilBufferEnabled(bool enabled);
Future<bool> isStencilBufferEnabled();
}

View File

@@ -1,4 +1,3 @@
import 'package:thermion_dart/src/viewer/src/events.dart';
import '../../utils/src/gizmo.dart';
import 'shared_types/shared_types.dart';
export 'shared_types/shared_types.dart';
@@ -9,30 +8,30 @@ import 'package:vector_math/vector_math_64.dart';
import 'dart:async';
import 'package:animation_tools_dart/animation_tools_dart.dart';
import 'shared_types/view.dart';
const double kNear = 0.05;
const double kFar = 1000.0;
const double kFocalLength = 28.0;
enum VisibilityLayers {
DEFAULT_ASSET(0),
LAYER_1(1),
LAYER_2(2),
LAYER_3(3),
LAYER_4(4),
LAYER_5(5),
BACKGROUND(6),
OVERLAY(7);
final int value;
const VisibilityLayers(this.value);
}
abstract class ThermionViewer {
///
/// A Future that resolves when the underlying rendering context has been successfully created.
///
Future<bool> get initialized;
///
/// The result(s) of calling [pick] (see below).
/// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick].
/// If [pick] is called without an active subscription to this stream, the results will be silently discarded.
///
Stream<FilamentPickResult> get pickResult;
///
/// A Stream containing entities added/removed to/from to the scene.
///
Stream<SceneUpdateEvent> get sceneUpdated;
///
/// Whether the controller is currently rendering at [framerate].
///
@@ -74,8 +73,7 @@ abstract class ThermionViewer {
///
///
///
Future destroySwapChain(
covariant SwapChain swapChain);
Future destroySwapChain(covariant SwapChain swapChain);
///
///
@@ -86,8 +84,7 @@ abstract class ThermionViewer {
///
///
///
Future destroyRenderTarget(
covariant RenderTarget renderTarget);
Future destroyRenderTarget(covariant RenderTarget renderTarget);
///
///
@@ -215,24 +212,24 @@ abstract class ThermionViewer {
Future clearLights();
///
/// Load the .glb asset at the given path and insert into the scene.
/// Load the .glb asset at the given path, adding all entities to the scene.
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
///
Future<ThermionEntity> loadGlb(String path,
Future<ThermionAsset> loadGlb(String path,
{int numInstances = 1, bool keepData = false});
///
/// Load the .glb asset from the specified buffer and insert into the scene.
/// Load the .glb asset from the specified buffer, adding all entities to the scene.
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
/// If [loadResourcesAsync] is true, resources (textures, materials, etc) will
/// If [loadResourcesAsync] is true, resources (textures, materials, etc) will
/// be loaded asynchronously (so expect some material/texture pop-in);
///
///
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data,
Future<ThermionAsset> loadGlbFromBuffer(Uint8List data,
{int numInstances = 1,
bool keepData = false,
int priority = 4,
@@ -240,28 +237,13 @@ abstract class ThermionViewer {
bool loadResourcesAsync});
///
/// Create a new instance of [entity].
///
Future<ThermionEntity> createInstance(ThermionEntity entity);
///
/// Returns the number of instances of the asset associated with [entity].
///
Future<int> getInstanceCount(ThermionEntity entity);
///
/// Returns all instances of [entity].
///
Future<List<ThermionEntity>> getInstances(ThermionEntity entity);
///
/// Load the .gltf asset at the given path and insert into the scene.
/// Load the .gltf asset at the given path, adding all entities to the scene.
/// [relativeResourcePath] is the folder path where the glTF resources are stored;
/// this is usually the parent directory of the .gltf file itself.
///
/// See [loadGlb] for an explanation of [keepData].
///
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
Future<ThermionAsset> loadGltf(String path, String relativeResourcePath,
{bool keepData = false});
///
@@ -277,32 +259,34 @@ abstract class ThermionViewer {
/// Gets the names of all morph targets for the child renderable [childEntity] under [entity].
///
Future<List<String>> getMorphTargetNames(
ThermionEntity entity, ThermionEntity childEntity);
covariant ThermionAsset asset, ThermionEntity childEntity);
///
/// Gets the names of all bones for the armature at [skinIndex] under the specified [entity].
///
Future<List<String>> getBoneNames(ThermionEntity entity, {int skinIndex = 0});
Future<List<String>> getBoneNames(covariant ThermionAsset asset,
{int skinIndex = 0});
///
/// Gets the names of all glTF animations embedded in the specified entity.
///
Future<List<String>> getAnimationNames(ThermionEntity entity);
Future<List<String>> getAnimationNames(covariant ThermionAsset asset);
///
/// Returns the length (in seconds) of the animation at the given index.
///
Future<double> getAnimationDuration(
ThermionEntity entity, int animationIndex);
covariant ThermionAsset asset, int animationIndex);
///
/// Animate the morph targets in [entity]. See [MorphTargetAnimation] for an explanation as to how to construct the animation frame data.
/// Construct animation(s) for every entity under [asset]. If [targetMeshNames] is provided, only entities with matching names will be animated.
/// [MorphTargetAnimation] for an explanation as to how to construct the animation frame data.
/// This method will check the morph target names specified in [animation] against the morph target names that actually exist exist under [meshName] in [entity],
/// throwing an exception if any cannot be found.
/// It is permissible for [animation] to omit any targets that do exist under [meshName]; these simply won't be animated.
///
Future setMorphAnimationData(
ThermionEntity entity, MorphAnimationData animation,
covariant ThermionAsset asset, MorphAnimationData animation,
{List<String>? targetMeshNames});
///
@@ -314,7 +298,7 @@ abstract class ThermionViewer {
/// Resets all bones in the given entity to their rest pose.
/// This should be done before every call to addBoneAnimation.
///
Future resetBones(ThermionEntity entity);
Future resetBones(ThermionAsset asset);
///
/// Enqueues and plays the [animation] for the specified bone(s).
@@ -334,7 +318,7 @@ abstract class ThermionViewer {
/// This will be applied in reverse after [fadeOutInSecs].
///
///
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
Future addBoneAnimation(ThermionAsset asset, BoneAnimationData animation,
{int skinIndex = 0,
double fadeInInSecs = 0.0,
double fadeOutInSecs = 0.0,
@@ -344,7 +328,7 @@ abstract class ThermionViewer {
/// Gets the entity representing the bone at [boneIndex]/[skinIndex].
/// The returned entity is only intended for use with [getWorldTransform].
///
Future<ThermionEntity> getBone(ThermionEntity parent, int boneIndex,
Future<ThermionEntity> getBone(covariant ThermionAsset asset, int boneIndex,
{int skinIndex = 0});
///
@@ -362,7 +346,8 @@ abstract class ThermionViewer {
/// Note that [parent] must be the ThermionEntity returned by [loadGlb/loadGltf], not any other method ([getChildEntity] etc).
/// This is because all joint information is internally stored with the parent entity.
///
Future<Matrix4> getInverseBindMatrix(ThermionEntity parent, int boneIndex,
Future<Matrix4> getInverseBindMatrix(
covariant ThermionAsset asset, int boneIndex,
{int skinIndex = 0});
///
@@ -398,7 +383,7 @@ abstract class ThermionViewer {
/// Removes/destroys the specified entity from the scene.
/// [entity] will no longer be a valid handle after this method is called; ensure you immediately discard all references once this method is complete.
///
Future removeEntity(ThermionEntity entity);
Future removeEntity(ThermionAsset asset);
///
/// Removes/destroys all renderable entities from the scene (including cameras).
@@ -407,9 +392,9 @@ abstract class ThermionViewer {
Future clearEntities();
///
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
/// Schedules the glTF animation at [index] in [asset] to start playing on the next frame.
///
Future playAnimation(ThermionEntity entity, int index,
Future playAnimation(ThermionAsset asset, int index,
{bool loop = false,
bool reverse = false,
bool replaceActive = true,
@@ -419,17 +404,27 @@ abstract class ThermionViewer {
///
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
///
Future playAnimationByName(ThermionEntity entity, String name,
Future playAnimationByName(covariant ThermionAsset asset, String name,
{bool loop = false,
bool reverse = false,
bool replaceActive = true,
double crossfade = 0.0});
Future setAnimationFrame(
ThermionEntity entity, int index, int animationFrame);
///
///
///
Future setGltfAnimationFrame(
covariant ThermionAsset asset, int index, int animationFrame);
Future stopAnimation(ThermionEntity entity, int animationIndex);
Future stopAnimationByName(ThermionEntity entity, String name);
///
///
///
Future stopAnimation(covariant ThermionAsset asset, int animationIndex);
///
///
///
Future stopAnimationByName(covariant ThermionAsset asset, String name);
///
/// Sets the current scene camera to the glTF camera under [name] in [entity].
@@ -576,44 +571,11 @@ abstract class ThermionViewer {
///
Future setCameraModelMatrix4(Matrix4 matrix);
///
/// Sets the `baseColorFactor` property for the material at index [materialIndex] in [entity] under node [meshName] to [color].
///
@Deprecated("Use setMaterialPropertyFloat4 instead")
Future setMaterialColor(ThermionEntity entity, String meshName,
int materialIndex, double r, double g, double b, double a);
///
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
/// [entity] must have a Renderable attached.
///
Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName,
int materialIndex, double f1, double f2, double f3, double f4);
///
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
/// [entity] must have a Renderable attached.
///
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName,
int materialIndex, double value);
///
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
/// [entity] must have a Renderable attached.
///
Future setMaterialPropertyInt(
ThermionEntity entity, String propertyName, int materialIndex, int value);
///
/// Scale [entity] to fit within the unit cube.
///
Future transformToUnitCube(ThermionEntity entity);
///
/// Directly sets the world space position for [entity] to the given coordinates.
///
Future setPosition(ThermionEntity entity, double x, double y, double z);
///
/// Set the world space position for [lightEntity] to the given coordinates.
///
@@ -625,17 +587,6 @@ abstract class ThermionViewer {
///
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction);
///
/// Directly sets the scale for [entity], skipping all collision detection.
///
Future setScale(ThermionEntity entity, double scale);
///
/// Directly sets the rotation for [entity] to [rads] around the axis {x,y,z}, skipping all collision detection.
///
Future setRotation(
ThermionEntity entity, double rads, double x, double y, double z);
///
/// TODO
///
@@ -674,28 +625,22 @@ abstract class ThermionViewer {
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
///
/// Sets the rotation for [entity] to the specified quaternion.
/// Adds a single [entity] to the scene.
///
Future setRotationQuat(ThermionEntity entity, Quaternion rotation);
Future addEntityToScene(ThermionEntity entity);
///
/// Reveal the node [meshName] under [entity]. Only applicable if [hide] had previously been called; this is a no-op otherwise.
/// Removes a single [entity] from the scene.
///
Future reveal(ThermionEntity entity, String? meshName);
Future removeEntityFromScene(ThermionEntity entity);
///
/// If [meshName] is provided, hide the node [meshName] under [entity], otherwise hide the root node for [entity].
/// The entity still exists in memory, but is no longer being rendered into the scene. Call [reveal] to re-commence rendering.
///
Future hide(ThermionEntity entity, String? meshName);
///
/// Used to select the entity in the scene at the given viewport coordinates.
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [pickResult] stream to receive the results of this method.
/// Hit test the viewport at the given coordinates. If the coordinates intersect
/// with a renderable entity, [resultHandler] will be called.
/// This is asynchronous and will require 2-3 frames to complete (so ensure you are calling render())
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
///
Future pick(int x, int y);
Future pick(int x, int y, void Function(PickResult) resultHandler);
///
/// Retrieves the name assigned to the given ThermionEntity (usually corresponds to the glTF mesh name).
@@ -703,23 +648,16 @@ abstract class ThermionViewer {
String? getNameForEntity(ThermionEntity entity);
///
/// Returns all child entities under [parent].
/// Returns all child entities under [asset].
///
Future<List<ThermionEntity>> getChildEntities(
ThermionEntity parent, bool renderableOnly);
Future<List<ThermionEntity>> getChildEntities(covariant ThermionAsset asset);
///
/// Finds the child entity named [childName] associated with the given parent.
/// Usually, [parent] will be the return value from [loadGlb]/[loadGltf] and [childName] will be the name of a node/mesh.
///
Future<ThermionEntity> getChildEntity(
ThermionEntity parent, String childName);
///
/// List the name of all child entities under the given entity.
///
Future<List<String>> getChildEntityNames(ThermionEntity entity,
{bool renderableOnly = true});
Future<ThermionEntity?> getChildEntity(
covariant ThermionAsset asset, String childName);
///
/// An [entity] will only be animatable after an animation component is attached.
@@ -750,8 +688,9 @@ abstract class ThermionViewer {
/// Creates a (renderable) entity with the specified geometry and adds to the scene.
/// If [keepData] is true, the source data will not be released.
///
Future createGeometry(Geometry geometry,
{MaterialInstance? materialInstance, bool keepData = false});
Future<ThermionAsset> createGeometry(Geometry geometry,
{covariant List<MaterialInstance>? materialInstances,
bool keepData = false});
///
/// Gets the parent entity of [entity]. Returns null if the entity has no parent.
@@ -783,7 +722,8 @@ abstract class ThermionViewer {
///
/// The gizmo for translating/rotating objects. Only one gizmo can be active for a given view.
///
Future<Gizmo> createGizmo(covariant View view);
Future<GizmoAsset> createGizmo(covariant View view,
GizmoType type);
///
/// Register a callback to be invoked when this viewer is disposed.
@@ -803,34 +743,23 @@ abstract class ThermionViewer {
///
/// Toggles the visibility of the respective layer.
///
Future setLayerVisibility(int layer, bool visible);
Future setLayerVisibility(VisibilityLayers layer, bool visible);
///
/// All renderable entities are assigned a layer mask.
///
/// By calling [setLayerVisibility], all renderable entities allocated to
/// the given layer can be efficiently hidden/revealed.
///
/// By default, all renderable entities are assigned to layer 0 (and this
/// layer is enabled by default). Call [setVisibilityLayer] to change the
/// All renderable entities are assigned a layer mask.
///
/// By calling [setLayerVisibility], all renderable entities allocated to
/// the given layer can be efficiently hidden/revealed.
///
/// By default, all renderable entities are assigned to layer 0 (and this
/// layer is enabled by default). Call [setVisibilityLayer] to change the
/// layer for the specified entity.
///
/// Note that we currently also assign gizmos to layer 1 (enabled by default)
/// and the world grid to layer 2 (disabled by default). We suggest you avoid
///
/// Note that we currently also assign gizmos to layer 1 (enabled by default)
/// and the world grid to layer 2 (disabled by default). We suggest you avoid
/// using these layers.
///
Future setVisibilityLayer(ThermionEntity entity, int layer);
///
/// Renders an outline around [entity] with the given color.
///
Future setStencilHighlight(ThermionEntity entity,
{double r = 1.0, double g = 0.0, double b = 0.0});
///
/// Removes the outline around [entity]. Noop if there was no highlight.
///
Future removeStencilHighlight(ThermionEntity entity);
Future setVisibilityLayer(ThermionEntity entity, VisibilityLayers layer);
///
/// Decodes the specified image data and creates a texture.
@@ -908,7 +837,7 @@ abstract class ThermionViewer {
///
///
///
Future<MaterialInstance?> getMaterialInstanceAt(
Future<MaterialInstance> getMaterialInstanceAt(
ThermionEntity entity, int index);
///

View File

@@ -8,7 +8,7 @@ import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart';
import 'dart:async';
import 'package:animation_tools_dart/animation_tools_dart.dart';
import 'events.dart';
import 'shared_types/camera.dart';
class ThermionViewerStub extends ThermionViewer {
@@ -18,16 +18,6 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
{int skinIndex = 0,
double fadeInInSecs = 0.0,
double fadeOutInSecs = 0.0,
double maxDelta = 1.0}) {
// TODO: implement addBoneAnimation
throw UnimplementedError();
}
@override
Future addCollisionComponent(ThermionEntity entity,
{void Function(int entityId1, int entityId2)? callback,
@@ -77,44 +67,12 @@ class ThermionViewerStub extends ThermionViewer {
}
@override
Future<ThermionEntity> createInstance(ThermionEntity entity) {
// TODO: implement createInstance
throw UnimplementedError();
}
@override
Future dispose() {
// TODO: implement dispose
throw UnimplementedError();
}
@override
Future<double> getAnimationDuration(
ThermionEntity entity, int animationIndex) {
// TODO: implement getAnimationDuration
throw UnimplementedError();
}
@override
Future<List<String>> getAnimationNames(ThermionEntity entity) {
// TODO: implement getAnimationNames
throw UnimplementedError();
}
@override
Future<ThermionEntity> getBone(ThermionEntity parent, int boneIndex,
{int skinIndex = 0}) {
// TODO: implement getBone
throw UnimplementedError();
}
@override
Future<List<String>> getBoneNames(ThermionEntity entity,
{int skinIndex = 0}) {
// TODO: implement getBoneNames
throw UnimplementedError();
}
@override
Future<double> getCameraCullingFar() {
@@ -170,58 +128,12 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future<List<ThermionEntity>> getChildEntities(
ThermionEntity parent, bool renderableOnly) {
// TODO: implement getChildEntities
throw UnimplementedError();
}
@override
Future<ThermionEntity> getChildEntity(
ThermionEntity parent, String childName) {
// TODO: implement getChildEntity
throw UnimplementedError();
}
@override
Future<List<String>> getChildEntityNames(ThermionEntity entity,
{bool renderableOnly = true}) {
// TODO: implement getChildEntityNames
throw UnimplementedError();
}
@override
Future<int> getInstanceCount(ThermionEntity entity) {
// TODO: implement getInstanceCount
throw UnimplementedError();
}
@override
Future<List<ThermionEntity>> getInstances(ThermionEntity entity) {
// TODO: implement getInstances
throw UnimplementedError();
}
@override
Future<Matrix4> getInverseBindMatrix(ThermionEntity parent, int boneIndex,
{int skinIndex = 0}) {
// TODO: implement getInverseBindMatrix
throw UnimplementedError();
}
@override
Future<Matrix4> getLocalTransform(ThermionEntity entity) {
// TODO: implement getLocalTransform
throw UnimplementedError();
}
@override
Future<List<String>> getMorphTargetNames(
ThermionEntity entity, ThermionEntity childEntity) {
// TODO: implement getMorphTargetNames
throw UnimplementedError();
}
@override
String? getNameForEntity(ThermionEntity entity) {
@@ -241,11 +153,6 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future hide(ThermionEntity entity, String? meshName) {
// TODO: implement hide
throw UnimplementedError();
}
@override
// TODO: implement initialized
@@ -296,27 +203,6 @@ class ThermionViewerStub extends ThermionViewer {
// TODO: implement pickResult
Stream<FilamentPickResult> get pickResult => throw UnimplementedError();
@override
Future playAnimation(ThermionEntity entity, int index,
{bool loop = false,
bool reverse = false,
bool replaceActive = true,
double crossfade = 0.0,
double startOffset=0.0}) {
// TODO: implement playAnimation
throw UnimplementedError();
}
@override
Future playAnimationByName(ThermionEntity entity, String name,
{bool loop = false,
bool reverse = false,
bool replaceActive = true,
double crossfade = 0.0}) {
// TODO: implement playAnimationByName
throw UnimplementedError();
}
@override
Future queuePositionUpdate(
ThermionEntity entity, double x, double y, double z,
@@ -352,12 +238,6 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future removeEntity(ThermionEntity entity) {
// TODO: implement removeEntity
throw UnimplementedError();
}
@override
Future removeIbl() {
// TODO: implement removeIbl
@@ -381,17 +261,6 @@ class ThermionViewerStub extends ThermionViewer {
// TODO: implement rendering
bool get rendering => throw UnimplementedError();
@override
Future resetBones(ThermionEntity entity) {
// TODO: implement resetBones
throw UnimplementedError();
}
@override
Future reveal(ThermionEntity entity, String? meshName) {
// TODO: implement reveal
throw UnimplementedError();
}
@override
Future rotateEnd() {
@@ -417,12 +286,7 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future setAnimationFrame(
ThermionEntity entity, int index, int animationFrame) {
// TODO: implement setAnimationFrame
throw UnimplementedError();
}
@override
Future setAntiAliasing(bool msaa, bool fxaa, bool taa) {
@@ -546,24 +410,6 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future clearMorphAnimationData(ThermionEntity entity) {
throw UnimplementedError();
}
@override
Future setMorphAnimationData(
ThermionEntity entity, MorphAnimationData animation,
{List<String>? targetMeshNames}) {
// TODO: implement setMorphAnimationData
throw UnimplementedError();
}
@override
Future setMorphTargetWeights(ThermionEntity entity, List<double> weights) {
// TODO: implement setMorphTargetWeights
throw UnimplementedError();
}
@override
Future setParent(ThermionEntity child, ThermionEntity parent, { bool preserveScaling = false}) {
@@ -644,17 +490,6 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future stopAnimation(ThermionEntity entity, int animationIndex) {
// TODO: implement stopAnimation
throw UnimplementedError();
}
@override
Future stopAnimationByName(ThermionEntity entity, String name) {
// TODO: implement stopAnimationByName
throw UnimplementedError();
}
@override
Future testCollisions(ThermionEntity entity) {
@@ -811,18 +646,7 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future<ThermionEntity> loadGlb(String path, {int numInstances = 1, bool keepData = false}) {
// TODO: implement loadGlb
throw UnimplementedError();
}
@override
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath, {bool keepData = false}) {
// TODO: implement loadGltf
throw UnimplementedError();
}
@override
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, int materialIndex, double value) {
@@ -836,9 +660,6 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
// TODO: implement sceneUpdated
Stream<SceneUpdateEvent> get sceneUpdated => throw UnimplementedError();
@override
Future<ThermionEntity> addDirectLight(DirectLight light) {
@@ -882,14 +703,6 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future createGeometry(Geometry geometry, {MaterialInstance? materialInstance, bool keepData = false}) {
// TODO: implement createGeometry
throw UnimplementedError();
}
@override
Future setMaterialPropertyInt(ThermionEntity entity, String propertyName, int materialIndex, int value) {
// TODO: implement setMaterialPropertyInt
@@ -1052,12 +865,6 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0, bool loadResourcesAsync= false}) {
// TODO: implement loadGlbFromBuffer
throw UnimplementedError();
}
@override
Future destroyRenderTarget(covariant RenderTarget renderTarget) {
// TODO: implement destroyRenderTarget
@@ -1081,6 +888,189 @@ class ThermionViewerStub extends ThermionViewer {
// TODO: implement getRenderableBoundingBox
throw UnimplementedError();
}
@override
Future pick(int x, int y) {
// TODO: implement pick
throw UnimplementedError();
}
@override
Future<ThermionAsset> createInstance(covariant ThermionAsset asset, {covariant List<MaterialInstance>? materialInstances = null}) {
// TODO: implement createInstance
throw UnimplementedError();
}
@override
Future<int> getInstanceCount(covariant ThermionAsset entity) {
// TODO: implement getInstanceCount
throw UnimplementedError();
}
@override
Future<List<ThermionEntity>> getInstances(covariant ThermionAsset entity) {
// TODO: implement getInstances
throw UnimplementedError();
}
@override
Future hide(ThermionEntity entity) {
// TODO: implement hide
throw UnimplementedError();
}
@override
Future<ThermionAsset> loadGlb(String path, {int numInstances = 1, bool keepData = false}) {
// TODO: implement loadGlb
throw UnimplementedError();
}
@override
Future<ThermionAsset> loadGltf(String path, String relativeResourcePath, {bool keepData = false}) {
// TODO: implement loadGltf
throw UnimplementedError();
}
@override
Future reveal(ThermionEntity entity) {
// TODO: implement reveal
throw UnimplementedError();
}
@override
Future<ThermionAsset> loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0, bool loadResourcesAsync=false}) {
// TODO: implement loadGlbFromBuffer
throw UnimplementedError();
}
@override
Future addBoneAnimation(ThermionAsset asset, BoneAnimationData animation, {int skinIndex = 0, double fadeInInSecs = 0.0, double fadeOutInSecs = 0.0, double maxDelta = 1.0}) {
// TODO: implement addBoneAnimation
throw UnimplementedError();
}
@override
Future<double> getAnimationDuration(covariant ThermionAsset asset, int animationIndex) {
// TODO: implement getAnimationDuration
throw UnimplementedError();
}
@override
Future<List<String>> getAnimationNames(covariant ThermionAsset asset) {
// TODO: implement getAnimationNames
throw UnimplementedError();
}
@override
Future<ThermionEntity> getBone(covariant ThermionAsset asset, int boneIndex, {int skinIndex = 0}) {
// TODO: implement getBone
throw UnimplementedError();
}
@override
Future<List<String>> getBoneNames(covariant ThermionAsset asset, {int skinIndex = 0}) {
// TODO: implement getBoneNames
throw UnimplementedError();
}
@override
Future<List<ThermionEntity>> getChildEntities(covariant ThermionAsset asset) {
// TODO: implement getChildEntities
throw UnimplementedError();
}
@override
Future<ThermionEntity?> getChildEntity(covariant ThermionAsset asset, String childName) {
// TODO: implement getChildEntity
throw UnimplementedError();
}
@override
Future<Matrix4> getInverseBindMatrix(covariant ThermionAsset asset, int boneIndex, {int skinIndex = 0}) {
// TODO: implement getInverseBindMatrix
throw UnimplementedError();
}
@override
Future<List<String>> getMorphTargetNames(covariant ThermionAsset asset, ThermionEntity childEntity) {
// TODO: implement getMorphTargetNames
throw UnimplementedError();
}
@override
Future playAnimationByName(covariant ThermionAsset asset, String name, {bool loop = false, bool reverse = false, bool replaceActive = true, double crossfade = 0.0}) {
// TODO: implement playAnimationByName
throw UnimplementedError();
}
@override
Future setAnimationFrame(covariant ThermionAsset asset, int index, int animationFrame) {
// TODO: implement setAnimationFrame
throw UnimplementedError();
}
@override
Future setMorphAnimationData(ThermionAsset asset, MorphAnimationData animation, {List<String>? targetMeshNames}) {
// TODO: implement setMorphAnimationData
throw UnimplementedError();
}
@override
Future stopAnimation(covariant ThermionAsset asset, int animationIndex) {
// TODO: implement stopAnimation
throw UnimplementedError();
}
@override
Future stopAnimationByName(covariant ThermionAsset asset, String name) {
// TODO: implement stopAnimationByName
throw UnimplementedError();
}
@override
Future playAnimation(ThermionAsset asset, int index, {bool loop = false, bool reverse = false, bool replaceActive = true, double crossfade = 0.0, double startOffset = 0.0}) {
// TODO: implement playAnimation
throw UnimplementedError();
}
@override
Future removeEntity(ThermionAsset asset) {
// TODO: implement removeEntity
throw UnimplementedError();
}
@override
Future resetBones(ThermionAsset asset) {
// TODO: implement resetBones
throw UnimplementedError();
}
@override
Future clearMorphAnimationData(ThermionEntity entity) {
// TODO: implement clearMorphAnimationData
throw UnimplementedError();
}
@override
Future<ThermionAsset> createGeometry(Geometry geometry, {covariant List<MaterialInstance>? materialInstances, bool keepData = false}) {
// TODO: implement createGeometry
throw UnimplementedError();
}
@override
Future setGltfAnimationFrame(covariant ThermionAsset asset, int index, int animationFrame) {
// TODO: implement setGltfAnimationFrame
throw UnimplementedError();
}
@override
Future setMorphTargetWeights(ThermionEntity entity, List<double> weights) {
// TODO: implement setMorphTargetWeights
throw UnimplementedError();
}
}

View File

@@ -4,17 +4,6 @@ class ThermionWasmMaterialInstance extends MaterialInstance {
final int pointer;
ThermionWasmMaterialInstance(this.pointer);
@override
Future setDepthCullingEnabled(bool enabled) {
// TODO: implement setDepthCullingEnabled
throw UnimplementedError();
}
@override
Future setDepthWriteEnabled(bool enabled) {
// TODO: implement setDepthWriteEnabled
throw UnimplementedError();
}
@override
Future setParameterFloat2(String name, double x, double y) {
@@ -45,4 +34,64 @@ class ThermionWasmMaterialInstance extends MaterialInstance {
// TODO: implement setParameterInt
throw UnimplementedError();
}
@override
Future setDepthCullingEnabled(enabled) {
// TODO: implement setDepthCullingEnabled
throw UnimplementedError();
}
@override
Future setDepthWriteEnabled(enabled) {
// TODO: implement setDepthWriteEnabled
throw UnimplementedError();
}
@override
Future setStencilCompareFunction(SamplerCompareFunction func, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilCompareFunction
throw UnimplementedError();
}
@override
Future setStencilOpDepthFail(StencilOperation op, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilOpDepthFail
throw UnimplementedError();
}
@override
Future setStencilOpDepthStencilPass(StencilOperation op, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilOpDepthStencilPass
throw UnimplementedError();
}
@override
Future setStencilOpStencilFail(StencilOperation op, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilOpStencilFail
throw UnimplementedError();
}
@override
Future setStencilReferenceValue(int value, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilReferenceValue
throw UnimplementedError();
}
@override
Future<bool> isStencilWriteEnabled() {
// TODO: implement isStencilWriteEnabled
throw UnimplementedError();
}
@override
Future setCullingMode(CullingMode cullingMode) {
// TODO: implement setCullingMode
throw UnimplementedError();
}
@override
Future setStencilWriteEnabled(bool enabled) {
// TODO: implement setStencilWriteEnabled
throw UnimplementedError();
}
}

View File

@@ -33,7 +33,7 @@
#include <chrono>
#include "ResourceBuffer.hpp"
#include "SceneManager.hpp"
#include "scene/SceneManager.hpp"
#include "ThreadPool.hpp"
namespace thermion
@@ -65,9 +65,6 @@ namespace thermion
void rotateIbl(const math::mat3f &matrix);
void createIbl(float r, float g, float b, float intensity);
void removeEntity(EntityId asset);
void clearEntities();
void render(
uint64_t frameTimeInNanos
);
@@ -98,15 +95,6 @@ namespace thermion
void clearBackgroundImage();
void setBackgroundImagePosition(float x, float y, bool clamp, uint32_t width, uint32_t height);
typedef void (*PickCallback)(EntityId entityId, int x, int y, View *view, float depth, float fragX, float fragY, float fragZ);
///
/// Returns true if the specified entity is a gizmo, grid or background image entity.
///
bool isNonPickableEntity(EntityId entityId);
void pick(View *view, uint32_t x, uint32_t y, PickCallback callback);
Engine* getEngine() {
return _engine;
}

View File

@@ -1,111 +0,0 @@
#pragma once
#include <utils/Entity.h>
#include <filament/Engine.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/Scene.h>
#include <filament/Camera.h>
#include <filament/View.h>
#include <filament/Viewport.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/FilamentInstance.h>
#include <gltfio/ResourceLoader.h>
#include <filament/IndexBuffer.h>
#include <filament/InstanceBuffer.h>
#include "ThermionDartApi.h"
namespace thermion {
using namespace filament;
using namespace utils;
class Gizmo {
enum Axis { X, Y, Z};
public:
Gizmo(Engine *engine, View *view, Scene *scene, Material* material);
~Gizmo();
typedef void (*PickCallback)(EntityId entityId, uint32_t x, uint32_t y, View *view);
Entity x() {
return _entities[0];
};
Entity y() {
return _entities[1];
};
Entity z() {
return _entities[2];
};
Entity center() {
return _entities[3];
};
bool isActive() {
return _isActive;
}
void pick(uint32_t x, uint32_t y, PickCallback callback);
bool isGizmoEntity(Entity entity);
void setVisibility(bool visible);
private:
class PickCallbackHandler {
public:
PickCallbackHandler(Gizmo* gizmo, PickCallback callback) : _gizmo(gizmo), _callback(callback) {};
void handle(filament::View::PickingQueryResult const &result) {
auto x = static_cast<int32_t>(result.fragCoords.x);
auto y= static_cast<int32_t>(result.fragCoords.y);
for(int i = 0; i < 7; i++) {
if(_gizmo->_entities[i] == result.renderable) {
if(i < 4) {
return;
}
_gizmo->highlight(_gizmo->_entities[i - 4]);
_callback(Entity::smuggle(_gizmo->_entities[i - 4]), x, y, _gizmo->_view);
return;
}
}
_gizmo->unhighlight();
_callback(0, x, y, _gizmo->_view);
delete(this);
}
private:
Gizmo* _gizmo;
PickCallback _callback;
};
void createTransparentRectangles();
void highlight(Entity entity);
void unhighlight();
Engine *_engine;
Scene *_scene;
View *_view;
Material* _material;
utils::Entity _entities[7] = { utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity() };
MaterialInstance* _materialInstances[7];
math::float4 inactiveColors[3] {
math::float4 { 1.0f, 0.0f, 0.0f, 0.5f },
math::float4 { 0.0f, 1.0f, 0.0f, 0.5f },
math::float4 { 0.0f, 0.0f, 1.0f, 0.5f },
};
math::float4 activeColors[3] {
math::float4 { 1.0f, 0.0f, 0.0f, 1.0f },
math::float4 { 0.0f, 1.0f, 0.0f, 1.0f },
math::float4 { 0.0f, 0.0f, 1.0f, 1.0f },
};
bool _isActive = true;
};
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include <math/mat4.h>
#include "APIBoundaryTypes.h"
#include "c_api/APIBoundaryTypes.h"
namespace thermion {

View File

@@ -1,365 +0,0 @@
#pragma once
#include <mutex>
#include <vector>
#include <memory>
#include <map>
#include <set>
#include <filament/Scene.h>
#include <filament/Camera.h>
#include <filament/View.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/FilamentInstance.h>
#include <gltfio/ResourceLoader.h>
#include <filament/IndexBuffer.h>
#include <filament/InstanceBuffer.h>
#include <utils/NameComponentManager.h>
#include "tsl/robin_map.h"
#include "APIBoundaryTypes.h"
#include "CustomGeometry.hpp"
#include "Gizmo.hpp"
#include "GridOverlay.hpp"
#include "ResourceBuffer.hpp"
#include "components/CollisionComponentManager.hpp"
#include "components/AnimationComponentManager.hpp"
namespace thermion
{
typedef int32_t EntityId;
using namespace filament;
using namespace filament::gltfio;
using namespace utils;
using std::string;
using std::unique_ptr;
using std::vector;
class SceneManager
{
public:
SceneManager(
const ResourceLoaderWrapperImpl *const loader,
Engine *engine,
Scene *scene,
const char *uberArchivePath,
Camera* mainCamera);
~SceneManager();
enum LAYERS {
DEFAULT_ASSETS = 0,
BACKGROUND = 6,
OVERLAY = 7,
};
class HighlightOverlay {
public:
HighlightOverlay(EntityId id, SceneManager* const sceneManager, Engine* const engine, float r, float g, float b);
~HighlightOverlay();
bool isValid() {
return !_entity.isNull();
}
private:
MaterialInstance* _highlightMaterialInstance = nullptr;
bool _isGeometryEntity = false;
bool _isGltfAsset = false;
FilamentInstance* _newInstance = nullptr;
Entity _entity;
Engine* const _engine;
SceneManager* const _sceneManager;
};
////
/// @brief Load the glTF file from the specified path and adds all entities to the scene.
/// @param uri the path to the asset. Should be either asset:// (representing a Flutter asset), or file:// (representing a filesystem file).
/// @param relativeResourcePath the (relative) path to the asset's resources.
/// @return the glTF entity.
///
EntityId loadGltf(const char *uri, const char *relativeResourcePath, bool keepData = false);
////
/// @brief Load the GLB from the specified path, optionally creating multiple instances.
/// @param uri the path to the asset. Should be either asset:// (representing a Flutter asset), or file:// (representing a filesystem file).
/// @param numInstances the number of instances to create.
/// @return an Entity representing the FilamentAsset associated with the loaded FilamentAsset.
///
EntityId loadGlb(const char *uri, int numInstances, bool keepData);
EntityId loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0, bool loadResourcesAsync = false);
EntityId createInstance(EntityId entityId);
void remove(EntityId entity);
void destroyAll();
unique_ptr<vector<string>> getAnimationNames(EntityId entity);
float getAnimationDuration(EntityId entity, int animationIndex);
unique_ptr<vector<string>> getMorphTargetNames(EntityId assetEntityId, EntityId childEntity);
unique_ptr<vector<string>> getBoneNames(EntityId assetEntityId, EntityId childEntity);
void transformToUnitCube(EntityId e);
inline void updateTransform(EntityId e);
void setScale(EntityId e, float scale);
void setPosition(EntityId e, float x, float y, float z);
void setRotation(EntityId e, float rads, float x, float y, float z, float w);
void queueTransformUpdates(EntityId* entities, math::mat4* transforms, int numEntities);
void queueRelativePositionUpdateWorldAxis(EntityId entity, float viewportCoordX, float viewportCoordY, float x, float y, float z);
void queueRelativePositionUpdateFromViewportVector(View* view, EntityId entityId, float viewportCoordX, float viewportCoordY);
const utils::Entity *getCameraEntities(EntityId e);
size_t getCameraEntityCount(EntityId e);
const utils::Entity *getLightEntities(EntityId e) noexcept;
size_t getLightEntityCount(EntityId e) noexcept;
void updateAnimations();
void updateTransforms();
void testCollisions(EntityId entity);
bool setMaterialColor(EntityId e, const char *meshName, int materialInstance, const float r, const float g, const float b, const float a);
bool setMorphAnimationBuffer(
EntityId entityId,
const float *const morphData,
const uint32_t *const morphIndices,
int numMorphTargets,
int numFrames,
float frameLengthInMs);
void clearMorphAnimationBuffer(
EntityId entityId);
bool setMorphTargetWeights(EntityId entityId, const float *const weights, int count);
math::mat4f getLocalTransform(EntityId entityId);
math::mat4f getWorldTransform(EntityId entityId);
EntityId getBone(EntityId entityId, int skinIndex, int boneIndex);
math::mat4f getInverseBindMatrix(EntityId entityId, int skinIndex, int boneIndex);
/// @brief Set the local transform for the bone at boneIndex/skinIndex in the given entity.
/// @param entityId the parent entity
/// @param entityName the name of the mesh under entityId for which the bone will be set.
/// @param skinIndex the index of the joint skin. Currently only 0 is supported.
/// @param boneName the name of the bone
/// @param transform the 4x4 matrix representing the local transform for the bone
/// @return true if the transform was successfully set, false otherwise
bool setBoneTransform(EntityId entityId, int skinIndex, int boneIndex, math::mat4f transform);
/// @brief Immediately start animating the bone at [boneIndex] under the parent instance [entity] at skin [skinIndex].
/// @param entity the mesh entity to animate
/// @param frameData frame data as quaternions
/// @param numFrames the number of frames
/// @param boneName the name of the bone to animate
/// @param frameLengthInMs the length of each frame in ms
/// @return true if the bone animation was successfully enqueued
bool addBoneAnimation(
EntityId parent,
int skinIndex,
int boneIndex,
const float *const frameData,
int numFrames,
float frameLengthInMs,
float fadeOutInSecs,
float fadeInInSecs,
float maxDelta
);
std::unique_ptr<std::vector<math::mat4f>> getBoneRestTranforms(EntityId entityId, int skinIndex);
void resetBones(EntityId entityId);
bool setTransform(EntityId entityId, math::mat4f transform);
bool setTransform(EntityId entityId, math::mat4 transform);
bool updateBoneMatrices(EntityId entityId);
void playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f, float startOffset = 0.0f);
void stopAnimation(EntityId e, int index);
void setMorphTargetWeights(const char *const entityName, float *weights, int count);
Texture* createTexture(const uint8_t* data, size_t length, const char* name);
bool applyTexture(EntityId entityId, Texture *texture, const char* slotName, int materialIndex);
void destroyTexture(Texture* texture);
void setAnimationFrame(EntityId entity, int animationIndex, int animationFrame);
bool hide(EntityId entity, const char *meshName);
bool reveal(EntityId entity, const char *meshName);
const char *getNameForEntity(EntityId entityId);
utils::Entity findChildEntityByName(
EntityId entityId,
const char *entityName);
int getEntityCount(EntityId entity, bool renderableOnly);
void getEntities(EntityId entity, bool renderableOnly, EntityId *out);
const char *getEntityNameAt(EntityId entity, int index, bool renderableOnly);
void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
void removeCollisionComponent(EntityId entityId);
EntityId getParent(EntityId child);
EntityId getAncestor(EntityId child);
void setParent(EntityId child, EntityId parent, bool preserveScaling);
bool addAnimationComponent(EntityId entity);
void removeAnimationComponent(EntityId entity);
/// @brief renders an outline around the specified entity.
///
///
void setStencilHighlight(EntityId entity, float r, float g, float b);
/// @brief removes the outline around the specified entity.
///
///
void removeStencilHighlight(EntityId entity);
/// @brief returns the number of instances of the FilamentAsset represented by the given entity.
/// @param entityId
/// @return the number of instances
int getInstanceCount(EntityId entityId);
/// @brief returns an array containing all instances of the FilamentAsset represented by the given entity.
/// @param entityId
void getInstances(EntityId entityId, EntityId *out);
///
/// Sets the draw priority for the given entity. See RenderableManager.h for more details.
///
void setPriority(EntityId entity, int priority);
/// @brief returns the 2D min/max viewport coordinates of the bounding box for the specified enitty;
/// @param out a pointer large enough to store four floats (the min/max coordinates of the bounding box)
/// @return
///
Aabb2 getScreenSpaceBoundingBox(View* view, EntityId entity);
/// @brief returns the 3D bounding box of the renderable instance for the given entity.
/// @return the bounding box
///
Aabb3 getRenderableBoundingBox(EntityId entity);
///
/// Creates an entity with the specified geometry/material/normals and adds to the scene.
/// If [keepData] is true, stores
///
EntityId createGeometry(
float *vertices,
uint32_t numVertices,
float *normals,
uint32_t numNormals,
float *uvs,
uint32_t numUvs,
uint16_t *indices,
uint32_t numIndices,
filament::RenderableManager::PrimitiveType primitiveType = RenderableManager::PrimitiveType::TRIANGLES,
MaterialInstance* materialInstance = nullptr,
bool keepData = false
);
friend class FilamentViewer;
gltfio::MaterialProvider * const unlitMaterialProvider() {
return _unlitMaterialProvider;
}
bool isGeometryInstance(EntityId entity) {
return std::find(_geometryInstances.begin(), _geometryInstances.end(), entity) != _geometryInstances.end();
}
bool isGeometryEntity(EntityId entity) {
return _geometry.find(entity) != _geometry.end();
}
CustomGeometry* const getGeometry(EntityId entityId) {
return _geometry[entityId].get();
}
bool isGltfAsset(EntityId entity) {
return getAssetByEntityId(entity) != nullptr;
}
gltfio::FilamentInstance *getInstanceByEntityId(EntityId entityId);
gltfio::FilamentAsset *getAssetByEntityId(EntityId entityId);
gltfio::FilamentInstance *createGltfAssetInstance(FilamentAsset* asset) {
return _assetLoader->createInstance(asset);
}
MaterialInstance* getMaterialInstanceAt(EntityId entityId, int materialIndex);
void setMaterialProperty(EntityId entity, int materialIndex, const char* property, float value);
void setMaterialProperty(EntityId entity, int materialIndex, const char* property, int32_t value);
void setMaterialProperty(EntityId entityId, int materialIndex, const char* property, filament::math::float4& value);
MaterialInstance* createUbershaderMaterialInstance(MaterialKey key);
void destroy(MaterialInstance* materialInstance);
gltfio::MaterialProvider* getUbershaderProvider() {
return _ubershaderProvider;
}
MaterialInstance* createUnlitFixedSizeMaterialInstance();
MaterialInstance* createUnlitMaterialInstance();
void setVisibilityLayer(EntityId entityId, int layer);
Camera* createCamera();
void destroyCamera(Camera* camera);
size_t getCameraCount();
Camera* getCameraAt(size_t index);
Gizmo *createGizmo(View *view, Scene *scene);
bool isGizmoEntity(utils::Entity entity);
Scene* getScene() {
return _scene;
}
private:
gltfio::AssetLoader *_assetLoader = nullptr;
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
Engine *_engine = nullptr;
Scene *_scene = nullptr;
Camera* _mainCamera;
gltfio::MaterialProvider *_ubershaderProvider = nullptr;
gltfio::MaterialProvider *_unlitMaterialProvider = nullptr;
gltfio::ResourceLoader *_gltfResourceLoader = nullptr;
gltfio::TextureProvider *_stbDecoder = nullptr;
gltfio::TextureProvider *_ktxDecoder = nullptr;
std::mutex _mutex;
std::mutex _stencilMutex;
std::vector<MaterialInstance*> _materialInstances;
Material* _gizmoMaterial = nullptr;
utils::NameComponentManager *_ncm;
tsl::robin_map<
EntityId,
gltfio::FilamentInstance *>
_instances;
tsl::robin_map<EntityId, gltfio::FilamentAsset *> _assets;
tsl::robin_map<EntityId, unique_ptr<CustomGeometry>> _geometry;
std::vector<EntityId> _geometryInstances;
tsl::robin_map<EntityId, unique_ptr<HighlightOverlay>> _highlighted;
tsl::robin_map<EntityId, math::mat4> _transformUpdates;
std::set<Texture*> _textures;
std::vector<Camera*> _cameras;
AnimationComponentManager *_animationComponentManager = nullptr;
CollisionComponentManager *_collisionComponentManager = nullptr;
utils::Entity findEntityByName(
const gltfio::FilamentInstance *instance,
const char *entityName);
GridOverlay* _gridOverlay = nullptr;
};
}

View File

@@ -1,18 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include "ThermionDartApi.h"
#include "TGizmo.h"
typedef void (*GizmoPickCallback)(EntityId entityId, uint32_t x, uint32_t y, TView* view);
EMSCRIPTEN_KEEPALIVE void Gizmo_pick(TGizmo *tGizmo, uint32_t x, uint32_t y, GizmoPickCallback callback);
EMSCRIPTEN_KEEPALIVE void Gizmo_setVisibility(TGizmo *tGizmo, bool visible);
#ifdef __cplusplus
}
#endif

View File

@@ -1,78 +0,0 @@
#pragma once
#ifdef _WIN32
#ifdef IS_DLL
#define EMSCRIPTEN_KEEPALIVE __declspec(dllimport)
#else
#define EMSCRIPTEN_KEEPALIVE __declspec(dllexport)
#endif
#else
#ifndef EMSCRIPTEN_KEEPALIVE
#define EMSCRIPTEN_KEEPALIVE __attribute__((visibility("default")))
#endif
#endif
// we copy the LLVM <stdbool.h> here rather than including,
// because on Windows it's difficult to pin the exact location which confuses dart ffigen
#ifndef __STDBOOL_H
#define __STDBOOL_H
#define __bool_true_false_are_defined 1
#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L
/* FIXME: We should be issuing a deprecation warning here, but cannot yet due
* to system headers which include this header file unconditionally.
*/
#elif !defined(__cplusplus)
#define bool _Bool
#define true 1
#define false 0
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* Define _Bool as a GNU extension. */
#define _Bool bool
#if defined(__cplusplus) && __cplusplus < 201103L
/* For C++98, define bool, false, true as a GNU extension. */
#define bool bool
#define false false
#define true true
#endif
#endif
#endif /* __STDBOOL_H */
#if defined(__APPLE__) || defined(__EMSCRIPTEN__)
#include <stddef.h>
#endif
typedef struct TMaterialInstance TMaterialInstance;
// copied from SamplerCompareFunc in DriverEnums.h
enum TDepthFunc {
// don't change the enums values
LE = 0, //!< Less or equal
GE, //!< Greater or equal
L, //!< Strictly less than
G, //!< Strictly greater than
E, //!< Equal
NE, //!< Not equal
A, //!< Always. Depth / stencil testing is deactivated.
N //!< Never. The depth / stencil test always fails.
};
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance* materialInstance, bool enabled);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance* materialInstance, bool enabled);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat4(TMaterialInstance* materialInstance, const char* name, double x, double y, double w, double z);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat2(TMaterialInstance* materialInstance, const char* name, double x, double y);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat(TMaterialInstance* materialInstance, const char* name, double value);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterInt(TMaterialInstance* materialInstance, const char* name, int value);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthFunc(TMaterialInstance* materialInstance, TDepthFunc depthFunc);
#ifdef __cplusplus
}
#endif

View File

@@ -1,54 +0,0 @@
#pragma once
#include "APIBoundaryTypes.h"
#include "ResourceBuffer.hpp"
#include "ThermionDartAPIUtils.h"
#include "TCamera.h"
#include "TMaterialInstance.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE TGizmo* SceneManager_createGizmo(TSceneManager *tSceneManager, TView *tView, TScene *tScene);
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_createGeometry(
TSceneManager *sceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance *materialInstance,
bool keepData);
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitMaterialInstance(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitFixedSizeMaterialInstance(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE bool SceneManager_setTransform(TSceneManager *sceneManager, EntityId entityId, const double *const transform);
EMSCRIPTEN_KEEPALIVE void SceneManager_queueTransformUpdates(TSceneManager *sceneManager, EntityId* entities, const double* const transforms, int numEntities);
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_findCameraByName(TSceneManager* tSceneManager, EntityId entity, const char* name);
EMSCRIPTEN_KEEPALIVE void SceneManager_setVisibilityLayer(TSceneManager *tSceneManager, EntityId entity, int layer);
EMSCRIPTEN_KEEPALIVE TScene* SceneManager_getScene(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_loadGlbFromBuffer(TSceneManager *sceneManager, const uint8_t *const, size_t length, bool keepData, int priority, int layer, bool loadResourcesAsync);
EMSCRIPTEN_KEEPALIVE bool SceneManager_setMorphAnimation(
TSceneManager *sceneManager,
EntityId entity,
const float *const morphData,
const uint32_t *const morphIndices,
int numMorphTargets,
int numFrames,
float frameLengthInMs);
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_createCamera(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyCamera(TSceneManager *sceneManager, TCamera* camera);
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getCameraAt(TSceneManager *sceneManager, size_t index);
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyMaterialInstance(TSceneManager *sceneManager, TMaterialInstance *instance);
#ifdef __cplusplus
}
#endif

View File

@@ -1,216 +0,0 @@
#ifndef _FLUTTER_FILAMENT_API_H
#define _FLUTTER_FILAMENT_API_H
#include "APIExport.h"
#include "APIBoundaryTypes.h"
#include "ResourceBuffer.hpp"
#include "ThermionDartAPIUtils.h"
#include "TMaterialInstance.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *const context, const void *const loader, void *const platform, const char *uberArchivePath);
EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE TRenderTarget* Viewer_createRenderTarget(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height);
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *viewer, TRenderTarget* tRenderTarget);
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *viewer, const void *const window);
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *viewer, uint32_t width, uint32_t height);
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *viewer, TSwapChain* swapChain);
EMSCRIPTEN_KEEPALIVE void Viewer_render(
TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
TViewer *viewer,
TView *view,
TSwapChain *swapChain,
uint8_t *pixelBuffer,
void (*callback)(void));
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
TViewer *viewer,
TView *view,
TSwapChain *swapChain,
TRenderTarget *renderTarget,
uint8_t *pixelBuffer,
void (*callback)(void));
EMSCRIPTEN_KEEPALIVE TView* Viewer_createView(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE TView* Viewer_getViewAt(TViewer *viewer, int index);
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView);
EMSCRIPTEN_KEEPALIVE TSwapChain* Viewer_getSwapChainAt(TViewer *tViewer, int index);
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *viewer, TSwapChain *swapChain, TView* view, bool renderable);
EMSCRIPTEN_KEEPALIVE void Viewer_pick(TViewer *viewer, TView* tView, int x, int y, void (*callback)(EntityId entityId, int x, int y, TView *tView, float depth, float fragX, float fragY, float fragZ));
EMSCRIPTEN_KEEPALIVE bool Viewer_isNonPickableEntity(TViewer *viewer, EntityId entityId);
// Engine
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer* viewer);
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine* tEngine, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void Engine_setTransform(TEngine* tEngine, EntityId entity, double4x4 transform);
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight);
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp);
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a);
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath);
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity);
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity);
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix);
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void remove_ibl(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE EntityId add_light(
TViewer *viewer,
uint8_t type,
float colour,
float intensity,
float posX,
float posY,
float posZ,
float dirX,
float dirY,
float dirZ,
float falloffRadius,
float spotLightConeInner,
float spotLightConeOuter,
float sunAngularRadius,
float sunHaloSize,
float sunHaloFallof,
bool shadows);
EMSCRIPTEN_KEEPALIVE void remove_light(TViewer *viewer, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void clear_lights(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, EntityId light, float x, float y, float z);
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, EntityId light, float x, float y, float z);
EMSCRIPTEN_KEEPALIVE EntityId load_glb(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData);
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData);
EMSCRIPTEN_KEEPALIVE EntityId create_instance(TSceneManager *sceneManager, EntityId id);
EMSCRIPTEN_KEEPALIVE int get_instance_count(TSceneManager *sceneManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void get_instances(TSceneManager *sceneManager, EntityId entityId, EntityId *out);
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void set_frame_interval(TViewer *viewer, float interval);
EMSCRIPTEN_KEEPALIVE void apply_weights(
TSceneManager *sceneManager,
EntityId entity,
const char *const entityName,
float *const weights,
int count);
EMSCRIPTEN_KEEPALIVE bool set_morph_target_weights(
TSceneManager *sceneManager,
EntityId entity,
const float *const morphData,
int numWeights);
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_material_instance(TSceneManager *sceneManager, TMaterialKey materialConfig);
EMSCRIPTEN_KEEPALIVE void clear_morph_animation(
TSceneManager *sceneManager,
EntityId entity);
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose(
TSceneManager *sceneManager,
EntityId asset);
EMSCRIPTEN_KEEPALIVE void add_bone_animation(
TSceneManager *sceneManager,
EntityId entity,
int skinIndex,
int boneIndex,
const float *const frameData,
int numFrames,
float frameLengthInMs,
float fadeOutInSecs,
float fadeInInSecs,
float maxDelta);
EMSCRIPTEN_KEEPALIVE void get_local_transform(TSceneManager *sceneManager,
EntityId entityId, float *const);
EMSCRIPTEN_KEEPALIVE void get_rest_local_transforms(TSceneManager *sceneManager,
EntityId entityId, int skinIndex, float *const out, int numBones);
EMSCRIPTEN_KEEPALIVE void get_world_transform(TSceneManager *sceneManager,
EntityId entityId, float *const);
EMSCRIPTEN_KEEPALIVE void get_inverse_bind_matrix(TSceneManager *sceneManager,
EntityId entityId, int skinIndex, int boneIndex, float *const);
EMSCRIPTEN_KEEPALIVE bool set_bone_transform(
TSceneManager *sceneManager,
EntityId entity,
int skinIndex,
int boneIndex,
const float *const transform);
EMSCRIPTEN_KEEPALIVE void play_animation(TSceneManager *sceneManager, EntityId entity, int index, bool loop, bool reverse, bool replaceActive, float crossfade, float startOffset);
EMSCRIPTEN_KEEPALIVE void set_animation_frame(TSceneManager *sceneManager, EntityId entity, int animationIndex, int animationFrame);
EMSCRIPTEN_KEEPALIVE void stop_animation(TSceneManager *sceneManager, EntityId entity, int index);
EMSCRIPTEN_KEEPALIVE int get_animation_count(TSceneManager *sceneManager, EntityId asset);
EMSCRIPTEN_KEEPALIVE void get_animation_name(TSceneManager *sceneManager, EntityId entity, char *const outPtr, int index);
EMSCRIPTEN_KEEPALIVE float get_animation_duration(TSceneManager *sceneManager, EntityId entity, int index);
EMSCRIPTEN_KEEPALIVE int get_bone_count(TSceneManager *sceneManager, EntityId assetEntity, int skinIndex);
EMSCRIPTEN_KEEPALIVE void get_bone_names(TSceneManager *sceneManager, EntityId assetEntity, const char **outPtr, int skinIndex);
EMSCRIPTEN_KEEPALIVE EntityId get_bone(TSceneManager *sceneManager,
EntityId entityId,
int skinIndex,
int boneIndex);
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(TSceneManager *sceneManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void get_morph_target_name(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index);
EMSCRIPTEN_KEEPALIVE int get_morph_target_name_count(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity);
EMSCRIPTEN_KEEPALIVE void remove_entity(TViewer *viewer, EntityId asset);
EMSCRIPTEN_KEEPALIVE void clear_entities(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE bool set_material_color(TSceneManager *sceneManager, EntityId entity, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a);
EMSCRIPTEN_KEEPALIVE void transform_to_unit_cube(TSceneManager *sceneManager, EntityId asset);
EMSCRIPTEN_KEEPALIVE void queue_relative_position_update_world_axis(TSceneManager *sceneManager, EntityId entity, float viewportX, float viewportY, float x, float y, float z);
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *view, EntityId entity, float viewportX, float viewportY);
EMSCRIPTEN_KEEPALIVE void set_position(TSceneManager *sceneManager, EntityId entity, float x, float y, float z);
EMSCRIPTEN_KEEPALIVE void set_rotation(TSceneManager *sceneManager, EntityId entity, float rads, float x, float y, float z, float w);
EMSCRIPTEN_KEEPALIVE void set_scale(TSceneManager *sceneManager, EntityId entity, float scale);
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine *engine, EntityId entity);
EMSCRIPTEN_KEEPALIVE TEntityManager *Engine_getEntityManager(TEngine *engine);
EMSCRIPTEN_KEEPALIVE int hide_mesh(TSceneManager *sceneManager, EntityId entity, const char *meshName);
EMSCRIPTEN_KEEPALIVE int reveal_mesh(TSceneManager *sceneManager, EntityId entity, const char *meshName);
EMSCRIPTEN_KEEPALIVE const char *get_name_for_entity(TSceneManager *sceneManager, const EntityId entityId);
EMSCRIPTEN_KEEPALIVE EntityId find_child_entity_by_name(TSceneManager *sceneManager, const EntityId parent, const char *name);
EMSCRIPTEN_KEEPALIVE int get_entity_count(TSceneManager *sceneManager, const EntityId target, bool renderableOnly);
EMSCRIPTEN_KEEPALIVE void get_entities(TSceneManager *sceneManager, const EntityId target, bool renderableOnly, EntityId *out);
EMSCRIPTEN_KEEPALIVE const char *get_entity_name_at(TSceneManager *sceneManager, const EntityId target, int index, bool renderableOnly);
EMSCRIPTEN_KEEPALIVE void ios_dummy();
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr);
EMSCRIPTEN_KEEPALIVE void add_collision_component(TSceneManager *sceneManager, EntityId entityId, void (*callback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
EMSCRIPTEN_KEEPALIVE void remove_collision_component(TSceneManager *sceneManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE bool add_animation_component(TSceneManager *sceneManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void remove_animation_component(TSceneManager *sceneManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE EntityId get_parent(TSceneManager *sceneManager, EntityId child);
EMSCRIPTEN_KEEPALIVE EntityId get_ancestor(TSceneManager *sceneManager, EntityId child);
EMSCRIPTEN_KEEPALIVE void set_parent(TSceneManager *sceneManager, EntityId child, EntityId parent, bool preserveScaling);
EMSCRIPTEN_KEEPALIVE void test_collisions(TSceneManager *sceneManager, EntityId entity);
EMSCRIPTEN_KEEPALIVE void set_priority(TSceneManager *sceneManager, EntityId entityId, int priority);
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *view, EntityId entity);
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *view, EntityId entity, float *minX, float *minY, float *maxX, float *maxY);
EMSCRIPTEN_KEEPALIVE void set_stencil_highlight(TSceneManager *sceneManager, EntityId entity, float r, float g, float b);
EMSCRIPTEN_KEEPALIVE void remove_stencil_highlight(TSceneManager *sceneManager, EntityId entity);
EMSCRIPTEN_KEEPALIVE void set_material_property_float(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, float value);
EMSCRIPTEN_KEEPALIVE void set_material_property_int(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, int value);
EMSCRIPTEN_KEEPALIVE void set_material_property_float4(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, double4 value);
EMSCRIPTEN_KEEPALIVE void set_material_depth_write(TSceneManager *sceneManager, EntityId entity, int materialIndex, bool enabled);
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer* viewer, EntityId entity,uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight);
EMSCRIPTEN_KEEPALIVE void *const create_texture(TSceneManager *sceneManager, uint8_t *data, size_t length);
EMSCRIPTEN_KEEPALIVE void destroy_texture(TSceneManager *sceneManager, void *const texture);
EMSCRIPTEN_KEEPALIVE void apply_texture_to_material(TSceneManager *sceneManager, EntityId entity, void *const texture, const char *parameterName, int materialIndex);
EMSCRIPTEN_KEEPALIVE TMaterialInstance* get_material_instance_at(TSceneManager *sceneManager, EntityId entity, int materialIndex);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,116 +0,0 @@
#ifndef _DART_FILAMENT_FFI_API_H
#define _DART_FILAMENT_FFI_API_H
#include "ThermionDartApi.h"
#include "TView.h"
#ifdef __cplusplus
namespace thermion {
extern "C"
{
#endif
///
/// This header replicates most of the methods in ThermionDartApi.h.
/// It represents the interface for:
/// - invoking those methods that must be called on the main Filament engine thread
/// - setting up a render loop
///
typedef int32_t EntityId;
typedef void (*FilamentRenderCallback)(void *const owner);
EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread(
void *const context,
void *const platform,
const char *uberArchivePath,
const void *const loader,
void (*renderCallback)(void *const renderCallbackOwner),
void *const renderCallbackOwner,
void (*callback)(TViewer *viewer));
EMSCRIPTEN_KEEPALIVE void Viewer_destroyOnRenderThread(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer, void *const surface, void (*onComplete)(TSwapChain*));
EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer, uint32_t width, uint32_t height, void (*onComplete)(TSwapChain*));
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain* swapChain, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain);
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain, uint8_t* out, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain, TRenderTarget* renderTarget, uint8_t* out, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void(*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void(*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height, void(*onComplete)(TRenderTarget*));
EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping);
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom);
FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
EMSCRIPTEN_KEEPALIVE void set_rendering_render_thread(TViewer *viewer, bool rendering, void(*onComplete)());
EMSCRIPTEN_KEEPALIVE void set_frame_interval_render_thread(TViewer *viewer, float frameInterval);
EMSCRIPTEN_KEEPALIVE void set_background_color_render_thread(TViewer *viewer, const float r, const float g, const float b, const float a);
EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer, const char *path, bool fillHeight, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer, float x, float y, bool clamp);
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer, const char *skyboxPath, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void SceneManager_createGeometryRenderThread(
TSceneManager *sceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance *materialInstance,
bool keepData,
void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, bool loadResourcesAsync, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance*));
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance*));
EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void create_instance_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(TViewer *viewer, EntityId asset, void (*callback)());
EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(TViewer *viewer, void (*callback)());
EMSCRIPTEN_KEEPALIVE void apply_weights_render_thread(
TSceneManager *sceneManager,
EntityId asset,
const char *const entityName,
float *const weights,
int count);
EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(TSceneManager *sceneManager, EntityId asset, int animationIndex, int animationFrame);
EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(TSceneManager *sceneManager, EntityId asset, int index);
EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(TSceneManager *sceneManager, EntityId asset, void (*callback)(int));
EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(TSceneManager *sceneManager, EntityId asset, char *const outPtr, int index, void (*callback)());
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_render_thread(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index, void (*callback)());
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_count_render_thread(TSceneManager *sceneManager, EntityId asset, EntityId childEntity, void (*callback)(int32_t));
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_render_thread(TSceneManager *sceneManager,
EntityId asset,
const float *const morphData,
int numWeights,
void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(TSceneManager *sceneManager,
EntityId asset, void(*callback)(bool));
EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
TSceneManager *sceneManager,
EntityId asset,
int skinIndex,
int boneIndex,
const float *const transform,
void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(TViewer *viewer, bool enabled);
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(TSceneManager *sceneManager, EntityId entityId, void(*callback)());
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight, void(*callback)());
#ifdef __cplusplus
}
}
#endif
#endif // _DART_FILAMENT_FFI_API_H

View File

@@ -15,7 +15,7 @@
#include <vector>
#include <algorithm>
#include "CustomGeometry.hpp"
#include "scene/CustomGeometry.hpp"
namespace thermion {

View File

@@ -6,7 +6,6 @@ extern "C"
#endif
#include <stdint.h>
#include "TMaterialInstance.h"
typedef int32_t EntityId;
typedef struct TCamera TCamera;
@@ -19,6 +18,15 @@ extern "C"
typedef struct TView TView;
typedef struct TGizmo TGizmo;
typedef struct TScene TScene;
typedef struct TTransformManager TTransformManager;
typedef struct TAnimationManager TAnimationManager;
typedef struct TCollisionComponentManager TCollisionComponentManager;
typedef struct TSceneAsset TSceneAsset;
typedef struct TNameComponentManager TNameComponentManager;
typedef struct TMaterialInstance TMaterialInstance;
typedef struct TMaterialProvider TMaterialProvider;
typedef struct TRenderableManager TRenderableManager;
typedef struct TRenderableInstance TRenderableInstance;
struct TMaterialKey {
bool doubleSided;

View File

@@ -0,0 +1,136 @@
#pragma once
#include "APIExport.h"
#include "APIBoundaryTypes.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE void AnimationManager_addAnimationComponent(TAnimationManager *tAnimationManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void AnimationManager_removeAnimationComponent(TAnimationManager *tAnimationManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE bool AnimationManager_setMorphAnimation(
TAnimationManager *tAnimationManager,
EntityId entityId,
const float *const morphData,
const uint32_t *const morphIndices,
int numMorphTargets,
int numFrames,
float frameLengthInMs);
EMSCRIPTEN_KEEPALIVE bool AnimationManager_clearMorphAnimation(TAnimationManager *tAnimationManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void AnimationManager_resetToRestPose(TAnimationManager *tAnimationManager, TSceneAsset *sceneAsset);
EMSCRIPTEN_KEEPALIVE void AnimationManager_addBoneAnimation(
TAnimationManager *tAnimationManager,
TSceneAsset *tSceneAsset,
int skinIndex,
int boneIndex,
const float *const frameData,
int numFrames,
float frameLengthInMs,
float fadeOutInSecs,
float fadeInInSecs,
float maxDelta);
EMSCRIPTEN_KEEPALIVE EntityId AnimationManager_getBone(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int skinIndex,
int boneIndex);
EMSCRIPTEN_KEEPALIVE void AnimationManager_getRestLocalTransforms(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int skinIndex,
float *const out,
int numBones);
EMSCRIPTEN_KEEPALIVE void AnimationManager_getInverseBindMatrix(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int skinIndex,
int boneIndex,
float *const out);
EMSCRIPTEN_KEEPALIVE void AnimationManager_playAnimation(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int index,
bool loop,
bool reverse,
bool replaceActive,
float crossfade,
float startOffset);
EMSCRIPTEN_KEEPALIVE void AnimationManager_stopAnimation(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int index);
// Additional methods found in implementation
EMSCRIPTEN_KEEPALIVE float AnimationManager_getAnimationDuration(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int animationIndex);
EMSCRIPTEN_KEEPALIVE int AnimationManager_getAnimationCount(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset);
EMSCRIPTEN_KEEPALIVE void AnimationManager_getAnimationName(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
char *const outPtr,
int index);
EMSCRIPTEN_KEEPALIVE int AnimationManager_getBoneCount(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int skinIndex);
EMSCRIPTEN_KEEPALIVE void AnimationManager_getBoneNames(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
const char **out,
int skinIndex);
EMSCRIPTEN_KEEPALIVE int AnimationManager_getMorphTargetNameCount(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
EntityId childEntity);
EMSCRIPTEN_KEEPALIVE void AnimationManager_getMorphTargetName(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
EntityId childEntity,
char *const outPtr,
int index);
EMSCRIPTEN_KEEPALIVE bool AnimationManager_updateBoneMatrices(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset);
EMSCRIPTEN_KEEPALIVE bool AnimationManager_setMorphTargetWeights(
TAnimationManager *tAnimationManager,
EntityId entityId,
const float *const morphData,
int numWeights);
EMSCRIPTEN_KEEPALIVE void AnimationManager_setGltfAnimationFrame(
TAnimationManager *tAnimationManager,
TSceneAsset *tSceneAsset,
int animationIndex,
int frame
);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,25 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include <stddef.h>
#include "APIBoundaryTypes.h"
#include "APIExport.h"
#include "TView.h"
enum TGizmoAxis { X, Y, Z };
enum TGizmoPickResultType { AxisX, AxisY, AxisZ, Parent, None };
typedef void (*GizmoPickCallback)(TGizmoPickResultType resultType, float x, float y, float z);
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);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,103 @@
#pragma once
#include "APIBoundaryTypes.h"
#include "APIExport.h"
#ifdef __cplusplus
extern "C"
{
#endif
// copied from SamplerCompareFunc in DriverEnums.h
enum TSamplerCompareFunc
{
// don't change the enums values
LE = 0, //!< Less or equal
GE, //!< Greater or equal
L, //!< Strictly less than
G, //!< Strictly greater than
E, //!< Equal
NE, //!< Not equal
A, //!< Always. Depth / stencil testing is deactivated.
N //!< Never. The depth / stencil test always fails.
};
// StencilOperation equivalent
enum TStencilOperation
{
KEEP = 0, // Keep the current value
ZERO, // Set the value to zero
REPLACE, // Set the value to reference value
INCR, // Increment the current value with saturation
INCR_WRAP, // Increment the current value without saturation
DECR, // Decrement the current value with saturation
DECR_WRAP, // Decrement the current value without saturation
INVERT // Invert the current value
};
// StencilFace equivalent
enum TStencilFace
{
STENCIL_FACE_FRONT = 1,
STENCIL_FACE_BACK = 2,
STENCIL_FACE_FRONT_AND_BACK = 3
};
// Add these enum definitions at the top with the other enums
enum TCullingMode
{
CULLING_MODE_NONE = 0,
CULLING_MODE_FRONT,
CULLING_MODE_BACK,
CULLING_MODE_FRONT_AND_BACK
};
EMSCRIPTEN_KEEPALIVE bool MaterialInstance_isStencilWriteEnabled(TMaterialInstance *materialInstance);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilWrite(TMaterialInstance *materialInstance, bool enabled);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setCullingMode(TMaterialInstance *materialInstance, TCullingMode culling);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance *materialInstance, bool enabled);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance *materialInstance, bool enabled);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat4(TMaterialInstance *materialInstance, const char *name, double x, double y, double w, double z);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat2(TMaterialInstance *materialInstance, const char *name, double x, double y);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat(TMaterialInstance *materialInstance, const char *name, double value);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterInt(TMaterialInstance *materialInstance, const char *name, int value);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthFunc(TMaterialInstance *materialInstance, TSamplerCompareFunc depthFunc);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilOpStencilFail(
TMaterialInstance *materialInstance,
TStencilOperation op,
TStencilFace face);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilOpDepthFail(
TMaterialInstance *materialInstance,
TStencilOperation op,
TStencilFace face);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilOpDepthStencilPass(
TMaterialInstance *materialInstance,
TStencilOperation op,
TStencilFace face);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilCompareFunction(
TMaterialInstance *materialInstance,
TSamplerCompareFunc func,
TStencilFace face);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilReferenceValue(
TMaterialInstance *materialInstance,
uint8_t value,
TStencilFace face);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilReadMask(
TMaterialInstance *materialInstance,
uint8_t mask);
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilWriteMask(
TMaterialInstance *materialInstance,
uint8_t mask);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,14 @@
#pragma once
#include "APIBoundaryTypes.h"
#include "APIExport.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE TMaterialInstance *MaterialProvider_createMaterialInstance(TMaterialProvider *provider, TMaterialKey *key);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,16 @@
#pragma once
#include "APIBoundaryTypes.h"
#include "APIExport.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE const char *NameComponentManager_getName(TNameComponentManager *tNameComponentManager, EntityId entity);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,17 @@
#pragma once
#include "APIExport.h"
#include "APIBoundaryTypes.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE void RenderableManager_setMaterialInstanceAt(TRenderableManager *tRenderableManager, EntityId entityId, int primitiveIndex, TMaterialInstance *tMaterialInstance);
EMSCRIPTEN_KEEPALIVE void RenderableManager_setPriority(TRenderableManager *tRenderableManager, EntityId entityId, int priority);
EMSCRIPTEN_KEEPALIVE TMaterialInstance *RenderableManager_getMaterialInstanceAt(TRenderableManager *tRenderableManager, EntityId entityId, int primitiveIndex);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,27 @@
#pragma once
#include <utils/Entity.h>
#include "APIExport.h"
#include "APIBoundaryTypes.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE void SceneAsset_addToScene(TSceneAsset *tSceneAsset, TScene *tScene);
EMSCRIPTEN_KEEPALIVE EntityId SceneAsset_getEntity(TSceneAsset *tSceneAsset);
EMSCRIPTEN_KEEPALIVE int SceneAsset_getChildEntityCount(TSceneAsset* tSceneAsset);
EMSCRIPTEN_KEEPALIVE void SceneAsset_getChildEntities(TSceneAsset* tSceneAsset, EntityId *out);
EMSCRIPTEN_KEEPALIVE const utils::Entity *SceneAsset_getCameraEntities(TSceneAsset* tSceneAsset);
EMSCRIPTEN_KEEPALIVE size_t SceneAsset_getCameraEntityCount(TSceneAsset *tSceneAsset);
EMSCRIPTEN_KEEPALIVE const utils::Entity *SceneAsset_getLightEntities(TSceneAsset* tSceneAsset);
EMSCRIPTEN_KEEPALIVE size_t SceneAsset_getLightEntityCount(TSceneAsset *tSceneAsset);
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneAsset_getInstance(TSceneAsset *tSceneAsset, int index);
EMSCRIPTEN_KEEPALIVE size_t SceneAsset_getInstanceCount(TSceneAsset *tSceneAsset);
EMSCRIPTEN_KEEPALIVE TSceneAsset * SceneAsset_createInstance(TSceneAsset *asset, TMaterialInstance **materialInstances, int materialInstanceCount);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,66 @@
#pragma once
#include "APIBoundaryTypes.h"
#include "ResourceBuffer.hpp"
#include "MathUtils.hpp"
#include "TCamera.h"
#include "TMaterialInstance.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE TGizmo *SceneManager_createGizmo(TSceneManager *tSceneManager, TView *tView, TScene *tScene);
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_createGeometry(
TSceneManager *sceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance **materialInstances,
int materialInstanceCount,
bool keepData);
EMSCRIPTEN_KEEPALIVE TMaterialProvider *SceneManager_getUbershaderMaterialProvider(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE TMaterialProvider *SceneManager_getUnlitMaterialProvider(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitMaterialInstance(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitFixedSizeMaterialInstance(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE void SceneManager_queueTransformUpdates(TSceneManager *sceneManager, EntityId *entities, const double *const transforms, int numEntities);
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_findCameraByName(TSceneManager *tSceneManager, EntityId entity, const char *name);
EMSCRIPTEN_KEEPALIVE void SceneManager_setVisibilityLayer(TSceneManager *tSceneManager, EntityId entity, int layer);
EMSCRIPTEN_KEEPALIVE TScene *SceneManager_getScene(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_createCamera(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyCamera(TSceneManager *sceneManager, TCamera *camera);
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *sceneManager);
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraAt(TSceneManager *sceneManager, size_t index);
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyMaterialInstance(TSceneManager *sceneManager, TMaterialInstance *instance);
EMSCRIPTEN_KEEPALIVE Aabb3 SceneManager_getRenderableBoundingBox(TSceneManager *tSceneManager, EntityId entity);
EMSCRIPTEN_KEEPALIVE int SceneManager_addToScene(TSceneManager *tSceneManager, EntityId entity);
EMSCRIPTEN_KEEPALIVE int SceneManager_removeFromScene(TSceneManager *tSceneManager, EntityId entity);
EMSCRIPTEN_KEEPALIVE void SceneManager_transformToUnitCube(TSceneManager *sceneManager, EntityId asset);
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_loadGlbFromBuffer(TSceneManager *tSceneManager, const uint8_t *const, size_t length, bool keepData, int priority, int layer, bool loadResourcesAsync);
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_loadGlb(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData);
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_loadGltf(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData);
EMSCRIPTEN_KEEPALIVE TAnimationManager *SceneManager_getAnimationManager(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAll(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAsset(TSceneManager *tSceneManager, TSceneAsset *sceneAsset);
EMSCRIPTEN_KEEPALIVE TNameComponentManager *SceneManager_getNameComponentManager(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getOverlayEntityCount(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_getOverlayEntityAt(TSceneManager *tSceneManager, size_t index);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,23 @@
#pragma once
#include "APIExport.h"
#include "APIBoundaryTypes.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE double4x4 TransformManager_getLocalTransform(TTransformManager *tTransformManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE double4x4 TransformManager_getWorldTransform(TTransformManager *tTransformManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void TransformManager_setTransform(TTransformManager *tTransformManager, EntityId entityId, double4x4 transform);
EMSCRIPTEN_KEEPALIVE void TransformManager_transformToUnitCube(TTransformManager *tTransformManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void TransformManager_setParent(TTransformManager *tTransformManager, EntityId child, EntityId parent, bool preserveScaling);
EMSCRIPTEN_KEEPALIVE EntityId TransformManager_getParent(TTransformManager *tTransformManager, EntityId child);
EMSCRIPTEN_KEEPALIVE EntityId TransformManager_getAncestor(TTransformManager *tTransformManager, EntityId childEntityId);
#ifdef __cplusplus
}
#endif

View File

@@ -6,7 +6,8 @@ extern "C"
{
#endif
#include "ThermionDartApi.h"
#include "APIBoundaryTypes.h"
#include "APIExport.h"
struct TViewport {
int32_t left;
@@ -42,6 +43,11 @@ EMSCRIPTEN_KEEPALIVE void View_setLayerEnabled(TView *tView, int layer, bool vis
EMSCRIPTEN_KEEPALIVE void View_setCamera(TView *tView, TCamera *tCamera);
EMSCRIPTEN_KEEPALIVE TScene* View_getScene(TView *tView);
EMSCRIPTEN_KEEPALIVE TCamera* View_getCamera(TView *tView);
EMSCRIPTEN_KEEPALIVE void View_setStencilBufferEnabled(TView *tView, bool enabled);
EMSCRIPTEN_KEEPALIVE bool View_isStencilBufferEnabled(TView *tView);
typedef void (*PickCallback)(uint32_t requestId, EntityId entityId, float depth, float fragX, float fragY, float fragZ);
EMSCRIPTEN_KEEPALIVE void View_pick(TView* tView, uint32_t requestId, uint32_t x, uint32_t y, PickCallback callback);
#ifdef __cplusplus
}

View File

@@ -0,0 +1,115 @@
#ifndef _FLUTTER_FILAMENT_API_H
#define _FLUTTER_FILAMENT_API_H
#include "APIExport.h"
#include "APIBoundaryTypes.h"
#include "TMaterialInstance.h"
#include "ResourceBuffer.hpp"
#include "MathUtils.hpp"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *const context, const void *const loader, void *const platform, const char *uberArchivePath);
EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE TRenderTarget* Viewer_createRenderTarget(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height);
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *viewer, TRenderTarget* tRenderTarget);
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *viewer, const void *const window);
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *viewer, uint32_t width, uint32_t height);
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *viewer, TSwapChain* swapChain);
EMSCRIPTEN_KEEPALIVE void Viewer_render(
TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
TViewer *viewer,
TView *view,
TSwapChain *swapChain,
uint8_t *pixelBuffer,
void (*callback)(void));
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
TViewer *viewer,
TView *view,
TSwapChain *swapChain,
TRenderTarget *renderTarget,
uint8_t *pixelBuffer,
void (*callback)(void));
EMSCRIPTEN_KEEPALIVE TView* Viewer_createView(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE TView* Viewer_getViewAt(TViewer *viewer, int index);
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView);
EMSCRIPTEN_KEEPALIVE TSwapChain* Viewer_getSwapChainAt(TViewer *tViewer, int index);
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *viewer, TSwapChain *swapChain, TView* view, bool renderable);
// Engine
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer* viewer);
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine* tEngine, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight);
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp);
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a);
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath);
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity);
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity);
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix);
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void remove_ibl(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE EntityId add_light(
TViewer *viewer,
uint8_t type,
float colour,
float intensity,
float posX,
float posY,
float posZ,
float dirX,
float dirY,
float dirZ,
float falloffRadius,
float spotLightConeInner,
float spotLightConeOuter,
float sunAngularRadius,
float sunHaloSize,
float sunHaloFallof,
bool shadows);
EMSCRIPTEN_KEEPALIVE void remove_light(TViewer *viewer, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void clear_lights(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, EntityId light, float x, float y, float z);
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, EntityId light, float x, float y, float z);
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void set_frame_interval(TViewer *viewer, float interval);
EMSCRIPTEN_KEEPALIVE void queue_relative_position_update_world_axis(TSceneManager *sceneManager, EntityId entity, float viewportX, float viewportY, float x, float y, float z);
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *view, EntityId entity, float viewportX, float viewportY);
EMSCRIPTEN_KEEPALIVE TTransformManager *Engine_getTransformManager(TEngine *engine);
EMSCRIPTEN_KEEPALIVE TRenderableManager *Engine_getRenderableManager(TEngine *engine);
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine *engine, EntityId entity);
EMSCRIPTEN_KEEPALIVE TEntityManager *Engine_getEntityManager(TEngine *engine);
EMSCRIPTEN_KEEPALIVE void ios_dummy();
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr);
EMSCRIPTEN_KEEPALIVE void add_collision_component(TSceneManager *sceneManager, EntityId entityId, void (*callback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
EMSCRIPTEN_KEEPALIVE void remove_collision_component(TSceneManager *sceneManager, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void test_collisions(TSceneManager *sceneManager, EntityId entity);
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *view, EntityId entity);
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *view, EntityId entity, float *minX, float *minY, float *maxX, float *maxY);
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer* viewer, EntityId entity,uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight);
EMSCRIPTEN_KEEPALIVE void *const create_texture(TSceneManager *sceneManager, uint8_t *data, size_t length);
EMSCRIPTEN_KEEPALIVE void destroy_texture(TSceneManager *sceneManager, void *const texture);
EMSCRIPTEN_KEEPALIVE void apply_texture_to_material(TSceneManager *sceneManager, EntityId entity, void *const texture, const char *parameterName, int materialIndex);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,115 @@
#ifndef _DART_FILAMENT_FFI_API_H
#define _DART_FILAMENT_FFI_API_H
#include "ThermionDartApi.h"
#include "TView.h"
#include "TMaterialProvider.h"
#ifdef __cplusplus
namespace thermion
{
extern "C"
{
#endif
///
/// This header replicates most of the methods in ThermionDartApi.h.
/// It represents the interface for:
/// - invoking those methods that must be called on the main Filament engine thread
/// - setting up a render loop
///
typedef int32_t EntityId;
typedef void (*FilamentRenderCallback)(void *const owner);
EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread(
void *const context,
void *const platform,
const char *uberArchivePath,
const void *const loader,
void (*renderCallback)(void *const renderCallbackOwner),
void *const renderCallbackOwner,
void (*callback)(TViewer *viewer));
EMSCRIPTEN_KEEPALIVE void Viewer_destroyOnRenderThread(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer, void *const surface, void (*onComplete)(TSwapChain *));
EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer, uint32_t width, uint32_t height, void (*onComplete)(TSwapChain *));
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain *swapChain, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView *view, TSwapChain *swapChain);
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderThread(TViewer *viewer, TView *view, TSwapChain *swapChain, uint8_t *out, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *swapChain, TRenderTarget *renderTarget, uint8_t *out, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height, void (*onComplete)(TRenderTarget *));
EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping);
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom);
FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
EMSCRIPTEN_KEEPALIVE void set_rendering_render_thread(TViewer *viewer, bool rendering, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void set_frame_interval_render_thread(TViewer *viewer, float frameInterval);
EMSCRIPTEN_KEEPALIVE void set_background_color_render_thread(TViewer *viewer, const float r, const float g, const float b, const float a);
EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer, const char *path, bool fillHeight, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer, float x, float y, bool clamp);
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer, const char *skyboxPath, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer);
EMSCRIPTEN_KEEPALIVE void SceneManager_createGeometryRenderThread(
TSceneManager *sceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance **materialInstances,
int materialInstanceCount,
bool keepData,
void (*callback)(TSceneAsset *));
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, bool loadResourcesAsync, void (*callback)(TSceneAsset *));
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance *));
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance *));
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbRenderThread(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(TSceneAsset *));
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGltfRenderThread(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(TSceneAsset *));
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAllRenderThread(TSceneManager *tSceneManager, void (*callback)());
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAssetRenderThread(TSceneManager *tSceneManager, TSceneAsset *sceneAsset, void (*callback)());
EMSCRIPTEN_KEEPALIVE void SceneAsset_createInstanceRenderThread(TSceneAsset *asset, TMaterialInstance **tMaterialInstances, int materialInstanceCount, void (*callback)(TSceneAsset *));
EMSCRIPTEN_KEEPALIVE void MaterialProvider_createMaterialInstanceRenderThread(TMaterialProvider *tMaterialProvider, TMaterialKey *tKey, void (*callback)(TMaterialInstance*));
EMSCRIPTEN_KEEPALIVE void AnimationManager_updateBoneMatricesRenderThread(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void AnimationManager_setMorphTargetWeightsRenderThread(
TAnimationManager *tAnimationManager,
EntityId entityId,
const float *const morphData,
int numWeights,
void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(TSceneManager *sceneManager,
EntityId asset, void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
TSceneManager *sceneManager,
EntityId asset,
int skinIndex,
int boneIndex,
const float *const transform,
void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(TViewer *viewer, bool enabled);
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)());
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer *viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight, void (*callback)());
#ifdef __cplusplus
}
}
#endif
#endif // _DART_FILAMENT_FFI_API_H

View File

@@ -1,7 +1,5 @@
#pragma once
#include "Log.hpp"
#include <chrono>
#include <variant>
@@ -18,10 +16,11 @@
#include <math/norm.h>
#include <gltfio/Animator.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/ResourceLoader.h>
#include <gltfio/math.h>
#include <utils/NameComponentManager.h>
#include <utils/SingleInstanceComponentManager.h>
#include "Log.hpp"
template class std::vector<float>;
namespace thermion
@@ -170,7 +169,6 @@ namespace thermion
if (std::holds_alternative<FilamentInstance *>(animationComponent.target))
{
auto target = std::get<FilamentInstance *>(animationComponent.target);
auto animator = target->getAnimator();
auto &gltfAnimations = animationComponent.gltfAnimations;
@@ -225,7 +223,6 @@ namespace thermion
if (elapsedInSecs >= (animationStatus.durationInSecs + animationStatus.fadeInInSecs + animationStatus.fadeOutInSecs))
{
if(!animationStatus.loop) {
Log("Bone animation %d finished", i);
boneAnimations.erase(boneAnimations.begin() + i);
continue;
}

View File

@@ -8,5 +8,5 @@ GRID_PACKAGE:
GRID_GRID_OFFSET:
.int 0
GRID_GRID_SIZE:
.int 43432
.int 44564

View File

@@ -8,5 +8,5 @@ _GRID_PACKAGE:
_GRID_GRID_OFFSET:
.int 0
_GRID_GRID_SIZE:
.int 43432
.int 44564

File diff suppressed because it is too large Load Diff

View File

@@ -8,5 +8,5 @@ UNLIT_FIXED_SIZE_PACKAGE:
UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_OFFSET:
.int 0
UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE:
.int 39924
.int 41110

View File

@@ -8,5 +8,5 @@ _UNLIT_FIXED_SIZE_PACKAGE:
_UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_OFFSET:
.int 0
_UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE:
.int 39924
.int 41110

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,172 @@
#pragma once
#include <mutex>
#include <vector>
#include <filament/Engine.h>
#include <filament/Scene.h>
#include "c_api/APIBoundaryTypes.h"
#include "components/CollisionComponentManager.hpp"
#include "components/AnimationComponentManager.hpp"
#include "GltfSceneAssetInstance.hpp"
#include "GltfSceneAsset.hpp"
#include "SceneAsset.hpp"
namespace thermion
{
using namespace filament;
using namespace filament::gltfio;
using namespace utils;
using std::string;
using std::unique_ptr;
using std::vector;
/// @brief
class AnimationManager
{
public:
AnimationManager(
Engine *engine,
Scene *scene);
~AnimationManager();
void update();
/// @brief
/// @param asset
/// @param childEntity
/// @return
vector<string> getMorphTargetNames(GltfSceneAsset *asset, EntityId childEntity);
/// @brief
/// @param instance
/// @param skinIndex
/// @return
vector<Entity> getBoneEntities(GltfSceneAssetInstance *instance, int skinIndex);
/// @brief
/// @param sceneAsset
/// @param morphData
/// @param morphIndices
/// @param numMorphTargets
/// @param numFrames
/// @param frameLengthInMs
/// @return
bool setMorphAnimationBuffer(
utils::Entity entity,
const float *const morphData,
const uint32_t *const morphIndices,
int numMorphTargets,
int numFrames,
float frameLengthInMs);
/// @brief
/// @param entityId
void clearMorphAnimationBuffer(
utils::Entity entity);
/// @brief
/// @param instance
/// @param skinIndex
/// @param boneIndex
/// @return
math::mat4f getInverseBindMatrix(GltfSceneAssetInstance *instance, int skinIndex, int boneIndex);
/// @brief Set the local transform for the bone at boneIndex/skinIndex in the given entity.
/// @param entityId the parent entity
/// @param entityName the name of the mesh under entityId for which the bone will be set.
/// @param skinIndex the index of the joint skin. Currently only 0 is supported.
/// @param boneName the name of the bone
/// @param transform the 4x4 matrix representing the local transform for the bone
/// @return true if the transform was successfully set, false otherwise
bool setBoneTransform(GltfSceneAssetInstance *instance, int skinIndex, int boneIndex, math::mat4f transform);
/// @brief Immediately start animating the bone at [boneIndex] under the parent instance [entity] at skin [skinIndex].
/// @param entity the mesh entity to animate
/// @param frameData frame data as quaternions
/// @param numFrames the number of frames
/// @param boneName the name of the bone to animate
/// @param frameLengthInMs the length of each frame in ms
/// @return true if the bone animation was successfully enqueued
bool addBoneAnimation(
GltfSceneAssetInstance *instance,
int skinIndex,
int boneIndex,
const float *const frameData,
int numFrames,
float frameLengthInMs,
float fadeOutInSecs,
float fadeInInSecs,
float maxDelta);
/// @brief
/// @param instance
/// @param skinIndex
/// @return
std::vector<math::mat4f> getBoneRestTranforms(GltfSceneAssetInstance *instance, int skinIndex);
/// @brief
/// @param instance
void resetToRestPose(GltfSceneAssetInstance *instance);
/// @brief
/// @param instance
void updateBoneMatrices(GltfSceneAssetInstance *instance);
/// @brief
/// @param instance
/// @param animationIndex
/// @param loop
/// @param reverse
/// @param replaceActive
/// @param crossfade
/// @param startOffset
void playGltfAnimation(GltfSceneAssetInstance *instance, int animationIndex, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f, float startOffset = 0.0f);
/// @brief
/// @param instance
/// @param animationIndex
void stopGltfAnimation(GltfSceneAssetInstance *instance, int animationIndex);
/// @brief
/// @param instance
/// @param weights
/// @param count
void setMorphTargetWeights(utils::Entity entity, const float *const weights, int count);
/// @brief
/// @param instance
/// @param animationIndex
/// @param animationFrame
void setGltfAnimationFrame(GltfSceneAssetInstance *instance, int animationIndex, int animationFrame);
/// @brief
/// @param instance
/// @return
vector<string> getGltfAnimationNames(GltfSceneAssetInstance *instance);
/// @brief
/// @param instance
/// @param animationIndex
/// @return
float getGltfAnimationDuration(GltfSceneAssetInstance *instance, int animationIndex);
/// @brief
/// @param entity
/// @return
bool addAnimationComponent(EntityId entity);
/// @brief
/// @param entity
void removeAnimationComponent(EntityId entity);
private:
Engine *_engine = nullptr;
Scene *_scene = nullptr;
std::mutex _mutex;
std::unique_ptr<AnimationComponentManager> _animationComponentManager = std::nullptr_t();
};
}

View File

@@ -17,9 +17,8 @@
namespace thermion
{
using namespace filament;
using namespace filament;
// CustomGeometry.h
class CustomGeometry {
public:
CustomGeometry(
@@ -31,6 +30,7 @@ public:
uint32_t numUvs,
uint16_t* indices,
uint32_t numIndices,
MaterialInstance* materialInstance,
RenderableManager::PrimitiveType primitiveType,
Engine* engine);
~CustomGeometry();
@@ -40,6 +40,8 @@ public:
private:
Engine* _engine;
MaterialInstance* _materialInstance = nullptr;
VertexBuffer* vertexBuffer;
IndexBuffer* indexBuffer;

View File

@@ -0,0 +1,143 @@
#pragma once
#include <memory>
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
#include <filament/VertexBuffer.h>
#include <filament/IndexBuffer.h>
#include <gltfio/MaterialProvider.h>
#include "scene/SceneAsset.hpp"
namespace thermion
{
using namespace filament;
class GeometrySceneAsset : public SceneAsset
{
public:
GeometrySceneAsset(bool isInstance,
Engine *engine,
VertexBuffer *vertexBuffer,
IndexBuffer *indexBuffer,
MaterialInstance **materialInstances,
size_t materialInstanceCount,
RenderableManager::PrimitiveType primitiveType,
Box boundingBox);
~GeometrySceneAsset();
SceneAsset *createInstance(MaterialInstance **materialInstances = nullptr, size_t materialInstanceCount = 0) override;
SceneAssetType getType() override
{
return SceneAsset::SceneAssetType::Geometry;
}
bool isInstance() override
{
return _isInstance;
}
utils::Entity getEntity() override
{
return _entity;
}
MaterialInstance **getMaterialInstances() override
{
return _materialInstances;
}
size_t getMaterialInstanceCount() override
{
return _materialInstanceCount;
}
const Box &getBoundingBox() const { return _boundingBox; }
VertexBuffer *getVertexBuffer() const { return _vertexBuffer; }
IndexBuffer *getIndexBuffer() const { return _indexBuffer; }
void addAllEntities(Scene *scene) override
{
scene->addEntity(_entity);
}
void removeAllEntities(Scene *scene) override
{
scene->remove(_entity);
}
void setPriority(RenderableManager &rm, int priority) override
{
auto renderableInstance = rm.getInstance(_entity);
rm.setPriority(renderableInstance, priority);
}
void setLayer(RenderableManager &rm, int layer) override
{
auto renderableInstance = rm.getInstance(_entity);
rm.setLayerMask(renderableInstance, 0xFF, 1u << (uint8_t)layer);
}
SceneAsset *getInstanceByEntity(utils::Entity entity) override
{
for (auto &instance : _instances)
{
if (instance->getEntity() == entity)
{
return instance.get();
}
}
return std::nullptr_t();
}
SceneAsset *getInstanceAt(size_t index) override
{
auto &asset = _instances[index];
return asset.get();
}
size_t getInstanceCount() override
{
return _instances.size();
}
size_t getChildEntityCount() override
{
return 0;
}
const Entity *getChildEntities() override
{
return nullptr;
}
Entity findEntityByName(const char *name) override
{
return Entity(); // not currently implemented
}
static std::unique_ptr<GeometrySceneAsset> create(
float *vertices, uint32_t numVertices,
float *normals, uint32_t numNormals,
float *uvs, uint32_t numUvs,
uint16_t *indices, uint32_t numIndices,
MaterialInstance *materialInstance,
RenderableManager::PrimitiveType primitiveType,
Engine *engine);
private:
Engine *_engine = nullptr;
VertexBuffer *_vertexBuffer = nullptr;
IndexBuffer *_indexBuffer = nullptr;
MaterialInstance **_materialInstances = nullptr;
size_t _materialInstanceCount = 0;
Box _boundingBox;
bool _isInstance = false;
utils::Entity _entity;
RenderableManager::PrimitiveType _primitiveType;
std::vector<std::unique_ptr<GeometrySceneAsset>> _instances;
};
} // namespace thermion

View File

@@ -0,0 +1,308 @@
#pragma once
#include <memory>
#include <vector>
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
#include <filament/VertexBuffer.h>
#include <filament/IndexBuffer.h>
#include <filament/geometry/SurfaceOrientation.h>
#include <filament/Box.h>
#include <gltfio/MaterialProvider.h>
#include "GeometrySceneAsset.hpp"
#include "Log.hpp"
namespace thermion
{
class GeometrySceneAssetBuilder
{
public:
GeometrySceneAssetBuilder(filament::Engine *engine) : mEngine(engine) {}
GeometrySceneAssetBuilder &vertices(const float *vertices, uint32_t count)
{
mVertices->resize(count);
std::copy(vertices, vertices + count, mVertices->data());
mNumVertices = count;
return *this;
}
GeometrySceneAssetBuilder &normals(const float *normals, uint32_t count)
{
if (normals)
{
mNormals->resize(count);
std::copy(normals, normals + count, mNormals->data());
}
else
{
mNormals->clear();
}
mNumNormals = count;
return *this;
}
GeometrySceneAssetBuilder &uvs(const float *uvs, uint32_t count)
{
if (uvs)
{
mUVs->resize(count);
std::copy(uvs, uvs + count, mUVs->data());
}
else
{
mUVs->clear();
}
mNumUVs = count;
return *this;
}
GeometrySceneAssetBuilder &indices(const uint16_t *indices, uint32_t count)
{
mIndices->resize(count);
std::copy(indices, indices + count, mIndices->data());
mNumIndices = count;
return *this;
}
GeometrySceneAssetBuilder &materials(filament::MaterialInstance **materials, size_t materialInstanceCount)
{
mMaterialInstances = materials;
mMaterialInstanceCount = materialInstanceCount;
return *this;
}
GeometrySceneAssetBuilder &primitiveType(filament::RenderableManager::PrimitiveType type)
{
mPrimitiveType = type;
return *this;
}
std::unique_ptr<GeometrySceneAsset> build()
{
Log("Starting build. Validating inputs...");
if (!validate())
{
Log("Validation failed!");
return nullptr;
}
Log("Creating buffers...");
auto [vertexBuffer, indexBuffer] = createBuffers();
if (!vertexBuffer || !indexBuffer)
{
Log("Failed to create buffers: VB=%p, IB=%p", vertexBuffer, indexBuffer);
return nullptr;
}
Log("Buffers created successfully: VB=%p, IB=%p", vertexBuffer, indexBuffer);
Log("Creating entity...");
auto entity = utils::EntityManager::get().create();
Log("Entity created: %d", entity.getId());
Box boundingBox = computeBoundingBox();
Log("Computed bounding box: min={%f,%f,%f}, max={%f,%f,%f}",
boundingBox.getMin().x, boundingBox.getMin().y, boundingBox.getMin().z,
boundingBox.getMax().x, boundingBox.getMax().y, boundingBox.getMax().z);
auto asset = std::make_unique<GeometrySceneAsset>(
false,
mEngine,
vertexBuffer,
indexBuffer,
mMaterialInstances,
mMaterialInstanceCount,
mPrimitiveType,
boundingBox);
Log("Asset created: %p", asset.get());
return asset;
}
private:
Box computeBoundingBox()
{
float minX = FLT_MAX, minY = FLT_MAX, minZ = FLT_MAX;
float maxX = -FLT_MAX, maxY = -FLT_MAX, maxZ = -FLT_MAX;
Box box;
for (uint32_t i = 0; i < mNumVertices; i += 3)
{
minX = std::min(mVertices->at(i), minX);
minY = std::min(mVertices->at(i + 1), minY);
minZ = std::min(mVertices->at(i + 2), minZ);
maxX = std::max(mVertices->at(i), maxX);
maxY = std::max(mVertices->at(i + 1), maxY);
maxZ = std::max(mVertices->at(i + 2), maxZ);
}
const filament::math::float3 min {minX, minY, minZ};
const filament::math::float3 max {maxX, maxY, maxZ};
box.set(min, max);
return box;
}
std::pair<filament::VertexBuffer *, filament::IndexBuffer *> createBuffers()
{
auto indexBuffer = IndexBuffer::Builder()
.indexCount(mNumIndices)
.bufferType(IndexBuffer::IndexType::USHORT)
.build(*mEngine);
indexBuffer->setBuffer(*mEngine,
IndexBuffer::BufferDescriptor(
mIndices->data(),
mNumIndices * sizeof(uint16_t),
[](void *, size_t, void *data)
{
delete static_cast<std::vector<float> *>(data);
},
mIndices));
if (mUVs->empty())
{
mUVs->resize(mNumVertices);
std::fill(mUVs->begin(), mUVs->end(), 0.0f);
}
auto dummyColors = new std::vector<filament::math::float4>(
mNumVertices, filament::math::float4{1.0f, 1.0f, 1.0f, 1.0f});
auto vertexBufferBuilder =
VertexBuffer::Builder()
.vertexCount(mNumVertices)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.attribute(VertexAttribute::UV0, 1, VertexBuffer::AttributeType::FLOAT2)
.attribute(VertexAttribute::UV1, 2, VertexBuffer::AttributeType::FLOAT2)
.attribute(VertexAttribute::COLOR, 3, VertexBuffer::AttributeType::FLOAT4);
if (!mNormals->empty())
{
vertexBufferBuilder.bufferCount(5)
.attribute(VertexAttribute::TANGENTS, 4, VertexBuffer::AttributeType::FLOAT4);
}
else
{
vertexBufferBuilder = vertexBufferBuilder.bufferCount(4);
}
auto vertexBuffer = vertexBufferBuilder.build(*mEngine);
vertexBuffer->setBufferAt(*mEngine, 0,
VertexBuffer::BufferDescriptor(
mVertices->data(), mNumVertices * sizeof(float),
[](void *, size_t, void *) {}));
vertexBuffer->setBufferAt(*mEngine, 1,
VertexBuffer::BufferDescriptor(
mUVs->data(), mUVs->size() * sizeof(float),
[](void *, size_t, void *data)
{
},
mUVs));
vertexBuffer->setBufferAt(*mEngine, 2,
VertexBuffer::BufferDescriptor(
mUVs->data(), mUVs->size() * sizeof(float),
[](void *, size_t, void *data) {
delete static_cast<std::vector<float> *>(data);
},
mUVs));
vertexBuffer->setBufferAt(*mEngine, 3,
VertexBuffer::BufferDescriptor(
dummyColors->data(), dummyColors->size() * sizeof(math::float4),
[](void *, size_t, void *data)
{
delete static_cast<std::vector<math::float4> *>(data);
},
dummyColors));
if (!mNormals->empty())
{
assert(mPrimitiveType == RenderableManager::PrimitiveType::TRIANGLES);
std::vector<filament::math::ushort3> triangles;
for (uint32_t i = 0; i < mNumIndices; i += 3)
{
triangles.push_back({mIndices->at(i),
mIndices->at(i + 1),
mIndices->at(i + 2)});
}
auto &builder = geometry::SurfaceOrientation::Builder()
.vertexCount(mNumVertices)
.normals((filament::math::float3 *)mNormals->data())
.positions((filament::math::float3 *)mVertices->data())
.triangleCount(triangles.size())
.triangles(triangles.data());
auto orientation = builder.build();
auto quats = new std::vector<filament::math::quatf>(mNumVertices);
orientation->getQuats(quats->data(), mNumVertices);
vertexBuffer->setBufferAt(*mEngine, 4,
VertexBuffer::BufferDescriptor(
quats->data(), quats->size() * sizeof(math::quatf),
[](void *, size_t, void *data)
{
delete static_cast<std::vector<math::quatf> *>(data);
},
quats));
}
return {vertexBuffer, indexBuffer};
}
bool validate() const
{
if (!mEngine)
{
Log("Validation failed: No engine");
return false;
}
if (mVertices->empty() || mNumVertices == 0)
{
Log("Validation failed: No vertices (empty=%d, count=%d)", mVertices->empty(), mNumVertices);
return false;
}
if (mNumNormals > 0 && !mNormals->empty() && mNumNormals != mNumVertices)
{
Log("Validation failed: Normal count mismatch (normals=%d, vertices=%d)", mNumNormals, mNumVertices);
return false;
}
if (mNumUVs > 0 && !mUVs->empty() && mNumUVs != mNumVertices)
{
Log("Validation failed: UV count mismatch (uvs=%d, vertices=%d)", mNumUVs, mNumVertices);
return false;
}
if (mIndices->empty() || mNumIndices == 0)
{
Log("Validation failed: No indices (empty=%d, count=%d)", mIndices->empty(), mNumIndices);
return false;
}
Log("Validation passed: vertices=%d, normals=%s, uvs=%d, indices=%d",
mNumVertices,
(!mNormals->empty() ? "yes" : "no"),
mNumUVs,
mNumIndices);
return true;
}
filament::Engine *mEngine = nullptr;
std::vector<float> *mVertices = new std::vector<float>();
std::vector<float> *mNormals = new std::vector<float>();
std::vector<float> *mUVs = new std::vector<float>();
std::vector<uint16_t> *mIndices = new std::vector<uint16_t>;
uint32_t mNumVertices = 0;
uint32_t mNumNormals = 0;
uint32_t mNumUVs = 0;
uint32_t mNumIndices = 0;
filament::MaterialInstance **mMaterialInstances = nullptr;
size_t mMaterialInstanceCount = 0;
filament::gltfio::MaterialProvider *mMaterialProvider = nullptr;
filament::RenderableManager::PrimitiveType mPrimitiveType =
filament::RenderableManager::PrimitiveType::TRIANGLES;
};
} // namespace thermion

View File

@@ -0,0 +1,201 @@
#pragma once
#include <utils/Entity.h>
#include <filament/Engine.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/Scene.h>
#include <filament/Camera.h>
#include <filament/View.h>
#include <filament/Viewport.h>
#include <filament/RenderableManager.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/FilamentInstance.h>
#include <gltfio/ResourceLoader.h>
#include <filament/IndexBuffer.h>
#include <filament/InstanceBuffer.h>
#include "c_api/ThermionDartApi.h"
#include "scene/SceneAsset.hpp"
namespace thermion
{
using namespace filament;
using namespace utils;
class Gizmo : public SceneAsset
{
public:
Gizmo(Engine *engine, View *view, Scene *scene, Material *material);
~Gizmo() override;
enum Axis
{
X,
Y,
Z
};
enum GizmoPickResultType {
AxisX,
AxisY,
AxisZ,
Parent,
None
};
typedef void (*GizmoPickCallback)(Gizmo::GizmoPickResultType result, float x, float y, float z);
void pick(uint32_t x, uint32_t y, GizmoPickCallback callback);
bool isGizmoEntity(Entity entity);
SceneAssetType getType() override { return SceneAssetType::Gizmo; }
utils::Entity getEntity() override { return _entities[0]; }
bool isInstance() override { return false; }
SceneAsset *createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount) override { return nullptr; }
MaterialInstance **getMaterialInstances() override { return _materialInstances.data(); }
size_t getMaterialInstanceCount() override { return _materialInstances.size(); }
void addAllEntities(Scene *scene) override
{
for (const auto &entity : _entities)
{
if (entity.isNull())
{
continue;
}
scene->addEntity(entity);
}
}
void removeAllEntities(Scene *scene) override
{
for (const auto &entity : _entities)
{
scene->remove(entity);
}
}
size_t getInstanceCount() override { return 0; }
SceneAsset *getInstanceByEntity(utils::Entity entity) override { return nullptr; }
SceneAsset *getInstanceAt(size_t index) override { return nullptr; }
size_t getChildEntityCount() override { return _entities.size() - 1; }
const Entity *getChildEntities() override { return _entities.data() + 1; }
Entity findEntityByName(const char *name) override
{
return utils::Entity::import(0);
}
void setPriority(RenderableManager &rm, int mask) override
{
}
void setLayer(RenderableManager &rm, int layer) override
{
}
void highlight(Gizmo::Axis axis);
void unhighlight(Gizmo::Axis axis);
private:
class PickCallbackHandler
{
public:
PickCallbackHandler(Gizmo *gizmo, GizmoPickCallback callback)
: _gizmo(gizmo), _callback(callback) {}
void handle(filament::View::PickingQueryResult const &result)
{
_gizmo->unhighlight(Gizmo::Axis::X);
_gizmo->unhighlight(Gizmo::Axis::Y);
_gizmo->unhighlight(Gizmo::Axis::Z);
Gizmo::GizmoPickResultType resultType;
if (result.renderable == _gizmo->_parent)
{
resultType = Gizmo::GizmoPickResultType::Parent;
}
else if (result.renderable == _gizmo->_x || result.renderable == _gizmo->_xHitTest)
{
resultType = Gizmo::GizmoPickResultType::AxisX;
_gizmo->highlight(Gizmo::Axis::X);
}
else if (result.renderable == _gizmo->_y || result.renderable == _gizmo->_yHitTest)
{
_gizmo->highlight(Gizmo::Axis::Y);
resultType = Gizmo::GizmoPickResultType::AxisY;
}
else if (result.renderable == _gizmo->_z || result.renderable == _gizmo->_zHitTest)
{
_gizmo->highlight(Gizmo::Axis::Z);
resultType = Gizmo::GizmoPickResultType::AxisZ;
} else {
resultType = Gizmo::GizmoPickResultType::None;
}
_callback(resultType, result.fragCoords.x, result.fragCoords.y, result.fragCoords.z);
}
private:
Gizmo *_gizmo;
GizmoPickCallback _callback;
};
Entity createParentEntity();
Entity createHitTestEntity(Gizmo::Axis axis, Entity parent);
Entity createAxisEntity(Gizmo::Axis axis, Entity parent);
math::mat4f getRotationForAxis(Gizmo::Axis axis);
Entity getEntityForAxis(Gizmo::Axis axis)
{
switch (axis)
{
case Gizmo::Axis::X:
return _x;
case Gizmo::Axis::Y:
return _y;
case Gizmo::Axis::Z:
return _z;
}
}
Engine *_engine;
Scene *_scene;
View *_view;
Material *_material;
utils::Entity _parent;
utils::Entity _x;
utils::Entity _y;
utils::Entity _z;
utils::Entity _xHitTest;
utils::Entity _yHitTest;
utils::Entity _zHitTest;
std::vector<utils::Entity> _entities;
std::vector<MaterialInstance *> _materialInstances;
math::float4 activeColors[3]{
math::float4{1.0f, 1.0f, 0.0f, 0.5f},
math::float4{1.0f, 1.0f, 0.0f, 0.5f},
math::float4{1.0f, 1.0f, 0.0f, 0.5f},
};
math::float4 inactiveColors[3]{
math::float4{1.0f, 0.0f, 0.0f, 1.0f},
math::float4{0.0f, 1.0f, 0.0f, 1.0f},
math::float4{0.0f, 0.0f, 1.0f, 1.0f},
};
};
}

View File

@@ -0,0 +1,163 @@
#pragma once
#include <memory>
#include <vector>
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
#include <filament/VertexBuffer.h>
#include <filament/IndexBuffer.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/MaterialProvider.h>
#include "scene/GltfSceneAssetInstance.hpp"
#include "components/AnimationComponentManager.hpp"
#include "components/CollisionComponentManager.hpp"
#include "scene/SceneAsset.hpp"
namespace thermion
{
using namespace filament;
class GltfSceneAsset : public SceneAsset
{
public:
GltfSceneAsset(
gltfio::FilamentAsset *asset,
gltfio::AssetLoader *assetLoader,
Engine *engine,
MaterialInstance **materialInstances = nullptr,
size_t materialInstanceCount = 0,
int instanceIndex = -1) : _asset(asset),
_assetLoader(assetLoader),
_engine(engine),
_materialInstances(materialInstances),
_materialInstanceCount(materialInstanceCount)
{
}
~GltfSceneAsset();
SceneAsset *createInstance(MaterialInstance **materialInstances = nullptr, size_t materialInstanceCount = 0) override;
SceneAssetType getType() override
{
return SceneAsset::SceneAssetType::Gltf;
}
bool isInstance() override
{
return false;
}
utils::Entity getEntity() override
{
return _asset->getRoot();
}
MaterialInstance **getMaterialInstances() override
{
return _materialInstances;
}
size_t getMaterialInstanceCount() override
{
return _materialInstanceCount;
}
gltfio::FilamentAsset *getAsset()
{
return _asset;
}
void addAllEntities(Scene *scene) override
{
scene->addEntities(_asset->getEntities(), _asset->getEntityCount());
scene->addEntities(_asset->getLightEntities(), _asset->getLightEntityCount());
scene->addEntities(_asset->getCameraEntities(), _asset->getCameraEntityCount());
}
void removeAllEntities(Scene *scene) override
{
scene->removeEntities(_asset->getEntities(), _asset->getEntityCount());
scene->removeEntities(_asset->getLightEntities(), _asset->getLightEntityCount());
scene->removeEntities(_asset->getCameraEntities(), _asset->getCameraEntityCount());
}
void setPriority(RenderableManager &rm, int priority) override
{
const Entity *entities = _asset->getEntities();
for (int i = 0; i < _asset->getEntityCount(); i++)
{
if (rm.hasComponent(entities[i]))
{
auto renderableInstance = rm.getInstance(entities[i]);
rm.setPriority(renderableInstance, priority);
}
}
}
void setLayer(RenderableManager &rm, int layer) override
{
const Entity *entities = _asset->getEntities();
for (int i = 0; i < _asset->getEntityCount(); i++)
{
if (rm.hasComponent(entities[i]))
{
auto renderableInstance = rm.getInstance(entities[i]);
rm.setLayerMask(renderableInstance, 0xFF, 1u << (uint8_t)layer);
}
}
}
SceneAsset *getInstanceByEntity(utils::Entity entity) override
{
for (auto &instance : _instances)
{
if (instance->getEntity() == entity)
{
return instance.get();
}
}
return std::nullptr_t();
}
SceneAsset *getInstanceAt(size_t index) override
{
auto &asset = _instances[index];
return asset.get();
}
size_t getInstanceCount() override
{
return _instances.size();
}
size_t getChildEntityCount() override
{
return _asset->getEntityCount();
}
const Entity* getChildEntities() override {
return _asset->getEntities();
}
Entity findEntityByName(const char* name) override {
Entity entities[1];
auto found = _asset->getEntitiesByName(name, entities, 1);
return entities[0];
}
private:
gltfio::FilamentAsset *_asset;
gltfio::AssetLoader *_assetLoader;
Engine *_engine;
MaterialInstance **_materialInstances = nullptr;
size_t _materialInstanceCount = 0;
std::vector<std::unique_ptr<GltfSceneAssetInstance>> _instances;
};
} // namespace thermion

View File

@@ -0,0 +1,143 @@
#pragma once
#include <memory>
#include <vector>
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
#include <filament/VertexBuffer.h>
#include <filament/IndexBuffer.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/FilamentInstance.h>
#include <gltfio/MaterialProvider.h>
#include "scene/SceneAsset.hpp"
namespace thermion
{
using namespace filament;
class GltfSceneAssetInstance : public SceneAsset
{
public:
GltfSceneAssetInstance(
gltfio::FilamentInstance *instance,
Engine *engine,
MaterialInstance **materialInstances = nullptr,
size_t materialInstanceCount = 0,
int instanceIndex = -1) : _instance(instance),
_materialInstances(materialInstances),
_materialInstanceCount(materialInstanceCount)
{
}
~GltfSceneAssetInstance();
SceneAsset *createInstance(MaterialInstance **materialInstances = nullptr, size_t materialInstanceCount = 0) override
{
return std::nullptr_t();
};
SceneAssetType getType() override
{
return SceneAsset::SceneAssetType::Gltf;
}
bool isInstance() override
{
return true;
}
utils::Entity getEntity() override
{
return _instance->getRoot();
}
MaterialInstance **getMaterialInstances() override
{
return _materialInstances;
}
size_t getMaterialInstanceCount() override
{
return _materialInstanceCount;
}
gltfio::FilamentInstance *getInstance()
{
return _instance;
}
void addAllEntities(Scene *scene) override
{
scene->addEntities(_instance->getEntities(), _instance->getEntityCount());
}
void removeAllEntities(Scene *scene) override {
scene->removeEntities(_instance->getEntities(), _instance->getEntityCount());
}
size_t getInstanceCount() override
{
return 0;
}
SceneAsset *getInstanceAt(size_t index) override
{
return std::nullptr_t();
}
size_t getChildEntityCount() override
{
return _instance->getEntityCount();
}
const Entity* getChildEntities() override {
return _instance->getEntities();
}
Entity findEntityByName(const char* name) override {
return Entity(); // not currently implemented
}
SceneAsset *getInstanceByEntity(utils::Entity entity) override {
return std::nullptr_t();
}
void setPriority(RenderableManager &rm, int priority) override
{
const Entity *entities = _instance->getEntities();
for (int i = 0; i < _instance->getEntityCount(); i++)
{
if (rm.hasComponent(entities[i]))
{
auto renderableInstance = rm.getInstance(entities[i]);
rm.setPriority(renderableInstance, priority);
}
}
}
void setLayer(RenderableManager &rm, int layer) override
{
const Entity *entities = _instance->getEntities();
for (int i = 0; i < _instance->getEntityCount(); i++)
{
if (rm.hasComponent(entities[i]))
{
auto renderableInstance = rm.getInstance(entities[i]);
rm.setLayerMask(renderableInstance, 0xFF, 1u << (uint8_t)layer);
}
}
}
private:
filament::Engine *_engine;
gltfio::FilamentInstance *_instance;
MaterialInstance **_materialInstances = nullptr;
size_t _materialInstanceCount = 0;
};
} // namespace thermion

View File

@@ -0,0 +1,53 @@
#pragma once
#include <memory>
#include <utils/Entity.h>
#include <gltfio/FilamentAsset.h>
#include <filament/Scene.h>
#include "CustomGeometry.hpp"
#include "Log.hpp"
namespace thermion {
using namespace filament;
using namespace utils;
class SceneAsset {
public:
enum SceneAssetType { Gltf, Geometry, Light, Skybox, Ibl, Image, Gizmo };
virtual ~SceneAsset() {
}
virtual SceneAssetType getType() = 0;
virtual utils::Entity getEntity() {
return utils::Entity::import(0);
}
virtual bool isInstance() = 0;
virtual SceneAsset* createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount) = 0;
virtual MaterialInstance **getMaterialInstances() = 0;
virtual size_t getMaterialInstanceCount() = 0;
virtual void addAllEntities(Scene *scene) = 0;
virtual void removeAllEntities(Scene *scene) = 0;
virtual size_t getInstanceCount() = 0;
virtual SceneAsset *getInstanceByEntity(utils::Entity entity) = 0;
virtual SceneAsset *getInstanceAt(size_t index) = 0;
virtual size_t getChildEntityCount() = 0;
virtual const Entity* getChildEntities() = 0;
virtual Entity findEntityByName(const char* name) = 0;
virtual void setPriority(RenderableManager& rm, int mask) = 0;
virtual void setLayer(RenderableManager& rm, int layer) = 0;
};
}

View File

@@ -0,0 +1,350 @@
#pragma once
#include <mutex>
#include <vector>
#include <memory>
#include <map>
#include <set>
#include <filament/Scene.h>
#include <filament/Camera.h>
#include <filament/View.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/FilamentInstance.h>
#include <gltfio/ResourceLoader.h>
#include <filament/IndexBuffer.h>
#include <filament/InstanceBuffer.h>
#include <utils/NameComponentManager.h>
#include "tsl/robin_map.h"
#include "AnimationManager.hpp"
#include "CustomGeometry.hpp"
#include "Gizmo.hpp"
#include "GridOverlay.hpp"
#include "ResourceBuffer.hpp"
#include "SceneAsset.hpp"
#include "components/CollisionComponentManager.hpp"
namespace thermion
{
typedef int32_t EntityId;
using namespace filament;
using namespace filament::gltfio;
using namespace utils;
using std::string;
using std::unique_ptr;
using std::vector;
class SceneManager
{
public:
SceneManager(
const ResourceLoaderWrapperImpl *const loader,
Engine *engine,
Scene *scene,
const char *uberArchivePath,
Camera *mainCamera);
~SceneManager();
enum LAYERS
{
DEFAULT_ASSETS = 0,
BACKGROUND = 6,
OVERLAY = 7,
};
////
/// @brief Load the glTF file from the specified path and adds all entities to the scene.
/// @param uri the path to the asset. Should be either asset:// (representing a Flutter asset), or file:// (representing a filesystem file).
/// @param relativeResourcePath the (relative) path to the asset's resources.
/// @return the glTF entity.
///
SceneAsset* loadGltf(const char *uri, const char *relativeResourcePath, int numInstances = 1, bool keepData = false);
////
/// @brief Load the GLB from the specified path, optionally creating multiple instances.
/// @param uri the path to the asset. Should be either asset:// (representing a Flutter asset), or file:// (representing a filesystem file).
/// @param numInstances the number of instances to create. Must be at least 1.
/// @return an Entity representing the FilamentAsset associated with the loaded FilamentAsset.
///
SceneAsset* loadGlb(const char *uri, int numInstances, bool keepData);
/// @brief
/// @param data
/// @param length
/// @param numInstances
/// @param keepData
/// @param priority
/// @param layer
/// @param loadResourcesAsync
/// @return
SceneAsset* loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0, bool loadResourcesAsync = false);
///
/// Creates an instance of the given entity.
/// This may return an instance from a pool of inactive instances; see [remove] for more information.
/// If [materialInstances] is provided, these wil
///
SceneAsset* createInstance(SceneAsset* asset, MaterialInstance **materialInstances = nullptr, size_t materialInstanceCount = 0);
/// @brief Removes the asset (and all its child entities) from the scene and "destroys" all resources.
/// If the asset is not an instance, the asset will be deleted.
/// If the asset is an instance, [remove] is not guaranted to delete the asset. It may be returned to a pool of inactive instances.
/// From the user's perspective, this can be considered as destroyed.
/// @param entity
void destroy(SceneAsset* entity);
/// @brief Destroys all assets, scenes, materials, etc.
///
void destroyAll();
/// @brief
/// @param entityId
void transformToUnitCube(EntityId entityId);
/// @brief
/// @param entities
/// @param transforms
/// @param numEntities
void queueTransformUpdates(EntityId *entities, math::mat4 *transforms, int numEntities);
/// @brief
/// @param entity
/// @param viewportCoordX
/// @param viewportCoordY
/// @param x
/// @param y
/// @param z
void queueRelativePositionUpdateWorldAxis(EntityId entity, float viewportCoordX, float viewportCoordY, float x, float y, float z);
/// @brief
/// @param view
/// @param entityId
/// @param viewportCoordX
/// @param viewportCoordY
void queueRelativePositionUpdateFromViewportVector(View *view, EntityId entityId, float viewportCoordX, float viewportCoordY);
const utils::Entity *getCameraEntities(EntityId e);
size_t getCameraEntityCount(EntityId e);
const utils::Entity *getLightEntities(EntityId e) noexcept;
size_t getLightEntityCount(EntityId e) noexcept;
/// @brief
void update();
/// @brief
/// @param data
/// @param length
/// @param name
/// @return
Texture *createTexture(const uint8_t *data, size_t length, const char *name);
/// @brief
/// @param entityId
/// @param texture
/// @param slotName
/// @param materialIndex
/// @return
bool applyTexture(EntityId entityId, Texture *texture, const char *slotName, int materialIndex);
/// @brief
/// @param texture
void destroyTexture(Texture *texture);
/// @brief
/// @param entity
/// @return
bool removeFromScene(EntityId entity);
/// @brief
/// @param entity
/// @return
bool addToScene(EntityId entity);
/// @brief
/// @param entity
/// @param onCollisionCallback
/// @param affectsCollidingTransform
void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
/// @brief
/// @param entityId
///
///
void removeCollisionComponent(EntityId entityId);
/// @brief
/// @param entity
void testCollisions(EntityId entity);
/// @brief returns the number of instances of the FilamentAsset represented by the given entity.
/// @param entityId
/// @return the number of instances
int getInstanceCount(EntityId entityId);
/// @brief returns an array containing all instances of the FilamentAsset represented by the given entity.
/// @param entityId
void getInstances(EntityId entityId, EntityId *out);
///
/// Sets the draw priority for the given entity. See RenderableManager.h for more details.
///
void setPriority(EntityId entity, int priority);
/// @brief returns the 2D min/max viewport coordinates of the bounding box for the specified enitty;
/// @param out a pointer large enough to store four floats (the min/max coordinates of the bounding box)
/// @return
///
Aabb2 getScreenSpaceBoundingBox(View *view, EntityId entity);
/// @brief returns the 3D bounding box of the renderable instance for the given entity.
/// @return the bounding box
///
Aabb3 getRenderableBoundingBox(EntityId entity);
///
/// Creates an entity with the specified geometry/material/normals and adds to the scene.
/// If [keepData] is true, stores
///
SceneAsset *createGeometry(
float *vertices,
uint32_t numVertices,
float *normals,
uint32_t numNormals,
float *uvs,
uint32_t numUvs,
uint16_t *indices,
uint32_t numIndices,
filament::RenderableManager::PrimitiveType primitiveType = RenderableManager::PrimitiveType::TRIANGLES,
MaterialInstance **materialInstances = nullptr,
size_t materialInstanceCount = 0,
bool keepData = false);
gltfio::MaterialProvider *const getUnlitMaterialProvider()
{
return _unlitMaterialProvider;
}
gltfio::MaterialProvider *const getUbershaderMaterialProvider()
{
return _ubershaderProvider;
}
/// @brief
/// @param materialInstance
void destroy(MaterialInstance *materialInstance);
/// @brief
/// @return
MaterialInstance *createUnlitFixedSizeMaterialInstance();
/// @brief
/// @return
MaterialInstance *createUnlitMaterialInstance();
/// @brief
/// @param entityId
/// @param layer
void setVisibilityLayer(EntityId entityId, int layer);
/// @brief
/// @return
Camera *createCamera();
/// @brief
/// @param camera
void destroyCamera(Camera *camera);
/// @brief
/// @return
size_t getCameraCount();
/// @brief
/// @param index
/// @return
Camera *getCameraAt(size_t index);
/// @brief
/// @param view
/// @param scene
/// @return
Gizmo *createGizmo(View *view, Scene *scene);
/// @brief
/// @return
Scene *getScene()
{
return _scene;
}
/// @brief
/// @return
AnimationManager *getAnimationManager() {
return _animationManager.get();
}
/// @brief
/// @return
NameComponentManager *getNameComponentManager() {
return _ncm;
}
Entity getOverlayEntity(size_t index) {
if(index == 0) {
return _gridOverlay->grid();
} else if(index == 1) {
return _gridOverlay->sphere();
}
}
size_t getOverlayEntityCount() {
return 2;
}
private:
gltfio::AssetLoader *_assetLoader = nullptr;
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
Engine *_engine = nullptr;
Scene *_scene = nullptr;
Camera *_mainCamera;
gltfio::MaterialKey _defaultUnlitConfig;
gltfio::MaterialProvider *_ubershaderProvider = nullptr;
gltfio::MaterialProvider *_unlitMaterialProvider = nullptr;
gltfio::ResourceLoader *_gltfResourceLoader = nullptr;
gltfio::TextureProvider *_stbDecoder = nullptr;
gltfio::TextureProvider *_ktxDecoder = nullptr;
std::mutex _mutex;
std::vector<MaterialInstance *> _materialInstances;
Material *_unlitFixedSizeMaterial = nullptr;
utils::NameComponentManager *_ncm;
tsl::robin_map<EntityId, math::mat4> _transformUpdates;
std::set<Texture *> _textures;
std::vector<Camera *> _cameras;
std::vector<std::unique_ptr<SceneAsset>> _sceneAssets;
std::vector<std::unique_ptr<Gizmo>> _gizmos;
std::unique_ptr<AnimationManager> _animationManager = std::nullptr_t();
std::unique_ptr<CollisionComponentManager> _collisionComponentManager = std::nullptr_t();
GridOverlay *_gridOverlay = std::nullptr_t();
void _updateTransforms();
};
}

View File

@@ -120,7 +120,8 @@ namespace thermion
static constexpr filament::math::float4 sFullScreenTriangleVertices[3] = {
{-1.0f, -1.0f, 1.0f, 1.0f},
{3.0f, -1.0f, 1.0f, 1.0f},
{-1.0f, 3.0f, 1.0f, 1.0f}};
{-1.0f, 3.0f, 1.0f, 1.0f}
};
static const uint16_t sFullScreenTriangleIndices[3] = {0, 1, 2};
@@ -705,8 +706,8 @@ namespace thermion
.width(width)
.height(height)
.levels(1)
.usage(filament::Texture::Usage::DEPTH_ATTACHMENT | filament::Texture::Usage::SAMPLEABLE)
.format(filament::Texture::InternalFormat::DEPTH32F)
.usage(filament::Texture::Usage::DEPTH_ATTACHMENT | filament::Texture::Usage::STENCIL_ATTACHMENT | filament::Texture::Usage::SAMPLEABLE)
.format(filament::Texture::InternalFormat::DEPTH24_STENCIL8)
.build(*_engine);
auto rt = filament::RenderTarget::Builder()
.texture(RenderTarget::AttachmentPoint::COLOR, rtColor)
@@ -767,6 +768,9 @@ namespace thermion
view->setStencilBufferEnabled(true);
view->setAmbientOcclusionOptions({.enabled = false});
view->setDynamicResolutionOptions({.enabled = false});
ACESToneMapper tm;
auto colorGrading = ColorGrading::Builder().toneMapper(&tm).build(*_engine);
view->setColorGrading(colorGrading);
#if defined(_WIN32)
view->setStereoscopicOptions({.enabled = false});
#endif
@@ -797,25 +801,6 @@ namespace thermion
return nullptr;
}
/// @brief
///
///
void FilamentViewer::clearEntities()
{
_sceneManager->destroyAll();
}
/// @brief
/// @param asset
///
void FilamentViewer::removeEntity(EntityId asset)
{
_renderMutex.lock();
// todo - what if we are using a camera from this asset?
_sceneManager->remove(asset);
_renderMutex.unlock();
}
///
///
///
@@ -1046,8 +1031,7 @@ namespace thermion
uint64_t frameTimeInNanos)
{
_sceneManager->updateTransforms();
_sceneManager->updateAnimations();
_sceneManager->update();
for(auto swapChain : _swapChains) {
auto views = _renderable[swapChain];
@@ -1091,7 +1075,6 @@ namespace thermion
}
};
// Create a fence
Fence *fence = nullptr;
if (useFence)
{
@@ -1127,7 +1110,7 @@ namespace thermion
{
if(swapChain && !_engine->isValid(swapChain)) {
Log("SWAPCHAIN PROVIDED BUT NOT VALID");
Log("SwapChain exists, but is not valid");
return;
}
@@ -1191,21 +1174,9 @@ namespace thermion
return _engine->getCameraComponent(Entity::import(entity));
}
bool FilamentViewer::isNonPickableEntity(EntityId entityId) {
auto renderable = Entity::import(entityId);
return _sceneManager->isGizmoEntity(renderable) || renderable == _imageEntity || renderable == _sceneManager->_gridOverlay->sphere() || _sceneManager->_gridOverlay->grid();
}
void FilamentViewer::pick(View *view, uint32_t x, uint32_t y, PickCallback callback)
{
view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
callback(Entity::smuggle(result.renderable), x, y, view, result.depth, result.fragCoords.x, result.fragCoords.y, result.fragCoords.z);
});
}
void FilamentViewer::unprojectTexture(EntityId entityId, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
{
const auto *geometry = _sceneManager->getGeometry(entityId);
// const auto *geometry = _sceneManager->getGeometry(entityId);
// if (!geometry->uvs)
// {
// Log("No UVS");

View File

@@ -1,345 +0,0 @@
#include "Gizmo.hpp"
#include <filament/Engine.h>
#include <utils/Entity.h>
#include <utils/EntityManager.h>
#include <filament/RenderableManager.h>
#include <filament/TransformManager.h>
#include <gltfio/math.h>
#include "SceneManager.hpp"
#include "material/unlit_fixed_size.h"
#include "Log.hpp"
namespace thermion {
using namespace filament::gltfio;
Gizmo::Gizmo(Engine *engine, View *view, Scene* scene, Material* material) : _engine(engine), _view(view), _scene(scene), _material(material)
{
auto &entityManager = EntityManager::get();
auto &transformManager = _engine->getTransformManager();
// First, create the black cube at the center
// The axes widgets will be parented to this entity
_entities[3] = entityManager.create();
_materialInstances[3] = _material->createInstance();
_materialInstances[3]->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 1.0f}); // Black color
// Create center cube vertices
float centerCubeSize = 0.01f;
float *centerCubeVertices = new float[8 * 3]{
-centerCubeSize, -centerCubeSize, -centerCubeSize,
centerCubeSize, -centerCubeSize, -centerCubeSize,
centerCubeSize, centerCubeSize, -centerCubeSize,
-centerCubeSize, centerCubeSize, -centerCubeSize,
-centerCubeSize, -centerCubeSize, centerCubeSize,
centerCubeSize, -centerCubeSize, centerCubeSize,
centerCubeSize, centerCubeSize, centerCubeSize,
-centerCubeSize, centerCubeSize, centerCubeSize};
// Create center cube indices
uint16_t *centerCubeIndices = new uint16_t[36]{
0, 1, 2, 2, 3, 0,
1, 5, 6, 6, 2, 1,
5, 4, 7, 7, 6, 5,
4, 0, 3, 3, 7, 4,
3, 2, 6, 6, 7, 3,
4, 5, 1, 1, 0, 4};
auto centerCubeVb = VertexBuffer::Builder()
.vertexCount(8)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(*engine);
centerCubeVb->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<float *>(buffer); }));
auto centerCubeIb = IndexBuffer::Builder().indexCount(36).bufferType(IndexBuffer::IndexType::USHORT).build(*engine);
centerCubeIb->setBuffer(*engine, IndexBuffer::BufferDescriptor(
centerCubeIndices, 36 * sizeof(uint16_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint16_t *>(buffer); }));
RenderableManager::Builder(1)
.boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
{centerCubeSize, centerCubeSize, centerCubeSize}})
.material(0, _materialInstances[3])
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.priority(7)
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
.culling(false)
.build(*engine, _entities[3]);
auto cubeTransformInstance = transformManager.getInstance(_entities[3]);
math::mat4f cubeTransform;
transformManager.setTransform(cubeTransformInstance, cubeTransform);
// Line and arrow vertices
float lineLength = 0.6f;
float lineWidth = 0.004f;
float arrowLength = 0.06f;
float arrowWidth = 0.02f;
float *vertices = new float[13 * 3]{
// Line vertices (8 vertices)
-lineWidth, -lineWidth, 0.0f,
lineWidth, -lineWidth, 0.0f,
lineWidth, lineWidth, 0.0f,
-lineWidth, lineWidth, 0.0f,
-lineWidth, -lineWidth, lineLength,
lineWidth, -lineWidth, lineLength,
lineWidth, lineWidth, lineLength,
-lineWidth, lineWidth, lineLength,
// Arrow vertices (5 vertices)
0.0f, 0.0f, lineLength + arrowLength, // Tip of the arrow
-arrowWidth, -arrowWidth, lineLength, // Base of the arrow
arrowWidth, -arrowWidth, lineLength,
arrowWidth, arrowWidth, lineLength,
-arrowWidth, arrowWidth, lineLength};
// Line and arrow indices
uint16_t *indices = new uint16_t[54]{
// Line indices (24 indices)
0, 1, 5, 5, 4, 0,
1, 2, 6, 6, 5, 1,
2, 3, 7, 7, 6, 2,
3, 0, 4, 4, 7, 3,
// Arrow indices (30 indices)
8, 9, 10, // Front face
8, 10, 11, // Right face
8, 11, 12, // Back face
8, 12, 9, // Left face
9, 12, 11, 11, 10, 9 // Base of the arrow
};
auto vb = VertexBuffer::Builder()
.vertexCount(13)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(*engine);
vb->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(vertices, 13 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<float *>(buffer); }));
auto ib = IndexBuffer::Builder().indexCount(54).bufferType(IndexBuffer::IndexType::USHORT).build(*engine);
ib->setBuffer(*engine, IndexBuffer::BufferDescriptor(
indices, 54 * sizeof(uint16_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint16_t *>(buffer); }));
// Create the three axes
for (int i = 0; i < 3; i++)
{
_entities[i] = entityManager.create();
_materialInstances[i] = _material->createInstance();
auto baseColor = inactiveColors[i];
math::mat4f transform;
switch (i)
{
case Axis::X:
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 1.0f, 0.0f, 0.0f});
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
break;
case 1:
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 0.0f, 1.0f, 0.0f});
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
break;
case 2:
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 0.0f, 0.0f, 1.0f});
break;
}
_materialInstances[i]->setParameter("baseColorFactor", baseColor);
RenderableManager::Builder(1)
.boundingBox({{-arrowWidth, -arrowWidth, 0},
{arrowWidth, arrowWidth, lineLength + arrowLength}})
.material(0, _materialInstances[i])
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb, ib, 0, 54)
.priority(6)
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(*engine, _entities[i]);
auto instance = transformManager.getInstance(_entities[i]);
transformManager.setTransform(instance, transform);
// parent the axis to the center cube
transformManager.setParent(instance, cubeTransformInstance);
}
createTransparentRectangles();
}
Gizmo::~Gizmo() {
_scene->removeEntities(_entities, 7);
for(int i = 0; i < 7; i++) {
_engine->destroy(_entities[i]);
}
for(int i = 0; i < 7; i++) {
_engine->destroy(_materialInstances[i]);
}
_engine->destroy(_material);
}
void Gizmo::createTransparentRectangles()
{
auto &entityManager = EntityManager::get();
auto &transformManager = _engine->getTransformManager();
float volumeWidth = 0.2f;
float volumeLength = 1.2f;
float volumeDepth = 0.2f;
float *volumeVertices = new float[8 * 3]{
-volumeWidth / 2, -volumeDepth / 2, 0,
volumeWidth / 2, -volumeDepth / 2, 0,
volumeWidth / 2, -volumeDepth / 2, volumeLength,
-volumeWidth / 2, -volumeDepth / 2, volumeLength,
-volumeWidth / 2, volumeDepth / 2, 0,
volumeWidth / 2, volumeDepth / 2, 0,
volumeWidth / 2, volumeDepth / 2, volumeLength,
-volumeWidth / 2, volumeDepth / 2, volumeLength
};
uint16_t *volumeIndices = new uint16_t[36]{
0, 1, 2, 2, 3, 0, // Bottom face
4, 5, 6, 6, 7, 4, // Top face
0, 4, 7, 7, 3, 0, // Left face
1, 5, 6, 6, 2, 1, // Right face
0, 1, 5, 5, 4, 0, // Front face
3, 2, 6, 6, 7, 3 // Back face
};
auto volumeVb = VertexBuffer::Builder()
.vertexCount(8)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(*_engine);
volumeVb->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(
volumeVertices, 8 * sizeof(filament::math::float3),
[](void *buffer, size_t size, void *) { delete[] static_cast<float *>(buffer); }
));
auto volumeIb = IndexBuffer::Builder()
.indexCount(36)
.bufferType(IndexBuffer::IndexType::USHORT)
.build(*_engine);
volumeIb->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
volumeIndices, 36 * sizeof(uint16_t),
[](void *buffer, size_t size, void *) { delete[] static_cast<uint16_t *>(buffer); }
));
for (int i = 4; i < 7; i++)
{
_entities[i] = entityManager.create();
_materialInstances[i] = _material->createInstance();
_materialInstances[i]->setParameter("color", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
math::mat4f transform;
switch (i-4)
{
case Axis::X:
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
break;
case Axis::Y:
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
break;
case Axis::Z:
break;
}
RenderableManager::Builder(1)
.boundingBox({{-volumeWidth / 2, -volumeDepth / 2, 0}, {volumeWidth / 2, volumeDepth / 2, volumeLength}})
.material(0, _materialInstances[i])
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, volumeVb, volumeIb, 0, 36)
.priority(7)
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(*_engine, _entities[i]);
auto instance = transformManager.getInstance(_entities[i]);
transformManager.setTransform(instance, transform);
// Parent the picking volume to the center cube
transformManager.setParent(instance, transformManager.getInstance(_entities[3]));
}
}
void Gizmo::highlight(Entity entity) {
auto &rm = _engine->getRenderableManager();
auto renderableInstance = rm.getInstance(entity);
auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
math::float4 baseColor;
if(entity == x()) {
baseColor = activeColors[Axis::X];
} else if(entity == y()) {
baseColor = activeColors[Axis::Y];
} else if(entity == z()) {
baseColor = activeColors[Axis::Z];
} else {
baseColor = math::float4 { 1.0f, 1.0f, 1.0f, 1.0f };
}
materialInstance->setParameter("color", baseColor);
}
void Gizmo::unhighlight() {
auto &rm = _engine->getRenderableManager();
for(int i = 0; i < 3; i++) {
auto renderableInstance = rm.getInstance(_entities[i]);
auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
math::float4 baseColor = inactiveColors[i];
materialInstance->setParameter("color", baseColor);
}
}
void Gizmo::pick(uint32_t x, uint32_t y, PickCallback callback)
{
auto handler = new Gizmo::PickCallbackHandler(this, callback);
_view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
handler->handle(result);
});
}
bool Gizmo::isGizmoEntity(Entity e) {
for(int i = 0; i < 7; i++) {
if(e == _entities[i]) {
return true;
}
}
return false;
}
void Gizmo::setVisibility(bool visible) {
if(visible) {
_scene->addEntities(_entities, 7);
} else {
_scene->removeEntities(_entities, 7);
}
}
}

View File

@@ -3,7 +3,7 @@
#include <cmath>
#endif
#include "GridOverlay.hpp"
#include "scene/GridOverlay.hpp"
#include <filament/Engine.h>
#include <utils/Entity.h>
@@ -13,190 +13,190 @@
#include <gltfio/math.h>
#include "material/grid.h"
#include "SceneManager.hpp"
#include "scene/SceneManager.hpp"
#include "Log.hpp"
namespace thermion {
using namespace filament::gltfio;
GridOverlay::GridOverlay(Engine &engine) : _engine(engine)
namespace thermion
{
auto &entityManager = EntityManager::get();
auto &transformManager = engine.getTransformManager();
const int gridSize = 100;
const float gridSpacing = 1.0f;
int vertexCount = (gridSize + 1) * 4; // 2 axes, 2 vertices per line
using namespace filament::gltfio;
float* gridVertices = new float[vertexCount * 3];
int index = 0;
GridOverlay::GridOverlay(Engine &engine) : _engine(engine)
{
auto &entityManager = EntityManager::get();
auto &transformManager = engine.getTransformManager();
// Create grid lines
for (int i = 0; i <= gridSize; ++i) {
float pos = i * gridSpacing - (gridSize * gridSpacing / 2);
const int gridSize = 100;
const float gridSpacing = 1.0f;
int vertexCount = (gridSize + 1) * 4; // 2 axes, 2 vertices per line
// X-axis lines
gridVertices[index++] = pos;
gridVertices[index++] = 0;
gridVertices[index++] = -(gridSize * gridSpacing / 2);
float *gridVertices = new float[vertexCount * 3];
int index = 0;
gridVertices[index++] = pos;
gridVertices[index++] = 0;
gridVertices[index++] = (gridSize * gridSpacing / 2);
// Create grid lines
for (int i = 0; i <= gridSize; ++i)
{
float pos = i * gridSpacing - (gridSize * gridSpacing / 2);
// Z-axis lines
gridVertices[index++] = -(gridSize * gridSpacing / 2);
gridVertices[index++] = 0;
gridVertices[index++] = pos;
// X-axis lines
gridVertices[index++] = pos;
gridVertices[index++] = 0;
gridVertices[index++] = -(gridSize * gridSpacing / 2);
gridVertices[index++] = (gridSize * gridSpacing / 2);
gridVertices[index++] = 0;
gridVertices[index++] = pos;
gridVertices[index++] = pos;
gridVertices[index++] = 0;
gridVertices[index++] = (gridSize * gridSpacing / 2);
// Z-axis lines
gridVertices[index++] = -(gridSize * gridSpacing / 2);
gridVertices[index++] = 0;
gridVertices[index++] = pos;
gridVertices[index++] = (gridSize * gridSpacing / 2);
gridVertices[index++] = 0;
gridVertices[index++] = pos;
}
auto vb = VertexBuffer::Builder()
.vertexCount(vertexCount)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(engine);
vb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(gridVertices, vertexCount * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<float *>(buffer); }));
uint32_t *gridIndices = new uint32_t[vertexCount];
for (uint32_t i = 0; i < vertexCount; ++i)
{
gridIndices[i] = i;
}
auto ib = IndexBuffer::Builder()
.indexCount(vertexCount)
.bufferType(IndexBuffer::IndexType::UINT)
.build(engine);
ib->setBuffer(engine, IndexBuffer::BufferDescriptor(
gridIndices, vertexCount * sizeof(uint32_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint32_t *>(buffer); }));
_gridEntity = entityManager.create();
_material = Material::Builder()
.package(GRID_PACKAGE, GRID_GRID_SIZE)
.build(engine);
_materialInstance = _material->createInstance();
_materialInstance->setParameter("maxDistance", 50.0f); // Adjust as needed
_materialInstance->setParameter("color", math::float3{0.5f, 0.5f, 0.5f}); // Gray color for the grid
RenderableManager::Builder(1)
.boundingBox({{-gridSize * gridSpacing / 2, 0, -gridSize * gridSpacing / 2},
{gridSize * gridSpacing / 2, 0, gridSize * gridSpacing / 2}})
.material(0, _materialInstance)
.geometry(0, RenderableManager::PrimitiveType::LINES, vb, ib, 0, vertexCount)
.priority(0)
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.culling(true)
.receiveShadows(false)
.castShadows(false)
.build(engine, _gridEntity);
const float sphereRadius = 0.05f;
const int sphereSegments = 16;
const int sphereRings = 16;
vertexCount = (sphereRings + 1) * (sphereSegments + 1);
int indexCount = sphereRings * sphereSegments * 6;
math::float3 *vertices = new math::float3[vertexCount];
uint32_t *indices = new uint32_t[indexCount];
int vertexIndex = 0;
// Generate sphere vertices
for (int ring = 0; ring <= sphereRings; ++ring)
{
float theta = ring * M_PI / sphereRings;
float sinTheta = std::sin(theta);
float cosTheta = std::cos(theta);
for (int segment = 0; segment <= sphereSegments; ++segment)
{
float phi = segment * 2 * M_PI / sphereSegments;
float sinPhi = std::sin(phi);
float cosPhi = std::cos(phi);
float x = cosPhi * sinTheta;
float y = cosTheta;
float z = sinPhi * sinTheta;
vertices[vertexIndex++] = {x * sphereRadius, y * sphereRadius, z * sphereRadius};
}
}
int indexIndex = 0;
// Generate sphere indices
for (int ring = 0; ring < sphereRings; ++ring)
{
for (int segment = 0; segment < sphereSegments; ++segment)
{
uint32_t current = ring * (sphereSegments + 1) + segment;
uint32_t next = current + sphereSegments + 1;
indices[indexIndex++] = current;
indices[indexIndex++] = next;
indices[indexIndex++] = current + 1;
indices[indexIndex++] = current + 1;
indices[indexIndex++] = next;
indices[indexIndex++] = next + 1;
}
}
auto sphereVb = VertexBuffer::Builder()
.vertexCount(vertexCount)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(engine);
sphereVb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(vertices, vertexCount * sizeof(math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<math::float3 *>(buffer); }));
auto sphereIb = IndexBuffer::Builder()
.indexCount(indexCount)
.bufferType(IndexBuffer::IndexType::UINT)
.build(engine);
sphereIb->setBuffer(engine, IndexBuffer::BufferDescriptor(
indices, indexCount * sizeof(uint32_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint32_t *>(buffer); }));
_sphereEntity = entityManager.create();
RenderableManager::Builder(1)
.boundingBox({{-sphereRadius, -sphereRadius, -sphereRadius},
{sphereRadius, sphereRadius, sphereRadius}})
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, sphereVb, sphereIb, 0, indexCount)
.priority(0)
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.culling(true)
.receiveShadows(false)
.castShadows(false)
.build(engine, _sphereEntity);
}
auto vb = VertexBuffer::Builder()
.vertexCount(vertexCount)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(engine);
vb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(
gridVertices, vertexCount * sizeof(filament::math::float3),
[](void* buffer, size_t size, void*) { delete[] static_cast<float*>(buffer); }
));
uint32_t* gridIndices = new uint32_t[vertexCount];
for (uint32_t i = 0; i < vertexCount; ++i) {
gridIndices[i] = i;
void GridOverlay::destroy()
{
auto &rm = _engine.getRenderableManager();
auto &tm = _engine.getTransformManager();
rm.destroy(_sphereEntity);
rm.destroy(_gridEntity);
tm.destroy(_sphereEntity);
tm.destroy(_gridEntity);
_engine.destroy(_sphereEntity);
_engine.destroy(_gridEntity);
}
auto ib = IndexBuffer::Builder()
.indexCount(vertexCount)
.bufferType(IndexBuffer::IndexType::UINT)
.build(engine);
ib->setBuffer(engine, IndexBuffer::BufferDescriptor(
gridIndices, vertexCount * sizeof(uint32_t),
[](void* buffer, size_t size, void*) { delete[] static_cast<uint32_t*>(buffer); }
));
_gridEntity = entityManager.create();
_material = Material::Builder()
.package(GRID_PACKAGE, GRID_GRID_SIZE)
.build(engine);
_materialInstance = _material->createInstance();
_materialInstance->setParameter("maxDistance", 50.0f); // Adjust as needed
_materialInstance->setParameter("color", math::float3{0.5f, 0.5f, 0.5f}); // Gray color for the grid
RenderableManager::Builder(1)
.boundingBox({{-gridSize * gridSpacing / 2, 0, -gridSize * gridSpacing / 2},
{gridSize * gridSpacing / 2, 0, gridSize * gridSpacing / 2}})
.material(0, _materialInstance)
.geometry(0, RenderableManager::PrimitiveType::LINES, vb, ib, 0, vertexCount)
.priority(6)
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(engine, _gridEntity);
const float sphereRadius = 0.05f;
const int sphereSegments = 16;
const int sphereRings = 16;
vertexCount = (sphereRings + 1) * (sphereSegments + 1);
int indexCount = sphereRings * sphereSegments * 6;
math::float3* vertices = new math::float3[vertexCount];
uint32_t* indices = new uint32_t[indexCount];
int vertexIndex = 0;
// Generate sphere vertices
for (int ring = 0; ring <= sphereRings; ++ring) {
float theta = ring * M_PI / sphereRings;
float sinTheta = std::sin(theta);
float cosTheta = std::cos(theta);
for (int segment = 0; segment <= sphereSegments; ++segment) {
float phi = segment * 2 * M_PI / sphereSegments;
float sinPhi = std::sin(phi);
float cosPhi = std::cos(phi);
float x = cosPhi * sinTheta;
float y = cosTheta;
float z = sinPhi * sinTheta;
vertices[vertexIndex++] = {x * sphereRadius, y * sphereRadius, z * sphereRadius};
}
}
int indexIndex = 0;
// Generate sphere indices
for (int ring = 0; ring < sphereRings; ++ring) {
for (int segment = 0; segment < sphereSegments; ++segment) {
uint32_t current = ring * (sphereSegments + 1) + segment;
uint32_t next = current + sphereSegments + 1;
indices[indexIndex++] = current;
indices[indexIndex++] = next;
indices[indexIndex++] = current + 1;
indices[indexIndex++] = current + 1;
indices[indexIndex++] = next;
indices[indexIndex++] = next + 1;
}
}
auto sphereVb = VertexBuffer::Builder()
.vertexCount(vertexCount)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(engine);
sphereVb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(
vertices, vertexCount * sizeof(math::float3),
[](void* buffer, size_t size, void*) { delete[] static_cast<math::float3*>(buffer); }
));
auto sphereIb = IndexBuffer::Builder()
.indexCount(indexCount)
.bufferType(IndexBuffer::IndexType::UINT)
.build(engine);
sphereIb->setBuffer(engine, IndexBuffer::BufferDescriptor(
indices, indexCount * sizeof(uint32_t),
[](void* buffer, size_t size, void*) { delete[] static_cast<uint32_t*>(buffer); }
));
_sphereEntity = entityManager.create();
RenderableManager::Builder(1)
.boundingBox({{-sphereRadius, -sphereRadius, -sphereRadius},
{sphereRadius, sphereRadius, sphereRadius}})
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, sphereVb, sphereIb, 0, indexCount)
.priority(6)
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(engine, _sphereEntity);
}
void GridOverlay::destroy()
{
auto &rm = _engine.getRenderableManager();
auto &tm = _engine.getTransformManager();
rm.destroy(_sphereEntity);
rm.destroy(_gridEntity);
tm.destroy(_sphereEntity);
tm.destroy(_gridEntity);
_engine.destroy(_sphereEntity);
_engine.destroy(_gridEntity);
}
} // namespace thermion

View File

@@ -1,172 +1,178 @@
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <utils/EntityManager.h>
// #include <filament/Material.h>
// #include <filament/MaterialInstance.h>
// #include <utils/EntityManager.h>
#include "SceneManager.hpp"
// #include "scene/SceneManager.hpp"
namespace thermion
{
// namespace thermion
// {
SceneManager::HighlightOverlay::HighlightOverlay(
EntityId entityId,
SceneManager *const sceneManager,
Engine *engine,
float r,
float g,
float b) : _sceneManager(sceneManager), _engine(engine)
{
// SceneManager::HighlightOverlay::HighlightOverlay(
// EntityId entityId,
// SceneManager *const sceneManager,
// Engine *engine,
// float r,
// float g,
// float b) : _sceneManager(sceneManager), _engine(engine)
// {
auto &rm = engine->getRenderableManager();
// auto &rm = engine->getRenderableManager();
auto &tm = engine->getTransformManager();
// auto &tm = engine->getTransformManager();
// Create the outline/highlight material instance
filament::gltfio::MaterialKey dummyKey; // We're not using the key for this simple material
filament::gltfio::UvMap dummyUvMap; // We're not using UV mapping for this simple material
// // Create the outline/highlight material instance
// filament::gltfio::MaterialKey dummyKey; // We're not using the key for this simple material
// filament::gltfio::UvMap dummyUvMap; // We're not using UV mapping for this simple material
auto materialProvider = sceneManager->unlitMaterialProvider();
// auto materialProvider = sceneManager->unlitMaterialProvider();
_highlightMaterialInstance = materialProvider->createMaterialInstance(&dummyKey, &dummyUvMap);
_highlightMaterialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
_highlightMaterialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
_highlightMaterialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
_highlightMaterialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::NE);
_highlightMaterialInstance->setStencilReferenceValue(1);
// _highlightMaterialInstance = materialProvider->createMaterialInstance(&dummyKey, &dummyUvMap);
// _highlightMaterialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
// _highlightMaterialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
// _highlightMaterialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
// _highlightMaterialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::NE);
// _highlightMaterialInstance->setStencilReferenceValue(1);
_highlightMaterialInstance->setParameter("baseColorFactor", filament::math::float3{r, g, b});
_highlightMaterialInstance->setParameter("vertexScale", 1.04f);
_highlightMaterialInstance->setCullingMode(filament::backend::CullingMode::FRONT);
// _highlightMaterialInstance->setParameter("baseColorFactor", filament::math::float3{r, g, b});
// _highlightMaterialInstance->setParameter("vertexScale", 1.04f);
// _highlightMaterialInstance->setCullingMode(filament::backend::CullingMode::FRONT);
// auto scene = sceneManager->getScene();
auto scene = sceneManager->getScene();
// // _isGeometryEntity = sceneManager->isGeometryEntity(entityId);
// // _isGltfAsset = sceneManager->isGltfAsset(entityId);
_isGeometryEntity = sceneManager->isGeometryEntity(entityId);
_isGltfAsset = sceneManager->isGltfAsset(entityId);
// if (!(_isGeometryEntity || _isGltfAsset))
// {
// Log("Failed to set stencil outline for entity %d: the entity is a child of another entity. "
// "Currently, we only support outlining top-level entities."
// "Call getAncestor() to get the ancestor of this entity, then set on that",
// entityId);
// return;
// }
if (!(_isGeometryEntity || _isGltfAsset))
{
Log("Failed to set stencil outline for entity %d: the entity is a child of another entity. "
"Currently, we only support outlining top-level entities."
"Call getAncestor() to get the ancestor of this entity, then set on that",
entityId);
return;
}
// if (_isGeometryEntity)
// {
if (_isGeometryEntity)
{
// auto geometryEntity = Entity::import(entityId);
// auto renderable = rm.getInstance(geometryEntity);
auto geometryEntity = Entity::import(entityId);
auto renderable = rm.getInstance(geometryEntity);
// auto materialInstance = rm.getMaterialInstanceAt(renderable, 0);
auto materialInstance = rm.getMaterialInstanceAt(renderable, 0);
// // set stencil write on the existing material
// materialInstance->setStencilWrite(true);
// materialInstance->setDepthWrite(true);
// materialInstance->setStencilReferenceValue(1);
// materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
// materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
// materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::KEEP);
// materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
// // materialInstance->setCullingMode(filament::MaterialInstance::CullingMode::BACK);
// set stencil write on the existing material
materialInstance->setStencilWrite(true);
materialInstance->setDepthWrite(true);
materialInstance->setStencilReferenceValue(1);
materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::KEEP);
materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
// materialInstance->setCullingMode(filament::MaterialInstance::CullingMode::BACK);
// // auto geometry = sceneManager->getGeometry(entityId);
auto geometry = sceneManager->getGeometry(entityId);
// // _entity = geometry->createInstance(materialInstance);
_entity = geometry->createInstance(materialInstance);
// scene->addEntity(_entity);
// auto outlineTransformInstance = tm.getInstance(_entity);
// auto entityTransformInstance = tm.getInstance(geometryEntity);
// tm.setParent(outlineTransformInstance, entityTransformInstance);
// }
// else if (_isGltfAsset)
// {
// Log("Entity %d is gltf", entityId);
// // auto *asset = sceneManager->getAssetByEntityId(entityId);
scene->addEntity(_entity);
auto outlineTransformInstance = tm.getInstance(_entity);
auto entityTransformInstance = tm.getInstance(geometryEntity);
tm.setParent(outlineTransformInstance, entityTransformInstance);
}
else if (_isGltfAsset)
{
Log("Entity %d is gltf", entityId);
auto *asset = sceneManager->getAssetByEntityId(entityId);
// // if (asset)
// // {
if (asset)
{
// // Log("Found glTF FilamentAsset with %d material instances", asset->getInstance()->getMaterialInstanceCount());
Log("Found glTF FilamentAsset with %d material instances", asset->getInstance()->getMaterialInstanceCount());
// // auto materialInstance = asset->getInstance()->getMaterialInstances()[0];
auto materialInstance = asset->getInstance()->getMaterialInstances()[0];
// // // set stencil write on the existing material
// // materialInstance->setStencilWrite(true);
// // materialInstance->setDepthWrite(true);
// // materialInstance->setStencilReferenceValue(1);
// // materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
// // materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::REPLACE);
// // materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
// // materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
// set stencil write on the existing material
materialInstance->setStencilWrite(true);
materialInstance->setDepthWrite(true);
materialInstance->setStencilReferenceValue(1);
materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::REPLACE);
materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
// // _newInstance = sceneManager->createGltfAssetInstance(asset);
_newInstance = sceneManager->createGltfAssetInstance(asset);
// // _entity = _newInstance->getRoot();
_entity = _newInstance->getRoot();
// // auto newTransformInstance = tm.getInstance(_entity);
auto newTransformInstance = tm.getInstance(_entity);
// // auto entityTransformInstance = tm.getInstance(asset->getRoot());
// // tm.setParent(newTransformInstance, entityTransformInstance);
// // if (!_newInstance)
// // {
// // Log("Couldn't create new instance");
// // }
// // else
// // {
// // for (int i = 0; i < _newInstance->getEntityCount(); i++)
// // {
// // auto entity = _newInstance->getEntities()[i];
// // auto renderableInstance = rm.getInstance(entity);
// // rm.setPriority(renderableInstance, 7);
// // if (renderableInstance.isValid())
// // {
// // for (int primitiveIndex = 0; primitiveIndex < rm.getPrimitiveCount(renderableInstance); primitiveIndex++)
// // {
// // rm.setMaterialInstanceAt(renderableInstance, primitiveIndex, _highlightMaterialInstance);
// // }
// // }
// // else
// // {
// // Log("Not renderable, ignoring");
// // }
// // }
// // scene->addEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
// // }
// }
// else
// {
// Log("Not FilamentAsset");
// }
// }
auto entityTransformInstance = tm.getInstance(asset->getRoot());
tm.setParent(newTransformInstance, entityTransformInstance);
if (!_newInstance)
{
Log("Couldn't create new instance");
}
else
{
for (int i = 0; i < _newInstance->getEntityCount(); i++)
{
auto entity = _newInstance->getEntities()[i];
auto renderableInstance = rm.getInstance(entity);
rm.setPriority(renderableInstance, 7);
if (renderableInstance.isValid())
{
for (int primitiveIndex = 0; primitiveIndex < rm.getPrimitiveCount(renderableInstance); primitiveIndex++)
{
rm.setMaterialInstanceAt(renderableInstance, primitiveIndex, _highlightMaterialInstance);
}
}
else
{
Log("Not renderable, ignoring");
}
}
scene->addEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
}
}
else
{
Log("Not FilamentAsset");
}
}
}
// SceneManager::HighlightOverlay::~HighlightOverlay()
// {
// if (_entity.isNull())
// {
// Log("Null entity");
// return;
// }
SceneManager::HighlightOverlay::~HighlightOverlay()
{
if (_entity.isNull())
{
Log("Null entity");
return;
}
if (_isGltfAsset)
{
_sceneManager->getScene()->removeEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
_newInstance->detachMaterialInstances();
_engine->destroy(_highlightMaterialInstance);
}
else if (_isGeometryEntity)
{
auto &tm = _engine->getTransformManager();
auto transformInstance = tm.getInstance(_entity);
_sceneManager->getScene()->remove(_entity);
utils::EntityManager::get().destroy(_entity);
_engine->destroy(_entity);
_engine->destroy(_highlightMaterialInstance);
}
else
{
Log("FATAL: Unknown highlight overlay entity type");
}
}
}
// if (_isGltfAsset)
// {
// Log("Destroyed gltf asset highlight overlay");
// _sceneManager->getScene()->removeEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
// // _sceneManager->destroyGltfAssetInstance(_newInstance);
// // auto materialInstances = _newInstance->getMaterialInstances();
// // auto numMaterialInstances = _newInstance->getMaterialInstanceCount();
// // _newInstance->detachMaterialInstances();
// // for(int i = 0; i < numMaterialInstances; i++) {
// // _engine->destroy(_highlightMaterialInstance);
// // }
// // _engine->destroy(_newInstance);
// }
// else if (_isGeometryEntity)
// {
// auto &tm = _engine->getTransformManager();
// auto transformInstance = tm.getInstance(_entity);
// _sceneManager->getScene()->remove(_entity);
// utils::EntityManager::get().destroy(_entity);
// _engine->destroy(_entity);
// _engine->destroy(_highlightMaterialInstance);
// }
// else
// {
// Log("FATAL: Unknown highlight overlay entity type");
// }
// }
// }

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +0,0 @@
#include <filament/View.h>
#include <filament/Engine.h>
#include <filament/Scene.h>
#include "ThermionDartApi.h"
#include "TGizmo.h"
#include "Gizmo.hpp"
#include "Log.hpp"
#ifdef __cplusplus
namespace thermion {
extern "C"
{
using namespace filament;
#endif
EMSCRIPTEN_KEEPALIVE void Gizmo_pick(TGizmo *tGizmo, uint32_t x, uint32_t y, GizmoPickCallback callback)
{
auto *gizmo = reinterpret_cast<Gizmo*>(tGizmo);
gizmo->pick(x, y, reinterpret_cast<Gizmo::PickCallback>(callback));
}
EMSCRIPTEN_KEEPALIVE void Gizmo_setVisibility(TGizmo *tGizmo, bool visible) {
auto *gizmo = reinterpret_cast<Gizmo*>(tGizmo);
gizmo->setVisibility(visible);
}
#ifdef __cplusplus
}
}
#endif

View File

@@ -1,57 +0,0 @@
#include <filament/MaterialInstance.h>
#include <math/mat4.h>
#include <math/vec4.h>
#include <math/vec2.h>
#include "Log.hpp"
#include "TMaterialInstance.h"
#ifdef __cplusplus
namespace thermion
{
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance *materialInstance, bool enabled)
{
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setDepthWrite(enabled);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance *materialInstance, bool enabled)
{
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setDepthCulling(enabled);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat4(TMaterialInstance *tMaterialInstance, const char *propertyName, double x, double y, double z, double w)
{
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
filament::math::float4 data{static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(w)};
materialInstance->setParameter(propertyName, data);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat2(TMaterialInstance *materialInstance, const char *propertyName, double x, double y)
{
filament::math::float2 data{static_cast<float>(x), static_cast<float>(y)};
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, data);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat(TMaterialInstance *materialInstance, const char *propertyName, double value)
{
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, static_cast<float>(value));
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterInt(TMaterialInstance *materialInstance, const char *propertyName, int value)
{
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, value);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthFunc(TMaterialInstance *tMaterialInstance, TDepthFunc tDepthFunc) {
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
auto depthFunc = static_cast<filament::MaterialInstance::DepthFunc>(tDepthFunc);
materialInstance->setDepthFunc(depthFunc);
}
#ifdef __cplusplus
}
}
#endif

View File

@@ -1,140 +0,0 @@
#include "filament/LightManager.h"
#include "ResourceBuffer.hpp"
#include "FilamentViewer.hpp"
#include "Log.hpp"
#include "APIExport.h"
using namespace thermion;
extern "C"
{
#include "TSceneManager.h"
EMSCRIPTEN_KEEPALIVE TGizmo *SceneManager_createGizmo(TSceneManager *tSceneManager, TView *tView, TScene *tScene)
{
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *scene = reinterpret_cast<Scene *>(tScene);
auto *view = reinterpret_cast<View *>(tView);
auto gizmo = sceneManager->createGizmo(view, scene);
return reinterpret_cast<TGizmo *>(gizmo);
}
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_loadGlbFromBuffer(TSceneManager *sceneManager, const uint8_t *const data, size_t length, bool keepData, int priority, int layer, bool loadResourcesAsync)
{
return ((SceneManager *)sceneManager)->loadGlbFromBuffer((const uint8_t *)data, length, 1, keepData, priority, layer, loadResourcesAsync);
}
EMSCRIPTEN_KEEPALIVE bool SceneManager_setMorphAnimation(
TSceneManager *sceneManager,
EntityId asset,
const float *const morphData,
const uint32_t *const morphIndices,
int numMorphTargets,
int numFrames,
float frameLengthInMs)
{
auto result = ((SceneManager *)sceneManager)->setMorphAnimationBuffer(asset, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs);
return result;
}
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraByName(TSceneManager *tSceneManager, EntityId entityId, const char *name)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return nullptr;
}
EMSCRIPTEN_KEEPALIVE bool SceneManager_setTransform(TSceneManager *sceneManager, EntityId entityId, const double *const transform)
{
auto matrix = math::mat4(
transform[0], transform[1], transform[2],
transform[3],
transform[4],
transform[5],
transform[6],
transform[7],
transform[8],
transform[9],
transform[10],
transform[11],
transform[12],
transform[13],
transform[14],
transform[15]);
return ((SceneManager *)sceneManager)->setTransform(entityId, matrix);
}
EMSCRIPTEN_KEEPALIVE Aabb3 SceneManager_getRenderableBoundingBox(TSceneManager *tSceneManager, EntityId entity)
{
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return sceneManager->getRenderableBoundingBox(entity);
}
EMSCRIPTEN_KEEPALIVE void SceneManager_setVisibilityLayer(TSceneManager *tSceneManager, EntityId entity, int layer)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
sceneManager->setVisibilityLayer(entity, layer);
}
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitMaterialInstance(TSceneManager *sceneManager)
{
auto *instance = ((SceneManager *)sceneManager)->createUnlitMaterialInstance();
return reinterpret_cast<TMaterialInstance *>(instance);
}
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitFixedSizeMaterialInstance(TSceneManager *sceneManager)
{
auto *instance = ((SceneManager *)sceneManager)->createUnlitFixedSizeMaterialInstance();
return reinterpret_cast<TMaterialInstance *>(instance);
}
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_createCamera(TSceneManager *tSceneManager)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return reinterpret_cast<TCamera *>(sceneManager->createCamera());
}
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyCamera(TSceneManager *tSceneManager, TCamera *tCamera)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *camera = reinterpret_cast<Camera *>(tCamera);
sceneManager->destroyCamera(camera);
}
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *tSceneManager)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return sceneManager->getCameraCount();
}
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraAt(TSceneManager *tSceneManager, size_t index)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *camera = sceneManager->getCameraAt(index);
return reinterpret_cast<TCamera *>(camera);
}
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_createGeometry(
TSceneManager *sceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance *materialInstance,
bool keepData)
{
return ((SceneManager *)sceneManager)->createGeometry(vertices, static_cast<uint32_t>(numVertices), normals, static_cast<uint32_t>(numNormals), uvs, static_cast<uint32_t>(numUvs), indices, static_cast<uint32_t>(numIndices), (filament::RenderableManager::PrimitiveType)primitiveType, reinterpret_cast<MaterialInstance *>(materialInstance), keepData);
}
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyMaterialInstance(TSceneManager *sceneManager, TMaterialInstance *instance)
{
((SceneManager *)sceneManager)->destroy(reinterpret_cast<MaterialInstance *>(instance));
}
}

View File

@@ -1,952 +0,0 @@
#ifdef _WIN32
#include "ThermionWin32.h"
#endif
#include <thread>
#include <functional>
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
#include "filament/LightManager.h"
#include "ResourceBuffer.hpp"
#include "FilamentViewer.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
using namespace thermion;
extern "C"
{
#include "ThermionDartApi.h"
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
{
const auto *loaderImpl = new ResourceLoaderWrapperImpl((ResourceLoaderWrapper *)loader);
auto viewer = new FilamentViewer(context, loaderImpl, platform, uberArchivePath);
return reinterpret_cast<TViewer *>(viewer);
}
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer *viewer)
{
auto *engine = reinterpret_cast<FilamentViewer *>(viewer)->getEngine();
return reinterpret_cast<TEngine *>(engine);
}
EMSCRIPTEN_KEEPALIVE TRenderTarget *Viewer_createRenderTarget(TViewer *tViewer, intptr_t texture, uint32_t width, uint32_t height)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto renderTarget = viewer->createRenderTarget(texture, width, height);
return reinterpret_cast<TRenderTarget *>(renderTarget);
}
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *tViewer, TRenderTarget *tRenderTarget)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
viewer->destroyRenderTarget(renderTarget);
}
EMSCRIPTEN_KEEPALIVE void Viewer_pick(TViewer *tViewer, TView* tView, int x, int y, void (*callback)(EntityId entityId, int x, int y, TView *tView, float depth, float fragX, float fragY, float fragZ))
{
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
auto *view = reinterpret_cast<View*>(tView);
((FilamentViewer *)viewer)->pick(view, static_cast<uint32_t>(x), static_cast<uint32_t>(y), reinterpret_cast<FilamentViewer::PickCallback>(callback));
}
EMSCRIPTEN_KEEPALIVE bool Viewer_isNonPickableEntity(TViewer *tViewer, EntityId entityId) {
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
return viewer->isNonPickableEntity(entityId);
}
EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *viewer)
{
delete ((FilamentViewer *)viewer);
}
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a)
{
((FilamentViewer *)viewer)->setBackgroundColor(r, g, b, a);
}
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer)
{
((FilamentViewer *)viewer)->clearBackgroundImage();
}
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight)
{
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight, 100, 100);
}
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp)
{
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp, 100, 100);
}
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath)
{
((FilamentViewer *)viewer)->loadSkybox(skyboxPath);
}
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity)
{
((FilamentViewer *)viewer)->createIbl(r, g, b, intensity);
}
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity)
{
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
}
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix)
{
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
rotationMatrix[2],
rotationMatrix[3],
rotationMatrix[4],
rotationMatrix[5],
rotationMatrix[6],
rotationMatrix[7],
rotationMatrix[8]);
((FilamentViewer *)viewer)->rotateIbl(matrix);
}
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer)
{
((FilamentViewer *)viewer)->removeSkybox();
}
EMSCRIPTEN_KEEPALIVE void remove_ibl(TViewer *viewer)
{
((FilamentViewer *)viewer)->removeIbl();
}
EMSCRIPTEN_KEEPALIVE EntityId add_light(
TViewer *viewer,
uint8_t type,
float colour,
float intensity,
float posX,
float posY,
float posZ,
float dirX,
float dirY,
float dirZ,
float falloffRadius,
float spotLightConeInner,
float spotLightConeOuter,
float sunAngularRadius,
float sunHaloSize,
float sunHaloFallof,
bool shadows)
{
return ((FilamentViewer *)viewer)->addLight((LightManager::Type)type, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, falloffRadius, spotLightConeInner, spotLightConeOuter, sunAngularRadius, sunHaloSize, sunHaloFallof, shadows);
}
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, int32_t entityId, float x, float y, float z)
{
((FilamentViewer *)viewer)->setLightPosition(entityId, x, y, z);
}
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, int32_t entityId, float x, float y, float z)
{
((FilamentViewer *)viewer)->setLightDirection(entityId, x, y, z);
}
EMSCRIPTEN_KEEPALIVE void remove_light(TViewer *viewer, int32_t entityId)
{
((FilamentViewer *)viewer)->removeLight(entityId);
}
EMSCRIPTEN_KEEPALIVE void clear_lights(TViewer *viewer)
{
((FilamentViewer *)viewer)->clearLights();
}
EMSCRIPTEN_KEEPALIVE EntityId load_glb(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData)
{
return ((SceneManager *)sceneManager)->loadGlb(assetPath, numInstances, keepData);
}
EMSCRIPTEN_KEEPALIVE EntityId create_instance(TSceneManager *sceneManager, EntityId entityId)
{
return ((SceneManager *)sceneManager)->createInstance(entityId);
}
EMSCRIPTEN_KEEPALIVE int get_instance_count(TSceneManager *sceneManager, EntityId entityId)
{
return ((SceneManager *)sceneManager)->getInstanceCount(entityId);
}
EMSCRIPTEN_KEEPALIVE void get_instances(TSceneManager *sceneManager, EntityId entityId, EntityId *out)
{
return ((SceneManager *)sceneManager)->getInstances(entityId, out);
}
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData)
{
return ((SceneManager *)sceneManager)->loadGltf(assetPath, relativePath, keepData);
}
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView)
{
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
auto *view = reinterpret_cast<View*>(tView);
viewer->setMainCamera(view);
}
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer)
{
return ((FilamentViewer *)viewer)->getMainCamera();
}
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getFieldOfViewInDegrees(horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
}
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getFocalLength();
}
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
cam->setProjection(fovInDegrees, aspect, near, far, horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
}
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity)
{
auto filamentCamera = ((FilamentViewer *)viewer)->getCamera(entity);
return reinterpret_cast<TCamera *>(filamentCamera);
}
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *camera)
{
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getModelMatrix();
return convert_mat4_to_double4x4(mat);
}
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *camera)
{
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getViewMatrix();
return convert_mat4_to_double4x4(mat);
}
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *camera)
{
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getProjectionMatrix();
return convert_mat4_to_double4x4(mat);
}
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *camera)
{
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getCullingProjectionMatrix();
return convert_mat4_to_double4x4(mat);
}
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
const auto &mat = convert_double4x4_to_mat4(matrix);
cam->setCustomProjection(mat, near, far);
}
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
cam->setLensProjection(focalLength, aspect, near, far);
}
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera *camera, double4x4 matrix)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
cam->setModelMatrix(convert_double4x4_to_mat4(matrix));
}
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getNear();
}
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getCullingFar();
}
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *camera)
{
const auto frustum = reinterpret_cast<filament::Camera *>(camera)->getFrustum();
const math::float4 *planes = frustum.getNormalizedPlanes();
double *array = (double *)calloc(24, sizeof(double));
for (int i = 0; i < 6; i++)
{
auto plane = planes[i];
array[i * 4] = double(plane.x);
array[i * 4 + 1] = double(plane.y);
array[i * 4 + 2] = double(plane.z);
array[i * 4 + 3] = double(plane.w);
}
return array;
}
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float distance)
{
auto *cam = reinterpret_cast<filament::Camera *>(camera);
cam->setFocusDistance(distance);
}
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity)
{
auto *cam = reinterpret_cast<filament::Camera *>(camera);
cam->setExposure(aperture, shutterSpeed, sensitivity);
}
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix)
{
auto *cam = reinterpret_cast<filament::Camera *>(camera);
const filament::math::mat4 &mat = convert_double4x4_to_mat4(matrix);
cam->setModelMatrix(mat);
}
EMSCRIPTEN_KEEPALIVE void Viewer_render(
TViewer *tViewer)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
viewer->render(0);
}
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *tViewer, TSwapChain *tSwapChain, TView *tView, bool renderable) {
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = reinterpret_cast<SwapChain*>(tSwapChain);
auto *view = reinterpret_cast<View*>(tView);
viewer->setRenderable(view, swapChain, renderable);
}
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
TViewer *tViewer,
TView *tView,
TSwapChain *tSwapChain,
uint8_t *pixelBuffer,
void (*callback)(void))
{
#ifdef __EMSCRIPTEN__
bool useFence = true;
#else
bool useFence = false;
#endif
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto *view = reinterpret_cast<View*>(tView);
viewer->capture(view, pixelBuffer, useFence, swapChain, callback);
};
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
TViewer *tViewer,
TView *tView,
TSwapChain *tSwapChain,
TRenderTarget *tRenderTarget,
uint8_t *pixelBuffer,
void (*callback)(void))
{
#ifdef __EMSCRIPTEN__
bool useFence = true;
#else
bool useFence = false;
#endif
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto *view = reinterpret_cast<View*>(tView);
viewer->capture(view, pixelBuffer, useFence, swapChain, renderTarget, callback);
};
EMSCRIPTEN_KEEPALIVE void set_frame_interval(
TViewer *viewer,
float frameInterval)
{
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
}
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *tViewer, TSwapChain *tSwapChain)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
viewer->destroySwapChain(swapChain);
}
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *tViewer, uint32_t width, uint32_t height)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = viewer->createSwapChain(width, height);
return reinterpret_cast<TSwapChain *>(swapChain);
}
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *tViewer, const void *const window)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = viewer->createSwapChain(window);
return reinterpret_cast<TSwapChain *>(swapChain);
}
EMSCRIPTEN_KEEPALIVE TSwapChain* Viewer_getSwapChainAt(TViewer *tViewer, int index) {
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = viewer->getSwapChainAt(index);
return reinterpret_cast<TSwapChain *>(swapChain);
}
EMSCRIPTEN_KEEPALIVE TView *Viewer_createView(TViewer *tViewer)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto view = viewer->createView();
return reinterpret_cast<TView *>(view);
}
EMSCRIPTEN_KEEPALIVE TView *Viewer_getViewAt(TViewer *tViewer, int32_t index)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto view = viewer->getViewAt(index);
return reinterpret_cast<TView *>(view);
}
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *tViewer)
{
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto *sceneManager = viewer->getSceneManager();
return reinterpret_cast<TSceneManager *>(sceneManager);
}
EMSCRIPTEN_KEEPALIVE void apply_weights(
TSceneManager *sceneManager,
EntityId asset,
const char *const entityName,
float *const weights,
int count)
{
// ((SceneManager*)sceneManager)->setMorphTargetWeights(asset, entityName, weights, count);
}
EMSCRIPTEN_KEEPALIVE bool set_morph_target_weights(
TSceneManager *sceneManager,
EntityId asset,
const float *const weights,
const int numWeights)
{
return ((SceneManager *)sceneManager)->setMorphTargetWeights(asset, weights, numWeights);
}
EMSCRIPTEN_KEEPALIVE void clear_morph_animation(TSceneManager *sceneManager, EntityId asset)
{
((SceneManager *)sceneManager)->clearMorphAnimationBuffer(asset);
}
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose(TSceneManager *sceneManager, EntityId entityId)
{
((SceneManager *)sceneManager)->resetBones(entityId);
}
EMSCRIPTEN_KEEPALIVE void add_bone_animation(
TSceneManager *sceneManager,
EntityId asset,
int skinIndex,
int boneIndex,
const float *const frameData,
int numFrames,
float frameLengthInMs,
float fadeOutInSecs,
float fadeInInSecs,
float maxDelta)
{
((SceneManager *)sceneManager)->addBoneAnimation(asset, skinIndex, boneIndex, frameData, numFrames, frameLengthInMs, fadeOutInSecs, fadeInInSecs, maxDelta);
}
EMSCRIPTEN_KEEPALIVE EntityId get_bone(TSceneManager *sceneManager,
EntityId entityId,
int skinIndex,
int boneIndex)
{
return ((SceneManager *)sceneManager)->getBone(entityId, skinIndex, boneIndex);
}
EMSCRIPTEN_KEEPALIVE void get_world_transform(TSceneManager *sceneManager,
EntityId entityId, float *const out)
{
auto transform = ((SceneManager *)sceneManager)->getWorldTransform(entityId);
out[0] = transform[0][0];
out[1] = transform[0][1];
out[2] = transform[0][2];
out[3] = transform[0][3];
out[4] = transform[1][0];
out[5] = transform[1][1];
out[6] = transform[1][2];
out[7] = transform[1][3];
out[8] = transform[2][0];
out[9] = transform[2][1];
out[10] = transform[2][2];
out[11] = transform[2][3];
out[12] = transform[3][0];
out[13] = transform[3][1];
out[14] = transform[3][2];
out[15] = transform[3][3];
}
EMSCRIPTEN_KEEPALIVE void get_local_transform(TSceneManager *sceneManager,
EntityId entityId, float *const out)
{
auto transform = ((SceneManager *)sceneManager)->getLocalTransform(entityId);
out[0] = transform[0][0];
out[1] = transform[0][1];
out[2] = transform[0][2];
out[3] = transform[0][3];
out[4] = transform[1][0];
out[5] = transform[1][1];
out[6] = transform[1][2];
out[7] = transform[1][3];
out[8] = transform[2][0];
out[9] = transform[2][1];
out[10] = transform[2][2];
out[11] = transform[2][3];
out[12] = transform[3][0];
out[13] = transform[3][1];
out[14] = transform[3][2];
out[15] = transform[3][3];
}
EMSCRIPTEN_KEEPALIVE void get_rest_local_transforms(TSceneManager *sceneManager,
EntityId entityId, int skinIndex, float *const out, int numBones)
{
const auto transforms = ((SceneManager *)sceneManager)->getBoneRestTranforms(entityId, skinIndex);
auto numTransforms = transforms->size();
if (numTransforms != numBones)
{
Log("Error - %d bone transforms available but you only specified %d.", numTransforms, numBones);
return;
}
for (int boneIndex = 0; boneIndex < numTransforms; boneIndex++)
{
const auto transform = transforms->at(boneIndex);
for (int colNum = 0; colNum < 4; colNum++)
{
for (int rowNum = 0; rowNum < 4; rowNum++)
{
out[(boneIndex * 16) + (colNum * 4) + rowNum] = transform[colNum][rowNum];
}
}
}
}
EMSCRIPTEN_KEEPALIVE void get_inverse_bind_matrix(TSceneManager *sceneManager,
EntityId entityId, int skinIndex, int boneIndex, float *const out)
{
auto transform = ((SceneManager *)sceneManager)->getInverseBindMatrix(entityId, skinIndex, boneIndex);
out[0] = transform[0][0];
out[1] = transform[0][1];
out[2] = transform[0][2];
out[3] = transform[0][3];
out[4] = transform[1][0];
out[5] = transform[1][1];
out[6] = transform[1][2];
out[7] = transform[1][3];
out[8] = transform[2][0];
out[9] = transform[2][1];
out[10] = transform[2][2];
out[11] = transform[2][3];
out[12] = transform[3][0];
out[13] = transform[3][1];
out[14] = transform[3][2];
out[15] = transform[3][3];
}
EMSCRIPTEN_KEEPALIVE bool set_bone_transform(
TSceneManager *sceneManager,
EntityId entityId,
int skinIndex,
int boneIndex,
const float *const transform)
{
auto matrix = math::mat4f(
transform[0], transform[1], transform[2],
transform[3],
transform[4],
transform[5],
transform[6],
transform[7],
transform[8],
transform[9],
transform[10],
transform[11],
transform[12],
transform[13],
transform[14],
transform[15]);
return ((SceneManager *)sceneManager)->setBoneTransform(entityId, skinIndex, boneIndex, matrix);
}
EMSCRIPTEN_KEEPALIVE void play_animation(
TSceneManager *sceneManager,
EntityId asset,
int index,
bool loop,
bool reverse,
bool replaceActive,
float crossfade,
float startOffset)
{
((SceneManager *)sceneManager)->playAnimation(asset, index, loop, reverse, replaceActive, crossfade, startOffset);
}
EMSCRIPTEN_KEEPALIVE void set_animation_frame(
TSceneManager *sceneManager,
EntityId asset,
int animationIndex,
int animationFrame)
{
// ((SceneManager*)sceneManager)->setAnimationFrame(asset, animationIndex, animationFrame);
}
float get_animation_duration(TSceneManager *sceneManager, EntityId asset, int animationIndex)
{
return ((SceneManager *)sceneManager)->getAnimationDuration(asset, animationIndex);
}
int get_animation_count(
TSceneManager *sceneManager,
EntityId asset)
{
auto names = ((SceneManager *)sceneManager)->getAnimationNames(asset);
return (int)names->size();
}
EMSCRIPTEN_KEEPALIVE void get_animation_name(
TSceneManager *sceneManager,
EntityId asset,
char *const outPtr,
int index)
{
auto names = ((SceneManager *)sceneManager)->getAnimationNames(asset);
std::string name = names->at(index);
strcpy(outPtr, name.c_str());
}
EMSCRIPTEN_KEEPALIVE int get_bone_count(TSceneManager *sceneManager, EntityId assetEntity, int skinIndex)
{
auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex);
return names->size();
}
EMSCRIPTEN_KEEPALIVE void get_bone_names(TSceneManager *sceneManager, EntityId assetEntity, const char **out, int skinIndex)
{
auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex);
for (int i = 0; i < names->size(); i++)
{
auto name_c = names->at(i).c_str();
memcpy((void *)out[i], name_c, strlen(name_c) + 1);
}
}
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(TSceneManager *sceneManager, EntityId entityId)
{
return ((SceneManager *)sceneManager)->updateBoneMatrices(entityId);
}
EMSCRIPTEN_KEEPALIVE int get_morph_target_name_count(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity)
{
auto names = ((SceneManager *)sceneManager)->getMorphTargetNames(assetEntity, childEntity);
return (int)names->size();
}
EMSCRIPTEN_KEEPALIVE void get_morph_target_name(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index)
{
auto names = ((SceneManager *)sceneManager)->getMorphTargetNames(assetEntity, childEntity);
std::string name = names->at(index);
strcpy(outPtr, name.c_str());
}
EMSCRIPTEN_KEEPALIVE void remove_entity(TViewer *viewer, EntityId asset)
{
((FilamentViewer *)viewer)->removeEntity(asset);
}
EMSCRIPTEN_KEEPALIVE void clear_entities(TViewer *viewer)
{
((FilamentViewer *)viewer)->clearEntities();
}
bool set_material_color(TSceneManager *sceneManager, EntityId asset, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a)
{
return ((SceneManager *)sceneManager)->setMaterialColor(asset, meshName, materialIndex, r, g, b, a);
}
EMSCRIPTEN_KEEPALIVE void transform_to_unit_cube(TSceneManager *sceneManager, EntityId asset)
{
((SceneManager *)sceneManager)->transformToUnitCube(asset);
}
EMSCRIPTEN_KEEPALIVE void set_position(TSceneManager *sceneManager, EntityId asset, float x, float y, float z)
{
((SceneManager *)sceneManager)->setPosition(asset, x, y, z);
}
EMSCRIPTEN_KEEPALIVE void set_rotation(TSceneManager *sceneManager, EntityId asset, float rads, float x, float y, float z, float w)
{
((SceneManager *)sceneManager)->setRotation(asset, rads, x, y, z, w);
}
EMSCRIPTEN_KEEPALIVE void set_scale(TSceneManager *sceneManager, EntityId asset, float scale)
{
((SceneManager *)sceneManager)->setScale(asset, scale);
}
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *tView, EntityId entity, float viewportX, float viewportY)
{
auto *view = reinterpret_cast<View*>(tView);
((SceneManager *)sceneManager)->queueRelativePositionUpdateFromViewportVector(view, entity, viewportX, viewportY);
}
EMSCRIPTEN_KEEPALIVE void stop_animation(TSceneManager *sceneManager, EntityId asset, int index)
{
((SceneManager *)sceneManager)->stopAnimation(asset, index);
}
EMSCRIPTEN_KEEPALIVE int hide_mesh(TSceneManager *sceneManager, EntityId asset, const char *meshName)
{
return ((SceneManager *)sceneManager)->hide(asset, meshName);
}
EMSCRIPTEN_KEEPALIVE int reveal_mesh(TSceneManager *sceneManager, EntityId asset, const char *meshName)
{
return ((SceneManager *)sceneManager)->reveal(asset, meshName);
}
EMSCRIPTEN_KEEPALIVE const char *get_name_for_entity(TSceneManager *sceneManager, const EntityId entityId)
{
return ((SceneManager *)sceneManager)->getNameForEntity(entityId);
}
EMSCRIPTEN_KEEPALIVE int get_entity_count(TSceneManager *sceneManager, const EntityId target, bool renderableOnly)
{
return ((SceneManager *)sceneManager)->getEntityCount(target, renderableOnly);
}
EMSCRIPTEN_KEEPALIVE void get_entities(TSceneManager *sceneManager, const EntityId target, bool renderableOnly, EntityId *out)
{
((SceneManager *)sceneManager)->getEntities(target, renderableOnly, out);
}
EMSCRIPTEN_KEEPALIVE const char *get_entity_name_at(TSceneManager *sceneManager, const EntityId target, int index, bool renderableOnly)
{
return ((SceneManager *)sceneManager)->getEntityNameAt(target, index, renderableOnly);
}
EMSCRIPTEN_KEEPALIVE void ios_dummy()
{
Log("Dummy called");
}
EMSCRIPTEN_KEEPALIVE void thermion_filament_free(void *ptr)
{
free(ptr);
}
EMSCRIPTEN_KEEPALIVE void add_collision_component(TSceneManager *sceneManager, EntityId entityId, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform)
{
((SceneManager *)sceneManager)->addCollisionComponent(entityId, onCollisionCallback, affectsCollidingTransform);
}
EMSCRIPTEN_KEEPALIVE void remove_collision_component(TSceneManager *sceneManager, EntityId entityId)
{
((SceneManager *)sceneManager)->removeCollisionComponent(entityId);
}
EMSCRIPTEN_KEEPALIVE bool add_animation_component(TSceneManager *sceneManager, EntityId entityId)
{
return ((SceneManager *)sceneManager)->addAnimationComponent(entityId);
}
EMSCRIPTEN_KEEPALIVE void remove_animation_component(TSceneManager *sceneManager, EntityId entityId)
{
((SceneManager *)sceneManager)->removeAnimationComponent(entityId);
}
EMSCRIPTEN_KEEPALIVE EntityId find_child_entity_by_name(TSceneManager *sceneManager, const EntityId parent, const char *name)
{
auto entity = ((SceneManager *)sceneManager)->findChildEntityByName(parent, name);
return utils::Entity::smuggle(entity);
}
EMSCRIPTEN_KEEPALIVE EntityId get_parent(TSceneManager *sceneManager, EntityId child)
{
return ((SceneManager *)sceneManager)->getParent(child);
}
EMSCRIPTEN_KEEPALIVE EntityId get_ancestor(TSceneManager *sceneManager, EntityId child)
{
return ((SceneManager *)sceneManager)->getAncestor(child);
}
EMSCRIPTEN_KEEPALIVE void set_parent(TSceneManager *sceneManager, EntityId child, EntityId parent, bool preserveScaling)
{
((SceneManager *)sceneManager)->setParent(child, parent, preserveScaling);
}
EMSCRIPTEN_KEEPALIVE void test_collisions(TSceneManager *sceneManager, EntityId entity)
{
((SceneManager *)sceneManager)->testCollisions(entity);
}
EMSCRIPTEN_KEEPALIVE void set_priority(TSceneManager *sceneManager, EntityId entity, int priority)
{
((SceneManager *)sceneManager)->setPriority(entity, priority);
}
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *tView, EntityId entity)
{
auto view = reinterpret_cast<View*>(tView);
return ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
}
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *tView, EntityId entity, float *minX, float *minY, float *maxX, float *maxY)
{
auto view = reinterpret_cast<View*>(tView);
auto box = ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
*minX = box.minX;
*minY = box.minY;
*maxX = box.maxX;
*maxY = box.maxY;
}
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr)
{
free(ptr);
}
EMSCRIPTEN_KEEPALIVE void set_stencil_highlight(TSceneManager *sceneManager, EntityId entityId, float r, float g, float b)
{
((SceneManager *)sceneManager)->setStencilHighlight(entityId, r, g, b);
}
EMSCRIPTEN_KEEPALIVE void remove_stencil_highlight(TSceneManager *sceneManager, EntityId entityId)
{
((SceneManager *)sceneManager)->removeStencilHighlight(entityId);
}
EMSCRIPTEN_KEEPALIVE void set_material_property_float(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, float value)
{
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, value);
}
EMSCRIPTEN_KEEPALIVE TMaterialInstance *get_material_instance_at(TSceneManager *sceneManager, EntityId entity, int materialIndex)
{
auto instance = ((SceneManager *)sceneManager)->getMaterialInstanceAt(entity, materialIndex);
return reinterpret_cast<TMaterialInstance *>(instance);
}
EMSCRIPTEN_KEEPALIVE void set_material_property_int(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, int32_t value)
{
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, value);
}
EMSCRIPTEN_KEEPALIVE void set_material_property_float4(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, double4 value)
{
filament::math::float4 filamentValue;
filamentValue.x = static_cast<float>(value.x);
filamentValue.y = static_cast<float>(value.y);
filamentValue.z = static_cast<float>(value.z);
filamentValue.w = static_cast<float>(value.w);
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, filamentValue);
}
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer *viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
{
((FilamentViewer *)viewer)->unprojectTexture(entity, input, inputWidth, inputHeight, out, outWidth, outHeight);
}
EMSCRIPTEN_KEEPALIVE void *const create_texture(TSceneManager *sceneManager, uint8_t *data, size_t length)
{
return (void *const)((SceneManager *)sceneManager)->createTexture(data, length, "SOMETEXTURE");
}
EMSCRIPTEN_KEEPALIVE void apply_texture_to_material(TSceneManager *sceneManager, EntityId entity, void *const texture, const char *parameterName, int materialIndex)
{
((SceneManager *)sceneManager)->applyTexture(entity, reinterpret_cast<Texture *>(texture), parameterName, materialIndex);
}
EMSCRIPTEN_KEEPALIVE void destroy_texture(TSceneManager *sceneManager, void *const texture)
{
((SceneManager *)sceneManager)->destroyTexture(reinterpret_cast<Texture *>(texture));
}
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_material_instance(TSceneManager *sceneManager, TMaterialKey materialConfig)
{
filament::gltfio::MaterialKey config;
memset(&config, 0, sizeof(MaterialKey));
// Set and log each field
config.unlit = materialConfig.unlit;
config.doubleSided = materialConfig.doubleSided;
config.useSpecularGlossiness = materialConfig.useSpecularGlossiness;
config.alphaMode = static_cast<filament::gltfio::AlphaMode>(materialConfig.alphaMode);
config.hasBaseColorTexture = materialConfig.hasBaseColorTexture;
config.hasClearCoat = materialConfig.hasClearCoat;
config.hasClearCoatNormalTexture = materialConfig.hasClearCoatNormalTexture;
config.hasClearCoatRoughnessTexture = materialConfig.hasClearCoatRoughnessTexture;
config.hasEmissiveTexture = materialConfig.hasEmissiveTexture;
config.hasIOR = materialConfig.hasIOR;
config.hasMetallicRoughnessTexture = materialConfig.hasMetallicRoughnessTexture;
config.hasNormalTexture = materialConfig.hasNormalTexture;
config.hasOcclusionTexture = materialConfig.hasOcclusionTexture;
config.hasSheen = materialConfig.hasSheen;
config.hasSheenColorTexture = materialConfig.hasSheenColorTexture;
config.hasSheenRoughnessTexture = materialConfig.hasSheenRoughnessTexture;
config.hasTextureTransforms = materialConfig.hasTextureTransforms;
config.hasTransmission = materialConfig.hasTransmission;
config.hasTransmissionTexture = materialConfig.hasTransmissionTexture;
config.hasVolume = materialConfig.hasVolume;
config.hasVolumeThicknessTexture = materialConfig.hasVolumeThicknessTexture;
config.baseColorUV = materialConfig.baseColorUV;
config.hasVertexColors = materialConfig.hasVertexColors;
auto materialInstance = ((SceneManager *)sceneManager)->createUbershaderMaterialInstance(config);
return reinterpret_cast<TMaterialInstance *>(materialInstance);
}
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine *tEngine, EntityId entityId)
{
auto *engine = reinterpret_cast<Engine *>(tEngine);
auto *camera = engine->getCameraComponent(utils::Entity::import(entityId));
return reinterpret_cast<TCamera *>(camera);
}
EMSCRIPTEN_KEEPALIVE void Engine_setTransform(TEngine *tEngine, EntityId entity, double4x4 transform)
{
auto *engine = reinterpret_cast<Engine *>(tEngine);
auto &transformManager = engine->getTransformManager();
auto transformInstance = transformManager.getInstance(utils::Entity::import(entity));
if (!transformInstance.isValid())
{
Log("Transform instance not valid");
}
transformManager.setTransform(transformInstance, convert_double4x4_to_mat4(transform));
}
}

View File

@@ -17,7 +17,7 @@
#include <iostream>
#include "CustomGeometry.hpp"
#include "scene/CustomGeometry.hpp"
#include "UnprojectTexture.hpp"
namespace thermion

View File

@@ -0,0 +1,300 @@
#include "Log.hpp"
#include "c_api/APIExport.h"
#include "scene/AnimationManager.hpp"
using namespace thermion;
extern "C"
{
#include "c_api/TAnimationManager.h"
EMSCRIPTEN_KEEPALIVE void AnimationManager_addAnimationComponent(TAnimationManager *tAnimationManager, EntityId entityId)
{
auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
animationManager->addAnimationComponent(entityId);
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_removeAnimationComponent(TAnimationManager *tAnimationManager, EntityId entityId)
{
auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
animationManager->removeAnimationComponent(entityId);
}
EMSCRIPTEN_KEEPALIVE bool AnimationManager_setMorphAnimation(
TAnimationManager *tAnimationManager,
EntityId entityId,
const float *const morphData,
const uint32_t *const morphIndices,
int numMorphTargets,
int numFrames,
float frameLengthInMs)
{
auto entity = utils::Entity::import(entityId);
auto *animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto result = animationManager->setMorphAnimationBuffer(entity, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs);
return result;
}
EMSCRIPTEN_KEEPALIVE bool AnimationManager_setMorphTargetWeights(
TAnimationManager *tAnimationManager,
EntityId entityId,
const float *const morphData,
int numWeights)
{
auto entity = utils::Entity::import(entityId);
auto *animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
animationManager->setMorphTargetWeights(entity, morphData, numWeights);
return true;
}
EMSCRIPTEN_KEEPALIVE bool AnimationManager_clearMorphAnimation(TAnimationManager *tAnimationManager, EntityId entityId)
{
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto entity = utils::Entity::import(entityId);
animManager->clearMorphAnimationBuffer(entity);
return true;
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_resetToRestPose(TAnimationManager *tAnimationManager, TSceneAsset *sceneAsset)
{
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
{
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
animManager->resetToRestPose(instance);
}
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_addBoneAnimation(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int skinIndex,
int boneIndex,
const float *const frameData,
int numFrames,
float frameLengthInMs,
float fadeOutInSecs,
float fadeInInSecs,
float maxDelta)
{
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
{
animManager->addBoneAnimation(reinterpret_cast<GltfSceneAssetInstance *>(asset), skinIndex, boneIndex, frameData, numFrames, frameLengthInMs,
fadeOutInSecs, fadeInInSecs, maxDelta);
}
}
EMSCRIPTEN_KEEPALIVE EntityId AnimationManager_getBone(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int skinIndex,
int boneIndex)
{
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
{
auto entities = animManager->getBoneEntities(reinterpret_cast<GltfSceneAssetInstance *>(asset), skinIndex);
if (boneIndex < entities.size())
{
return utils::Entity::smuggle(entities[boneIndex]);
}
}
return 0;
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_getRestLocalTransforms(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int skinIndex,
float *const out,
int numBones)
{
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
{
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
const auto transforms = animManager->getBoneRestTranforms(instance, skinIndex);
auto numTransforms = transforms.size();
if (numTransforms != numBones)
{
Log("Error - %d bone transforms available but you only specified %d.", numTransforms, numBones);
return;
}
for (int boneIndex = 0; boneIndex < numTransforms; boneIndex++)
{
const auto transform = transforms[boneIndex];
for (int colNum = 0; colNum < 4; colNum++)
{
for (int rowNum = 0; rowNum < 4; rowNum++)
{
out[(boneIndex * 16) + (colNum * 4) + rowNum] = transform[colNum][rowNum];
}
}
}
}
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_getInverseBindMatrix(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int skinIndex,
int boneIndex,
float *const out)
{
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
{
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
auto transform = animManager->getInverseBindMatrix(instance, skinIndex, boneIndex);
for (int colNum = 0; colNum < 4; colNum++)
{
for (int rowNum = 0; rowNum < 4; rowNum++)
{
out[(colNum * 4) + rowNum] = transform[colNum][rowNum];
}
}
}
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_playAnimation(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int index,
bool loop,
bool reverse,
bool replaceActive,
float crossfade,
float startOffset)
{
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
{
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
animManager->playGltfAnimation(instance, index, loop, reverse, replaceActive, crossfade, startOffset);
}
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_stopAnimation(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int index)
{
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
{
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
animManager->stopGltfAnimation(instance, index);
}
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_setGltfAnimationFrame(
TAnimationManager *tAnimationManager,
TSceneAsset *tSceneAsset,
int animationIndex,
int frame)
{
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(tSceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
{
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
animManager->setGltfAnimationFrame(instance, animationIndex, frame);
}
}
EMSCRIPTEN_KEEPALIVE float AnimationManager_getAnimationDuration(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int animationIndex)
{
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
return ((AnimationManager *)tAnimationManager)->getGltfAnimationDuration(instance, animationIndex);
}
EMSCRIPTEN_KEEPALIVE int AnimationManager_getAnimationCount(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset)
{
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
auto names = ((AnimationManager *)tAnimationManager)->getGltfAnimationNames(instance);
return (int)names.size();
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_getAnimationName(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
char *const outPtr,
int index)
{
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
auto names = ((AnimationManager *)tAnimationManager)->getGltfAnimationNames(instance);
std::string name = names[index];
strcpy(outPtr, name.c_str());
}
EMSCRIPTEN_KEEPALIVE int AnimationManager_getBoneCount(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
int skinIndex)
{
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
auto entities = ((AnimationManager *)tAnimationManager)->getBoneEntities(instance, skinIndex);
return (int)entities.size();
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_getBoneNames(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
const char **out,
int skinIndex)
{
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
auto entities = ((AnimationManager *)tAnimationManager)->getBoneEntities(instance, skinIndex);
// Note: This needs implementation of a method to get bone names from entities
// Current source doesn't show how bone names are retrieved
}
EMSCRIPTEN_KEEPALIVE bool AnimationManager_updateBoneMatrices(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset)
{
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
((AnimationManager *)tAnimationManager)->updateBoneMatrices(instance);
return true;
}
EMSCRIPTEN_KEEPALIVE int AnimationManager_getMorphTargetNameCount(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
EntityId childEntity)
{
auto asset = ((GltfSceneAsset *)sceneAsset);
auto names = ((AnimationManager *)tAnimationManager)->getMorphTargetNames(asset, childEntity);
return (int)names.size();
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_getMorphTargetName(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
EntityId childEntity,
char *const outPtr,
int index)
{
auto asset = ((GltfSceneAsset *)sceneAsset);
auto names = ((AnimationManager *)tAnimationManager)->getMorphTargetNames(asset, childEntity);
std::string name = names[index];
strcpy(outPtr, name.c_str());
}
}

View File

@@ -6,11 +6,11 @@
#include <filament/Camera.h>
#include <utils/Entity.h>
#include "ThermionDartApi.h"
#include "TCamera.h"
#include "ThermionDartAPIUtils.h"
#include "c_api/ThermionDartApi.h"
#include "c_api/TCamera.h"
#include "Log.hpp"
#include "MathUtils.hpp"
#ifdef __cplusplus
namespace thermion

View File

@@ -0,0 +1,41 @@
#include <filament/View.h>
#include <filament/Engine.h>
#include <filament/Scene.h>
#include "c_api/TGizmo.h"
#include "scene/Gizmo.hpp"
#include "Log.hpp"
#ifdef __cplusplus
namespace thermion
{
extern "C"
{
using namespace filament;
#endif
EMSCRIPTEN_KEEPALIVE void Gizmo_pick(TGizmo *tGizmo, uint32_t x, uint32_t y, GizmoPickCallback callback)
{
auto *gizmo = reinterpret_cast<Gizmo *>(tGizmo);
gizmo->pick(x, y, reinterpret_cast<Gizmo::GizmoPickCallback>(callback));
}
EMSCRIPTEN_KEEPALIVE void Gizmo_highlight(TGizmo *tGizmo, TGizmoAxis tAxis)
{
auto *gizmo = reinterpret_cast<Gizmo *>(tGizmo);
auto axis = static_cast<Gizmo::Axis>(tAxis);
gizmo->highlight(axis);
}
EMSCRIPTEN_KEEPALIVE void Gizmo_unhighlight(TGizmo *tGizmo)
{
auto *gizmo = reinterpret_cast<Gizmo *>(tGizmo);
gizmo->unhighlight(Gizmo::Axis::X);
gizmo->unhighlight(Gizmo::Axis::Y);
gizmo->unhighlight(Gizmo::Axis::Z);
}
#ifdef __cplusplus
}
}
#endif

View File

@@ -0,0 +1,136 @@
#include <filament/MaterialInstance.h>
#include <math/mat4.h>
#include <math/vec4.h>
#include <math/vec2.h>
#include "Log.hpp"
#include "c_api/TMaterialInstance.h"
#ifdef __cplusplus
namespace thermion
{
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE bool MaterialInstance_isStencilWriteEnabled(TMaterialInstance *tMaterialInstance)
{
return reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance)->isStencilWriteEnabled();
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance *materialInstance, bool enabled)
{
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setDepthWrite(enabled);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance *materialInstance, bool enabled)
{
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setDepthCulling(enabled);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat4(TMaterialInstance *tMaterialInstance, const char *propertyName, double x, double y, double z, double w)
{
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
filament::math::float4 data{static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(w)};
materialInstance->setParameter(propertyName, data);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat2(TMaterialInstance *materialInstance, const char *propertyName, double x, double y)
{
filament::math::float2 data{static_cast<float>(x), static_cast<float>(y)};
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, data);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat(TMaterialInstance *materialInstance, const char *propertyName, double value)
{
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, static_cast<float>(value));
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterInt(TMaterialInstance *materialInstance, const char *propertyName, int value)
{
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, value);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthFunc(TMaterialInstance *tMaterialInstance, TSamplerCompareFunc tDepthFunc)
{
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
auto depthFunc = static_cast<filament::MaterialInstance::DepthFunc>(tDepthFunc);
materialInstance->setDepthFunc(depthFunc);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilOpStencilFail(TMaterialInstance *tMaterialInstance,
TStencilOperation tOp, TStencilFace tFace)
{
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
auto op = static_cast<filament::MaterialInstance::StencilOperation>(tOp);
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
materialInstance->setStencilOpStencilFail(op, face);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilOpDepthFail(TMaterialInstance *tMaterialInstance,
TStencilOperation tOp, TStencilFace tFace)
{
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
auto op = static_cast<filament::MaterialInstance::StencilOperation>(tOp);
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
materialInstance->setStencilOpDepthFail(op, face);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilOpDepthStencilPass(TMaterialInstance *tMaterialInstance,
TStencilOperation tOp, TStencilFace tFace)
{
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
auto op = static_cast<filament::MaterialInstance::StencilOperation>(tOp);
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
materialInstance->setStencilOpDepthStencilPass(op, face);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilCompareFunction(TMaterialInstance *tMaterialInstance,
TSamplerCompareFunc tFunc, TStencilFace tFace)
{
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
auto func = static_cast<filament::MaterialInstance::StencilCompareFunc>(tFunc);
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
materialInstance->setStencilCompareFunction(func, face);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilReferenceValue(TMaterialInstance *tMaterialInstance,
uint8_t value, TStencilFace tFace)
{
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
materialInstance->setStencilReferenceValue(value, face);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilWrite(TMaterialInstance *materialInstance, bool enabled)
{
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setStencilWrite(enabled);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setCullingMode(TMaterialInstance *materialInstance, TCullingMode culling)
{
auto *instance = reinterpret_cast<::filament::MaterialInstance *>(materialInstance);
auto cullingMode = static_cast<filament::MaterialInstance::CullingMode>(culling);
instance->setCullingMode(cullingMode);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilReadMask(
TMaterialInstance *materialInstance,
uint8_t mask)
{
auto *instance = reinterpret_cast<::filament::MaterialInstance *>(materialInstance);
instance->setStencilReadMask(mask);
}
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilWriteMask(
TMaterialInstance *materialInstance,
uint8_t mask)
{
auto *instance = reinterpret_cast<::filament::MaterialInstance *>(materialInstance);
instance->setStencilWriteMask(mask);
}
#ifdef __cplusplus
}
}
#endif

View File

@@ -0,0 +1,57 @@
#include <filament/MaterialInstance.h>
#include <gltfio/MaterialProvider.h>
#include <math/mat4.h>
#include <math/vec4.h>
#include <math/vec2.h>
#include "Log.hpp"
#include "c_api/TMaterialProvider.h"
#include "c_api/TMaterialInstance.h"
#ifdef __cplusplus
namespace thermion
{
using namespace filament;
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE TMaterialInstance *MaterialProvider_createMaterialInstance(TMaterialProvider *tMaterialProvider, TMaterialKey *materialConfig)
{
gltfio::MaterialKey config;
gltfio::UvMap uvMap;
memset(&config, 0, sizeof(gltfio::MaterialKey));
// Set and log each field
config.unlit = materialConfig->unlit;
config.doubleSided = materialConfig->doubleSided;
config.useSpecularGlossiness = materialConfig->useSpecularGlossiness;
config.alphaMode = static_cast<filament::gltfio::AlphaMode>(materialConfig->alphaMode);
config.hasBaseColorTexture = materialConfig->hasBaseColorTexture;
config.hasClearCoat = materialConfig->hasClearCoat;
config.hasClearCoatNormalTexture = materialConfig->hasClearCoatNormalTexture;
config.hasClearCoatRoughnessTexture = materialConfig->hasClearCoatRoughnessTexture;
config.hasEmissiveTexture = materialConfig->hasEmissiveTexture;
config.hasIOR = materialConfig->hasIOR;
config.hasMetallicRoughnessTexture = materialConfig->hasMetallicRoughnessTexture;
config.hasNormalTexture = materialConfig->hasNormalTexture;
config.hasOcclusionTexture = materialConfig->hasOcclusionTexture;
config.hasSheen = materialConfig->hasSheen;
config.hasSheenColorTexture = materialConfig->hasSheenColorTexture;
config.hasSheenRoughnessTexture = materialConfig->hasSheenRoughnessTexture;
config.hasTextureTransforms = materialConfig->hasTextureTransforms;
config.hasTransmission = materialConfig->hasTransmission;
config.hasTransmissionTexture = materialConfig->hasTransmissionTexture;
config.hasVolume = materialConfig->hasVolume;
config.hasVolumeThicknessTexture = materialConfig->hasVolumeThicknessTexture;
config.baseColorUV = materialConfig->baseColorUV;
config.hasVertexColors = materialConfig->hasVertexColors;
auto *materialProvider = reinterpret_cast<gltfio::MaterialProvider *>(tMaterialProvider);
auto materialInstance = materialProvider->createMaterialInstance(&config, &uvMap);
return reinterpret_cast<TMaterialInstance *>(materialInstance);
}
#ifdef __cplusplus
}
}
#endif

View File

@@ -0,0 +1,20 @@
#include <utils/NameComponentManager.h>
#include "c_api/APIExport.h"
#include "c_api/APIBoundaryTypes.h"
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE const char *NameComponentManager_getName(TNameComponentManager *tNameComponentManager, EntityId entity)
{
auto ncm = reinterpret_cast<utils::NameComponentManager *>(tNameComponentManager);
auto instance = ncm->getInstance(utils::Entity::import(entity));
return ncm->getName(instance);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,44 @@
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <utils/Entity.h>
#include "Log.hpp"
#include "c_api/TRenderableManager.h"
namespace thermion
{
extern "C"
{
using namespace filament;
using namespace utils;
EMSCRIPTEN_KEEPALIVE void RenderableManager_setMaterialInstanceAt(TRenderableManager *tRenderableManager, EntityId entityId, int primitiveIndex, TMaterialInstance *tMaterialInstance)
{
auto *renderableManager = reinterpret_cast<filament::RenderableManager *>(tRenderableManager);
const auto &entity = utils::Entity::import(entityId);
auto renderableInstance = renderableManager->getInstance(entity);
auto materialInstance = reinterpret_cast<MaterialInstance *>(tMaterialInstance);
renderableManager->setMaterialInstanceAt(renderableInstance, primitiveIndex, materialInstance);
}
EMSCRIPTEN_KEEPALIVE TMaterialInstance *RenderableManager_getMaterialInstanceAt(TRenderableManager *tRenderableManager, EntityId entityId, int primitiveIndex) {
auto *renderableManager = reinterpret_cast<filament::RenderableManager *>(tRenderableManager);
const auto &entity = utils::Entity::import(entityId);
auto renderableInstance = renderableManager->getInstance(entity);
if(!renderableInstance.isValid()) {
return nullptr;
}
auto materialInstance = renderableManager->getMaterialInstanceAt(renderableInstance, primitiveIndex);
return reinterpret_cast<TMaterialInstance*>(materialInstance);
}
EMSCRIPTEN_KEEPALIVE void RenderableManager_setPriority(TRenderableManager *tRenderableManager, EntityId entityId, int priority) {
auto *renderableManager = reinterpret_cast<filament::RenderableManager *>(tRenderableManager);
const auto &entity = utils::Entity::import(entityId);
auto renderableInstance = renderableManager->getInstance(entity);
renderableManager->setPriority(renderableInstance, priority);
}
}
}

View File

@@ -0,0 +1,108 @@
#include "c_api/TSceneAsset.h"
#include "scene/SceneAsset.hpp"
#include "scene/GltfSceneAsset.hpp"
using namespace thermion;
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE void SceneAsset_addToScene(TSceneAsset *tSceneAsset, TScene *tScene) {
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
auto *scene = reinterpret_cast<Scene*>(tScene);
asset->addAllEntities(scene);
}
EMSCRIPTEN_KEEPALIVE EntityId SceneAsset_getEntity(TSceneAsset *tSceneAsset) {
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
return utils::Entity::smuggle(asset->getEntity());
}
EMSCRIPTEN_KEEPALIVE int SceneAsset_getChildEntityCount(TSceneAsset* tSceneAsset) {
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
return asset->getChildEntityCount();
}
EMSCRIPTEN_KEEPALIVE void SceneAsset_getChildEntities(TSceneAsset* tSceneAsset, EntityId *out)
{
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
auto entities = asset->getChildEntities();
for(int i = 0; i < asset->getChildEntityCount(); i++) {
out[i] = utils::Entity::smuggle(entities[i]);
}
}
EMSCRIPTEN_KEEPALIVE const utils::Entity *SceneAsset_getCameraEntities(TSceneAsset* tSceneAsset)
{
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && !asset->isInstance())
{
auto gltfSceneAsset = reinterpret_cast<GltfSceneAsset *>(asset);
return gltfSceneAsset->getAsset()->getCameraEntities();
}
else
{
return std::nullptr_t();
}
}
EMSCRIPTEN_KEEPALIVE size_t SceneAsset_getCameraEntityCount(TSceneAsset* tSceneAsset)
{
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && !asset->isInstance())
{
auto gltfSceneAsset = reinterpret_cast<GltfSceneAsset *>(asset);
return gltfSceneAsset->getAsset()->getCameraEntityCount();
}
return -1;
}
EMSCRIPTEN_KEEPALIVE const utils::Entity *SceneAsset_getLightEntities(TSceneAsset* tSceneAsset)
{
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && !asset->isInstance())
{
auto gltfSceneAsset = reinterpret_cast<GltfSceneAsset *>(asset);
return gltfSceneAsset->getAsset()->getLightEntities();
}
return std::nullptr_t();
}
EMSCRIPTEN_KEEPALIVE size_t SceneAsset_getLightEntityCount(TSceneAsset* tSceneAsset)
{
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && !asset->isInstance())
{
auto gltfSceneAsset = reinterpret_cast<GltfSceneAsset *>(asset);
return gltfSceneAsset->getAsset()->getLightEntityCount();
}
return -1;
}
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneAsset_getInstance(TSceneAsset *tSceneAsset, int index) {
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
auto *instance = asset->getInstanceAt(index);
return reinterpret_cast<TSceneAsset*>(instance);
}
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneAsset_createInstance(TSceneAsset *tSceneAsset, TMaterialInstance **tMaterialInstances, int materialInstanceCount)
{
auto *materialInstances = reinterpret_cast<MaterialInstance **>(tMaterialInstances);
auto *sceneAsset = reinterpret_cast<SceneAsset*>(tSceneAsset);
auto *instance = sceneAsset->createInstance(materialInstances, materialInstanceCount);
return reinterpret_cast<TSceneAsset *>(instance);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,219 @@
#include <filament/LightManager.h>
#include "c_api/APIExport.h"
#include "ResourceBuffer.hpp"
#include "FilamentViewer.hpp"
#include "Log.hpp"
using namespace thermion;
extern "C"
{
#include "c_api/TSceneManager.h"
EMSCRIPTEN_KEEPALIVE TScene *SceneManager_getScene(TSceneManager *tSceneManager) {
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return reinterpret_cast<TScene*>(sceneManager->getScene());
}
EMSCRIPTEN_KEEPALIVE TMaterialProvider *SceneManager_getUnlitMaterialProvider(TSceneManager *tSceneManager) {
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto provider = sceneManager->getUnlitMaterialProvider();
return reinterpret_cast<TMaterialProvider*>(provider);
}
EMSCRIPTEN_KEEPALIVE TMaterialProvider *SceneManager_getUbershaderMaterialProvider(TSceneManager *tSceneManager) {
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto provider = sceneManager->getUbershaderMaterialProvider();
return reinterpret_cast<TMaterialProvider*>(provider);
}
EMSCRIPTEN_KEEPALIVE TGizmo *SceneManager_createGizmo(TSceneManager *tSceneManager, TView *tView, TScene *tScene)
{
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *scene = reinterpret_cast<Scene *>(tScene);
auto *view = reinterpret_cast<View *>(tView);
auto gizmo = sceneManager->createGizmo(view, scene);
return reinterpret_cast<TGizmo *>(gizmo);
}
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_loadGlb(TSceneManager *tSceneManager, const char *assetPath, int numInstances, bool keepData)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *asset = sceneManager->loadGlb(assetPath, numInstances, keepData);
return reinterpret_cast<TSceneAsset *>(asset);
}
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_loadGltf(TSceneManager *tSceneManager,
const char *assetPath,
const char *relativeResourcePath,
bool keepData)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *asset = sceneManager->loadGltf(assetPath, relativeResourcePath, 1, keepData);
return reinterpret_cast<TSceneAsset *>(asset);
}
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_loadGlbFromBuffer(TSceneManager *tSceneManager, const uint8_t *const data, size_t length, bool keepData, int priority, int layer, bool loadResourcesAsync)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *asset = sceneManager->loadGlbFromBuffer((const uint8_t *)data, length, 1, keepData, priority, layer, loadResourcesAsync);
return reinterpret_cast<TSceneAsset *>(asset);
}
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraByName(TSceneManager *tSceneManager, EntityId entityId, const char *name)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return nullptr;
}
EMSCRIPTEN_KEEPALIVE Aabb3 SceneManager_getRenderableBoundingBox(TSceneManager *tSceneManager, EntityId entity)
{
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return sceneManager->getRenderableBoundingBox(entity);
}
EMSCRIPTEN_KEEPALIVE void SceneManager_setVisibilityLayer(TSceneManager *tSceneManager, EntityId entity, int layer)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
sceneManager->setVisibilityLayer(entity, layer);
}
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitMaterialInstance(TSceneManager *sceneManager)
{
auto *instance = ((SceneManager *)sceneManager)->createUnlitMaterialInstance();
return reinterpret_cast<TMaterialInstance *>(instance);
}
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitFixedSizeMaterialInstance(TSceneManager *sceneManager)
{
auto *instance = ((SceneManager *)sceneManager)->createUnlitFixedSizeMaterialInstance();
return reinterpret_cast<TMaterialInstance *>(instance);
}
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_createCamera(TSceneManager *tSceneManager)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return reinterpret_cast<TCamera *>(sceneManager->createCamera());
}
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyCamera(TSceneManager *tSceneManager, TCamera *tCamera)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *camera = reinterpret_cast<Camera *>(tCamera);
sceneManager->destroyCamera(camera);
}
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *tSceneManager)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return sceneManager->getCameraCount();
}
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraAt(TSceneManager *tSceneManager, size_t index)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *camera = sceneManager->getCameraAt(index);
return reinterpret_cast<TCamera *>(camera);
}
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_createGeometry(
TSceneManager *tSceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance **tMaterialInstances,
int materialInstanceCount,
bool keepData)
{
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto castedNumVertices = static_cast<uint32_t>(numVertices);
auto castedNumNormals = static_cast<uint32_t>(numNormals);
auto castedNumUvs = static_cast<uint32_t>(numUvs);
auto castedNumIndices = static_cast<uint32_t>(numIndices);
auto castedPrimitiveType = static_cast<filament::RenderableManager::PrimitiveType>(primitiveType);
auto materialInstances = reinterpret_cast<MaterialInstance **>(tMaterialInstances);
auto *asset = sceneManager->createGeometry(
vertices,
castedNumVertices,
normals,
castedNumNormals,
uvs,
castedNumUvs,
indices,
castedNumIndices,
castedPrimitiveType,
materialInstances,
materialInstanceCount,
keepData);
return reinterpret_cast<TSceneAsset *>(asset);
}
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyMaterialInstance(TSceneManager *sceneManager, TMaterialInstance *instance)
{
((SceneManager *)sceneManager)->destroy(reinterpret_cast<MaterialInstance *>(instance));
}
EMSCRIPTEN_KEEPALIVE int SceneManager_removeFromScene(TSceneManager *sceneManager, EntityId entityId)
{
return ((SceneManager *)sceneManager)->removeFromScene(entityId);
}
EMSCRIPTEN_KEEPALIVE int SceneManager_addToScene(TSceneManager *sceneManager, EntityId entityId)
{
return ((SceneManager *)sceneManager)->addToScene(entityId);
}
EMSCRIPTEN_KEEPALIVE void SceneManager_transformToUnitCube(TSceneManager *sceneManager, EntityId entityId)
{
((SceneManager *)sceneManager)->transformToUnitCube(entityId);
}
EMSCRIPTEN_KEEPALIVE TAnimationManager *SceneManager_getAnimationManager(TSceneManager *tSceneManager)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *animationManager = sceneManager->getAnimationManager();
return reinterpret_cast<TAnimationManager *>(animationManager);
}
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAll(TSceneManager *tSceneManager)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
sceneManager->destroyAll();
return nullptr;
}
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAsset(TSceneManager *tSceneManager, TSceneAsset *tSceneAsset)
{
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto *sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset);
sceneManager->destroy(sceneAsset);
return nullptr;
}
EMSCRIPTEN_KEEPALIVE TNameComponentManager *SceneManager_getNameComponentManager(TSceneManager *tSceneManager) {
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return reinterpret_cast<TNameComponentManager*>(sceneManager->getNameComponentManager());
}
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getOverlayEntityCount(TSceneManager *tSceneManager) {
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return sceneManager->getOverlayEntityCount();
}
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_getOverlayEntityAt(TSceneManager *tSceneManager, size_t index) {
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto entity = sceneManager->getOverlayEntity(index);
return utils::Entity::smuggle(entity);
}
}

View File

@@ -0,0 +1,155 @@
#include <utils/Entity.h>
#include <filament/TransformManager.h>
#include <filament/math/mat4.h>
#include <gltfio/math.h>
#include "c_api/APIExport.h"
#include "MathUtils.hpp"
#include "Log.hpp"
using namespace thermion;
extern "C"
{
using namespace filament;
using namespace utils;
using namespace filament::gltfio;
#include "c_api/TTransformManager.h"
EMSCRIPTEN_KEEPALIVE double4x4 TransformManager_getLocalTransform(TTransformManager *tTransformManager, EntityId entityId)
{
auto *transformManager = reinterpret_cast<filament::TransformManager *>(tTransformManager);
const auto &entity = utils::Entity::import(entityId);
auto transformInstance = transformManager->getInstance(entity);
if (!transformInstance)
{
Log("Failed to find transform instance");
return double4x4();
}
auto transform = transformManager->getTransformAccurate(transformInstance);
return convert_mat4_to_double4x4(transform);
}
EMSCRIPTEN_KEEPALIVE double4x4 TransformManager_getWorldTransform(TTransformManager *tTransformManager, EntityId entityId)
{
auto *transformManager = reinterpret_cast<filament::TransformManager *>(tTransformManager);
const auto &entity = utils::Entity::import(entityId);
auto transformInstance = transformManager->getInstance(entity);
if (!transformInstance)
{
Log("Failed to find transform instance");
return double4x4();
}
auto transform = transformManager->getWorldTransformAccurate(transformInstance);
return convert_mat4_to_double4x4(transform);
}
EMSCRIPTEN_KEEPALIVE void TransformManager_setTransform(TTransformManager *tTransformManager, EntityId entityId, double4x4 transform)
{
auto *transformManager = reinterpret_cast<filament::TransformManager *>(tTransformManager);
const auto &entity = utils::Entity::import(entityId);
auto transformInstance = transformManager->getInstance(entity);
if (!transformInstance)
{
return;
}
transformManager->setTransform(transformInstance, convert_double4x4_to_mat4(transform));
}
// EMSCRIPTEN_KEEPALIVE void TransformManager_transformToUnitCube(TTransformManager *tTransformManager, EntityId entityId) {
// auto *transformManager = reinterpret_cast<filament::TransformManager*>(tTransformManager);
// const auto &entity = utils::Entity::import(entityId);
// auto transformInstance = transformManager->getInstance(entity);
// if (!transformInstance)
// {
// return;
// }
// auto aabb = instance->getBoundingBox();
// auto center = aabb.center();
// auto halfExtent = aabb.extent();
// auto maxExtent = max(halfExtent) * 2;
// auto scaleFactor = 2.0f / maxExtent;
// auto transform = math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center);
// tm.setTransform(tm.getInstance(instance->getRoot()), transform);
// }
EMSCRIPTEN_KEEPALIVE void TransformManager_setParent(TTransformManager *tTransformManager, EntityId childId, EntityId parentId, bool preserveScaling)
{
auto tm = reinterpret_cast<TransformManager *>(tTransformManager);
const auto child = Entity::import(childId);
const auto parent = Entity::import(parentId);
const auto &parentInstance = tm->getInstance(parent);
const auto &childInstance = tm->getInstance(child);
if (!parentInstance.isValid())
{
Log("Parent instance is not valid");
return;
}
if (!childInstance.isValid())
{
Log("Child instance is not valid");
return;
}
if (preserveScaling)
{
auto parentTransform = tm->getWorldTransform(parentInstance);
math::float3 parentTranslation;
math::quatf parentRotation;
math::float3 parentScale;
decomposeMatrix(parentTransform, &parentTranslation, &parentRotation, &parentScale);
auto childTransform = tm->getTransform(childInstance);
math::float3 childTranslation;
math::quatf childRotation;
math::float3 childScale;
decomposeMatrix(childTransform, &childTranslation, &childRotation, &childScale);
childScale = childScale * (1 / parentScale);
childTransform = composeMatrix(childTranslation, childRotation, childScale);
tm->setTransform(childInstance, childTransform);
}
tm->setParent(childInstance, parentInstance);
}
EMSCRIPTEN_KEEPALIVE EntityId TransformManager_getParent(TTransformManager *tTransformManager, EntityId childId)
{
auto tm = reinterpret_cast<TransformManager *>(tTransformManager);
const auto child = Entity::import(childId);
const auto &childInstance = tm->getInstance(child);
return Entity::smuggle(tm->getParent(childInstance));
}
EMSCRIPTEN_KEEPALIVE EntityId TransformManager_getAncestor(TTransformManager *tTransformManager, EntityId childEntityId)
{
auto tm = reinterpret_cast<TransformManager *>(tTransformManager);
const auto child = Entity::import(childEntityId);
auto transformInstance = tm->getInstance(child);
Entity parent;
while (true)
{
auto newParent = tm->getParent(transformInstance);
if (newParent.isNull())
{
break;
}
parent = newParent;
transformInstance = tm->getInstance(parent);
}
return Entity::smuggle(parent);
}
}

View File

@@ -5,8 +5,8 @@
#include <filament/ColorGrading.h>
#include <filament/Camera.h>
#include "ThermionDartApi.h"
#include "TView.h"
#include "c_api/ThermionDartApi.h"
#include "c_api/TView.h"
#include "Log.hpp"
#ifdef __cplusplus
@@ -155,6 +155,25 @@ using namespace filament;
return reinterpret_cast<TCamera*>(&(view->getCamera()));
}
EMSCRIPTEN_KEEPALIVE void View_setStencilBufferEnabled(TView *tView, bool enabled) {
auto view = reinterpret_cast<View *>(tView);
view->setStencilBufferEnabled(enabled);
}
EMSCRIPTEN_KEEPALIVE bool View_isStencilBufferEnabled(TView *tView) {
auto view = reinterpret_cast<View *>(tView);
return view->isStencilBufferEnabled();
}
EMSCRIPTEN_KEEPALIVE void View_pick(TView *tView, uint32_t requestId, uint32_t x, uint32_t y, PickCallback callback)
{
auto *view = reinterpret_cast<View *>(tView);
view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
callback(requestId, utils::Entity::smuggle(result.renderable), result.depth, result.fragCoords.x, result.fragCoords.y, result.fragCoords.z);
});
}
#ifdef __cplusplus
}

View File

@@ -0,0 +1,511 @@
#ifdef _WIN32
#include "ThermionWin32.h"
#endif
#include <thread>
#include <functional>
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
#include "filament/LightManager.h"
#include "ResourceBuffer.hpp"
#include "FilamentViewer.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
using namespace thermion;
extern "C"
{
#include "c_api/ThermionDartApi.h"
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
{
const auto *loaderImpl = new ResourceLoaderWrapperImpl((ResourceLoaderWrapper *)loader);
auto viewer = new FilamentViewer(context, loaderImpl, platform, uberArchivePath);
return reinterpret_cast<TViewer *>(viewer);
}
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer *viewer)
{
auto *engine = reinterpret_cast<FilamentViewer *>(viewer)->getEngine();
return reinterpret_cast<TEngine *>(engine);
}
EMSCRIPTEN_KEEPALIVE TRenderTarget *Viewer_createRenderTarget(TViewer *tViewer, intptr_t texture, uint32_t width, uint32_t height)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto renderTarget = viewer->createRenderTarget(texture, width, height);
return reinterpret_cast<TRenderTarget *>(renderTarget);
}
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *tViewer, TRenderTarget *tRenderTarget)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
viewer->destroyRenderTarget(renderTarget);
}
EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *viewer)
{
delete ((FilamentViewer *)viewer);
}
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a)
{
((FilamentViewer *)viewer)->setBackgroundColor(r, g, b, a);
}
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer)
{
((FilamentViewer *)viewer)->clearBackgroundImage();
}
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight)
{
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight, 100, 100);
}
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp)
{
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp, 100, 100);
}
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath)
{
((FilamentViewer *)viewer)->loadSkybox(skyboxPath);
}
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity)
{
((FilamentViewer *)viewer)->createIbl(r, g, b, intensity);
}
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity)
{
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
}
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix)
{
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
rotationMatrix[2],
rotationMatrix[3],
rotationMatrix[4],
rotationMatrix[5],
rotationMatrix[6],
rotationMatrix[7],
rotationMatrix[8]);
((FilamentViewer *)viewer)->rotateIbl(matrix);
}
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer)
{
((FilamentViewer *)viewer)->removeSkybox();
}
EMSCRIPTEN_KEEPALIVE void remove_ibl(TViewer *viewer)
{
((FilamentViewer *)viewer)->removeIbl();
}
EMSCRIPTEN_KEEPALIVE EntityId add_light(
TViewer *viewer,
uint8_t type,
float colour,
float intensity,
float posX,
float posY,
float posZ,
float dirX,
float dirY,
float dirZ,
float falloffRadius,
float spotLightConeInner,
float spotLightConeOuter,
float sunAngularRadius,
float sunHaloSize,
float sunHaloFallof,
bool shadows)
{
return ((FilamentViewer *)viewer)->addLight((LightManager::Type)type, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, falloffRadius, spotLightConeInner, spotLightConeOuter, sunAngularRadius, sunHaloSize, sunHaloFallof, shadows);
}
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, int32_t entityId, float x, float y, float z)
{
((FilamentViewer *)viewer)->setLightPosition(entityId, x, y, z);
}
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, int32_t entityId, float x, float y, float z)
{
((FilamentViewer *)viewer)->setLightDirection(entityId, x, y, z);
}
EMSCRIPTEN_KEEPALIVE void remove_light(TViewer *viewer, int32_t entityId)
{
((FilamentViewer *)viewer)->removeLight(entityId);
}
EMSCRIPTEN_KEEPALIVE void clear_lights(TViewer *viewer)
{
((FilamentViewer *)viewer)->clearLights();
}
EMSCRIPTEN_KEEPALIVE int get_instance_count(TSceneManager *sceneManager, EntityId entityId)
{
return ((SceneManager *)sceneManager)->getInstanceCount(entityId);
}
EMSCRIPTEN_KEEPALIVE void get_instances(TSceneManager *sceneManager, EntityId entityId, EntityId *out)
{
return ((SceneManager *)sceneManager)->getInstances(entityId, out);
}
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView)
{
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto *view = reinterpret_cast<View *>(tView);
viewer->setMainCamera(view);
}
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer)
{
return ((FilamentViewer *)viewer)->getMainCamera();
}
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getFieldOfViewInDegrees(horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
}
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getFocalLength();
}
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
cam->setProjection(fovInDegrees, aspect, near, far, horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
}
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity)
{
auto filamentCamera = ((FilamentViewer *)viewer)->getCamera(entity);
return reinterpret_cast<TCamera *>(filamentCamera);
}
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *camera)
{
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getModelMatrix();
return convert_mat4_to_double4x4(mat);
}
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *camera)
{
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getViewMatrix();
return convert_mat4_to_double4x4(mat);
}
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *camera)
{
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getProjectionMatrix();
return convert_mat4_to_double4x4(mat);
}
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *camera)
{
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getCullingProjectionMatrix();
return convert_mat4_to_double4x4(mat);
}
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
const auto &mat = convert_double4x4_to_mat4(matrix);
cam->setCustomProjection(mat, near, far);
}
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
cam->setLensProjection(focalLength, aspect, near, far);
}
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera *camera, double4x4 matrix)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
cam->setModelMatrix(convert_double4x4_to_mat4(matrix));
}
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getNear();
}
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera)
{
auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getCullingFar();
}
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *camera)
{
const auto frustum = reinterpret_cast<filament::Camera *>(camera)->getFrustum();
const math::float4 *planes = frustum.getNormalizedPlanes();
double *array = (double *)calloc(24, sizeof(double));
for (int i = 0; i < 6; i++)
{
auto plane = planes[i];
array[i * 4] = double(plane.x);
array[i * 4 + 1] = double(plane.y);
array[i * 4 + 2] = double(plane.z);
array[i * 4 + 3] = double(plane.w);
}
return array;
}
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float distance)
{
auto *cam = reinterpret_cast<filament::Camera *>(camera);
cam->setFocusDistance(distance);
}
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity)
{
auto *cam = reinterpret_cast<filament::Camera *>(camera);
cam->setExposure(aperture, shutterSpeed, sensitivity);
}
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix)
{
auto *cam = reinterpret_cast<filament::Camera *>(camera);
const filament::math::mat4 &mat = convert_double4x4_to_mat4(matrix);
cam->setModelMatrix(mat);
}
EMSCRIPTEN_KEEPALIVE void Viewer_render(
TViewer *tViewer)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
viewer->render(0);
}
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *tViewer, TSwapChain *tSwapChain, TView *tView, bool renderable)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
auto *view = reinterpret_cast<View *>(tView);
viewer->setRenderable(view, swapChain, renderable);
}
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
TViewer *tViewer,
TView *tView,
TSwapChain *tSwapChain,
uint8_t *pixelBuffer,
void (*callback)(void))
{
#ifdef __EMSCRIPTEN__
bool useFence = true;
#else
bool useFence = false;
#endif
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto *view = reinterpret_cast<View *>(tView);
viewer->capture(view, pixelBuffer, useFence, swapChain, callback);
};
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
TViewer *tViewer,
TView *tView,
TSwapChain *tSwapChain,
TRenderTarget *tRenderTarget,
uint8_t *pixelBuffer,
void (*callback)(void))
{
#ifdef __EMSCRIPTEN__
bool useFence = true;
#else
bool useFence = false;
#endif
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto *view = reinterpret_cast<View *>(tView);
viewer->capture(view, pixelBuffer, useFence, swapChain, renderTarget, callback);
};
EMSCRIPTEN_KEEPALIVE void set_frame_interval(
TViewer *viewer,
float frameInterval)
{
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
}
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *tViewer, TSwapChain *tSwapChain)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
viewer->destroySwapChain(swapChain);
}
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *tViewer, uint32_t width, uint32_t height)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = viewer->createSwapChain(width, height);
return reinterpret_cast<TSwapChain *>(swapChain);
}
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *tViewer, const void *const window)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = viewer->createSwapChain(window);
return reinterpret_cast<TSwapChain *>(swapChain);
}
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_getSwapChainAt(TViewer *tViewer, int index)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto swapChain = viewer->getSwapChainAt(index);
return reinterpret_cast<TSwapChain *>(swapChain);
}
EMSCRIPTEN_KEEPALIVE TView *Viewer_createView(TViewer *tViewer)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto view = viewer->createView();
return reinterpret_cast<TView *>(view);
}
EMSCRIPTEN_KEEPALIVE TView *Viewer_getViewAt(TViewer *tViewer, int32_t index)
{
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto view = viewer->getViewAt(index);
return reinterpret_cast<TView *>(view);
}
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *tViewer)
{
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
auto *sceneManager = viewer->getSceneManager();
return reinterpret_cast<TSceneManager *>(sceneManager);
}
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *tView, EntityId entity, float viewportX, float viewportY)
{
auto *view = reinterpret_cast<View *>(tView);
((SceneManager *)sceneManager)->queueRelativePositionUpdateFromViewportVector(view, entity, viewportX, viewportY);
}
EMSCRIPTEN_KEEPALIVE void ios_dummy()
{
Log("Dummy called");
}
EMSCRIPTEN_KEEPALIVE void thermion_filament_free(void *ptr)
{
free(ptr);
}
EMSCRIPTEN_KEEPALIVE void add_collision_component(TSceneManager *sceneManager, EntityId entityId, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform)
{
((SceneManager *)sceneManager)->addCollisionComponent(entityId, onCollisionCallback, affectsCollidingTransform);
}
EMSCRIPTEN_KEEPALIVE void remove_collision_component(TSceneManager *sceneManager, EntityId entityId)
{
((SceneManager *)sceneManager)->removeCollisionComponent(entityId);
}
EMSCRIPTEN_KEEPALIVE void test_collisions(TSceneManager *sceneManager, EntityId entity)
{
((SceneManager *)sceneManager)->testCollisions(entity);
}
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *tView, EntityId entity)
{
auto view = reinterpret_cast<View *>(tView);
return ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
}
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *tView, EntityId entity, float *minX, float *minY, float *maxX, float *maxY)
{
auto view = reinterpret_cast<View *>(tView);
auto box = ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
*minX = box.minX;
*minY = box.minY;
*maxX = box.maxX;
*maxY = box.maxY;
}
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr)
{
free(ptr);
}
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer *viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
{
((FilamentViewer *)viewer)->unprojectTexture(entity, input, inputWidth, inputHeight, out, outWidth, outHeight);
}
EMSCRIPTEN_KEEPALIVE void *const create_texture(TSceneManager *sceneManager, uint8_t *data, size_t length)
{
return (void *const)((SceneManager *)sceneManager)->createTexture(data, length, "SOMETEXTURE");
}
EMSCRIPTEN_KEEPALIVE void apply_texture_to_material(TSceneManager *sceneManager, EntityId entity, void *const texture, const char *parameterName, int materialIndex)
{
((SceneManager *)sceneManager)->applyTexture(entity, reinterpret_cast<Texture *>(texture), parameterName, materialIndex);
}
EMSCRIPTEN_KEEPALIVE void destroy_texture(TSceneManager *sceneManager, void *const texture)
{
((SceneManager *)sceneManager)->destroyTexture(reinterpret_cast<Texture *>(texture));
}
EMSCRIPTEN_KEEPALIVE TTransformManager *Engine_getTransformManager(TEngine *tEngine)
{
auto *engine = reinterpret_cast<Engine *>(tEngine);
auto &transformManager = engine->getTransformManager();
return reinterpret_cast<TTransformManager *>(&transformManager);
}
EMSCRIPTEN_KEEPALIVE TRenderableManager *Engine_getRenderableManager(TEngine *tEngine)
{
auto *engine = reinterpret_cast<Engine *>(tEngine);
auto &renderableManager = engine->getRenderableManager();
return reinterpret_cast<TRenderableManager *>(&renderableManager);
}
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine *tEngine, EntityId entityId)
{
auto *engine = reinterpret_cast<Engine *>(tEngine);
auto *camera = engine->getCameraComponent(utils::Entity::import(entityId));
return reinterpret_cast<TCamera *>(camera);
}
EMSCRIPTEN_KEEPALIVE void Engine_setTransform(TEngine *tEngine, EntityId entity, double4x4 transform)
{
auto *engine = reinterpret_cast<Engine *>(tEngine);
auto &transformManager = engine->getTransformManager();
auto transformInstance = transformManager.getInstance(utils::Entity::import(entity));
if (!transformInstance.isValid())
{
Log("Transform instance not valid");
}
transformManager.setTransform(transformInstance, convert_double4x4_to_mat4(transform));
}
}

View File

@@ -3,14 +3,20 @@
#include <thread>
#include <stdlib.h>
#include "ThermionDartRenderThreadApi.h"
#include "FilamentViewer.hpp"
#include "TView.h"
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "TSceneManager.h"
#include <filament/LightManager.h>
#include "c_api/APIBoundaryTypes.h"
#include "c_api/TView.h"
#include "c_api/TSceneAsset.h"
#include "c_api/TSceneManager.h"
#include "c_api/TAnimationManager.h"
#include "c_api/ThermionDartRenderThreadApi.h"
#include "FilamentViewer.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "filament/LightManager.h"
using namespace thermion;
using namespace std::chrono_literals;
@@ -99,8 +105,7 @@ public:
}
_cv.wait_for(taskLock, std::chrono::microseconds(2000), [this]
{ return !_tasks.empty() || _stop; });
{ return !_tasks.empty() || _stop; });
}
void createViewer(void *const context,
@@ -109,7 +114,7 @@ public:
const ResourceLoaderWrapper *const loader,
void (*renderCallback)(void *),
void *const owner,
void (*callback)(TViewer*))
void (*callback)(TViewer *))
{
_renderCallback = renderCallback;
_renderCallbackOwner = owner;
@@ -117,8 +122,7 @@ public:
{
auto viewer = (FilamentViewer *)Viewer_create(context, loader, platform, uberArchivePath);
_viewer = reinterpret_cast<TViewer*>(viewer);
callback(_viewer);
});
callback(_viewer); });
auto fut = add_task(lambda);
}
@@ -159,7 +163,7 @@ public:
}
private:
void(*_requestFrameRenderCallback)() = nullptr;
void (*_requestFrameRenderCallback)() = nullptr;
bool _stop = false;
int _frameIntervalInMicroseconds = 1000000 / 60;
std::mutex _mutex;
@@ -205,9 +209,9 @@ extern "C"
}
EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer,
uint32_t width,
uint32_t height,
void (*onComplete)(TSwapChain*))
uint32_t width,
uint32_t height,
void (*onComplete)(TSwapChain *))
{
std::packaged_task<void()> lambda(
[=]() mutable
@@ -219,8 +223,8 @@ extern "C"
}
EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer,
void *const surface,
void (*onComplete)(TSwapChain*))
void *const surface,
void (*onComplete)(TSwapChain *))
{
std::packaged_task<void()> lambda(
[=]() mutable
@@ -242,8 +246,7 @@ extern "C"
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void(*onComplete)())
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void (*onComplete)())
{
if (!_rl)
{
@@ -255,24 +258,26 @@ extern "C"
}
}
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void(*onComplete)()) {
std::packaged_task<void()> lambda(
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void (*onComplete)())
{
std::packaged_task<void()> lambda(
[=]() mutable
{
Viewer_loadIbl(viewer, iblPath, intensity);
onComplete();
});
auto fut = _rl->add_task(lambda);
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height, void(*onComplete)(TRenderTarget*)) {
EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height, void (*onComplete)(TRenderTarget *))
{
std::packaged_task<void()> lambda(
[=]() mutable
{
auto renderTarget = Viewer_createRenderTarget(viewer, texture, width, height);
onComplete(renderTarget);
});
auto fut = _rl->add_task(lambda);
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
@@ -287,9 +292,7 @@ extern "C"
EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView *tView, TSwapChain *tSwapChain)
{
std::packaged_task<void()> lambda([=]() mutable
{
_rl->doRender();
});
{ _rl->doRender(); });
auto fut = _rl->add_task(lambda);
}
@@ -300,7 +303,7 @@ extern "C"
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, TRenderTarget* tRenderTarget, uint8_t *pixelBuffer, void (*onComplete)())
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, TRenderTarget *tRenderTarget, uint8_t *pixelBuffer, void (*onComplete)())
{
std::packaged_task<void()> lambda([=]() mutable
{ Viewer_captureRenderTarget(viewer, view, tSwapChain, tRenderTarget, pixelBuffer, onComplete); });
@@ -317,32 +320,30 @@ extern "C"
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(TSceneManager *sceneManager,
const char *path,
const char *relativeResourcePath,
bool keepData,
void (*callback)(EntityId))
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGltfRenderThread(TSceneManager *sceneManager,
const char *path,
const char *relativeResourcePath,
bool keepData,
void (*callback)(TSceneAsset *))
{
std::packaged_task<EntityId()> lambda([=]() mutable
{
auto entity = load_gltf(sceneManager, path, relativeResourcePath, keepData);
callback(entity);
return entity; });
std::packaged_task<void()> lambda([=]() mutable
{
auto entity = SceneManager_loadGltf(sceneManager, path, relativeResourcePath, keepData);
callback(entity); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(TSceneManager *sceneManager,
const char *path,
int numInstances,
bool keepData,
void (*callback)(EntityId))
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbRenderThread(TSceneManager *sceneManager,
const char *path,
int numInstances,
bool keepData,
void (*callback)(TSceneAsset *))
{
std::packaged_task<EntityId()> lambda(
std::packaged_task<void()> lambda(
[=]() mutable
{
auto entity = load_glb(sceneManager, path, numInstances, keepData);
callback(entity);
return entity;
auto asset = SceneManager_loadGlb(sceneManager, path, numInstances, keepData);
callback(asset);
});
auto fut = _rl->add_task(lambda);
}
@@ -358,22 +359,47 @@ extern "C"
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance *materialInstance,
TMaterialInstance **materialInstances,
int materialInstanceCount,
bool keepData,
void (*callback)(EntityId))
void (*callback)(TSceneAsset *))
{
std::packaged_task<EntityId()> lambda(
std::packaged_task<void()> lambda(
[=]
{
auto entity = SceneManager_createGeometry(sceneManager, vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, primitiveType, materialInstance, keepData);
callback(entity);
return entity;
auto *asset = SceneManager_createGeometry(sceneManager, vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, primitiveType, materialInstances, materialInstanceCount, keepData);
callback(asset);
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void SceneAsset_createInstanceRenderThread(
TSceneAsset *asset, TMaterialInstance **tMaterialInstances,
int materialInstanceCount,
void (*callback)(TSceneAsset *))
{
std::packaged_task<void()> lambda(
[=]
{
auto instanceAsset = SceneAsset_createInstance(asset, tMaterialInstances, materialInstanceCount);
callback(instanceAsset);
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance*)) {
EMSCRIPTEN_KEEPALIVE void MaterialProvider_createMaterialInstanceRenderThread(TMaterialProvider *tMaterialProvider, TMaterialKey *tKey, void (*callback)(TMaterialInstance *))
{
std::packaged_task<void()> lambda(
[=]
{
auto materialInstance = MaterialProvider_createMaterialInstance(tMaterialProvider, tKey);
callback(materialInstance);
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance *))
{
std::packaged_task<void()> lambda(
[=]() mutable
{
@@ -383,7 +409,8 @@ extern "C"
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance*)) {
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance *))
{
std::packaged_task<void()> lambda(
[=]() mutable
{
@@ -394,21 +421,20 @@ extern "C"
}
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager,
const uint8_t *const data,
size_t length,
int numInstances,
bool keepData,
int priority,
int layer,
bool loadResourcesAsync,
void (*callback)(EntityId))
const uint8_t *const data,
size_t length,
int numInstances,
bool keepData,
int priority,
int layer,
bool loadResourcesAsync,
void (*callback)(TSceneAsset *))
{
std::packaged_task<EntityId()> lambda(
std::packaged_task<void()> lambda(
[=]() mutable
{
auto entity = SceneManager_loadGlbFromBuffer(sceneManager, data, length, keepData, priority, layer, loadResourcesAsync);
callback(entity);
return entity;
auto *asset = SceneManager_loadGlbFromBuffer(sceneManager, data, length, keepData, priority, layer, loadResourcesAsync);
callback(asset);
});
auto fut = _rl->add_task(lambda);
}
@@ -432,7 +458,7 @@ extern "C"
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer,
float x, float y,
bool clamp)
@@ -442,7 +468,7 @@ extern "C"
{ set_background_image_position(viewer, x, y, clamp); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer,
const char *skyboxPath,
void (*onComplete)())
@@ -450,11 +476,10 @@ extern "C"
std::packaged_task<void()> lambda([=]
{
load_skybox(viewer, skyboxPath);
onComplete();
});
onComplete(); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer)
{
std::packaged_task<void()> lambda([=]
@@ -469,159 +494,8 @@ extern "C"
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(TViewer *viewer,
EntityId asset, void (*callback)())
EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping)
{
std::packaged_task<void()> lambda([=]
{
remove_entity(viewer, asset);
callback();
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(TViewer *viewer, void (*callback)())
{
std::packaged_task<void()> lambda([=]
{
clear_entities(viewer);
callback();
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
get_morph_target_name_render_thread(TSceneManager *sceneManager, EntityId assetEntity,
EntityId childEntity, char *const outPtr, int index, void (*callback)())
{
std::packaged_task<void()> lambda([=]
{
get_morph_target_name(sceneManager, assetEntity, childEntity, outPtr, index);
callback();
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
get_morph_target_name_count_render_thread(TSceneManager *sceneManager, EntityId assetEntity,
EntityId childEntity, void (*callback)(int))
{
std::packaged_task<int()> lambda([=]
{
auto count = get_morph_target_name_count(sceneManager, assetEntity, childEntity);
callback(count);
return count; });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(TSceneManager *sceneManager,
EntityId asset,
int animationIndex,
int animationFrame)
{
std::packaged_task<void()> lambda([=]
{ set_animation_frame(sceneManager, asset, animationIndex, animationFrame); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(TSceneManager *sceneManager,
EntityId asset, int index)
{
std::packaged_task<void()> lambda(
[=]
{ stop_animation(sceneManager, asset, index); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(TSceneManager *sceneManager,
EntityId asset,
void (*callback)(int))
{
std::packaged_task<int()> lambda(
[=]
{
auto count = get_animation_count(sceneManager, asset);
callback(count);
return count;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(TSceneManager *sceneManager,
EntityId asset,
char *const outPtr,
int index,
void (*callback)())
{
std::packaged_task<void()> lambda(
[=]
{
get_animation_name(sceneManager, asset, outPtr, index);
callback();
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
get_name_for_entity_render_thread(TSceneManager *sceneManager, const EntityId entityId, void (*callback)(const char *))
{
std::packaged_task<const char *()> lambda(
[=]
{
auto name = get_name_for_entity(sceneManager, entityId);
callback(name);
return name;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_render_thread(TSceneManager *sceneManager,
EntityId asset,
const float *const morphData,
int numWeights,
void (*callback)(bool))
{
std::packaged_task<void()> lambda(
[=]
{
auto result = set_morph_target_weights(sceneManager, asset, morphData, numWeights);
callback(result);
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
TSceneManager *sceneManager,
EntityId asset,
int skinIndex,
int boneIndex,
const float *const transform,
void (*callback)(bool))
{
std::packaged_task<bool()> lambda(
[=]
{
auto success = set_bone_transform(sceneManager, asset, skinIndex, boneIndex, transform);
callback(success);
return success;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(TSceneManager *sceneManager,
EntityId entity, void (*callback)(bool))
{
std::packaged_task<void()> lambda(
[=]
{
auto success = update_bone_matrices(sceneManager, entity);
callback(success);
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping) {
std::packaged_task<void()> lambda(
[=]
{
@@ -629,8 +503,9 @@ extern "C"
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom) {
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom)
{
std::packaged_task<void()> lambda(
[=]
{
@@ -639,20 +514,31 @@ extern "C"
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)())
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAllRenderThread(TSceneManager *tSceneManager, void (*callback)())
{
std::packaged_task<void()> lambda(
[=]
[=]() mutable
{
reset_to_rest_pose(sceneManager, entityId);
SceneManager_destroyAll(tSceneManager);
callback();
});
auto fut = _rl->add_task(lambda);
return nullptr;
}
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAssetRenderThread(TSceneManager *tSceneManager, TSceneAsset *tSceneAsset, void (*callback)())
{
std::packaged_task<void()> lambda(
[=]() mutable
{
SceneManager_destroyAsset(tSceneManager, tSceneAsset);
callback();
});
auto fut = _rl->add_task(lambda);
return nullptr;
}
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight, void (*callback)())
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer *viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight, void (*callback)())
{
std::packaged_task<void()> lambda(
[=]
@@ -662,4 +548,34 @@ extern "C"
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_updateBoneMatricesRenderThread(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
void (*callback)(bool))
{
std::packaged_task<void()> lambda(
[=]() mutable
{
bool result = AnimationManager_updateBoneMatrices(tAnimationManager, sceneAsset);
callback(result);
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void AnimationManager_setMorphTargetWeightsRenderThread(
TAnimationManager *tAnimationManager,
EntityId entityId,
const float *const morphData,
int numWeights,
void (*callback)(bool))
{
std::packaged_task<void()> lambda(
[=]() mutable
{
bool result = AnimationManager_setMorphTargetWeights(tAnimationManager, entityId, morphData, numWeights);
callback(result);
});
auto fut = _rl->add_task(lambda);
}
}

View File

@@ -0,0 +1,521 @@
#include <memory>
#include <stack>
#include <unordered_set>
#include <vector>
#include <filament/Engine.h>
#include <filament/TransformManager.h>
#include <filament/RenderableManager.h>
#include <gltfio/Animator.h>
#include "Log.hpp"
#include "scene/AnimationManager.hpp"
#include "scene/SceneAsset.hpp"
#include "scene/GltfSceneAssetInstance.hpp"
namespace thermion
{
using namespace filament;
using namespace utils;
AnimationManager::AnimationManager(Engine *engine, Scene *scene) : _engine(engine), _scene(scene)
{
auto &transformManager = _engine->getTransformManager();
auto &renderableManager = _engine->getRenderableManager();
_animationComponentManager = std::make_unique<AnimationComponentManager>(transformManager, renderableManager);
}
AnimationManager::~AnimationManager()
{
_animationComponentManager = std::nullptr_t();
}
bool AnimationManager::setMorphAnimationBuffer(
utils::Entity entity,
const float *const morphData,
const uint32_t *const morphIndices,
int numMorphTargets,
int numFrames,
float frameLengthInMs)
{
std::lock_guard lock(_mutex);
if (!_animationComponentManager->hasComponent(entity))
{
_animationComponentManager->addAnimationComponent(entity);
}
MorphAnimation morphAnimation;
morphAnimation.meshTarget = entity;
morphAnimation.frameData.clear();
morphAnimation.frameData.insert(
morphAnimation.frameData.begin(),
morphData,
morphData + (numFrames * numMorphTargets));
morphAnimation.frameLengthInMs = frameLengthInMs;
morphAnimation.morphIndices.resize(numMorphTargets);
for (int i = 0; i < numMorphTargets; i++)
{
morphAnimation.morphIndices[i] = morphIndices[i];
}
morphAnimation.durationInSecs = (frameLengthInMs * numFrames) / 1000.0f;
morphAnimation.start = high_resolution_clock::now();
morphAnimation.lengthInFrames = static_cast<int>(
morphAnimation.durationInSecs * 1000.0f /
frameLengthInMs);
auto animationComponentInstance = _animationComponentManager->getInstance(entity);
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
auto &morphAnimations = animationComponent.morphAnimations;
morphAnimations.emplace_back(morphAnimation);
return true;
}
void AnimationManager::clearMorphAnimationBuffer(
utils::Entity entity)
{
std::lock_guard lock(_mutex);
auto animationComponentInstance = _animationComponentManager->getInstance(entity);
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
auto &morphAnimations = animationComponent.morphAnimations;
morphAnimations.clear();
}
void AnimationManager::resetToRestPose(GltfSceneAssetInstance *instance)
{
std::lock_guard lock(_mutex);
auto filamentInstance = instance->getInstance();
auto skinCount = filamentInstance->getSkinCount();
TransformManager &transformManager = _engine->getTransformManager();
//
// To reset the skeleton to its rest pose, we could just call animator->resetBoneMatrices(),
// which sets all bone matrices to the identity matrix. However, any subsequent calls to animator->updateBoneMatrices()
// may result in unexpected poses, because that method uses each bone's transform to calculate
// the bone matrices (and resetBoneMatrices does not affect this transform).
// To "fully" reset the bone, we need to set its local transform (i.e. relative to its parent)
// to its original orientation in rest pose.
//
// This can be calculated as:
//
// auto rest = inverse(parentTransformInModelSpace) * bindMatrix
//
// (where bindMatrix is the inverse of the inverseBindMatrix).
//
// The only requirement is that parent bone transforms are reset before child bone transforms.
// glTF/Filament does not guarantee that parent bones are listed before child bones under a FilamentInstance.
// We ensure that parents are reset before children by:
// - pushing all bones onto a stack
// - iterate over the stack
// - look at the bone at the top of the stack
// - if the bone already been reset, pop and continue iterating over the stack
// - otherwise
// - if the bone has a parent that has not been reset, push the parent to the top of the stack and continue iterating
// - otherwise
// - pop the bone, reset its transform and mark it as completed
for (int skinIndex = 0; skinIndex < skinCount; skinIndex++)
{
std::unordered_set<Entity, Entity::Hasher> joints;
std::unordered_set<Entity, Entity::Hasher> completed;
std::stack<Entity> stack;
auto transforms = getBoneRestTranforms(instance, skinIndex);
for (int i = 0; i < filamentInstance->getJointCountAt(skinIndex); i++)
{
auto restTransform = transforms[i];
const auto &joint = filamentInstance->getJointsAt(skinIndex)[i];
auto transformInstance = transformManager.getInstance(joint);
transformManager.setTransform(transformInstance, restTransform);
}
}
filamentInstance->getAnimator()->updateBoneMatrices();
return;
}
std::vector<math::mat4f> AnimationManager::getBoneRestTranforms(GltfSceneAssetInstance *instance, int skinIndex)
{
std::vector<math::mat4f> transforms;
auto filamentInstance = instance->getInstance();
auto skinCount = filamentInstance->getSkinCount();
TransformManager &transformManager = _engine->getTransformManager();
transforms.resize(filamentInstance->getJointCountAt(skinIndex));
//
// To reset the skeleton to its rest pose, we could just call animator->resetBoneMatrices(),
// which sets all bone matrices to the identity matrix. However, any subsequent calls to animator->updateBoneMatrices()
// may result in unexpected poses, because that method uses each bone's transform to calculate
// the bone matrices (and resetBoneMatrices does not affect this transform).
// To "fully" reset the bone, we need to set its local transform (i.e. relative to its parent)
// to its original orientation in rest pose.
//
// This can be calculated as:
//
// auto rest = inverse(parentTransformInModelSpace) * bindMatrix
//
// (where bindMatrix is the inverse of the inverseBindMatrix).
//
// The only requirement is that parent bone transforms are reset before child bone transforms.
// glTF/Filament does not guarantee that parent bones are listed before child bones under a FilamentInstance.
// We ensure that parents are reset before children by:
// - pushing all bones onto a stack
// - iterate over the stack
// - look at the bone at the top of the stack
// - if the bone already been reset, pop and continue iterating over the stack
// - otherwise
// - if the bone has a parent that has not been reset, push the parent to the top of the stack and continue iterating
// - otherwise
// - pop the bone, reset its transform and mark it as completed
std::vector<Entity> joints;
std::unordered_set<Entity, Entity::Hasher> completed;
std::stack<Entity> stack;
for (int i = 0; i < filamentInstance->getJointCountAt(skinIndex); i++)
{
const auto &joint = filamentInstance->getJointsAt(skinIndex)[i];
joints.push_back(joint);
stack.push(joint);
}
while (!stack.empty())
{
const auto &joint = stack.top();
// if we've already handled this node previously (e.g. when we encountered it as a parent), then skip
if (completed.find(joint) != completed.end())
{
stack.pop();
continue;
}
const auto transformInstance = transformManager.getInstance(joint);
auto parent = transformManager.getParent(transformInstance);
// we need to handle parent joints before handling their children
// therefore, if this joint has a parent that hasn't been handled yet,
// push the parent to the top of the stack and start the loop again
const auto &jointIter = std::find(joints.begin(), joints.end(), joint);
auto parentIter = std::find(joints.begin(), joints.end(), parent);
if (parentIter != joints.end() && completed.find(parent) == completed.end())
{
stack.push(parent);
continue;
}
// otherwise let's get the inverse bind matrix for the joint
math::mat4f inverseBindMatrix;
bool found = false;
for (int i = 0; i < filamentInstance->getJointCountAt(skinIndex); i++)
{
if (filamentInstance->getJointsAt(skinIndex)[i] == joint)
{
inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[i];
found = true;
break;
}
}
ASSERT_PRECONDITION(found, "Failed to find inverse bind matrix for joint %d", joint);
// now we need to ascend back up the hierarchy to calculate the modelSpaceTransform
math::mat4f modelSpaceTransform;
while (parentIter != joints.end())
{
const auto transformInstance = transformManager.getInstance(parent);
const auto parentIndex = distance(joints.begin(), parentIter);
const auto transform = transforms[parentIndex];
modelSpaceTransform = transform * modelSpaceTransform;
parent = transformManager.getParent(transformInstance);
parentIter = std::find(joints.begin(), joints.end(), parent);
}
const auto bindMatrix = inverse(inverseBindMatrix);
const auto inverseModelSpaceTransform = inverse(modelSpaceTransform);
const auto jointIndex = distance(joints.begin(), jointIter);
transforms[jointIndex] = inverseModelSpaceTransform * bindMatrix;
completed.insert(joint);
stack.pop();
}
return transforms;
}
void AnimationManager::updateBoneMatrices(GltfSceneAssetInstance *instance)
{
instance->getInstance()->getAnimator()->updateBoneMatrices();
}
bool AnimationManager::addBoneAnimation(GltfSceneAssetInstance *instance,
int skinIndex,
int boneIndex,
const float *const frameData,
int numFrames,
float frameLengthInMs,
float fadeOutInSecs,
float fadeInInSecs,
float maxDelta)
{
std::lock_guard lock(_mutex);
BoneAnimation animation;
animation.boneIndex = boneIndex;
animation.frameData.clear();
const auto &inverseBindMatrix = instance->getInstance()->getInverseBindMatricesAt(skinIndex)[boneIndex];
for (int i = 0; i < numFrames; i++)
{
math::mat4f frame(
frameData[i * 16],
frameData[(i * 16) + 1],
frameData[(i * 16) + 2],
frameData[(i * 16) + 3],
frameData[(i * 16) + 4],
frameData[(i * 16) + 5],
frameData[(i * 16) + 6],
frameData[(i * 16) + 7],
frameData[(i * 16) + 8],
frameData[(i * 16) + 9],
frameData[(i * 16) + 10],
frameData[(i * 16) + 11],
frameData[(i * 16) + 12],
frameData[(i * 16) + 13],
frameData[(i * 16) + 14],
frameData[(i * 16) + 15]);
animation.frameData.push_back(frame);
}
animation.frameLengthInMs = frameLengthInMs;
animation.start = std::chrono::high_resolution_clock::now();
animation.reverse = false;
animation.durationInSecs = (frameLengthInMs * numFrames) / 1000.0f;
animation.lengthInFrames = numFrames;
animation.frameLengthInMs = frameLengthInMs;
animation.fadeOutInSecs = fadeOutInSecs;
animation.fadeInInSecs = fadeInInSecs;
animation.maxDelta = maxDelta;
animation.skinIndex = skinIndex;
if (!_animationComponentManager->hasComponent(instance->getInstance()->getRoot()))
{
Log("ERROR: specified entity is not animatable (has no animation component attached).");
return false;
}
auto animationComponentInstance = _animationComponentManager->getInstance(instance->getInstance()->getRoot());
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
auto &boneAnimations = animationComponent.boneAnimations;
boneAnimations.emplace_back(animation);
return true;
}
void AnimationManager::playGltfAnimation(GltfSceneAssetInstance *instance, int index, bool loop, bool reverse, bool replaceActive, float crossfade, float startOffset)
{
std::lock_guard lock(_mutex);
if (index < 0)
{
Log("ERROR: glTF animation index must be greater than zero.");
return;
}
if (!_animationComponentManager->hasComponent(instance->getEntity()))
{
Log("ERROR: specified entity is not animatable (has no animation component attached).");
return;
}
auto animationComponentInstance = _animationComponentManager->getInstance(instance->getEntity());
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
if (replaceActive)
{
if (animationComponent.gltfAnimations.size() > 0)
{
auto &last = animationComponent.gltfAnimations.back();
animationComponent.fadeGltfAnimationIndex = last.index;
animationComponent.fadeDuration = crossfade;
auto now = high_resolution_clock::now();
auto elapsedInSecs = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - last.start).count()) / 1000.0f;
animationComponent.fadeOutAnimationStart = elapsedInSecs;
animationComponent.gltfAnimations.clear();
}
else
{
animationComponent.fadeGltfAnimationIndex = -1;
animationComponent.fadeDuration = 0.0f;
}
}
else if (crossfade > 0)
{
Log("ERROR: crossfade only supported when replaceActive is true.");
return;
}
else
{
animationComponent.fadeGltfAnimationIndex = -1;
animationComponent.fadeDuration = 0.0f;
}
GltfAnimation animation;
animation.startOffset = startOffset;
animation.index = index;
animation.start = std::chrono::high_resolution_clock::now();
animation.loop = loop;
animation.reverse = reverse;
animation.durationInSecs = instance->getInstance()->getAnimator()->getAnimationDuration(index);
bool found = false;
// don't play the animation if it's already running
for (int i = 0; i < animationComponent.gltfAnimations.size(); i++)
{
if (animationComponent.gltfAnimations[i].index == index)
{
found = true;
break;
}
}
if (!found)
{
animationComponent.gltfAnimations.push_back(animation);
}
}
void AnimationManager::stopGltfAnimation(GltfSceneAssetInstance *instance, int index)
{
auto animationComponentInstance = _animationComponentManager->getInstance(instance->getEntity());
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
auto erased = std::remove_if(animationComponent.gltfAnimations.begin(),
animationComponent.gltfAnimations.end(),
[=](GltfAnimation &anim)
{ return anim.index == index; });
animationComponent.gltfAnimations.erase(erased,
animationComponent.gltfAnimations.end());
return;
}
void AnimationManager::setMorphTargetWeights(utils::Entity entity, const float *const weights, const int count)
{
RenderableManager &rm = _engine->getRenderableManager();
auto renderableInstance = rm.getInstance(entity);
rm.setMorphWeights(
renderableInstance,
weights,
count);
}
void AnimationManager::setGltfAnimationFrame(GltfSceneAssetInstance *instance, int animationIndex, int animationFrame)
{
auto offset = 60 * animationFrame * 1000; // TODO - don't hardcore 60fps framerate
instance->getInstance()->getAnimator()->applyAnimation(animationIndex, offset);
instance->getInstance()->getAnimator()->updateBoneMatrices();
return;
}
float AnimationManager::getGltfAnimationDuration(GltfSceneAssetInstance *instance, int animationIndex)
{
return instance->getInstance()->getAnimator()->getAnimationDuration(animationIndex);
}
std::vector<std::string> AnimationManager::getGltfAnimationNames(GltfSceneAssetInstance *instance)
{
std::vector<std::string> names;
size_t count = instance->getInstance()->getAnimator()->getAnimationCount();
for (size_t i = 0; i < count; i++)
{
names.push_back(instance->getInstance()->getAnimator()->getAnimationName(i));
}
return names;
}
std::vector<std::string> AnimationManager::getMorphTargetNames(GltfSceneAsset *asset, EntityId childEntity)
{
std::vector<std::string> names;
auto filamentAsset = asset->getAsset();
const utils::Entity targetEntity = utils::Entity::import(childEntity);
size_t count = filamentAsset->getMorphTargetCountAt(targetEntity);
for (int j = 0; j < count; j++)
{
const char *morphName = filamentAsset->getMorphTargetNameAt(targetEntity, j);
names.push_back(morphName);
}
return names;
}
vector<Entity> AnimationManager::getBoneEntities(GltfSceneAssetInstance *instance, int skinIndex)
{
auto *joints = instance->getInstance()->getJointsAt(skinIndex);
auto jointCount = instance->getInstance()->getJointCountAt(skinIndex);
std::vector<Entity> boneEntities(joints, joints + jointCount);
return boneEntities;
}
void AnimationManager::update()
{
std::lock_guard lock(_mutex);
_animationComponentManager->update();
}
math::mat4f AnimationManager::getInverseBindMatrix(GltfSceneAssetInstance *instance, int skinIndex, int boneIndex)
{
return instance->getInstance()->getInverseBindMatricesAt(skinIndex)[boneIndex];
}
bool AnimationManager::setBoneTransform(GltfSceneAssetInstance *instance, int32_t skinIndex, int boneIndex, math::mat4f transform)
{
std::lock_guard lock(_mutex);
RenderableManager &rm = _engine->getRenderableManager();
const auto &renderableInstance = rm.getInstance(instance->getEntity());
if (!renderableInstance.isValid())
{
Log("Specified entity is not a renderable. You probably provided the ultimate parent entity of a glTF asset, which is non-renderable. ");
return false;
}
rm.setBones(
renderableInstance,
&transform,
1,
boneIndex);
return true;
}
bool AnimationManager::addAnimationComponent(EntityId entity)
{
_animationComponentManager->addAnimationComponent(utils::Entity::import(entity));
return true;
}
void AnimationManager::removeAnimationComponent(EntityId entity)
{
_animationComponentManager->removeComponent(utils::Entity::import(entity));
}
}

View File

@@ -10,7 +10,7 @@
#include <filament/Viewport.h>
#include <filament/geometry/SurfaceOrientation.h>
#include "CustomGeometry.hpp"
#include "scene/CustomGeometry.hpp"
#include "Log.hpp"
namespace thermion
@@ -22,9 +22,10 @@ namespace thermion
float *normals, uint32_t numNormals, float *uvs,
uint32_t numUvs, uint16_t *indices,
uint32_t numIndices,
MaterialInstance* materialInstance,
RenderableManager::PrimitiveType primitiveType,
Engine *engine)
: numVertices(numVertices), numIndices(numIndices), _engine(engine)
: numVertices(numVertices), numIndices(numIndices), _materialInstance(materialInstance), _engine(engine)
{
this->primitiveType = primitiveType;
@@ -214,7 +215,6 @@ namespace thermion
CustomGeometry::~CustomGeometry()
{
Log("GEOMETRY DESTRUCTOR");
_engine->destroy(vertexBuffer);
_engine->destroy(indexBuffer);
}

View File

@@ -0,0 +1,125 @@
#include <vector>
#include <gltfio/MaterialProvider.h>
#include <filament/Engine.h>
#include <filament/Frustum.h>
#include <filament/RenderableManager.h>
#include <filament/Texture.h>
#include <filament/TransformManager.h>
#include <filament/Viewport.h>
#include <filament/geometry/SurfaceOrientation.h>
#include "Log.hpp"
#include "scene/GeometrySceneAsset.hpp"
#include "scene/GeometrySceneAssetBuilder.hpp"
namespace thermion
{
using namespace filament;
GeometrySceneAsset::GeometrySceneAsset(
bool isInstance,
Engine *engine,
VertexBuffer *vertexBuffer,
IndexBuffer *indexBuffer,
MaterialInstance **materialInstances,
size_t materialInstanceCount,
RenderableManager::PrimitiveType primitiveType,
Box boundingBox)
: _isInstance(isInstance),
_engine(engine), _vertexBuffer(vertexBuffer), _indexBuffer(indexBuffer), _materialInstances(materialInstances), _materialInstanceCount(materialInstanceCount), _primitiveType(primitiveType), _boundingBox(boundingBox)
{
_entity = utils::EntityManager::get().create();
RenderableManager::Builder builder(1);
builder.boundingBox(_boundingBox)
.geometry(0, _primitiveType, _vertexBuffer, _indexBuffer)
.culling(true)
.receiveShadows(true)
.castShadows(true);
for (int i = 0; i < materialInstanceCount; i++)
{
builder.material(i, materialInstances[i]);
}
builder.build(*_engine, _entity);
}
GeometrySceneAsset::~GeometrySceneAsset()
{
if (_engine)
{
if (_vertexBuffer && !_isInstance)
_engine->destroy(_vertexBuffer);
if (_indexBuffer && !_isInstance)
_engine->destroy(_indexBuffer);
}
}
SceneAsset *GeometrySceneAsset::createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount)
{
if (_isInstance)
{
Log("Cannot create an instance from another instance. Ensure you are calling createInstance with the original asset.");
return nullptr;
}
std::unique_ptr<GeometrySceneAsset> instance = std::make_unique<GeometrySceneAsset>(
true,
_engine,
_vertexBuffer,
_indexBuffer,
materialInstances,
materialInstanceCount,
_primitiveType,
_boundingBox);
auto *raw = instance.get();
_instances.push_back(std::move(instance));
return raw;
}
// std::unique_ptr<GeometrySceneAsset> GeometrySceneAsset::create(
// float *vertices, uint32_t numVertices,
// float *normals, uint32_t numNormals,
// float *uvs, uint32_t numUvs,
// uint16_t *indices, uint32_t numIndices,
// MaterialInstance **materialInstances,
// size_t materialInstanceCount,
// RenderableManager::PrimitiveType primitiveType,
// Engine *engine)
// {
// // Setup texture if needed
// if (asset && uvs && numUvs > 0 &&
// asset->getMaterialInstance() &&
// asset->getMaterialInstance()->getMaterial()->hasParameter("baseColorMap"))
// {
// static constexpr uint32_t textureSize = 1;
// static constexpr uint32_t white = 0x00ffffff;
// auto texture = Texture::Builder()
// .width(textureSize)
// .height(textureSize)
// .levels(1)
// .format(Texture::InternalFormat::RGBA8)
// .build(*engine);
// filament::backend::PixelBufferDescriptor pbd(
// &white, 4, Texture::Format::RGBA, Texture::Type::UBYTE);
// texture->setImage(*engine, 0, std::move(pbd));
// TextureSampler sampler(
// TextureSampler::MinFilter::NEAREST,
// TextureSampler::MagFilter::NEAREST);
// sampler.setWrapModeS(TextureSampler::WrapMode::REPEAT);
// sampler.setWrapModeT(TextureSampler::WrapMode::REPEAT);
// asset->getMaterialInstance()->setParameter("baseColorMap", texture, sampler);
// }
// return asset;
// }
} // namespace thermion

View File

@@ -0,0 +1,367 @@
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
#include <filament/TransformManager.h>
#include <utils/Entity.h>
#include <utils/EntityManager.h>
#include <gltfio/math.h>
#include "scene/Gizmo.hpp"
#include "scene/SceneManager.hpp"
#include "material/unlit_fixed_size.h"
#include "Log.hpp"
namespace thermion
{
using namespace filament::gltfio;
// First, create the black cube at the center
// The axes widgets will be parented to this entity
Entity Gizmo::createParentEntity()
{
auto &transformManager = _engine->getTransformManager();
auto &entityManager = _engine->getEntityManager();
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);
_materialInstances.push_back(parentMaterialInstance);
// Create center cube vertices
float centerCubeSize = 0.1f;
float *centerCubeVertices = new float[8 * 3]{
-centerCubeSize, -centerCubeSize, -centerCubeSize,
centerCubeSize, -centerCubeSize, -centerCubeSize,
centerCubeSize, centerCubeSize, -centerCubeSize,
-centerCubeSize, centerCubeSize, -centerCubeSize,
-centerCubeSize, -centerCubeSize, centerCubeSize,
centerCubeSize, -centerCubeSize, centerCubeSize,
centerCubeSize, centerCubeSize, centerCubeSize,
-centerCubeSize, centerCubeSize, centerCubeSize};
// Create center cube indices
uint16_t *centerCubeIndices = new uint16_t[36]{
0, 1, 2, 2, 3, 0,
1, 5, 6, 6, 2, 1,
5, 4, 7, 7, 6, 5,
4, 0, 3, 3, 7, 4,
3, 2, 6, 6, 7, 3,
4, 5, 1, 1, 0, 4};
auto centerCubeVb = VertexBuffer::Builder()
.vertexCount(8)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(*_engine);
centerCubeVb->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<float *>(buffer); }));
auto centerCubeIb = IndexBuffer::Builder().indexCount(36).bufferType(IndexBuffer::IndexType::USHORT).build(*_engine);
centerCubeIb->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
centerCubeIndices, 36 * sizeof(uint16_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint16_t *>(buffer); }));
RenderableManager::Builder(1)
.boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
{centerCubeSize, centerCubeSize, centerCubeSize}})
.material(0, parentMaterialInstance)
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.priority(7)
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
.culling(false)
.build(*_engine, parent);
auto parentTransformInstance = transformManager.getInstance(parent);
math::mat4f cubeTransform;
transformManager.setTransform(parentTransformInstance, cubeTransform);
return parent;
}
Gizmo::Gizmo(Engine *engine, View *view, Scene *scene, Material *material) : _engine(engine), _view(view), _scene(scene), _material(material)
{
auto parent = createParentEntity();
auto x = createAxisEntity(Gizmo::Axis::X, parent);
auto y = createAxisEntity(Gizmo::Axis::Y, parent);
auto z = createAxisEntity(Gizmo::Axis::Z, parent);
auto xHitTest = createHitTestEntity(Gizmo::Axis::X, parent);
auto yHitTest = createHitTestEntity(Gizmo::Axis::Y, parent);
auto zHitTest = createHitTestEntity(Gizmo::Axis::Z, parent);
_entities = std::vector{parent, x, y, z, xHitTest, yHitTest, zHitTest};
_parent = parent;
_x = x;
_y = y;
_z = z;
_xHitTest = xHitTest;
_yHitTest = yHitTest;
_zHitTest = zHitTest;
}
Entity Gizmo::createAxisEntity(Gizmo::Axis axis, Entity parent)
{
auto &entityManager = _engine->getEntityManager();
auto &transformManager = _engine->getTransformManager();
auto *materialInstance = _material->createInstance();
_materialInstances.push_back(materialInstance);
auto entity = entityManager.create();
auto baseColor = inactiveColors[axis];
// Line and arrow vertices
float lineLength = 0.6f;
float lineWidth = 0.008f;
float arrowLength = 0.06f;
float arrowWidth = 0.02f;
float *vertices = new float[13 * 3]{
// Line vertices (8 vertices)
-lineWidth, -lineWidth, 0.0f,
lineWidth, -lineWidth, 0.0f,
lineWidth, lineWidth, 0.0f,
-lineWidth, lineWidth, 0.0f,
-lineWidth, -lineWidth, lineLength,
lineWidth, -lineWidth, lineLength,
lineWidth, lineWidth, lineLength,
-lineWidth, lineWidth, lineLength,
// Arrow vertices (5 vertices)
0.0f, 0.0f, lineLength + arrowLength, // Tip of the arrow
-arrowWidth, -arrowWidth, lineLength, // Base of the arrow
arrowWidth, -arrowWidth, lineLength,
arrowWidth, arrowWidth, lineLength,
-arrowWidth, arrowWidth, lineLength};
// Line and arrow indices
uint16_t *indices = new uint16_t[24 + 18]{
// Line indices (24 indices)
0, 1, 5, 5, 4, 0,
1, 2, 6, 6, 5, 1,
2, 3, 7, 7, 6, 2,
3, 0, 4, 4, 7, 3,
// // Arrow indices (18 indices)
8, 9, 10, // Front face
8, 10, 11, // Right face
8, 11, 12, // Back face
8, 12, 9, // Left face
9, 12, 11, 11, 10, 9 // Base of the arrow
};
auto vb = VertexBuffer::Builder()
.vertexCount(13)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(*_engine);
vb->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(vertices, 13 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<float *>(buffer); }));
auto ib = IndexBuffer::Builder().indexCount(42).bufferType(IndexBuffer::IndexType::USHORT).build(*_engine);
ib->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
indices, 42 * sizeof(uint16_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint16_t *>(buffer); }));
materialInstance->setParameter("baseColorFactor", baseColor);
materialInstance->setParameter("scale", 4.0f);
materialInstance->setDepthCulling(false);
materialInstance->setDepthFunc(MaterialInstance::DepthFunc::A);
RenderableManager::Builder(1)
.boundingBox({{-arrowWidth, -arrowWidth, 0},
{arrowWidth, arrowWidth, lineLength + arrowLength}})
.material(0, materialInstance)
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb, ib, 0, 42)
.priority(6)
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(*_engine, entity);
auto transformInstance = transformManager.getInstance(entity);
transformManager.setTransform(transformInstance, getRotationForAxis(axis));
// parent the axis to the center cube
auto parentTransformInstance = transformManager.getInstance(parent);
transformManager.setParent(transformInstance, parentTransformInstance);
return entity;
}
Gizmo::~Gizmo()
{
_scene->removeEntities(_entities.data(), _entities.size());
for (auto entity : _entities)
{
_engine->destroy(entity);
}
for (auto *materialInstance : _materialInstances)
{
_engine->destroy(materialInstance);
}
}
Entity Gizmo::createHitTestEntity(Gizmo::Axis axis, Entity parent)
{
auto &entityManager = EntityManager::get();
auto &transformManager = _engine->getTransformManager();
auto parentTransformInstance = transformManager.getInstance(parent);
float volumeWidth = 0.2f;
float volumeLength = 1.2f;
float volumeDepth = 0.2f;
float *volumeVertices = new float[8 * 3]{
-volumeWidth / 2, -volumeDepth / 2, 0,
volumeWidth / 2, -volumeDepth / 2, 0,
volumeWidth / 2, -volumeDepth / 2, volumeLength,
-volumeWidth / 2, -volumeDepth / 2, volumeLength,
-volumeWidth / 2, volumeDepth / 2, 0,
volumeWidth / 2, volumeDepth / 2, 0,
volumeWidth / 2, volumeDepth / 2, volumeLength,
-volumeWidth / 2, volumeDepth / 2, volumeLength};
uint16_t *volumeIndices = new uint16_t[36]{
0, 1, 2, 2, 3, 0, // Bottom face
4, 5, 6, 6, 7, 4, // Top face
0, 4, 7, 7, 3, 0, // Left face
1, 5, 6, 6, 2, 1, // Right face
0, 1, 5, 5, 4, 0, // Front face
3, 2, 6, 6, 7, 3 // Back face
};
auto volumeVb = VertexBuffer::Builder()
.vertexCount(8)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(*_engine);
volumeVb->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(volumeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<float *>(buffer); }));
auto volumeIb = IndexBuffer::Builder()
.indexCount(36)
.bufferType(IndexBuffer::IndexType::USHORT)
.build(*_engine);
volumeIb->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
volumeIndices, 36 * sizeof(uint16_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint16_t *>(buffer); }));
auto entity = entityManager.create();
auto *materialInstance = _material->createInstance();
_materialInstances.push_back(materialInstance);
materialInstance->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
materialInstance->setParameter("scale", 4.0f);
RenderableManager::Builder(1)
.boundingBox({{-volumeWidth / 2, -volumeDepth / 2, 0}, {volumeWidth / 2, volumeDepth / 2, volumeLength}})
.material(0, materialInstance)
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, volumeVb, volumeIb, 0, 36)
.priority(7)
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(*_engine, entity);
auto transformInstance = transformManager.getInstance(entity);
transformManager.setTransform(transformInstance, getRotationForAxis(axis));
// Parent the picking volume to the center cube
transformManager.setParent(transformInstance, parentTransformInstance);
return entity;
}
void Gizmo::highlight(Gizmo::Axis axis)
{
auto &rm = _engine->getRenderableManager();
auto entity = getEntityForAxis(axis);
if (entity.isNull())
{
return;
}
auto renderableInstance = rm.getInstance(entity);
if (!renderableInstance.isValid())
{
Log("Invalid renderable for axis");
return;
}
auto *materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
math::float4 baseColor = activeColors[axis];
materialInstance->setParameter("baseColorFactor", baseColor);
}
void Gizmo::unhighlight(Gizmo::Axis axis)
{
auto &rm = _engine->getRenderableManager();
auto entity = getEntityForAxis(axis);
if (entity.isNull())
{
return;
}
auto renderableInstance = rm.getInstance(entity);
if (!renderableInstance.isValid())
{
Log("Invalid renderable for axis");
return;
}
auto *materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
math::float4 baseColor = inactiveColors[axis];
materialInstance->setParameter("baseColorFactor", baseColor);
}
void Gizmo::pick(uint32_t x, uint32_t y, GizmoPickCallback callback)
{
auto handler = new Gizmo::PickCallbackHandler(this, callback);
_view->pick(x, y, [=](filament::View::PickingQueryResult const &result)
{
handler->handle(result);
delete handler; });
}
bool Gizmo::isGizmoEntity(Entity e)
{
for (int i = 0; i < 7; i++)
{
if (e == _entities[i])
{
return true;
}
}
return false;
}
math::mat4f Gizmo::getRotationForAxis(Gizmo::Axis axis)
{
math::mat4f transform;
switch (axis)
{
case Axis::X:
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
break;
case Axis::Y:
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
break;
case Axis::Z:
break;
}
return transform;
}
}

View File

@@ -0,0 +1,61 @@
#include "scene/GltfSceneAsset.hpp"
#include "scene/GltfSceneAssetInstance.hpp"
#include "gltfio/FilamentInstance.h"
#include "Log.hpp"
namespace thermion
{
GltfSceneAsset::~GltfSceneAsset()
{
_instances.clear();
_asset->releaseSourceData();
_assetLoader->destroyAsset(_asset);
}
SceneAsset *GltfSceneAsset::createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount)
{
auto instanceNumber = _instances.size();
if (instanceNumber > _asset->getAssetInstanceCount() - 1)
{
Log("No instances available for reuse. When loading the asset, you must pre-allocate the number of instances you wish to make available for use. Try increasing this number.");
return std::nullptr_t();
}
Log("Creating instance %d", instanceNumber);
auto instance = _asset->getAssetInstances()[instanceNumber];
instance->recomputeBoundingBoxes();
instance->getAnimator()->updateBoneMatrices();
auto& rm = _engine->getRenderableManager();
if(materialInstanceCount > 0) {
for(int i = 0; i < instance->getEntityCount(); i++) {
auto renderableInstance = rm.getInstance(instance->getEntities()[i]);
if(!renderableInstance.isValid()) {
Log("Instance is not renderable");
} else {
for(int i = 0; i < materialInstanceCount; i++) {
rm.setMaterialInstanceAt(renderableInstance, i, materialInstances[i]);
}
}
}
}
std::unique_ptr<GltfSceneAssetInstance> sceneAssetInstance = std::make_unique<GltfSceneAssetInstance>(
instance,
_engine,
materialInstances,
materialInstanceCount
);
auto *raw = sceneAssetInstance.get();
_instances.push_back(std::move(sceneAssetInstance));
return raw;
}
}

View File

@@ -0,0 +1,14 @@
#include "scene/GltfSceneAssetInstance.hpp"
#include "gltfio/FilamentInstance.h"
#include "Log.hpp"
namespace thermion
{
GltfSceneAssetInstance::~GltfSceneAssetInstance()
{
}
}

View File

@@ -0,0 +1,349 @@
// #include <filament/Engine.h>
// #include <filament/RenderableManager.h>
// #include <filament/TransformManager.h>
// #include <gltfio/math.h>
// #include <utils/Entity.h>
// #include <utils/EntityManager.h>
// #include <math.h>
// #include "scene/SceneManager.hpp"
// namespace thermion {
// using namespace filament::gltfio;
// RotationGizmo::RotationGizmo(Engine* engine, View* view, Scene* scene, Material* material)
// : _engine(engine), _view(view), _scene(scene), _material(material) {
// auto& entityManager = EntityManager::get();
// auto& transformManager = _engine->getTransformManager();
// // Create center cube
// auto parentEntity = entityManager.create();
// auto* parentMaterialInstance = _material->createInstance();
// parentMaterialInstance->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 1.0f});
// parentMaterialInstance->setParameter("scale", 4.0f);
// _entities[0] = parentEntity;
// _materialInstances[0] = parentMaterialInstance;
// // Create center cube geometry
// float centerCubeSize = 0.01f;
// float* centerCubeVertices = new float[8 * 3]{
// -centerCubeSize, -centerCubeSize, -centerCubeSize,
// centerCubeSize, -centerCubeSize, -centerCubeSize,
// centerCubeSize, centerCubeSize, -centerCubeSize,
// -centerCubeSize, centerCubeSize, -centerCubeSize,
// -centerCubeSize, -centerCubeSize, centerCubeSize,
// centerCubeSize, -centerCubeSize, centerCubeSize,
// centerCubeSize, centerCubeSize, centerCubeSize,
// -centerCubeSize, centerCubeSize, centerCubeSize
// };
// uint16_t* centerCubeIndices = new uint16_t[36]{
// 0, 1, 2, 2, 3, 0,
// 1, 5, 6, 6, 2, 1,
// 5, 4, 7, 7, 6, 5,
// 4, 0, 3, 3, 7, 4,
// 3, 2, 6, 6, 7, 3,
// 4, 5, 1, 1, 0, 4
// };
// auto centerCubeVb = VertexBuffer::Builder()
// .vertexCount(8)
// .bufferCount(1)
// .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
// .build(*engine);
// centerCubeVb->setBufferAt(*engine, 0,
// VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3),
// [](void* buffer, size_t size, void*) { delete[] static_cast<float*>(buffer); }));
// auto centerCubeIb = IndexBuffer::Builder()
// .indexCount(36)
// .bufferType(IndexBuffer::IndexType::USHORT)
// .build(*engine);
// centerCubeIb->setBuffer(*engine,
// IndexBuffer::BufferDescriptor(centerCubeIndices, 36 * sizeof(uint16_t),
// [](void* buffer, size_t size, void*) { delete[] static_cast<uint16_t*>(buffer); }));
// RenderableManager::Builder(1)
// .boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
// {centerCubeSize, centerCubeSize, centerCubeSize}})
// .material(0, parentMaterialInstance)
// .layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
// .priority(7)
// .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
// .culling(false)
// .build(*engine, parentEntity);
// // Create rotation circles
// constexpr int segments = 32;
// float radius = 0.5f;
// float* vertices;
// uint16_t* indices;
// int vertexCount, indexCount;
// createCircle(radius, segments, vertices, indices, vertexCount, indexCount);
// auto vb = VertexBuffer::Builder()
// .vertexCount(vertexCount)
// .bufferCount(1)
// .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
// .build(*engine);
// vb->setBufferAt(*engine, 0,
// VertexBuffer::BufferDescriptor(vertices, vertexCount * sizeof(filament::math::float3),
// [](void* buffer, size_t size, void*) { delete[] static_cast<float*>(buffer); }));
// auto ib = IndexBuffer::Builder()
// .indexCount(indexCount)
// .bufferType(IndexBuffer::IndexType::USHORT)
// .build(*engine);
// ib->setBuffer(*engine,
// IndexBuffer::BufferDescriptor(indices, indexCount * sizeof(uint16_t),
// [](void* buffer, size_t size, void*) { delete[] static_cast<uint16_t*>(buffer); }));
// // Create the three circular rotation handles
// for (int i = 0; i < 3; i++) {
// auto* materialInstance = _material->createInstance();
// auto entity = entityManager.create();
// _entities[i + 1] = entity;
// _materialInstances[i + 1] = materialInstance;
// auto baseColor = inactiveColors[i];
// math::mat4f transform;
// switch (i) {
// case Axis::X:
// transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
// break;
// case Axis::Y:
// transform = math::mat4f::rotation(math::F_PI_2, math::float3{1, 0, 0});
// break;
// case Axis::Z:
// break;
// }
// materialInstance->setParameter("baseColorFactor", baseColor);
// materialInstance->setParameter("scale", 4.0f);
// RenderableManager::Builder(1)
// .boundingBox({{-radius, -radius, -0.01f}, {radius, radius, 0.01f}})
// .material(0, materialInstance)
// .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb, ib, 0, indexCount)
// .priority(6)
// .layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
// .culling(false)
// .receiveShadows(false)
// .castShadows(false)
// .build(*engine, entity);
// auto transformInstance = transformManager.getInstance(entity);
// transformManager.setTransform(transformInstance, transform);
// transformManager.setParent(transformInstance, transformManager.getInstance(parentEntity));
// }
// createHitTestEntities();
// setVisibility(true);
// }
// void RotationGizmo::createCircle(float radius, int segments, float*& vertices, uint16_t*& indices, int& vertexCount, int& indexCount) {
// vertexCount = segments * 2;
// indexCount = segments * 6;
// vertices = new float[vertexCount * 3];
// indices = new uint16_t[indexCount];
// float thickness = 0.01f;
// // Generate vertices for inner and outer circles
// for (int i = 0; i < segments; i++) {
// float angle = (2.0f * M_PI * i) / segments;
// float x = cosf(angle);
// float y = sinf(angle);
// // Inner circle vertex
// vertices[i * 6] = x * (radius - thickness);
// vertices[i * 6 + 1] = y * (radius - thickness);
// vertices[i * 6 + 2] = 0.0f;
// // Outer circle vertex
// vertices[i * 6 + 3] = x * (radius + thickness);
// vertices[i * 6 + 4] = y * (radius + thickness);
// vertices[i * 6 + 5] = 0.0f;
// }
// // Generate indices for triangles
// for (int i = 0; i < segments; i++) {
// int next = (i + 1) % segments;
// // First triangle
// indices[i * 6] = i * 2;
// indices[i * 6 + 1] = i * 2 + 1;
// indices[i * 6 + 2] = next * 2 + 1;
// // Second triangle
// indices[i * 6 + 3] = i * 2;
// indices[i * 6 + 4] = next * 2 + 1;
// indices[i * 6 + 5] = next * 2;
// }
// }
// void RotationGizmo::createHitTestEntities() {
// auto& entityManager = EntityManager::get();
// auto& transformManager = _engine->getTransformManager();
// float radius = 0.5f;
// float thickness = 0.1f;
// // Create hit test volumes for each rotation circle
// for (int i = 4; i < 7; i++) {
// _entities[i] = entityManager.create();
// _materialInstances[i] = _material->createInstance();
// _materialInstances[i]->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
// _materialInstances[i]->setParameter("scale", 4.0f);
// math::mat4f transform;
// switch (i - 4) {
// case Axis::X:
// transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
// break;
// case Axis::Y:
// transform = math::mat4f::rotation(math::F_PI_2, math::float3{1, 0, 0});
// break;
// case Axis::Z:
// break;
// }
// // Create a thicker invisible volume aroun
// // Create a thicker invisible volume around each rotation circle for hit testing
// float* volumeVertices;
// uint16_t* volumeIndices;
// int volumeVertexCount, volumeIndexCount;
// createCircle(radius, 32, volumeVertices, volumeIndices, volumeVertexCount, volumeIndexCount);
// auto volumeVb = VertexBuffer::Builder()
// .vertexCount(volumeVertexCount)
// .bufferCount(1)
// .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
// .build(*_engine);
// volumeVb->setBufferAt(*_engine, 0,
// VertexBuffer::BufferDescriptor(volumeVertices, volumeVertexCount * sizeof(filament::math::float3),
// [](void* buffer, size_t size, void*) { delete[] static_cast<float*>(buffer); }));
// auto volumeIb = IndexBuffer::Builder()
// .indexCount(volumeIndexCount)
// .bufferType(IndexBuffer::IndexType::USHORT)
// .build(*_engine);
// volumeIb->setBuffer(*_engine,
// IndexBuffer::BufferDescriptor(volumeIndices, volumeIndexCount * sizeof(uint16_t),
// [](void* buffer, size_t size, void*) { delete[] static_cast<uint16_t*>(buffer); }));
// RenderableManager::Builder(1)
// .boundingBox({{-radius, -radius, -thickness/2}, {radius, radius, thickness/2}})
// .material(0, _materialInstances[i])
// .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, volumeVb, volumeIb, 0, volumeIndexCount)
// .priority(7)
// .layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
// .culling(false)
// .receiveShadows(false)
// .castShadows(false)
// .build(*_engine, _entities[i]);
// auto instance = transformManager.getInstance(_entities[i]);
// transformManager.setTransform(instance, transform);
// transformManager.setParent(instance, transformManager.getInstance(_entities[0]));
// }
// }
// RotationGizmo::~RotationGizmo() {
// _scene->removeEntities(_entities, 7);
// for (int i = 0; i < 7; i++) {
// _engine->destroy(_entities[i]);
// _engine->destroy(_materialInstances[i]);
// }
// }
// void RotationGizmo::highlight(Entity entity) {
// auto& rm = _engine->getRenderableManager();
// auto renderableInstance = rm.getInstance(entity);
// auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
// math::float4 baseColor;
// if (entity == x()) {
// baseColor = activeColors[Axis::X];
// } else if (entity == y()) {
// baseColor = activeColors[Axis::Y];
// } else if (entity == z()) {
// baseColor = activeColors[Axis::Z];
// } else {
// baseColor = math::float4{1.0f, 1.0f, 1.0f, 1.0f};
// }
// materialInstance->setParameter("baseColorFactor", baseColor);
// }
// void RotationGizmo::unhighlight() {
// auto& rm = _engine->getRenderableManager();
// for (int i = 0; i < 3; i++) {
// auto renderableInstance = rm.getInstance(_entities[i + 1]);
// auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
// materialInstance->setParameter("baseColorFactor", inactiveColors[i]);
// }
// }
// void RotationGizmo::pick(uint32_t x, uint32_t y, PickCallback callback) {
// auto handler = new RotationGizmo::PickCallbackHandler(this, callback);
// _view->pick(x, y, [=](filament::View::PickingQueryResult const& result) {
// handler->handle(result);
// delete handler;
// });
// }
// void RotationGizmo::PickCallbackHandler::handle(filament::View::PickingQueryResult const& result) {
// auto x = static_cast<int32_t>(result.fragCoords.x);
// auto y = static_cast<int32_t>(result.fragCoords.y);
// for (int i = 0; i < 7; i++) {
// if (_gizmo->_entities[i] == result.renderable) {
// if (i < 4) {
// return;
// }
// _gizmo->highlight(_gizmo->_entities[i - 4]);
// _callback(static_cast<Axis>(i - 4), x, y, _gizmo->_view);
// return;
// }
// }
// _gizmo->unhighlight();
// }
// bool RotationGizmo::isGizmoEntity(Entity e) {
// for (int i = 0; i < 7; i++) {
// if (e == _entities[i]) {
// return true;
// }
// }
// return false;
// }
// void RotationGizmo::setVisibility(bool visible) {
// if (visible) {
// _scene->addEntities(_entities, 7);
// } else {
// _scene->removeEntities(_entities, 7);
// }
// }
// }

Some files were not shown because too many files have changed in this diff Show More