diff --git a/thermion_dart/lib/thermion_dart.dart b/thermion_dart/lib/thermion_dart.dart index 0d69812a..6ccf7c64 100644 --- a/thermion_dart/lib/thermion_dart.dart +++ b/thermion_dart/lib/thermion_dart.dart @@ -1,5 +1,5 @@ library filament_dart; export 'thermion_dart/thermion_viewer.dart'; -export 'thermion_dart/thermion_viewer_ffi.dart'; +export 'thermion_dart/compatibility/web/interop/thermion_viewer_wasm.dart' if (dart.library.io) 'thermion_dart/thermion_viewer_ffi.dart'; export 'thermion_dart/entities/entity_transform_controller.dart'; diff --git a/thermion_dart/lib/thermion_dart/compatibility/web/compatibility.dart b/thermion_dart/lib/thermion_dart/compatibility/web/compatibility.dart index f8da247c..e69de29b 100644 --- a/thermion_dart/lib/thermion_dart/compatibility/web/compatibility.dart +++ b/thermion_dart/lib/thermion_dart/compatibility/web/compatibility.dart @@ -1,118 +0,0 @@ -import 'dart:async'; -import 'dart:js_interop'; -import 'package:thermion_dart/thermion_dart/compatibility/web/interop.dart'; - -import "allocator.dart"; - -export "allocator.dart"; -export "thermion_dart.g.dart"; - -export 'package:ffi/ffi.dart' hide StringUtf8Pointer, Utf8Pointer; -export 'dart:ffi' - hide - Uint8Pointer, - FloatPointer, - DoublePointer, - Int32Pointer, - Int64Pointer, - PointerPointer, - Allocator; - -const allocator = Allocator(); - -@AbiSpecificIntegerMapping({ - Abi.androidArm: Uint8(), - Abi.androidArm64: Uint8(), - Abi.androidIA32: Int8(), - Abi.androidX64: Int8(), - Abi.androidRiscv64: Uint8(), - Abi.fuchsiaArm64: Uint8(), - Abi.fuchsiaX64: Int8(), - Abi.fuchsiaRiscv64: Uint8(), - Abi.iosArm: Int8(), - Abi.iosArm64: Int8(), - Abi.iosX64: Int8(), - Abi.linuxArm: Uint8(), - Abi.linuxArm64: Uint8(), - Abi.linuxIA32: Int8(), - Abi.linuxX64: Int8(), - Abi.linuxRiscv32: Uint8(), - Abi.linuxRiscv64: Uint8(), - Abi.macosArm64: Int8(), - Abi.macosX64: Int8(), - Abi.windowsArm64: Int8(), - Abi.windowsIA32: Int8(), - Abi.windowsX64: Int8(), -}) -final class FooChar extends AbiSpecificInteger { - const FooChar(); -} - -class Compatibility { - final _foo = FooChar(); -} - -Future withVoidCallback( - Function(Pointer>) func) async { - JSArray retVal = createVoidCallback(); - var promise = retVal.toDart[0] as JSPromise; - var fnPtrAddress = retVal.toDart[1] as JSNumber; - var fnPtr = Pointer>.fromAddress( - fnPtrAddress.toDartInt); - func(fnPtr); - await promise.toDart; -} - -Future withVoidPointerCallback( - void Function(Pointer)>>) - func) async { - JSArray retVal = createVoidPointerCallback(); - var promise = retVal.toDart[0] as JSPromise; - - var fnPtrAddress = retVal.toDart[1] as JSNumber; - var fnPtr = Pointer)>>.fromAddress( - fnPtrAddress.toDartInt); - func(fnPtr); - final addr = await promise.toDart; - return addr.toDartInt; -} - -Future withBoolCallback( - Function(Pointer>) func) async { - JSArray retVal = createBoolCallback(); - var promise = retVal.toDart[0] as JSPromise; - - var fnPtrAddress = retVal.toDart[1] as JSNumber; - var fnPtr = Pointer>.fromAddress( - fnPtrAddress.toDartInt); - func(fnPtr); - final addr = await promise.toDart; - return addr.toDart; -} - -Future withIntCallback( - Function(Pointer>) func) async { - JSArray retVal = createBoolCallback(); - var promise = retVal.toDart[0] as JSPromise; - - var fnPtrAddress = retVal.toDart[1] as JSNumber; - var fnPtr = Pointer>.fromAddress( - fnPtrAddress.toDartInt); - func(fnPtr); - final addr = await promise.toDart; - return addr.toDartInt; -} - -Future withCharPtrCallback( - Function(Pointer)>>) - func) async { - JSArray retVal = createVoidPointerCallback(); - var promise = retVal.toDart[0] as JSPromise; - - var fnPtrAddress = retVal.toDart[1] as JSNumber; - var fnPtr = Pointer)>>.fromAddress( - fnPtrAddress.toDartInt); - func(fnPtr); - final addr = await promise.toDart; - return Pointer.fromAddress(addr.toDartInt).toDartString(); -} diff --git a/thermion_dart/lib/thermion_dart/compatibility/web/interop/shims/thermion_dart_api_js_shim.dart b/thermion_dart/lib/thermion_dart/compatibility/web/interop/shims/thermion_dart_api_js_shim.dart deleted file mode 100644 index dab1daed..00000000 --- a/thermion_dart/lib/thermion_dart/compatibility/web/interop/shims/thermion_dart_api_js_shim.dart +++ /dev/null @@ -1,403 +0,0 @@ -@JS() -library thermion_flutter_js; - -import 'dart:js_interop'; - -import 'package:thermion_dart/thermion_dart/thermion_viewer.dart'; - -/// -/// An extension type on [JSObject] that represents a -/// Javascript shim implementation for the [ThermionViewer] interface. -/// -extension type ThermionDartAPIJSShim(JSObject _) implements JSObject { - - @JS('wasm_test') - external JSPromise wasm_test(String str); - - @JS('set_rendering') - external JSPromise set_rendering(bool render); - - @JS('render') - external JSPromise render(); - - @JS('setFrameRate') - external JSPromise setFrameRate(int framerate); - - @JS('setBackgroundImage') - external JSPromise setBackgroundImage(String path, bool fillHeight); - - @JS('setBackgroundImagePosition') - external JSPromise setBackgroundImagePosition(double x, double y, bool clamp); - - @JS('clearBackgroundImage') - external JSPromise clearBackgroundImage(); - - @JS('setBackgroundColor') - external JSPromise setBackgroundColor( - double r, double g, double b, double alpha); - - @JS('loadSkybox') - external JSPromise loadSkybox(String skyboxPath); - - @JS('removeSkybox') - external JSPromise removeSkybox(); - - @JS('loadIbl') - external JSPromise loadIbl(String lightingPath, double intensity); - - @JS('rotateIbl') - external JSPromise rotateIbl(JSArray rotationMatrix); - - @JS('removeIbl') - external JSPromise removeIbl(); - - @JS('addLight') - external JSPromise addLight( - int type, - double colour, - double intensity, - double posX, - double posY, - double posZ, - double dirX, - double dirY, - double dirZ, - double falloffRadius, - double spotLightConeInner, - double spotLightConeOuter, - double sunAngularRadius, - double sunHaloSize, - double sunHaloFallof, - bool castShadows); - - @JS('removeLight') - external JSPromise removeLight(ThermionEntity light); - - @JS('clearLights') - external JSPromise clearLights(); - - @JS('loadGlb') - external JSPromise loadGlb(String path, int numInstances); - - @JS('createInstance') - external JSPromise createInstance(ThermionEntity entity); - - @JS('getInstanceCount') - external JSPromise getInstanceCount(ThermionEntity entity); - - @JS('getInstances') - external JSPromise> getInstances(ThermionEntity entity); - - @JS('loadGltf') - external JSPromise loadGltf( - String path, String relativeResourcePath); - - @JS('panStart') - external JSPromise panStart(double x, double y); - - @JS('panUpdate') - external JSPromise panUpdate(double x, double y); - - @JS('panEnd') - external JSPromise panEnd(); - - @JS('rotateStart') - external JSPromise rotateStart(double x, double y); - - @JS('rotateUpdate') - external JSPromise rotateUpdate(double x, double y); - - @JS('rotateEnd') - external JSPromise rotateEnd(); - - @JS('setMorphTargetWeights') - external JSPromise setMorphTargetWeights( - ThermionEntity entity, JSArray weights); - - @JS('getMorphTargetNames') - external JSPromise> getMorphTargetNames( - ThermionEntity entity, ThermionEntity childEntity); - - @JS('getBoneNames') - external JSPromise> getBoneNames( - ThermionEntity entity, int skinIndex); - - @JS('getAnimationNames') - external JSPromise> getAnimationNames( - ThermionEntity entity); - - @JS('getAnimationDuration') - external JSPromise getAnimationDuration( - ThermionEntity entity, int animationIndex); - - @JS('setMorphAnimationData') - external JSPromise setMorphAnimationData( - ThermionEntity entity, - JSArray> animation, - JSArray morphTargets, - JSArray? targetMeshNames, - double frameLengthInMs); - - @JS('resetBones') - external JSPromise resetBones(ThermionEntity entity); - - @JS('addBoneAnimation') - external JSPromise addBoneAnimation( - ThermionEntity entity, - JSArray bones, - JSArray>> frameData, - JSNumber frameLengthInMs, - JSNumber spaceEnum, - JSNumber skinIndex, - JSNumber fadeInInSecs, - JSNumber fadeOutInSecs, - JSNumber maxDelta); - - @JS('removeEntity') - external JSPromise removeEntity(ThermionEntity entity); - - @JS('clearEntities') - external JSPromise clearEntities(); - - @JS('zoomBegin') - external JSPromise zoomBegin(); - - @JS('zoomUpdate') - external JSPromise zoomUpdate(double x, double y, double z); - - @JS('zoomEnd') - external JSPromise zoomEnd(); - - @JS('playAnimation') - external JSPromise playAnimation( - ThermionEntity entity, - int index, - bool loop, - bool reverse, - bool replaceActive, - double crossfade, - ); - - @JS('playAnimationByName') - external JSPromise playAnimationByName( - ThermionEntity entity, - String name, - bool loop, - bool reverse, - bool replaceActive, - double crossfade, - ); - - @JS('setAnimationFrame') - external JSPromise setAnimationFrame( - ThermionEntity entity, int index, int animationFrame); - - @JS('stopAnimation') - external JSPromise stopAnimation(ThermionEntity entity, int animationIndex); - - @JS('stopAnimationByName') - external JSPromise stopAnimationByName(ThermionEntity entity, String name); - - @JS('setCamera') - external JSPromise setCamera(ThermionEntity entity, String? name); - - @JS('setMainCamera') - external JSPromise setMainCamera(); - - @JS('getMainCamera') - external JSPromise getMainCamera(); - - @JS('setCameraFov') - external JSPromise setCameraFov(double degrees, double width, double height); - - @JS('setToneMapping') - external JSPromise setToneMapping(int mapper); - - @JS('setBloom') - external JSPromise setBloom(double bloom); - - @JS('setCameraFocalLength') - external JSPromise setCameraFocalLength(double focalLength); - - @JS('setCameraCulling') - external JSPromise setCameraCulling(double near, double far); - - @JS('getCameraCullingNear') - external JSPromise getCameraCullingNear(); - - @JS('getCameraCullingFar') - external JSPromise getCameraCullingFar(); - - @JS('setCameraFocusDistance') - external JSPromise setCameraFocusDistance(double focusDistance); - - @JS('getCameraPosition') - external JSPromise> getCameraPosition(); - - @JS('getCameraModelMatrix') - external JSPromise> getCameraModelMatrix(); - - @JS('getCameraViewMatrix') - external JSPromise> getCameraViewMatrix(); - - @JS('getCameraProjectionMatrix') - external JSPromise> getCameraProjectionMatrix(); - - @JS('getCameraCullingProjectionMatrix') - external JSPromise> getCameraCullingProjectionMatrix(); - - @JS('getCameraFrustum') - external JSPromise getCameraFrustum(); - - @JS('setCameraPosition') - external JSPromise setCameraPosition(double x, double y, double z); - - @JS('getCameraRotation') - external JSPromise> getCameraRotation(); - - @JS('moveCameraToAsset') - external JSPromise moveCameraToAsset(ThermionEntity entity); - - @JS('setViewFrustumCulling') - external JSPromise setViewFrustumCulling(JSBoolean enabled); - - @JS('setCameraExposure') - external JSPromise setCameraExposure( - double aperture, double shutterSpeed, double sensitivity); - - @JS('setCameraRotation') - external JSPromise setCameraRotation(JSArray quaternion); - - @JS('setCameraModelMatrix') - external JSPromise setCameraModelMatrix(JSArray matrix); - - @JS('setMaterialColor') - external JSPromise setMaterialColor(ThermionEntity entity, String meshName, - int materialIndex, double r, double g, double b, double a); - - @JS('transformToUnitCube') - external JSPromise transformToUnitCube(ThermionEntity entity); - - @JS('setPosition') - external JSPromise setPosition( - ThermionEntity entity, double x, double y, double z); - - @JS('setScale') - external JSPromise setScale(ThermionEntity entity, double scale); - - @JS('setRotation') - external JSPromise setRotation( - ThermionEntity entity, double rads, double x, double y, double z); - - @JS('queuePositionUpdate') - external JSPromise queuePositionUpdate( - ThermionEntity entity, double x, double y, double z, bool relative); - - @JS('queueRotationUpdate') - external JSPromise queueRotationUpdate(ThermionEntity entity, double rads, - double x, double y, double z, bool relative); - - @JS('queueRotationUpdateQuat') - external JSPromise queueRotationUpdateQuat( - ThermionEntity entity, JSArray quat, bool relative); - - @JS('setPostProcessing') - external JSPromise setPostProcessing(bool enabled); - - @JS('setAntiAliasing') - external JSPromise setAntiAliasing(bool msaa, bool fxaa, bool taa); - - @JS('setRotationQuat') - external JSPromise setRotationQuat( - ThermionEntity entity, JSArray rotation); - - @JS('reveal') - external JSPromise reveal(ThermionEntity entity, String? meshName); - - @JS('hide') - external JSPromise hide(ThermionEntity entity, String? meshName); - - @JS('pick') - external void pick(int x, int y); - - @JS('getNameForEntity') - external String? getNameForEntity(ThermionEntity entity); - - @JS('setCameraManipulatorOptions') - external JSPromise setCameraManipulatorOptions( - int mode, - double orbitSpeedX, - double orbitSpeedY, - double zoomSpeed, - ); - - @JS('getChildEntities') - external JSPromise> getChildEntities( - ThermionEntity parent, bool renderableOnly); - - @JS('getChildEntity') - external JSPromise getChildEntity( - ThermionEntity parent, String childName); - - @JS('getChildEntityNames') - external JSPromise> getChildEntityNames( - ThermionEntity entity, bool renderableOnly); - - @JS('setRecording') - external JSPromise setRecording(JSBoolean recording); - - @JS('setRecordingOutputDirectory') - external JSPromise setRecordingOutputDirectory(String outputDirectory); - - @JS('addAnimationComponent') - external JSPromise addAnimationComponent(ThermionEntity entity); - - @JS('removeAnimationComponent') - external JSPromise removeAnimationComponent(ThermionEntity entity); - - @JS('addCollisionComponent') - external JSPromise addCollisionComponent(ThermionEntity entity); - - @JS('removeCollisionComponent') - external JSPromise removeCollisionComponent(ThermionEntity entity); - - @JS('createGeometry') - external JSPromise createGeometry(JSArray vertices, - JSArray indices, String? materialPath, int primitiveType); - - @JS('setParent') - external JSPromise setParent(ThermionEntity child, ThermionEntity parent); - - @JS('getParent') - external JSPromise getParent(ThermionEntity child); - - @JS('getParent') - external JSPromise getBone( - ThermionEntity child, int boneIndex, int skinIndex); - - @JS('testCollisions') - external JSPromise testCollisions(ThermionEntity entity); - - @JS('setPriority') - external JSPromise setPriority(ThermionEntity entityId, int priority); - - @JS('getLocalTransform') - external JSPromise> getLocalTransform( - ThermionEntity entity); - - @JS('getWorldTransform') - external JSPromise> getWorldTransform( - ThermionEntity entity); - - @JS('updateBoneMatrices') - external JSPromise updateBoneMatrices(ThermionEntity entity); - - @JS('setTransform') - external JSPromise setTransform( - ThermionEntity entity, JSArray transform); - - @JS('setBoneTransform') - external JSPromise setBoneTransform( - ThermionEntity entity, int boneIndex, JSArray transform, int skinIndex); -} - diff --git a/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_dart_bridge.dart b/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_dart_bridge.dart index d3ed6db2..85db072c 100644 --- a/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_dart_bridge.dart +++ b/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_dart_bridge.dart @@ -2,7 +2,7 @@ library thermion_flutter_js; import 'dart:js_interop'; -import 'package:thermion_dart/thermion_dart/compatibility/web/interop/shims/thermion_viewer_js_shim.dart'; +import 'package:thermion_dart/thermion_dart/compatibility/web/interop/thermion_viewer_js_shim.dart'; import 'package:vector_math/vector_math_64.dart' as v64; import 'package:animation_tools_dart/animation_tools_dart.dart'; @@ -15,8 +15,8 @@ import 'package:vector_math/vector_math_64.dart'; /// A (Dart) class that wraps a (Dart) instance of [ThermionViewer], /// but exported to JS by binding to a global property. /// This is effectively an implementation of [ThermionViewerJSShim]; -/// allowing users to interact with an instance of [ThermionViewer] -/// (presumably compiled to WASM) from any Javascript context (including +/// allowing users to interact with an instance of [ThermionViewer] +/// (presumably compiled to WASM) from any Javascript context (including /// the browser console). /// @JSExport() @@ -24,9 +24,8 @@ class ThermionViewerJSDartBridge { final ThermionViewer viewer; ThermionViewerJSDartBridge(this.viewer); - - void bind( - {String globalPropertyName = "filamentViewer"}) { + + void bind({String globalPropertyName = "thermionViewer"}) { var wrapper = createJSInteropWrapper(this) as ThermionViewerJSShim; globalContext.setProperty(globalPropertyName.toJS, wrapper); @@ -131,10 +130,13 @@ class ThermionViewerJSDartBridge { @JSExport() JSPromise loadGlb(String path, {int numInstances = 1}) { + print("Loading GLB from path $path with numInstances $numInstances"); return viewer .loadGlb(path, numInstances: numInstances) .then((entity) => entity.toJS) - .toJS; + .catchError((err) { + print("Error: $err"); + }).toJS; } @JSExport() diff --git a/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_js.dart b/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_js.dart index fbd47777..ab325097 100644 --- a/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_js.dart +++ b/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_js.dart @@ -8,7 +8,7 @@ import 'package:thermion_dart/thermion_dart/thermion_viewer.dart'; import 'package:thermion_dart/thermion_dart/scene_impl.dart'; import 'package:vector_math/vector_math_64.dart'; -import 'shims/thermion_viewer_js_shim.dart'; +import 'thermion_viewer_js_shim.dart'; /// /// An [ThermionViewer] implementation that forwards calls to diff --git a/thermion_dart/lib/thermion_dart/compatibility/web/interop/shims/thermion_viewer_js_shim.dart b/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_js_shim.dart similarity index 100% rename from thermion_dart/lib/thermion_dart/compatibility/web/interop/shims/thermion_viewer_js_shim.dart rename to thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_js_shim.dart diff --git a/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_wasm.dart b/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_wasm.dart index 46d2341b..abde3ba6 100644 --- a/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_wasm.dart +++ b/thermion_dart/lib/thermion_dart/compatibility/web/interop/thermion_viewer_wasm.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:js_interop'; import 'dart:js_interop_unsafe'; import 'dart:math'; @@ -9,6 +10,8 @@ import 'package:animation_tools_dart/animation_tools_dart.dart'; import 'package:thermion_dart/thermion_dart/thermion_viewer.dart'; import 'package:vector_math/vector_math_64.dart'; +export 'thermion_viewer_dart_bridge.dart'; + extension type _EmscriptenModule(JSObject _) implements JSObject { external JSAny? ccall(String name, String returnType, JSArray argTypes, JSArray args, JSAny? opts); @@ -40,7 +43,7 @@ class ThermionViewerWasm implements ThermionViewer { bool _initialized = false; bool _rendering = false; - ThermionViewerWasm({String moduleName="thermion_dart"}) { + ThermionViewerWasm({String moduleName = "thermion_dart"}) { _module = window.getProperty<_EmscriptenModule>(moduleName.toJS); } @@ -124,7 +127,6 @@ class ThermionViewerWasm implements ThermionViewer { await callback.call(); } _onDispose.clear(); - } void _destroyViewer() { @@ -375,51 +377,6 @@ class ThermionViewerWasm implements ThermionViewer { return entityId.toDartInt; } - @override - Future clearBackgroundImage() { - // TODO: implement clearBackgroundImage - throw UnimplementedError(); - } - - @override - Future clearEntities() { - // TODO: implement clearEntities - throw UnimplementedError(); - } - - @override - Future clearLights() { - // TODO: implement clearLights - throw UnimplementedError(); - } - - @override - Future createGeometry(List vertices, List indices, - {String? materialPath, - PrimitiveType primitiveType = PrimitiveType.TRIANGLES}) { - // TODO: implement createGeometry - throw UnimplementedError(); - } - - @override - Future createInstance(ThermionEntity entity) { - // TODO: implement createInstance - throw UnimplementedError(); - } - - @override - Future getAnimationDuration( - ThermionEntity entity, int animationIndex) { - // TODO: implement getAnimationDuration - throw UnimplementedError(); - } - - @override - Future> getAnimationNames(ThermionEntity entity) { - // TODO: implement getAnimationNames - throw UnimplementedError(); - } - @override Future> getBoneNames(ThermionEntity entity, {int skinIndex = 0}) async { @@ -455,60 +412,6 @@ class ThermionViewerWasm implements ThermionViewer { return names; } - @override - Future getCameraCullingFar() { - // TODO: implement getCameraCullingFar - throw UnimplementedError(); - } - - @override - Future getCameraCullingNear() { - // TODO: implement getCameraCullingNear - throw UnimplementedError(); - } - - @override - Future getCameraCullingProjectionMatrix() { - // TODO: implement getCameraCullingProjectionMatrix - throw UnimplementedError(); - } - - @override - Future getCameraFrustum() { - // TODO: implement getCameraFrustum - throw UnimplementedError(); - } - - @override - Future getCameraModelMatrix() { - // TODO: implement getCameraModelMatrix - throw UnimplementedError(); - } - - @override - Future getCameraPosition() { - // TODO: implement getCameraPosition - throw UnimplementedError(); - } - - @override - Future getCameraProjectionMatrix() { - // TODO: implement getCameraProjectionMatrix - throw UnimplementedError(); - } - - @override - Future getCameraRotation() { - // TODO: implement getCameraRotation - throw UnimplementedError(); - } - - @override - Future getCameraViewMatrix() { - // TODO: implement getCameraViewMatrix - throw UnimplementedError(); - } - @override Future> getChildEntities( ThermionEntity parent, bool renderableOnly) async { @@ -575,31 +478,6 @@ class ThermionViewerWasm implements ThermionViewer { return names; } - @override - Future getInstanceCount(ThermionEntity entity) { - // TODO: implement getInstanceCount - throw UnimplementedError(); - } - - @override - Future> getInstances(ThermionEntity entity) { - // TODO: implement getInstances - throw UnimplementedError(); - } - - @override - Future getInverseBindMatrix(ThermionEntity parent, int boneIndex, - {int skinIndex = 0}) { - // TODO: implement getInverseBindMatrix - throw UnimplementedError(); - } - - @override - Future getLocalTransform(ThermionEntity entity) { - // TODO: implement getLocalTransform - throw UnimplementedError(); - } - @override Future getMainCamera() async { final entityId = _module.ccall( @@ -782,35 +660,6 @@ class ThermionViewerWasm implements ThermionViewer { await promise.toDart; } - @override - Future moveCameraToAsset(ThermionEntity entity) { - // TODO: implement moveCameraToAsset - throw UnimplementedError(); - } - - @override - Future panEnd() { - // TODO: implement panEnd - throw UnimplementedError(); - } - - @override - Future panStart(double x, double y) { - // TODO: implement panStart - throw UnimplementedError(); - } - - @override - Future panUpdate(double x, double y) { - // TODO: implement panUpdate - throw UnimplementedError(); - } - - @override - void pick(int x, int y) { - // TODO: implement pick - } - @override Future playAnimation(ThermionEntity entity, int index, {bool loop = false, @@ -841,75 +690,6 @@ class ThermionViewerWasm implements ThermionViewer { null); } - @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, - {bool relative = false}) { - // TODO: implement queuePositionUpdate - throw UnimplementedError(); - } - - @override - Future queueRotationUpdate( - ThermionEntity entity, double rads, double x, double y, double z, - {bool relative = false}) { - // TODO: implement queueRotationUpdate - throw UnimplementedError(); - } - - @override - Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat, - {bool relative = false}) { - // TODO: implement queueRotationUpdateQuat - throw UnimplementedError(); - } - - @override - Future removeAnimationComponent(ThermionEntity entity) { - // TODO: implement removeAnimationComponent - throw UnimplementedError(); - } - - @override - Future removeCollisionComponent(ThermionEntity entity) { - // TODO: implement removeCollisionComponent - throw UnimplementedError(); - } - - @override - Future removeEntity(ThermionEntity entity) { - // TODO: implement removeEntity - throw UnimplementedError(); - } - - @override - Future removeIbl() { - // TODO: implement removeIbl - throw UnimplementedError(); - } - - @override - Future removeLight(ThermionEntity light) { - // TODO: implement removeLight - throw UnimplementedError(); - } - - @override - Future removeSkybox() { - // TODO: implement removeSkybox - throw UnimplementedError(); - } - int _last = 0; @override @@ -935,52 +715,9 @@ class ThermionViewerWasm implements ThermionViewer { null); } - @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() { - // TODO: implement rotateEnd - throw UnimplementedError(); - } - - @override - Future rotateIbl(Matrix3 rotation) { - // TODO: implement rotateIbl - throw UnimplementedError(); - } - - @override - Future rotateStart(double x, double y) { - // TODO: implement rotateStart - throw UnimplementedError(); - } - - @override - Future rotateUpdate(double x, double y) { - // TODO: implement rotateUpdate - throw UnimplementedError(); - } - @override Scene get scene => 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) async { _module.ccall( @@ -991,85 +728,6 @@ class ThermionViewerWasm implements ThermionViewer { null); } - @override - Future setBackgroundImage(String path, {bool fillHeight = false}) { - // TODO: implement setBackgroundImage - throw UnimplementedError(); - } - - @override - Future setBackgroundImagePosition(double x, double y, {bool clamp = false}) { - // TODO: implement setBackgroundImagePosition - throw UnimplementedError(); - } - - @override - Future setBloom(double bloom) { - // TODO: implement setBloom - throw UnimplementedError(); - } - - @override - Future setBoneTransform( - ThermionEntity entity, int boneIndex, Matrix4 transform, - {int skinIndex = 0}) { - // TODO: implement setBoneTransform - throw UnimplementedError(); - } - - @override - Future setCamera(ThermionEntity entity, String? name) { - // TODO: implement setCamera - throw UnimplementedError(); - } - - @override - Future setCameraCulling(double near, double far) { - // TODO: implement setCameraCulling - throw UnimplementedError(); - } - - @override - Future setCameraExposure( - double aperture, double shutterSpeed, double sensitivity) { - // TODO: implement setCameraExposure - throw UnimplementedError(); - } - - @override - Future setCameraFocalLength(double focalLength) { - // TODO: implement setCameraFocalLength - throw UnimplementedError(); - } - - @override - Future setCameraFocusDistance(double focusDistance) { - // TODO: implement setCameraFocusDistance - throw UnimplementedError(); - } - - @override - Future setCameraFov(double degrees, double width, double height) { - // TODO: implement setCameraFov - throw UnimplementedError(); - } - - @override - Future setCameraManipulatorOptions( - {ManipulatorMode mode = ManipulatorMode.ORBIT, - double orbitSpeedX = 0.01, - double orbitSpeedY = 0.01, - double zoomSpeed = 0.01}) { - // TODO: implement setCameraManipulatorOptions - throw UnimplementedError(); - } - - @override - Future setCameraModelMatrix(List matrix) { - // TODO: implement setCameraModelMatrix - throw UnimplementedError(); - } - @override Future setCameraPosition(double x, double y, double z) async { _module.ccall( @@ -1097,80 +755,6 @@ class ThermionViewerWasm implements ThermionViewer { null); } - @override - Future setFrameRate(int framerate) { - // TODO: implement setFrameRate - throw UnimplementedError(); - } - - @override - Future setMainCamera() { - // TODO: implement setMainCamera - throw UnimplementedError(); - } - - @override - Future setMaterialColor(ThermionEntity entity, String meshName, - int materialIndex, double r, double g, double b, double a) { - // TODO: implement setMaterialColor - throw UnimplementedError(); - } - - // @override - // Future setMorphAnimationData( - // ThermionEntity entity, MorphAnimationData animation, - // {List? targetMeshNames}) async { - // final morphTargetNames = await getMorphTargetNames(entity, entity); - - // // We need to create a JS array for the morph indices and morph data - // final numFrames = animation.numFrames; - // final numMorphTargets = morphTargetNames.length; - // final numBytes = numFrames * numMorphTargets * 4; - // final floatPtr = _module._malloc(numBytes); - // final morphIndicesPtr = _module._malloc(numFrames * 4); - - // // Extract the morph data for the target morph targets - // final morphData = animation.extract(morphTargets: targetMeshNames); - - // // Create a list of morph indices based on the target morph targets - // final morphIndices = targetMeshNames != null - // ? animation._getMorphTargetIndices(targetMeshNames) - // : List.generate(morphTargetNames.length, (i) => i); - // final morphIndicesList = td.Int32List.fromList(morphIndices); - - // // Set the morph data and indices into the JS arrays - // _module.writeArrayToMemory(morphData.buffer.asUint8List(morphData.offsetInBytes).toJS, floatPtr); - // _module.writeArrayToMemory(morphIndicesList.buffer.asUint8List(morphData.offsetInBytes).toJS, morphIndicesPtr); - - // // Set the morph animation data - // _module.ccall( - // "set_morph_animation", - // "bool", - // [ - // "void*".toJS, - // "int".toJS, - // "float*".toJS, - // "int*".toJS, - // "int".toJS, - // "int".toJS, - // "float".toJS - // ].toJS, - // [ - // _sceneManager!, - // entity.toJS, - // floatPtr, - // morphIndicesPtr, - // numMorphTargets.toJS, - // numFrames.toJS, - // animation.frameLengthInMs.toJS - // ].toJS, - // null); - - // // Free the memory allocated for the JS arrays - // _module._free(floatPtr); - // _module._free(morphIndicesPtr); - // } - @override Future setMorphAnimationData( ThermionEntity entity, MorphAnimationData animation, @@ -1282,18 +866,6 @@ class ThermionViewerWasm implements ThermionViewer { } } - @override - Future setMorphTargetWeights(ThermionEntity entity, List weights) { - // TODO: implement setMorphTargetWeights - throw UnimplementedError(); - } - - @override - Future setParent(ThermionEntity child, ThermionEntity parent) { - // TODO: implement setParent - throw UnimplementedError(); - } - @override Future setPosition( ThermionEntity entity, double x, double y, double z) async { @@ -1312,30 +884,6 @@ class ThermionViewerWasm implements ThermionViewer { ["void*".toJS, "bool".toJS].toJS, [_viewer!, enabled.toJS].toJS, null); } - @override - Future setPriority(ThermionEntity entityId, int priority) { - // TODO: implement setPriority - throw UnimplementedError(); - } - - @override - Future setRecording(bool recording) { - // TODO: implement setRecording - throw UnimplementedError(); - } - - @override - Future setRecordingOutputDirectory(String outputDirectory) { - // TODO: implement setRecordingOutputDirectory - throw UnimplementedError(); - } - - @override - Future setRendering(bool render) { - // TODO: implement setRendering - throw UnimplementedError(); - } - @override Future setRotation( ThermionEntity entity, double rads, double x, double y, double z) async { @@ -1388,36 +936,873 @@ class ThermionViewerWasm implements ThermionViewer { null); } + final _onDispose = []; + + /// + /// + /// + void onDispose(Future Function() callback) { + _onDispose.add(callback); + } + @override - Future setScale(ThermionEntity entity, double scale) { - // TODO: implement setScale + Future clearBackgroundImage() async { + _module.ccall("clear_background_image", "void", ["void*".toJS].toJS, + [_viewer!].toJS, null); + } + + @override + Future clearEntities() async { + _module.ccall( + "clear_entities", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); + } + + @override + Future clearLights() async { + _module.ccall( + "clear_lights", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); + } + + @override + Future createGeometry(List vertices, List indices, + {String? materialPath, + PrimitiveType primitiveType = PrimitiveType.TRIANGLES}) async { + final verticesData = td.Float32List.fromList(vertices); + final indicesData = Uint16List.fromList(indices); + final verticesPtr = _module._malloc(verticesData.lengthInBytes); + final indicesPtr = _module._malloc(indicesData.lengthInBytes); + _module.writeArrayToMemory( + verticesData.buffer.asUint8List().toJS, verticesPtr); + _module.writeArrayToMemory( + indicesData.buffer.asUint8List().toJS, indicesPtr); + + final entityId = _module.ccall( + "create_geometry", + "int", + [ + "void*".toJS, + "float*".toJS, + "int".toJS, + "uint16_t*".toJS, + "int".toJS, + "int".toJS, + "string".toJS + ].toJS, + [ + _viewer!, + verticesPtr, + vertices.length.toJS, + indicesPtr, + indices.length.toJS, + primitiveType.index.toJS, + materialPath?.toJS ?? "".toJS, + ].toJS, + null) as JSNumber; + + _module._free(verticesPtr); + _module._free(indicesPtr); + + if (entityId.toDartInt == -1) { + throw Exception("Failed to create geometry"); + } + return entityId.toDartInt; + } + + @override + Future createInstance(ThermionEntity entity) async { + final result = _module.ccall( + "create_instance", + "int", + ["void*".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS].toJS, + null) as JSNumber; + if (result.toDartInt == -1) { + throw Exception("Failed to create instance of entity ${entity}"); + } + return result.toDartInt; + } + + @override + Future getAnimationDuration( + ThermionEntity entity, int animationIndex) async { + final result = _module.ccall( + "get_animation_duration", + "float", + ["void*".toJS, "int".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS, animationIndex.toJS].toJS, + null) as JSNumber; + return result.toDartDouble; + } + + @override + Future getAnimationCount(ThermionEntity entity) async { + final animationCount = _module.ccall( + "get_animation_count", + "int", + ["void*".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS].toJS, + null) as JSNumber; + return animationCount.toDartInt; + } + + @override + Future> getAnimationNames(ThermionEntity entity) async { + final animationCount = await getAnimationCount(entity); + final names = []; + for (int i = 0; i < animationCount; i++) { + final namePtr = _module._malloc(256) as JSNumber; + _module.ccall( + "get_animation_name", + "void", + ["void*".toJS, "int".toJS, "char*".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS, namePtr, i.toJS].toJS, + null); + names.add(_module.UTF8ToString(namePtr).toDart); + _module._free(namePtr); + } + return names; + } + + @override + Future getCameraCullingFar() async { + final result = _module.ccall("get_camera_culling_far", "double", + ["void*".toJS].toJS, [_viewer!].toJS, null) as JSNumber; + return result.toDartDouble; + } + + @override + Future getCameraCullingNear() async { + final result = _module.ccall("get_camera_culling_near", "double", + ["void*".toJS].toJS, [_viewer!].toJS, null) as JSNumber; + return result.toDartDouble; + } + + @override + Future getCameraCullingProjectionMatrix() async { + final ptr = _module._malloc(16 * 8) as JSNumber; + _module.ccall("get_camera_culling_projection_matrix", "void", + ["void*".toJS, "double*".toJS].toJS, [_viewer!, ptr].toJS, null); + final matrix = Matrix4.zero(); + for (int i = 0; i < 16; i++) { + matrix[i] = (_module.getValue((ptr.toDartInt + (i * 8)).toJS, "double") + as JSNumber) + .toDartDouble; + } + _module._free(ptr); + return matrix; + } + + @override + Future getCameraFrustum() async { + final ptr = _module._malloc(24 * 8) as JSNumber; + _module.ccall("get_camera_frustum", "void", + ["void*".toJS, "double*".toJS].toJS, [_viewer!, ptr].toJS, null); + final planes = List.generate(6, (i) { + final offset = i * 4; + return Plane() + ..setFromComponents( + (_module.getValue((ptr.toDartInt + (offset * 8)).toJS, "double") + as JSNumber) + .toDartDouble, + (_module.getValue( + (ptr.toDartInt + ((offset + 1) * 8)).toJS, "double") + as JSNumber) + .toDartDouble, + (_module.getValue( + (ptr.toDartInt + ((offset + 2) * 8)).toJS, "double") + as JSNumber) + .toDartDouble, + (_module.getValue( + (ptr.toDartInt + ((offset + 3) * 8)).toJS, "double") + as JSNumber) + .toDartDouble); + }); + _module._free(ptr); + throw UnimplementedError(); + // return Frustum()..plane0 = planes[0]..plane1 =planes[1]..plane2 =planes[2]..plane3 =planes[3], planes[4], planes[5]); + } + + @override + Future getCameraModelMatrix() async { + final ptr = _module._malloc(16 * 8) as JSNumber; + _module.ccall("get_camera_model_matrix", "void", + ["void*".toJS, "double*".toJS].toJS, [_viewer!, ptr].toJS, null); + final matrix = _matrixFromPtr(ptr); + _module._free(ptr); + return matrix; + } + + @override + Future getCameraPosition() async { + final ptr = _module._malloc(3 * 8) as JSNumber; + _module.ccall("get_camera_position", "void", + ["void*".toJS, "void*".toJS].toJS, [_viewer!, ptr].toJS, null); + final pos = Vector3( + (_module.getValue(ptr.toDartInt.toJS, "double") as JSNumber) + .toDartDouble, + (_module.getValue((ptr.toDartInt + 8).toJS, "double") as JSNumber) + .toDartDouble, + (_module.getValue((ptr.toDartInt + 16).toJS, "double") as JSNumber) + .toDartDouble); + _module._free(ptr); + return pos; + } + + @override + Future getCameraProjectionMatrix() async { + final ptr = _module._malloc(16 * 8) as JSNumber; + _module.ccall("get_camera_projection_matrix", "void", + ["void*".toJS, "double*".toJS].toJS, [_viewer!, ptr].toJS, null); + final matrix = _matrixFromPtr(ptr); + _module._free(ptr); + return matrix; + } + + @override + Future getCameraRotation() async { + final model = await getCameraModelMatrix(); + final rotation = model.getRotation(); + return rotation; + } + + @override + Future getCameraViewMatrix() async { + final ptr = _module._malloc(16 * 8) as JSNumber; + _module.ccall("get_camera_view_matrix", "void", + ["void*".toJS, "double*".toJS].toJS, [_viewer!, ptr].toJS, null); + final matrix = Matrix4.zero(); + for (int i = 0; i < 16; i++) { + matrix[i] = (_module.getValue((ptr.toDartInt + (i * 8)).toJS, "double") + as JSNumber) + .toDartDouble; + } + _module._free(ptr); + return matrix; + } + + @override + Future getInstanceCount(ThermionEntity entity) async { + final result = _module.ccall( + "get_instance_count", + "int", + ["void*".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS].toJS, + null) as JSNumber; + return result.toDartInt; + } + + @override + Future> getInstances(ThermionEntity entity) async { + final instanceCount = await getInstanceCount(entity); + final buf = _module._malloc(instanceCount * 4) as JSNumber; + _module.ccall( + "get_instances", + "void", + ["void*".toJS, "int".toJS, "int*".toJS].toJS, + [_sceneManager!, entity.toJS, buf].toJS, + null); + final instances = []; + for (int i = 0; i < instanceCount; i++) { + final instanceId = + _module.getValue((buf.toDartInt + (i * 4)).toJS, "i32") as JSNumber; + instances.add(instanceId.toDartInt); + } + _module._free(buf); + return instances; + } + + @override + Future getInverseBindMatrix(ThermionEntity parent, int boneIndex, + {int skinIndex = 0}) async { + final ptr = _module._malloc(16 * 4) as JSNumber; + _module.ccall( + "get_inverse_bind_matrix", + "void", + ["void*".toJS, "int".toJS, "int".toJS, "int".toJS, "float*".toJS].toJS, + [_sceneManager!, parent.toJS, skinIndex.toJS, boneIndex.toJS, ptr].toJS, + null); + final matrix = _matrixFromPtr(ptr); + _module._free(ptr); + return matrix; + } + + @override + Future getLocalTransform(ThermionEntity entity) async { + final ptr = _module._malloc(16 * 4) as JSNumber; + _module.ccall( + "get_local_transform", + "void", + ["void*".toJS, "int".toJS, "float*".toJS].toJS, + [_sceneManager!, entity.toJS, ptr].toJS, + null); + final matrix = _matrixFromPtr(ptr); + _module._free(ptr); + return matrix; + } + + @override + Future moveCameraToAsset(ThermionEntity entity) async { + _module.ccall("move_camera_to_asset", "void", + ["void*".toJS, "int".toJS].toJS, [_viewer!, entity.toJS].toJS, null); + } + + @override + Future panEnd() { + // TODO: implement panEnd throw UnimplementedError(); } @override - Future setToneMapping(ToneMapper mapper) { - // TODO: implement setToneMapping + Future panStart(double x, double y) { + // TODO: implement panStart throw UnimplementedError(); } @override - Future setTransform(ThermionEntity entity, Matrix4 transform) { - // TODO: implement setTransform + Future panUpdate(double x, double y) { + // TODO: implement panUpdate throw UnimplementedError(); } @override - Future setViewFrustumCulling(bool enabled) { - // TODO: implement setViewFrustumCulling + void pick(int x, int y) { + throw UnimplementedError(); + // _module.ccall("filament_pick", "void", + // ["void*".toJS, "int".toJS, "int".toJS, "void*".toJS].toJS, [ + // _viewer!, + // x.toJS, + // y.toJS, + // (entityId, x, y) {}.toJS + // ]); + } + + @override + Future playAnimationByName(ThermionEntity entity, String name, + {bool loop = false, + bool reverse = false, + bool replaceActive = true, + double crossfade = 0.0}) async { + final animationNames = await getAnimationNames(entity); + final index = animationNames.indexOf(name); + if (index == -1) { + throw Exception("Animation ${name} not found."); + } + return playAnimation(entity, index, + loop: loop, + reverse: reverse, + replaceActive: replaceActive, + crossfade: crossfade); + } + + @override + Future queuePositionUpdate( + ThermionEntity entity, double x, double y, double z, + {bool relative = false}) async { + _module.ccall( + "queue_position_update", + "void", + [ + "void*".toJS, + "int".toJS, + "float".toJS, + "float".toJS, + "float".toJS, + "bool".toJS + ].toJS, + [_sceneManager!, entity.toJS, x.toJS, y.toJS, z.toJS, relative.toJS] + .toJS, + null); + } + + @override + Future queueRotationUpdate( + ThermionEntity entity, double rads, double x, double y, double z, + {bool relative = false}) async { + _module.ccall( + "queue_rotation_update", + "void", + [ + "void*".toJS, + "int".toJS, + "float".toJS, + "float".toJS, + "float".toJS, + "float".toJS, + "bool".toJS + ].toJS, + [ + _sceneManager!, + entity.toJS, + rads.toJS, + x.toJS, + y.toJS, + z.toJS, + relative.toJS + ].toJS, + null); + } + + @override + Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat, + {bool relative = false}) async { + _module.ccall( + "queue_rotation_update", + "void", + [ + "void*".toJS, + "int".toJS, + "float".toJS, + "float".toJS, + "float".toJS, + "float".toJS, + "bool".toJS + ].toJS, + [ + _sceneManager!, + entity.toJS, + quat.radians.toJS, + quat.x.toJS, + quat.y.toJS, + quat.z.toJS, + relative.toJS + ].toJS, + null); + } + + @override + Future removeAnimationComponent(ThermionEntity entity) async { + _module.ccall( + "remove_animation_component", + "void", + ["void*".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS].toJS, + null); + } + + @override + Future removeCollisionComponent(ThermionEntity entity) async { + _module.ccall( + "remove_collision_component", + "void", + ["void*".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS].toJS, + null); + } + + @override + Future removeEntity(ThermionEntity entity) async { + _module.ccall("remove_entity", "void", ["void*".toJS, "int".toJS].toJS, + [_viewer!, entity.toJS].toJS, null); + } + + @override + Future removeIbl() async { + _module.ccall( + "remove_ibl", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); + } + + @override + Future removeLight(ThermionEntity light) async { + _module.ccall("remove_light", "void", ["void*".toJS, "int".toJS].toJS, + [_viewer!, light.toJS].toJS, null); + } + + @override + Future removeSkybox() async { + _module.ccall( + "remove_skybox", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); + } + + @override + Future resetBones(ThermionEntity entity) async { + _module.ccall("reset_to_rest_pose", "void", ["void*".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS].toJS, null); + } + + @override + Future reveal(ThermionEntity entity, String? meshName) async { + if (meshName != null) { + final result = _module.ccall( + "reveal_mesh", + "int", + ["void*".toJS, "int".toJS, "string".toJS].toJS, + [_sceneManager!, entity.toJS, meshName.toJS].toJS, + null) as JSNumber; + if (result.toDartInt == -1) { + throw Exception( + "Failed to reveal mesh ${meshName} on entity ${entity.toJS}"); + } + } else { + throw Exception( + "Cannot reveal mesh, meshName must be specified when invoking this method"); + } + } + + @override + Future rotateEnd() { + // TODO: implement rotateEnd throw UnimplementedError(); } @override - Future stopAnimation(ThermionEntity entity, int animationIndex) { - // TODO: implement stopAnimation + Future rotateIbl(Matrix3 rotation) async { + final ptr = _module._malloc(9 * 4) as JSNumber; + for (int i = 0; i < 9; i++) { + _module.setValue( + (ptr.toDartInt + (i * 4)).toJS, rotation.storage[i].toJS, "float"); + } + _module.ccall("rotate_ibl", "void", ["void*".toJS, "float*".toJS].toJS, + [_viewer!, ptr].toJS, null); + _module._free(ptr); + } + + @override + Future rotateStart(double x, double y) { + // TODO: implement rotateStart throw UnimplementedError(); } + @override + Future rotateUpdate(double x, double y) { + // TODO: implement rotateUpdate + throw UnimplementedError(); + } + + @override + Future setAnimationFrame( + ThermionEntity entity, int index, int animationFrame) async { + _module.ccall( + "set_animation_frame", + "void", + ["void*".toJS, "int".toJS, "int".toJS, "int".toJS].toJS, + [ + _sceneManager!, + entity.toJS, + index.toJS, + animationFrame.toJS, + ].toJS, + null); + } + + @override + Future setBackgroundImage(String path, {bool fillHeight = false}) async { + _module.ccall( + "set_background_image", + "void", + ["void*".toJS, "string".toJS, "bool".toJS].toJS, + [_viewer!, path.toJS, fillHeight.toJS].toJS, + null); + } + + @override + Future setBackgroundImagePosition(double x, double y, + {bool clamp = false}) async { + _module.ccall( + "set_background_image_position", + "void", + ["void*".toJS, "float".toJS, "float".toJS, "bool".toJS].toJS, + [_viewer!, x.toJS, y.toJS, clamp.toJS].toJS, + null); + } + + @override + Future setBloom(double bloom) async { + _module.ccall("set_bloom", "void", ["void*".toJS, "float".toJS].toJS, + [_viewer!, bloom.toJS].toJS, null); + } + + @override + Future setBoneTransform( + ThermionEntity entity, int boneIndex, Matrix4 transform, + {int skinIndex = 0}) async { + final ptr = _module._malloc(16 * 4) as JSNumber; + for (int i = 0; i < 16; i++) { + _module.setValue( + (ptr.toDartInt + (i * 4)).toJS, transform.storage[i].toJS, "float"); + } + final result = _module.ccall( + "set_bone_transform", + "bool", + ["void*".toJS, "int".toJS, "int".toJS, "int".toJS, "float*".toJS].toJS, + [_sceneManager!, entity.toJS, skinIndex.toJS, boneIndex.toJS, ptr].toJS, + null) as JSBoolean; + _module._free(ptr); + if (!result.toDart) { + throw Exception("Failed to set bone transform"); + } + } + + @override + Future setCamera(ThermionEntity entity, String? name) async { + final result = _module.ccall( + "set_camera", + "bool", + ["void*".toJS, "int".toJS, "string".toJS].toJS, + [_viewer!, entity.toJS, (name ?? "").toJS].toJS, + null) as JSBoolean; + if (!result.toDart) { + throw Exception("Failed to set camera to entity ${entity}"); + } + } + + @override + Future setCameraCulling(double near, double far) async { + _module.ccall( + "set_camera_culling", + "void", + ["void*".toJS, "double".toJS, "double".toJS].toJS, + [_viewer!, near.toJS, far.toJS].toJS, + null); + } + + @override + Future setCameraExposure( + double aperture, double shutterSpeed, double sensitivity) async { + _module.ccall( + "set_camera_exposure", + "void", + ["void*".toJS, "float".toJS, "float".toJS, "float".toJS].toJS, + [ + _viewer!, + aperture.toJS, + shutterSpeed.toJS, + sensitivity.toJS, + ].toJS, + null); + } + + @override + Future setCameraFocalLength(double focalLength) async { + _module.ccall( + "set_camera_focal_length", + "void", + ["void*".toJS, "float".toJS].toJS, + [_viewer!, focalLength.toJS].toJS, + null); + } + + @override + Future setCameraFocusDistance(double focusDistance) async { + _module.ccall( + "set_camera_focus_distance", + "void", + ["void*".toJS, "float".toJS].toJS, + [_viewer!, focusDistance.toJS].toJS, + null); + } + + @override + Future setCameraFov(double degrees, double width, double height) async { + _module.ccall( + "set_camera_fov", + "void", + ["void*".toJS, "float".toJS, "float".toJS].toJS, + [_viewer!, degrees.toJS, (width / height).toJS].toJS, + null); + } + + @override + Future setCameraManipulatorOptions( + {ManipulatorMode mode = ManipulatorMode.ORBIT, + double orbitSpeedX = 0.01, + double orbitSpeedY = 0.01, + double zoomSpeed = 0.01}) async { + _module.ccall( + "set_camera_manipulator_options", + "void", + ["void*".toJS, "int".toJS, "double".toJS, "double".toJS, "double".toJS] + .toJS, + [ + _viewer!, + mode.index.toJS, + orbitSpeedX.toJS, + orbitSpeedY.toJS, + zoomSpeed.toJS + ].toJS, + null); + } + + @override + Future setCameraModelMatrix(List matrix) async { + assert(matrix.length == 16, "Matrix must have 16 elements"); + final ptr = _module._malloc(16 * 8) as JSNumber; + for (int i = 0; i < 16; i++) { + _module.setValue( + (ptr.toDartInt + (i * 8)).toJS, matrix[i].toJS, "double"); + } + _module.ccall("set_camera_model_matrix", "void", + ["void*".toJS, "float*".toJS].toJS, [_viewer!, ptr].toJS, null); + _module._free(ptr); + } + + @override + Future setFrameRate(int framerate) async { + _module.ccall( + "set_frame_interval", + "void", + ["void*".toJS, "float".toJS].toJS, + [_viewer!, (1 / framerate).toJS].toJS, + null); + } + + @override + Future setMainCamera() async { + _module.ccall( + "set_main_camera", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); + } + + @override + Future setMaterialColor(ThermionEntity entity, String meshName, + int materialIndex, double r, double g, double b, double a) async { + final result = _module.ccall( + "set_material_color", + "bool", + [ + "void*".toJS, + "int".toJS, + "string".toJS, + "int".toJS, + "float".toJS, + "float".toJS, + "float".toJS, + "float".toJS + ].toJS, + [ + _sceneManager!, + entity.toJS, + meshName.toJS, + materialIndex.toJS, + r.toJS, + g.toJS, + b.toJS, + a.toJS + ].toJS, + null) as JSBoolean; + if (!result.toDart) { + throw Exception("Failed to set material color"); + } + } + + @override + Future setMorphTargetWeights( + ThermionEntity entity, List weights) async { + final numWeights = weights.length; + final ptr = _module._malloc(numWeights * 4) as JSNumber; + for (int i = 0; i < numWeights; i++) { + _module.setValue( + (ptr.toDartInt + (i * 4)).toJS, weights[i].toJS, "float"); + } + final result = _module.ccall( + "set_morph_target_weights", + "bool", + ["void*".toJS, "int".toJS, "float*".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS, ptr, numWeights.toJS].toJS, + null) as JSBoolean; + _module._free(ptr); + if (!result.toDart) { + throw Exception("Failed to set morph target weights"); + } + } + + @override + Future setParent(ThermionEntity child, ThermionEntity parent) async { + _module.ccall( + "set_parent", + "void", + ["void*".toJS, "int".toJS, "int".toJS].toJS, + [_sceneManager!, child.toJS, parent.toJS].toJS, + null); + } + + @override + Future setPriority(ThermionEntity entityId, int priority) { + // TODO: implement setPriority + throw UnimplementedError(); + } + + @override + Future setRecording(bool recording) async { + _module.ccall("set_recording", "void", ["void*".toJS, "bool".toJS].toJS, + [_viewer!, recording.toJS].toJS, null); + } + + @override + Future setRecordingOutputDirectory(String outputDirectory) async { + _module.ccall( + "set_recording_output_directory", + "void", + ["void*".toJS, "string".toJS].toJS, + [_viewer!, outputDirectory.toJS].toJS, + null); + } + + Timer? _renderLoop; + + @override + Future setRendering(bool render) async { + if (render && !_rendering) { + _rendering = true; + _renderLoop = Timer.periodic(Duration(microseconds: 16667), (_) { + this.render(); + }); + } else if (!render && _rendering) { + _rendering = false; + _renderLoop?.cancel(); + _renderLoop = null; + } + } + + @override + Future setScale(ThermionEntity entity, double scale) async { + _module.ccall( + "set_scale", + "void", + ["void*".toJS, "int".toJS, "float".toJS].toJS, + [_sceneManager!, entity.toJS, scale.toJS].toJS, + null); + } + + @override + Future setToneMapping(ToneMapper mapper) async { + _module.ccall("set_tone_mapping", "void", ["void*".toJS, "int".toJS].toJS, + [_viewer!, mapper.index.toJS].toJS, null); + } + + @override + Future setTransform(ThermionEntity entity, Matrix4 transform) async { + final ptr = _module._malloc(16 * 4) as JSNumber; + for (int i = 0; i < 16; i++) { + _module.setValue( + (ptr.toDartInt + (i * 4)).toJS, transform.storage[i].toJS, "float"); + } + final result = _module.ccall( + "set_transform", + "bool", + ["void*".toJS, "int".toJS, "float*".toJS].toJS, + [_sceneManager!, entity.toJS, ptr].toJS, + null) as JSBoolean; + _module._free(ptr); + if (!result.toDart) { + throw Exception("Failed to set transform"); + } + } + + @override + Future setViewFrustumCulling(bool enabled) async { + _module.ccall("set_view_frustum_culling", "void", + ["void*".toJS, "bool".toJS].toJS, [_viewer!, enabled.toJS].toJS, null); + } + + @override + Future stopAnimation(ThermionEntity entity, int animationIndex) async { + _module.ccall( + "stop_animation", + "void", + ["void*".toJS, "int".toJS, "int".toJS].toJS, + [_sceneManager!, entity.toJS, animationIndex.toJS].toJS, + null); + } + @override Future stopAnimationByName(ThermionEntity entity, String name) { // TODO: implement stopAnimationByName @@ -1459,13 +1844,4 @@ class ThermionViewerWasm implements ThermionViewer { // TODO: implement zoomUpdate throw UnimplementedError(); } - - final _onDispose = []; - - /// - /// - /// - void onDispose(Future Function() callback) { - _onDispose.add(callback); - } } diff --git a/thermion_dart/native/web/CMakeLists.txt b/thermion_dart/native/web/CMakeLists.txt index f9587ffe..42fdf646 100644 --- a/thermion_dart/native/web/CMakeLists.txt +++ b/thermion_dart/native/web/CMakeLists.txt @@ -49,7 +49,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY build/out) add_executable(${MODULE_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/../src/SceneManager.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/../src/ThermionViewerFFI.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../src/FilamentViewer.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../src/ThermionDartApi.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../src/ThermionDartFFIApi.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../src/StreamBufferAdapter.cpp" @@ -221,10 +221,10 @@ target_link_libraries(${MODULE_NAME} tinyexr ) -add_custom_command(TARGET ${MODULE_NAME} POST_BUILD - COMMAND dart --enable-experiment=native-assets run ffigen --config ffigen/web.yaml WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../ - COMMAND ${CMAKE_COMMAND} -DINPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/../../lib/thermion_dart/compatibility/web/thermion_dart.g.dart -DOUTPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/../../lib/thermion_dart/compatibility/web/thermion_dart.g.dart "-DTO_REPLACE=symbol: '" "-DREPLACEMENT=symbol: '_" -P ${CMAKE_CURRENT_SOURCE_DIR}/replace_in_file.cmake - # COMMAND ${CMAKE_COMMAND} -DINPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/build/build/out/thermion_dart.js -DOUTPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/build/build/out/thermion_dart.js "-DTO_REPLACE=var moduleRtn" "-DREPLACEMENT=var moduleRtn\;GLctx=moduleArg.ctx" -P ${CMAKE_CURRENT_SOURCE_DIR}/replace_in_file.cmake - VERBATIM -) +# add_custom_command(TARGET ${MODULE_NAME} POST_BUILD +# COMMAND dart --enable-experiment=native-assets run ffigen --config ffigen/web.yaml WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../ +# COMMAND ${CMAKE_COMMAND} -DINPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/../../lib/thermion_dart/compatibility/web/thermion_dart.g.dart -DOUTPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/../../lib/thermion_dart/compatibility/web/thermion_dart.g.dart "-DTO_REPLACE=symbol: '" "-DREPLACEMENT=symbol: '_" -P ${CMAKE_CURRENT_SOURCE_DIR}/replace_in_file.cmake +# # COMMAND ${CMAKE_COMMAND} -DINPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/build/build/out/thermion_dart.js -DOUTPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/build/build/out/thermion_dart.js "-DTO_REPLACE=var moduleRtn" "-DREPLACEMENT=var moduleRtn\;GLctx=moduleArg.ctx" -P ${CMAKE_CURRENT_SOURCE_DIR}/replace_in_file.cmake +# VERBATIM +# ) diff --git a/thermion_flutter/thermion_flutter/lib/thermion_flutter.dart b/thermion_flutter/thermion_flutter/lib/thermion_flutter.dart index d48d5747..efb90338 100644 --- a/thermion_flutter/thermion_flutter/lib/thermion_flutter.dart +++ b/thermion_flutter/thermion_flutter/lib/thermion_flutter.dart @@ -3,5 +3,4 @@ library thermion_flutter; export 'thermion/thermion_flutter_plugin.dart'; export 'thermion/widgets/thermion_widget.dart'; export 'thermion/widgets/camera/gestures/thermion_gesture_detector.dart'; - export 'package:thermion_dart/thermion_dart.dart'; diff --git a/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web.dart b/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web.dart index c5a20055..5cad8d52 100644 --- a/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web.dart +++ b/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web.dart @@ -1,9 +1,9 @@ +import 'package:thermion_dart/thermion_dart/compatibility/web/interop/thermion_viewer_wasm.dart'; import 'package:thermion_dart/thermion_dart/thermion_viewer.dart'; import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart'; import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; -import 'package:thermion_dart/thermion_dart/compatibility/web/interop/thermion_dart_js_extension_type.dart'; -import 'package:thermion_dart/thermion_dart/compatibility/web/interop/js_interop_filament_viewer.dart'; +import 'package:web/web.dart'; class ThermionFlutterWebPlugin extends ThermionFlutterPlatform { static void registerWith(Registrar registrar) { @@ -12,30 +12,31 @@ class ThermionFlutterWebPlugin extends ThermionFlutterPlatform { @override Future createTexture( - int width, int height, int offsetLeft, int offsetRight) async {} - - @override - Future destroyTexture(ThermionFlutterTexture texture) async {} - - @override - void dispose() { - // TODO: implement dispose + int width, int height, int offsetLeft, int offsetRight) async { + return ThermionFlutterTexture(null, null, 0, 0, null); } @override - Future initialize({String? uberArchivePath}) async { - print("Creating viewer in web plugin"); - viewer = JsInteropThermionViewerFFI("filamentViewer"); - print("Waiting for initialized"); - await viewer.initialized; - print("int complete"); + Future destroyTexture(ThermionFlutterTexture texture) async { + // noop } @override Future resizeTexture(ThermionFlutterTexture texture, - int width, int height, int offsetLeft, int offsetRight) async {} + int width, int height, int offsetLeft, int offsetRight) async { + return ThermionFlutterTexture(null, null, 0, 0, null); + } - @override - // TODO: implement viewer - late final ThermionViewer viewer; + Future createViewer({String? uberArchivePath}) async { + final canvas = document.getElementById("canvas") as HTMLCanvasElement; + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + + var width = window.innerWidth; + var height = window.innerHeight; + + var viewer = ThermionViewerWasm(); + await viewer.initialize(width, height, uberArchivePath: uberArchivePath); + return viewer; + } }