diff --git a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_dart_bridge.dart b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_dart_bridge.dart index e428e2a2..656017da 100644 --- a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_dart_bridge.dart +++ b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_dart_bridge.dart @@ -1,759 +1,759 @@ -@JS() -library thermion_flutter_js; - -import 'dart:js_interop'; -import 'package:logging/logging.dart'; -import 'package:vector_math/vector_math_64.dart' as v64; -import 'package:animation_tools_dart/animation_tools_dart.dart'; -import 'dart:js_interop_unsafe'; -import 'package:vector_math/vector_math_64.dart'; -import '../../../viewer.dart'; -import 'thermion_viewer_js_shim.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 -/// the browser console). -/// -@JSExport() -class ThermionViewerJSDartBridge { - final _logger = Logger("ThermionViewerJSDartBridge"); - final ThermionViewer viewer; - - ThermionViewerJSDartBridge(this.viewer); - - void bind({String globalPropertyName = "thermionViewer"}) { - var wrapper = createJSInteropWrapper(this) - as ThermionViewerJSShim; - globalContext.setProperty(globalPropertyName.toJS, wrapper); - } - - JSPromise get initialized { - return viewer.initialized.then((v) => v.toJS).toJS; - } - - @JSExport() - JSBoolean get rendering => viewer.rendering.toJS; - - @JSExport() - JSPromise setRendering(bool render) { - return viewer.setRendering(render).toJS; - } - - @JSExport() - JSPromise render() => viewer.render().toJS; - - @JSExport() - JSPromise capture() { - return viewer.capture().then((captured) => captured.toJS).toJS; - } - - @JSExport() - JSPromise setFrameRate(int framerate) => viewer.setFrameRate(framerate).toJS; - - @JSExport() - JSPromise dispose() => viewer.dispose().toJS; - - @JSExport() - JSPromise setBackgroundImage(String path, {bool fillHeight = false}) => - viewer.setBackgroundImage(path, fillHeight: fillHeight).toJS; - - @JSExport() - JSPromise setBackgroundImagePosition(double x, double y, - {bool clamp = false}) => - viewer.setBackgroundImagePosition(x, y, clamp: clamp).toJS; - - @JSExport() - JSPromise clearBackgroundImage() => viewer.clearBackgroundImage().toJS; - - @JSExport() - JSPromise setBackgroundColor(double r, double g, double b, double alpha) => - viewer.setBackgroundColor(r, g, b, alpha).toJS; - - @JSExport() - JSPromise loadSkybox(String skyboxPath) => viewer.loadSkybox(skyboxPath).toJS; - - @JSExport() - JSPromise removeSkybox() => viewer.removeSkybox().toJS; - - @JSExport() - JSPromise loadIbl(String lightingPath, double intensity) { - _logger.info("Loading IBL from $lightingPath with intensity $intensity"); - return viewer.loadIbl(lightingPath, intensity: intensity).toJS; - } - - @JSExport() - JSPromise rotateIbl(JSArray rotation) { - var matrix = - Matrix3.fromList(rotation.toDart.map((v) => v.toDartDouble).toList()); - return viewer.rotateIbl(matrix).toJS; - } - - @JSExport() - JSPromise removeIbl() => viewer.removeIbl().toJS; - - @JSExport() - 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) { - return viewer - .addLight(LightType.values[type], colour, intensity, posX, posY, posZ, - dirX, dirY, dirZ, - falloffRadius: falloffRadius, - spotLightConeInner: spotLightConeInner, - spotLightConeOuter: spotLightConeOuter, - sunAngularRadius: sunAngularRadius, - sunHaloSize: sunHaloSize, - sunHaloFallof: sunHaloFallof, - castShadows: castShadows) - .then((entity) => entity.toJS) - .toJS; - } - - @JSExport() - JSPromise removeLight(ThermionEntity light) => viewer.removeLight(light).toJS; - - @JSExport() - JSPromise clearLights() => viewer.clearLights().toJS; - - @JSExport() - JSPromise loadGlb(String path, {int numInstances = 1}) { - _logger.info("Loading GLB from path $path with numInstances $numInstances"); - return viewer - .loadGlb(path, numInstances: numInstances) - .then((entity) => entity.toJS) - .catchError((err) { - _logger.info("Error: $err"); - }).toJS; - } - - @JSExport() - JSPromise createInstance(ThermionEntity entity) { - return viewer.createInstance(entity).then((instance) => instance.toJS).toJS; - } - - @JSExport() - JSPromise getInstanceCount(ThermionEntity entity) => - viewer.getInstanceCount(entity).then((v) => v.toJS).toJS; - - @JSExport() - JSPromise> getInstances(ThermionEntity entity) { - return viewer - .getInstances(entity) - .then((instances) => - instances.map((instance) => instance.toJS).toList().toJS) - .toJS; - } - - @JSExport() - JSPromise loadGltf(String path, String relativeResourcePath, - {bool keepData = false}) { - return viewer - .loadGltf(path, relativeResourcePath, keepData: keepData) - .then((entity) => entity.toJS) - .toJS; - } - - @JSExport() - JSPromise panStart(double x, double y) => viewer.panStart(x, y).toJS; - - @JSExport() - JSPromise panUpdate(double x, double y) => viewer.panUpdate(x, y).toJS; - - @JSExport() - JSPromise panEnd() => viewer.panEnd().toJS; - - @JSExport() - JSPromise rotateStart(double x, double y) => viewer.rotateStart(x, y).toJS; - - @JSExport() - JSPromise rotateUpdate(double x, double y) => viewer.rotateUpdate(x, y).toJS; - - @JSExport() - JSPromise rotateEnd() => viewer.rotateEnd().toJS; - - @JSExport() - JSPromise setMorphTargetWeights( - ThermionEntity entity, JSArray weights) { - var dartWeights = weights.toDart.map((w) => w.toDartDouble).toList(); - return viewer.setMorphTargetWeights(entity, dartWeights).toJS; - } - - @JSExport() - JSPromise> getMorphTargetNames( - ThermionEntity entity, ThermionEntity childEntity) { - var morphTargetNames = viewer - .getMorphTargetNames(entity, childEntity) - .then((v) => v.map((s) => s.toJS).toList().toJS); - return morphTargetNames.toJS; - } - - @JSExport() - JSPromise> getBoneNames( - ThermionEntity entity, int skinIndex) { - return viewer - .getBoneNames(entity, skinIndex: skinIndex) - .then((v) => v.map((s) => s.toJS).toList().toJS) - .toJS; - } - - @JSExport() - JSPromise> getAnimationNames(ThermionEntity entity) => - viewer - .getAnimationNames(entity) - .then((v) => v.map((s) => s.toJS).toList().toJS) - .toJS; - - @JSExport() - JSPromise getAnimationDuration( - ThermionEntity entity, int animationIndex) => - viewer - .getAnimationDuration(entity, animationIndex) - .then((v) => v.toJS) - .toJS; - - @JSExport() - void clearMorphAnimationData(ThermionEntity entity) { - viewer.clearMorphAnimationData(entity); - } - - @JSExport() - JSPromise setMorphAnimationData( - ThermionEntity entity, - JSArray> animation, - JSArray morphTargets, - JSArray? targetMeshNames, - double frameLengthInMs) { - try { - var morphTargetsDart = morphTargets.toDart.map((m) => m.toDart).toList(); - var animationDataDart = animation.toDart - .map((x) => x.toDart.map((y) => y.toDartDouble).toList()) - .toList(); - - var morphAnimationData = MorphAnimationData( - animationDataDart, morphTargetsDart, - frameLengthInMs: frameLengthInMs); - var targetMeshNamesDart = - targetMeshNames?.toDart.map((x) => x.toDart).toList(); - if (animationDataDart.first.length != morphTargetsDart.length) { - throw Exception( - "Length mismatch between morph targets and animation data"); - } - var result = viewer - .setMorphAnimationData( - entity, - morphAnimationData, - targetMeshNames: targetMeshNamesDart, - ) - .onError((err, st) { - _logger.severe("ERROR SETTING MORPH ANIMATION DATA : $err\n$st"); - return null; - }); - return result.toJS; - } catch (err, st) { - _logger.severe(err); - _logger.severe(st); - rethrow; - } - } - - @JSExport() - JSPromise resetBones(ThermionEntity entity) => viewer.resetBones(entity).toJS; - - @JSExport() - JSPromise addBoneAnimation( - ThermionEntity entity, - JSArray bones, - JSArray>> frameData, - JSNumber frameLengthInMs, - JSNumber spaceEnum, - JSNumber skinIndex, - JSNumber fadeInInSecs, - JSNumber fadeOutInSecs, - JSNumber maxDelta) { - var frameDataDart = frameData.toDart - .map((frame) => frame.toDart - .map((v) { - var values = v.toDart; - var trans = v64.Vector3(values[0].toDartDouble, - values[1].toDartDouble, values[2].toDartDouble); - var rot = v64.Quaternion( - values[3].toDartDouble, - values[4].toDartDouble, - values[5].toDartDouble, - values[6].toDartDouble); - return (rotation: rot, translation: trans); - }) - .cast() - .toList()) - .toList(); - - var data = BoneAnimationData( - bones.toDart.map((n) => n.toDart).toList(), frameDataDart, - frameLengthInMs: frameLengthInMs.toDartDouble, - space: Space.values[spaceEnum.toDartInt]); - - return viewer - .addBoneAnimation(entity, data, - skinIndex: skinIndex.toDartInt, - fadeInInSecs: fadeInInSecs.toDartDouble, - fadeOutInSecs: fadeOutInSecs.toDartDouble) - .toJS; - } - - @JSExport() - JSPromise removeEntity(ThermionEntity entity) => - viewer.removeEntity(entity).toJS; - - @JSExport() - JSPromise clearEntities() { - return viewer.clearEntities().toJS; - } - - @JSExport() - JSPromise zoomBegin() => viewer.zoomBegin().toJS; - - @JSExport() - JSPromise zoomUpdate(double x, double y, double z) => - viewer.zoomUpdate(x, y, z).toJS; - - @JSExport() - JSPromise zoomEnd() => viewer.zoomEnd().toJS; - - @JSExport() - JSPromise playAnimation(ThermionEntity entity, int index, - {bool loop = false, - bool reverse = false, - bool replaceActive = true, - double crossfade = 0.0, - double startOffset = 0.0}) => - viewer - .playAnimation(entity, index, - loop: loop, - reverse: reverse, - replaceActive: replaceActive, - crossfade: crossfade, - startOffset: startOffset) - .toJS; - - @JSExport() - JSPromise playAnimationByName(ThermionEntity entity, String name, - {bool loop = false, - bool reverse = false, - bool replaceActive = true, - double crossfade = 0.0}) => - viewer - .playAnimationByName( - entity, - name, - loop: loop, - reverse: reverse, - replaceActive: replaceActive, - crossfade: crossfade, - ) - .toJS; - - @JSExport() - JSPromise setAnimationFrame( - ThermionEntity entity, int index, int animationFrame) => - viewer - .setAnimationFrame( - entity, - index, - animationFrame, - ) - .toJS; - - @JSExport() - JSPromise stopAnimation(ThermionEntity entity, int animationIndex) => - viewer.stopAnimation(entity, animationIndex).toJS; - - @JSExport() - JSPromise stopAnimationByName(ThermionEntity entity, String name) => - viewer.stopAnimationByName(entity, name).toJS; - - @JSExport() - JSPromise setCamera(ThermionEntity entity, String? name) => - viewer.setCamera(entity, name).toJS; - - @JSExport() - JSPromise setMainCamera() => viewer.setMainCamera().toJS; - - @JSExport() - JSPromise getMainCamera() { - throw UnimplementedError("TODO"); - // return viewer.getMainCamera().then((camera) => camera.toJS).toJS; - } - - @JSExport() - JSPromise setParent( - ThermionEntity child, ThermionEntity parent, bool preserveScaling) { - return viewer - .setParent(child, parent, preserveScaling: preserveScaling) - .toJS; - } - - @JSExport() - JSPromise setCameraFov(double degrees, bool horizontal) => - viewer.setCameraFov(degrees, horizontal: horizontal).toJS; - - @JSExport() - JSPromise setToneMapping(int mapper) => - viewer.setToneMapping(ToneMapper.values[mapper]).toJS; - - @JSExport() - JSPromise setBloom(double bloom) => viewer.setBloom(bloom).toJS; - - @JSExport() - JSPromise setCameraFocalLength(double focalLength) => - viewer.setCameraFocalLength(focalLength).toJS; - - @JSExport() - JSPromise setCameraCulling(double near, double far) => - viewer.setCameraCulling(near, far).toJS; - - @JSExport() - JSPromise getCameraCullingNear() => - viewer.getCameraCullingNear().then((v) => v.toJS).toJS; - - @JSExport() - JSPromise getCameraCullingFar() => - viewer.getCameraCullingFar().then((v) => v.toJS).toJS; - - @JSExport() - JSPromise setCameraFocusDistance(double focusDistance) => - viewer.setCameraFocusDistance(focusDistance).toJS; - - @JSExport() - JSPromise> getCameraPosition() { - throw UnimplementedError(); - // return viewer.getCameraPosition().then((position) => position.toJS).toJS; - } - - @JSExport() - JSPromise> getCameraModelMatrix() { - throw UnimplementedError(); - // return viewer.getCameraModelMatrix().then((matrix) => matrix.toJSArray()).toJS; - } - - @JSExport() - JSPromise> getCameraViewMatrix() { - throw UnimplementedError(); - // return viewer.getCameraViewMatrix().then((matrix) => matrix.toJSArray()).toJS; - } - - @JSExport() - JSPromise> getCameraProjectionMatrix() { - throw UnimplementedError(); - // return viewer.getCameraProjectionMatrix().then((matrix) => matrix.toJSArray()).toJS; - } - - @JSExport() - JSPromise> getCameraCullingProjectionMatrix() { - throw UnimplementedError(); - // return viewer.getCameraCullingProjectionMatrix().then((matrix) => matrix.toJSArray()).toJS; - } - - @JSExport() - JSPromise getCameraFrustum() { - throw UnimplementedError(); - // return viewer.getCameraFrustum().then((frustum) => frustum.toJS).toJS; - } - - @JSExport() - JSPromise setCameraPosition(double x, double y, double z) => - viewer.setCameraPosition(x, y, z).toJS; - @JSExport() - JSPromise> getCameraRotation() { - return viewer - .getCameraRotation() - .then((rotation) => rotation.storage.map((v) => v.toJS).toList().toJS) - .toJS; - } - - @JSExport() - JSPromise moveCameraToAsset(ThermionEntity entity) => - throw UnimplementedError(); -// viewer.moveCameraToAsset(entity)).toJS; - - @JSExport() - JSPromise setViewFrustumCulling(JSBoolean enabled) => - throw UnimplementedError(); -// viewer.setViewFrustumCulling(enabled).toJS; - - @JSExport() - JSPromise setCameraExposure( - double aperture, double shutterSpeed, double sensitivity) => - viewer.setCameraExposure(aperture, shutterSpeed, sensitivity).toJS; - - @JSExport() - JSPromise setCameraRotation(JSArray quaternion) { - var dartVals = quaternion.toDart; - return viewer - .setCameraRotation(v64.Quaternion( - dartVals[0].toDartDouble, - dartVals[1].toDartDouble, - dartVals[2].toDartDouble, - dartVals[3].toDartDouble)) - .toJS; - } - - @JSExport() - JSPromise setCameraModelMatrix(JSArray matrix) { - throw UnimplementedError(); - // viewer.setCameraModelMatrix(matrix).toJS; - } - - @JSExport() - JSPromise setMaterialColor(ThermionEntity entity, String meshName, - int materialIndex, double r, double g, double b, double a) => - throw UnimplementedError(); -// viewer.setMaterialColor( -// entity), -// meshName, -// materialIndex, -// r, -// g, -// b, -// a, -// ).toJS; - - @JSExport() - JSPromise transformToUnitCube(ThermionEntity entity) => - viewer.transformToUnitCube(entity).toJS; - - @JSExport() - JSPromise setPosition(ThermionEntity entity, double x, double y, double z) => - viewer.setPosition(entity, x, y, z).toJS; - @JSExport() - JSPromise setScale(ThermionEntity entity, double scale) => - viewer.setScale(entity, scale).toJS; - @JSExport() - JSPromise setRotation( - ThermionEntity entity, double rads, double x, double y, double z) => - viewer.setRotation(entity, rads, x, y, z).toJS; - @JSExport() - JSPromise queuePositionUpdate( - ThermionEntity entity, double x, double y, double z, bool relative) => - viewer - .queuePositionUpdate( - entity, - x, - y, - z, - relative: relative, - ) - .toJS; - @JSExport() - JSPromise queueRotationUpdate(ThermionEntity entity, double rads, double x, - double y, double z, bool relative) => - viewer - .queueRotationUpdate( - entity, - rads, - x, - y, - z, - relative: relative, - ) - .toJS; - @JSExport() - JSPromise queueRotationUpdateQuat( - ThermionEntity entity, JSArray quat, JSBoolean relative) => - throw UnimplementedError(); -// viewer.queueRotationUpdateQuat( -// entity, -// quat.toDartQuaternion(), -// relative: relative, -// ).toJS; - - @JSExport() - JSPromise setPostProcessing(bool enabled) => - viewer.setPostProcessing(enabled).toJS; - - @JSExport() - JSPromise setAntiAliasing(bool msaa, bool fxaa, bool taa) => - viewer.setAntiAliasing(msaa, fxaa, taa).toJS; - - @JSExport() - JSPromise setRotationQuat( - ThermionEntity entity, JSArray rotation) => - throw UnimplementedError(); - - @JSExport() - JSPromise reveal(ThermionEntity entity, String? meshName) => - viewer.reveal(entity, meshName).toJS; - - @JSExport() - JSPromise hide(ThermionEntity entity, String? meshName) => - viewer.hide(entity, meshName).toJS; - - @JSExport() - void pick(int x, int y) => viewer.pick(x, y); - - @JSExport() - String? getNameForEntity(ThermionEntity entity) => - viewer.getNameForEntity(entity); - - @JSExport() - JSPromise setCameraManipulatorOptions({ - int mode = 0, - double orbitSpeedX = 0.01, - double orbitSpeedY = 0.01, - double zoomSpeed = 0.01, - }) => - viewer - .setCameraManipulatorOptions( - mode: ManipulatorMode.values[mode], - orbitSpeedX: orbitSpeedX, - orbitSpeedY: orbitSpeedY, - zoomSpeed: zoomSpeed, - ) - .toJS; - - @JSExport() - JSPromise> getChildEntities( - ThermionEntity parent, bool renderableOnly) { - return viewer - .getChildEntities( - parent, - renderableOnly, - ) - .then((entities) => entities.map((entity) => entity.toJS).toList().toJS) - .onError((e, st) async { - _logger.severe("Error : $e\n$st"); - return [].toJS; - }).toJS; - } - - @JSExport() - JSPromise getChildEntity(ThermionEntity parent, String childName) { - return viewer - .getChildEntity( - parent, - childName, - ) - .then((entity) => entity.toJS) - .onError((e, st) async { - _logger.severe("Error getChildEntity : $e\n$st"); - return 0.toJS; - }).toJS; - } - - @JSExport() - JSPromise> getChildEntityNames( - ThermionEntity entity, bool renderableOnly) => - viewer - .getChildEntityNames( - entity, - renderableOnly: renderableOnly, - ) - .then((v) => v.map((s) => s.toJS).toList().toJS) - .toJS; - - @JSExport() - JSPromise setRecording(bool recording) => viewer.setRecording(recording).toJS; - - @JSExport() - JSPromise setRecordingOutputDirectory(String outputDirectory) => - viewer.setRecordingOutputDirectory(outputDirectory).toJS; - - @JSExport() - JSPromise addAnimationComponent(ThermionEntity entity) => - viewer.addAnimationComponent(entity).toJS; - - @JSExport() - JSPromise removeAnimationComponent(ThermionEntity entity) => - viewer.removeAnimationComponent(entity).toJS; - - @JSExport() - JSPromise getParent(ThermionEntity entity) => - viewer.removeAnimationComponent(entity).toJS; - - @JSExport() - JSPromise getBone(ThermionEntity entity, int boneIndex, int skinIndex) => - viewer.getBone(entity, boneIndex, skinIndex: skinIndex).toJS; - - @JSExport() - JSPromise> getLocalTransform(ThermionEntity entity) { - return viewer - .getLocalTransform(entity) - .then((t) => t.storage.map((v) => v.toJS).toList().toJS) - .toJS; - } - - @JSExport() - JSPromise> getWorldTransform(ThermionEntity entity) { - return viewer - .getWorldTransform(entity) - .then((t) => t.storage.map((v) => v.toJS).toList().toJS) - .toJS; - } - - @JSExport() - JSPromise setTransform(ThermionEntity entity, JSArray transform) { - return viewer - .setTransform( - entity, - Matrix4.fromList( - transform.toDart.map((v) => v.toDartDouble).toList())) - .toJS; - } - - @JSExport() - JSPromise updateBoneMatrices(ThermionEntity entity) { - return viewer.updateBoneMatrices(entity).toJS; - } - - @JSExport() - JSPromise setBoneTransform(ThermionEntity entity, int boneIndex, - JSArray transform, int skinIndex) { - return viewer - .setBoneTransform( - entity, - boneIndex, - Matrix4.fromList( - transform.toDart.map((v) => v.toDartDouble).toList()), - skinIndex: skinIndex) - .toJS; - } - - @JSExport() - JSPromise addCollisionComponent(ThermionEntity entity, - {JSFunction? callback, bool affectsTransform = false}) { - throw UnimplementedError(); - } - - @JSExport() - JSPromise setShadowsEnabled(bool enabled) { - return viewer.setShadowsEnabled(enabled).toJS; - } - - @JSExport() - JSPromise setShadowType(int shadowType) { - return viewer.setShadowType(ShadowType.values[shadowType]).toJS; - } - - @JSExport() - JSPromise setSoftShadowOptions( - double penumbraScale, double penumbraRatioScale) { - return viewer.setSoftShadowOptions(penumbraScale, penumbraRatioScale).toJS; - } -} +// @JS() +// library thermion_flutter_js; + +// import 'dart:js_interop'; +// import 'package:logging/logging.dart'; +// import 'package:vector_math/vector_math_64.dart' as v64; +// import 'package:animation_tools_dart/animation_tools_dart.dart'; +// import 'dart:js_interop_unsafe'; +// import 'package:vector_math/vector_math_64.dart'; +// import '../../../viewer.dart'; +// import 'thermion_viewer_js_shim.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 +// /// the browser console). +// /// +// @JSExport() +// class ThermionViewerJSDartBridge { +// final _logger = Logger("ThermionViewerJSDartBridge"); +// final ThermionViewer viewer; + +// ThermionViewerJSDartBridge(this.viewer); + +// void bind({String globalPropertyName = "thermionViewer"}) { +// var wrapper = createJSInteropWrapper(this) +// as ThermionViewerJSShim; +// globalContext.setProperty(globalPropertyName.toJS, wrapper); +// } + +// JSPromise get initialized { +// return viewer.initialized.then((v) => v.toJS).toJS; +// } + +// @JSExport() +// JSBoolean get rendering => viewer.rendering.toJS; + +// @JSExport() +// JSPromise setRendering(bool render) { +// return viewer.setRendering(render).toJS; +// } + +// @JSExport() +// JSPromise render() => viewer.render().toJS; + +// @JSExport() +// JSPromise capture() { +// return viewer.capture().then((captured) => captured.toJS).toJS; +// } + +// @JSExport() +// JSPromise setFrameRate(int framerate) => viewer.setFrameRate(framerate).toJS; + +// @JSExport() +// JSPromise dispose() => viewer.dispose().toJS; + +// @JSExport() +// JSPromise setBackgroundImage(String path, {bool fillHeight = false}) => +// viewer.setBackgroundImage(path, fillHeight: fillHeight).toJS; + +// @JSExport() +// JSPromise setBackgroundImagePosition(double x, double y, +// {bool clamp = false}) => +// viewer.setBackgroundImagePosition(x, y, clamp: clamp).toJS; + +// @JSExport() +// JSPromise clearBackgroundImage() => viewer.clearBackgroundImage().toJS; + +// @JSExport() +// JSPromise setBackgroundColor(double r, double g, double b, double alpha) => +// viewer.setBackgroundColor(r, g, b, alpha).toJS; + +// @JSExport() +// JSPromise loadSkybox(String skyboxPath) => viewer.loadSkybox(skyboxPath).toJS; + +// @JSExport() +// JSPromise removeSkybox() => viewer.removeSkybox().toJS; + +// @JSExport() +// JSPromise loadIbl(String lightingPath, double intensity) { +// _logger.info("Loading IBL from $lightingPath with intensity $intensity"); +// return viewer.loadIbl(lightingPath, intensity: intensity).toJS; +// } + +// @JSExport() +// JSPromise rotateIbl(JSArray rotation) { +// var matrix = +// Matrix3.fromList(rotation.toDart.map((v) => v.toDartDouble).toList()); +// return viewer.rotateIbl(matrix).toJS; +// } + +// @JSExport() +// JSPromise removeIbl() => viewer.removeIbl().toJS; + +// @JSExport() +// 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) { +// return viewer +// .addLight(LightType.values[type], colour, intensity, posX, posY, posZ, +// dirX, dirY, dirZ, +// falloffRadius: falloffRadius, +// spotLightConeInner: spotLightConeInner, +// spotLightConeOuter: spotLightConeOuter, +// sunAngularRadius: sunAngularRadius, +// sunHaloSize: sunHaloSize, +// sunHaloFallof: sunHaloFallof, +// castShadows: castShadows) +// .then((entity) => entity.toJS) +// .toJS; +// } + +// @JSExport() +// JSPromise removeLight(ThermionEntity light) => viewer.removeLight(light).toJS; + +// @JSExport() +// JSPromise clearLights() => viewer.clearLights().toJS; + +// @JSExport() +// JSPromise loadGlb(String path, {int numInstances = 1}) { +// _logger.info("Loading GLB from path $path with numInstances $numInstances"); +// return viewer +// .loadGlb(path, numInstances: numInstances) +// .then((entity) => entity.toJS) +// .catchError((err) { +// _logger.info("Error: $err"); +// }).toJS; +// } + +// @JSExport() +// JSPromise createInstance(ThermionEntity entity) { +// return viewer.createInstance(entity).then((instance) => instance.toJS).toJS; +// } + +// @JSExport() +// JSPromise getInstanceCount(ThermionEntity entity) => +// viewer.getInstanceCount(entity).then((v) => v.toJS).toJS; + +// @JSExport() +// JSPromise> getInstances(ThermionEntity entity) { +// return viewer +// .getInstances(entity) +// .then((instances) => +// instances.map((instance) => instance.toJS).toList().toJS) +// .toJS; +// } + +// @JSExport() +// JSPromise loadGltf(String path, String relativeResourcePath, +// {bool keepData = false}) { +// return viewer +// .loadGltf(path, relativeResourcePath, keepData: keepData) +// .then((entity) => entity.toJS) +// .toJS; +// } + +// @JSExport() +// JSPromise panStart(double x, double y) => viewer.panStart(x, y).toJS; + +// @JSExport() +// JSPromise panUpdate(double x, double y) => viewer.panUpdate(x, y).toJS; + +// @JSExport() +// JSPromise panEnd() => viewer.panEnd().toJS; + +// @JSExport() +// JSPromise rotateStart(double x, double y) => viewer.rotateStart(x, y).toJS; + +// @JSExport() +// JSPromise rotateUpdate(double x, double y) => viewer.rotateUpdate(x, y).toJS; + +// @JSExport() +// JSPromise rotateEnd() => viewer.rotateEnd().toJS; + +// @JSExport() +// JSPromise setMorphTargetWeights( +// ThermionEntity entity, JSArray weights) { +// var dartWeights = weights.toDart.map((w) => w.toDartDouble).toList(); +// return viewer.setMorphTargetWeights(entity, dartWeights).toJS; +// } + +// @JSExport() +// JSPromise> getMorphTargetNames( +// ThermionEntity entity, ThermionEntity childEntity) { +// var morphTargetNames = viewer +// .getMorphTargetNames(entity, childEntity) +// .then((v) => v.map((s) => s.toJS).toList().toJS); +// return morphTargetNames.toJS; +// } + +// @JSExport() +// JSPromise> getBoneNames( +// ThermionEntity entity, int skinIndex) { +// return viewer +// .getBoneNames(entity, skinIndex: skinIndex) +// .then((v) => v.map((s) => s.toJS).toList().toJS) +// .toJS; +// } + +// @JSExport() +// JSPromise> getAnimationNames(ThermionEntity entity) => +// viewer +// .getAnimationNames(entity) +// .then((v) => v.map((s) => s.toJS).toList().toJS) +// .toJS; + +// @JSExport() +// JSPromise getAnimationDuration( +// ThermionEntity entity, int animationIndex) => +// viewer +// .getAnimationDuration(entity, animationIndex) +// .then((v) => v.toJS) +// .toJS; + +// @JSExport() +// void clearMorphAnimationData(ThermionEntity entity) { +// viewer.clearMorphAnimationData(entity); +// } + +// @JSExport() +// JSPromise setMorphAnimationData( +// ThermionEntity entity, +// JSArray> animation, +// JSArray morphTargets, +// JSArray? targetMeshNames, +// double frameLengthInMs) { +// try { +// var morphTargetsDart = morphTargets.toDart.map((m) => m.toDart).toList(); +// var animationDataDart = animation.toDart +// .map((x) => x.toDart.map((y) => y.toDartDouble).toList()) +// .toList(); + +// var morphAnimationData = MorphAnimationData( +// animationDataDart, morphTargetsDart, +// frameLengthInMs: frameLengthInMs); +// var targetMeshNamesDart = +// targetMeshNames?.toDart.map((x) => x.toDart).toList(); +// if (animationDataDart.first.length != morphTargetsDart.length) { +// throw Exception( +// "Length mismatch between morph targets and animation data"); +// } +// var result = viewer +// .setMorphAnimationData( +// entity, +// morphAnimationData, +// targetMeshNames: targetMeshNamesDart, +// ) +// .onError((err, st) { +// _logger.severe("ERROR SETTING MORPH ANIMATION DATA : $err\n$st"); +// return null; +// }); +// return result.toJS; +// } catch (err, st) { +// _logger.severe(err); +// _logger.severe(st); +// rethrow; +// } +// } + +// @JSExport() +// JSPromise resetBones(ThermionEntity entity) => viewer.resetBones(entity).toJS; + +// @JSExport() +// JSPromise addBoneAnimation( +// ThermionEntity entity, +// JSArray bones, +// JSArray>> frameData, +// JSNumber frameLengthInMs, +// JSNumber spaceEnum, +// JSNumber skinIndex, +// JSNumber fadeInInSecs, +// JSNumber fadeOutInSecs, +// JSNumber maxDelta) { +// var frameDataDart = frameData.toDart +// .map((frame) => frame.toDart +// .map((v) { +// var values = v.toDart; +// var trans = v64.Vector3(values[0].toDartDouble, +// values[1].toDartDouble, values[2].toDartDouble); +// var rot = v64.Quaternion( +// values[3].toDartDouble, +// values[4].toDartDouble, +// values[5].toDartDouble, +// values[6].toDartDouble); +// return (rotation: rot, translation: trans); +// }) +// .cast() +// .toList()) +// .toList(); + +// var data = BoneAnimationData( +// bones.toDart.map((n) => n.toDart).toList(), frameDataDart, +// frameLengthInMs: frameLengthInMs.toDartDouble, +// space: Space.values[spaceEnum.toDartInt]); + +// return viewer +// .addBoneAnimation(entity, data, +// skinIndex: skinIndex.toDartInt, +// fadeInInSecs: fadeInInSecs.toDartDouble, +// fadeOutInSecs: fadeOutInSecs.toDartDouble) +// .toJS; +// } + +// @JSExport() +// JSPromise removeEntity(ThermionEntity entity) => +// viewer.removeEntity(entity).toJS; + +// @JSExport() +// JSPromise clearEntities() { +// return viewer.clearEntities().toJS; +// } + +// @JSExport() +// JSPromise zoomBegin() => viewer.zoomBegin().toJS; + +// @JSExport() +// JSPromise zoomUpdate(double x, double y, double z) => +// viewer.zoomUpdate(x, y, z).toJS; + +// @JSExport() +// JSPromise zoomEnd() => viewer.zoomEnd().toJS; + +// @JSExport() +// JSPromise playAnimation(ThermionEntity entity, int index, +// {bool loop = false, +// bool reverse = false, +// bool replaceActive = true, +// double crossfade = 0.0, +// double startOffset = 0.0}) => +// viewer +// .playAnimation(entity, index, +// loop: loop, +// reverse: reverse, +// replaceActive: replaceActive, +// crossfade: crossfade, +// startOffset: startOffset) +// .toJS; + +// @JSExport() +// JSPromise playAnimationByName(ThermionEntity entity, String name, +// {bool loop = false, +// bool reverse = false, +// bool replaceActive = true, +// double crossfade = 0.0}) => +// viewer +// .playAnimationByName( +// entity, +// name, +// loop: loop, +// reverse: reverse, +// replaceActive: replaceActive, +// crossfade: crossfade, +// ) +// .toJS; + +// @JSExport() +// JSPromise setAnimationFrame( +// ThermionEntity entity, int index, int animationFrame) => +// viewer +// .setAnimationFrame( +// entity, +// index, +// animationFrame, +// ) +// .toJS; + +// @JSExport() +// JSPromise stopAnimation(ThermionEntity entity, int animationIndex) => +// viewer.stopAnimation(entity, animationIndex).toJS; + +// @JSExport() +// JSPromise stopAnimationByName(ThermionEntity entity, String name) => +// viewer.stopAnimationByName(entity, name).toJS; + +// @JSExport() +// JSPromise setCamera(ThermionEntity entity, String? name) => +// viewer.setCamera(entity, name).toJS; + +// @JSExport() +// JSPromise setMainCamera() => viewer.setMainCamera().toJS; + +// @JSExport() +// JSPromise getMainCamera() { +// throw UnimplementedError("TODO"); +// // return viewer.getMainCamera().then((camera) => camera.toJS).toJS; +// } + +// @JSExport() +// JSPromise setParent( +// ThermionEntity child, ThermionEntity parent, bool preserveScaling) { +// return viewer +// .setParent(child, parent, preserveScaling: preserveScaling) +// .toJS; +// } + +// @JSExport() +// JSPromise setCameraFov(double degrees, bool horizontal) => +// viewer.setCameraFov(degrees, horizontal: horizontal).toJS; + +// @JSExport() +// JSPromise setToneMapping(int mapper) => +// viewer.setToneMapping(ToneMapper.values[mapper]).toJS; + +// @JSExport() +// JSPromise setBloom(double bloom) => viewer.setBloom(bloom).toJS; + +// @JSExport() +// JSPromise setCameraFocalLength(double focalLength) => +// viewer.setCameraFocalLength(focalLength).toJS; + +// @JSExport() +// JSPromise setCameraCulling(double near, double far) => +// viewer.setCameraCulling(near, far).toJS; + +// @JSExport() +// JSPromise getCameraCullingNear() => +// viewer.getCameraCullingNear().then((v) => v.toJS).toJS; + +// @JSExport() +// JSPromise getCameraCullingFar() => +// viewer.getCameraCullingFar().then((v) => v.toJS).toJS; + +// @JSExport() +// JSPromise setCameraFocusDistance(double focusDistance) => +// viewer.setCameraFocusDistance(focusDistance).toJS; + +// @JSExport() +// JSPromise> getCameraPosition() { +// throw UnimplementedError(); +// // return viewer.getCameraPosition().then((position) => position.toJS).toJS; +// } + +// @JSExport() +// JSPromise> getCameraModelMatrix() { +// throw UnimplementedError(); +// // return viewer.getCameraModelMatrix().then((matrix) => matrix.toJSArray()).toJS; +// } + +// @JSExport() +// JSPromise> getCameraViewMatrix() { +// throw UnimplementedError(); +// // return viewer.getCameraViewMatrix().then((matrix) => matrix.toJSArray()).toJS; +// } + +// @JSExport() +// JSPromise> getCameraProjectionMatrix() { +// throw UnimplementedError(); +// // return viewer.getCameraProjectionMatrix().then((matrix) => matrix.toJSArray()).toJS; +// } + +// @JSExport() +// JSPromise> getCameraCullingProjectionMatrix() { +// throw UnimplementedError(); +// // return viewer.getCameraCullingProjectionMatrix().then((matrix) => matrix.toJSArray()).toJS; +// } + +// @JSExport() +// JSPromise getCameraFrustum() { +// throw UnimplementedError(); +// // return viewer.getCameraFrustum().then((frustum) => frustum.toJS).toJS; +// } + +// @JSExport() +// JSPromise setCameraPosition(double x, double y, double z) => +// viewer.setCameraPosition(x, y, z).toJS; +// @JSExport() +// JSPromise> getCameraRotation() { +// return viewer +// .getCameraRotation() +// .then((rotation) => rotation.storage.map((v) => v.toJS).toList().toJS) +// .toJS; +// } + +// @JSExport() +// JSPromise moveCameraToAsset(ThermionEntity entity) => +// throw UnimplementedError(); +// // viewer.moveCameraToAsset(entity)).toJS; + +// @JSExport() +// JSPromise setViewFrustumCulling(JSBoolean enabled) => +// throw UnimplementedError(); +// // viewer.setViewFrustumCulling(enabled).toJS; + +// @JSExport() +// JSPromise setCameraExposure( +// double aperture, double shutterSpeed, double sensitivity) => +// viewer.setCameraExposure(aperture, shutterSpeed, sensitivity).toJS; + +// @JSExport() +// JSPromise setCameraRotation(JSArray quaternion) { +// var dartVals = quaternion.toDart; +// return viewer +// .setCameraRotation(v64.Quaternion( +// dartVals[0].toDartDouble, +// dartVals[1].toDartDouble, +// dartVals[2].toDartDouble, +// dartVals[3].toDartDouble)) +// .toJS; +// } + +// @JSExport() +// JSPromise setCameraModelMatrix(JSArray matrix) { +// throw UnimplementedError(); +// // viewer.setCameraModelMatrix(matrix).toJS; +// } + +// @JSExport() +// JSPromise setMaterialColor(ThermionEntity entity, String meshName, +// int materialIndex, double r, double g, double b, double a) => +// throw UnimplementedError(); +// // viewer.setMaterialColor( +// // entity), +// // meshName, +// // materialIndex, +// // r, +// // g, +// // b, +// // a, +// // ).toJS; + +// @JSExport() +// JSPromise transformToUnitCube(ThermionEntity entity) => +// viewer.transformToUnitCube(entity).toJS; + +// @JSExport() +// JSPromise setPosition(ThermionEntity entity, double x, double y, double z) => +// viewer.setPosition(entity, x, y, z).toJS; +// @JSExport() +// JSPromise setScale(ThermionEntity entity, double scale) => +// viewer.setScale(entity, scale).toJS; +// @JSExport() +// JSPromise setRotation( +// ThermionEntity entity, double rads, double x, double y, double z) => +// viewer.setRotation(entity, rads, x, y, z).toJS; +// @JSExport() +// JSPromise queuePositionUpdate( +// ThermionEntity entity, double x, double y, double z, bool relative) => +// viewer +// .queuePositionUpdate( +// entity, +// x, +// y, +// z, +// relative: relative, +// ) +// .toJS; +// @JSExport() +// JSPromise queueRotationUpdate(ThermionEntity entity, double rads, double x, +// double y, double z, bool relative) => +// viewer +// .queueRotationUpdate( +// entity, +// rads, +// x, +// y, +// z, +// relative: relative, +// ) +// .toJS; +// @JSExport() +// JSPromise queueRotationUpdateQuat( +// ThermionEntity entity, JSArray quat, JSBoolean relative) => +// throw UnimplementedError(); +// // viewer.queueRotationUpdateQuat( +// // entity, +// // quat.toDartQuaternion(), +// // relative: relative, +// // ).toJS; + +// @JSExport() +// JSPromise setPostProcessing(bool enabled) => +// viewer.setPostProcessing(enabled).toJS; + +// @JSExport() +// JSPromise setAntiAliasing(bool msaa, bool fxaa, bool taa) => +// viewer.setAntiAliasing(msaa, fxaa, taa).toJS; + +// @JSExport() +// JSPromise setRotationQuat( +// ThermionEntity entity, JSArray rotation) => +// throw UnimplementedError(); + +// @JSExport() +// JSPromise reveal(ThermionEntity entity, String? meshName) => +// viewer.reveal(entity, meshName).toJS; + +// @JSExport() +// JSPromise hide(ThermionEntity entity, String? meshName) => +// viewer.hide(entity, meshName).toJS; + +// @JSExport() +// void pick(int x, int y) => viewer.pick(x, y); + +// @JSExport() +// String? getNameForEntity(ThermionEntity entity) => +// viewer.getNameForEntity(entity); + +// @JSExport() +// JSPromise setCameraManipulatorOptions({ +// int mode = 0, +// double orbitSpeedX = 0.01, +// double orbitSpeedY = 0.01, +// double zoomSpeed = 0.01, +// }) => +// viewer +// .setCameraManipulatorOptions( +// mode: ManipulatorMode.values[mode], +// orbitSpeedX: orbitSpeedX, +// orbitSpeedY: orbitSpeedY, +// zoomSpeed: zoomSpeed, +// ) +// .toJS; + +// @JSExport() +// JSPromise> getChildEntities( +// ThermionEntity parent, bool renderableOnly) { +// return viewer +// .getChildEntities( +// parent, +// renderableOnly, +// ) +// .then((entities) => entities.map((entity) => entity.toJS).toList().toJS) +// .onError((e, st) async { +// _logger.severe("Error : $e\n$st"); +// return [].toJS; +// }).toJS; +// } + +// @JSExport() +// JSPromise getChildEntity(ThermionEntity parent, String childName) { +// return viewer +// .getChildEntity( +// parent, +// childName, +// ) +// .then((entity) => entity.toJS) +// .onError((e, st) async { +// _logger.severe("Error getChildEntity : $e\n$st"); +// return 0.toJS; +// }).toJS; +// } + +// @JSExport() +// JSPromise> getChildEntityNames( +// ThermionEntity entity, bool renderableOnly) => +// viewer +// .getChildEntityNames( +// entity, +// renderableOnly: renderableOnly, +// ) +// .then((v) => v.map((s) => s.toJS).toList().toJS) +// .toJS; + +// @JSExport() +// JSPromise setRecording(bool recording) => viewer.setRecording(recording).toJS; + +// @JSExport() +// JSPromise setRecordingOutputDirectory(String outputDirectory) => +// viewer.setRecordingOutputDirectory(outputDirectory).toJS; + +// @JSExport() +// JSPromise addAnimationComponent(ThermionEntity entity) => +// viewer.addAnimationComponent(entity).toJS; + +// @JSExport() +// JSPromise removeAnimationComponent(ThermionEntity entity) => +// viewer.removeAnimationComponent(entity).toJS; + +// @JSExport() +// JSPromise getParent(ThermionEntity entity) => +// viewer.removeAnimationComponent(entity).toJS; + +// @JSExport() +// JSPromise getBone(ThermionEntity entity, int boneIndex, int skinIndex) => +// viewer.getBone(entity, boneIndex, skinIndex: skinIndex).toJS; + +// @JSExport() +// JSPromise> getLocalTransform(ThermionEntity entity) { +// return viewer +// .getLocalTransform(entity) +// .then((t) => t.storage.map((v) => v.toJS).toList().toJS) +// .toJS; +// } + +// @JSExport() +// JSPromise> getWorldTransform(ThermionEntity entity) { +// return viewer +// .getWorldTransform(entity) +// .then((t) => t.storage.map((v) => v.toJS).toList().toJS) +// .toJS; +// } + +// @JSExport() +// JSPromise setTransform(ThermionEntity entity, JSArray transform) { +// return viewer +// .setTransform( +// entity, +// Matrix4.fromList( +// transform.toDart.map((v) => v.toDartDouble).toList())) +// .toJS; +// } + +// @JSExport() +// JSPromise updateBoneMatrices(ThermionEntity entity) { +// return viewer.updateBoneMatrices(entity).toJS; +// } + +// @JSExport() +// JSPromise setBoneTransform(ThermionEntity entity, int boneIndex, +// JSArray transform, int skinIndex) { +// return viewer +// .setBoneTransform( +// entity, +// boneIndex, +// Matrix4.fromList( +// transform.toDart.map((v) => v.toDartDouble).toList()), +// skinIndex: skinIndex) +// .toJS; +// } + +// @JSExport() +// JSPromise addCollisionComponent(ThermionEntity entity, +// {JSFunction? callback, bool affectsTransform = false}) { +// throw UnimplementedError(); +// } + +// @JSExport() +// JSPromise setShadowsEnabled(bool enabled) { +// return viewer.setShadowsEnabled(enabled).toJS; +// } + +// @JSExport() +// JSPromise setShadowType(int shadowType) { +// return viewer.setShadowType(ShadowType.values[shadowType]).toJS; +// } + +// @JSExport() +// JSPromise setSoftShadowOptions( +// double penumbraScale, double penumbraRatioScale) { +// return viewer.setSoftShadowOptions(penumbraScale, penumbraRatioScale).toJS; +// } +// } diff --git a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js.dart b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js.dart index 68295449..48357131 100644 --- a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js.dart +++ b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js.dart @@ -1,1107 +1,1107 @@ -import 'dart:js_interop'; -import 'dart:js_interop_unsafe'; -import 'dart:math'; -import 'dart:typed_data'; - -import 'package:animation_tools_dart/animation_tools_dart.dart'; -import 'package:logging/logging.dart'; -import 'package:vector_math/vector_math_64.dart'; -import '../../shared_types/internal/gizmo.dart'; -import '../../../viewer.dart'; -import '../../events.dart'; -import '../../shared_types/camera.dart'; -import 'thermion_viewer_js_shim.dart'; - -/// -/// An [ThermionViewer] implementation that forwards calls to -/// a corresponding Javascript shim implementation (see [ThermionViewerJSShim]). -/// -class ThermionViewerJS implements ThermionViewer { - final _logger = Logger("ThermionViewerJS"); - late final ThermionViewerJSShim _shim; - - ThermionViewerJS.fromGlobalProperty(String globalPropertyName) { - this._shim = globalContext.getProperty(globalPropertyName.toJS) - as ThermionViewerJSShim; - } - - ThermionViewerJS(this._shim); - - @override - Future get initialized async { - var inited = _shim.initialized; - final JSBoolean result = await inited.toDart; - return result.toDart; - } - - @override - Stream get pickResult { - throw UnimplementedError(); - } - - @override - bool get rendering => _shim.rendering; - - @override - Future setRendering(bool render) async { - await _shim.setRendering(render).toDart; - } - - @override - Future render() async { - await _shim.render().toDart; - } - - @override - Future setFrameRate(int framerate) async { - await _shim.setFrameRate(framerate).toDart; - } - - @override - Future dispose() async { - await _shim.dispose().toDart; - for (final callback in _onDispose) { - callback.call(); - } - } - - @override - Future setBackgroundImage(String path, - {bool fillHeight = false}) async { - await _shim.setBackgroundImage(path, fillHeight).toDart; - } - - @override - Future setBackgroundImagePosition(double x, double y, - {bool clamp = false}) async { - await _shim.setBackgroundImagePosition(x, y, clamp).toDart; - } - - @override - Future clearBackgroundImage() async { - await _shim.clearBackgroundImage().toDart; - } - - @override - Future setBackgroundColor( - double r, double g, double b, double alpha) async { - await _shim.setBackgroundColor(r, g, b, alpha).toDart; - } - - @override - Future loadSkybox(String skyboxPath) async { - await _shim.loadSkybox(skyboxPath).toDart; - } - - @override - Future removeSkybox() async { - await _shim.removeSkybox().toDart; - } - - @override - Future loadIbl(String lightingPath, {double intensity = 30000}) async { - await _shim.loadIbl(lightingPath, intensity).toDart; - } - - @override - Future rotateIbl(Matrix3 rotation) async { - await _shim - .rotateIbl(rotation.storage.map((v) => v.toJS).toList().toJS) - .toDart; - } - - @override - Future removeIbl() async { - await _shim.removeIbl().toDart; - } - - @override - Future addLight( - LightType type, - double colour, - double intensity, - double posX, - double posY, - double posZ, - double dirX, - double dirY, - double dirZ, - {double falloffRadius = 1.0, - double spotLightConeInner = pi / 8, - double spotLightConeOuter = pi / 4, - double sunAngularRadius = 0.545, - double sunHaloSize = 10.0, - double sunHaloFallof = 80.0, - bool castShadows = true}) async { - return (await _shim - .addLight( - type.index, - colour, - intensity, - posX, - posY, - posZ, - dirX, - dirY, - dirZ, - falloffRadius, - spotLightConeInner, - spotLightConeOuter, - sunAngularRadius, - sunHaloSize, - sunHaloFallof, - castShadows) - .toDart) - .toDartInt; - } - - @override - Future removeLight(ThermionEntity light) async { - await _shim.removeLight(light).toDart; - } - - @override - Future clearLights() async { - await _shim.clearLights().toDart; - } - - @override - Future loadGlb(String path, {int numInstances = 1, bool keepData=false}) async { - var entity = (await _shim.loadGlb(path, numInstances).toDart).toDartInt; - return entity; - } - - @override - Future createInstance(ThermionEntity entity) async { - return (await _shim.createInstance(entity).toDart).toDartInt; - } - - @override - Future getInstanceCount(ThermionEntity entity) async { - return (await _shim.getInstanceCount(entity).toDart).toDartInt; - } - - @override - Future> getInstances(ThermionEntity entity) async { - throw UnimplementedError(); - // final List jsInstances = - // await _shim.getInstances(entity).toDart; - // return jsInstances - // .map((js) => ThermionEntity._fromJSObject(js)) - // .toList() - // .toDart; - } - - @override - Future loadGltf(String path, String relativeResourcePath, - {bool keepData = false}) async { - throw UnimplementedError(); - // final ThermionEntity jsEntity = await _shim - // .loadGltf(path, relativeResourcePath, force: force) - // .toDart; - // return ThermionEntity._fromJSObject(jsEntity).toDart; - } - - @override - Future panStart(double x, double y) async { - await _shim.panStart(x, y).toDart; - } - - @override - Future panUpdate(double x, double y) async { - await _shim.panUpdate(x, y).toDart; - } - - @override - Future panEnd() async { - await _shim.panEnd().toDart; - } - - @override - Future rotateStart(double x, double y) async { - await _shim.rotateStart(x, y).toDart; - } - - @override - Future rotateUpdate(double x, double y) async { - await _shim.rotateUpdate(x, y).toDart; - } - - @override - Future rotateEnd() async { - await _shim.rotateEnd().toDart; - } - - @override - Future setMorphTargetWeights( - ThermionEntity entity, List weights) async { - var jsWeights = weights.map((x) => x.toJS).cast().toList().toJS; - var promise = _shim.setMorphTargetWeights(entity, jsWeights); - await promise.toDart; - } - - @override - Future> getMorphTargetNames( - ThermionEntity entity, ThermionEntity childEntity) async { - var result = await _shim.getMorphTargetNames(entity, childEntity).toDart; - return result.toDart.map((r) => r.toDart).toList(); - } - - @override - Future> getAnimationNames(ThermionEntity entity) async { - var names = (await (_shim.getAnimationNames(entity).toDart)) - .toDart - .map((x) => x.toDart) - .toList(); - return names; - } - - @override - Future getAnimationDuration( - ThermionEntity entity, int animationIndex) async { - return (await _shim.getAnimationDuration(entity, animationIndex).toDart) - .toDartDouble; - } - - @override - Future clearMorphAnimationData(ThermionEntity entity) async { - _shim.clearMorphAnimationData(entity); - } - - @override - Future setMorphAnimationData( - ThermionEntity entity, MorphAnimationData animation, - {List? targetMeshNames}) async { - try { - var animationDataJs = animation.data - .map((x) => x.map((y) => y.toJS).toList().toJS) - .toList() - .toJS; - var morphTargetsJs = animation.morphTargets - .map((x) => x.toJS) - .cast() - .toList() - .toJS; - var targetMeshNamesJS = - targetMeshNames?.map((x) => x.toJS).cast().toList().toJS; - await _shim - .setMorphAnimationData(entity, animationDataJs, morphTargetsJs, - targetMeshNamesJS, animation.frameLengthInMs) - .toDart; - } catch (err, st) { - _logger.severe(err); - _logger.severe(st); - rethrow; - } - } - - @override - Future resetBones(ThermionEntity entity) async { - await _shim.resetBones(entity).toDart; - } - - @override - Future addBoneAnimation( - ThermionEntity entity, BoneAnimationData animation, - {int skinIndex = 0, - double fadeInInSecs = 0.0, - double fadeOutInSecs = 0.0, - double maxDelta = 1.0}) async { - var boneNames = animation.bones.map((n) => n.toJS).toList().toJS; - var frameData = animation.frameData - .map((frame) => frame - .map((q) => [ - q.translation[0].toJS, - q.translation[1].toJS, - q.translation[2].toJS, - q.rotation.x.toJS, - q.rotation.y.toJS, - q.rotation.z.toJS, - q.rotation.w.toJS, - ].toJS) - .toList() - .toJS) - .toList() - .toJS; - - await _shim - .addBoneAnimation( - entity, - boneNames, - frameData, - animation.frameLengthInMs.toJS, - animation.space.index.toJS, - skinIndex.toJS, - fadeInInSecs.toJS, - fadeOutInSecs.toJS, - maxDelta.toJS) - .toDart; - } - - @override - Future removeEntity(ThermionEntity entity) async { - await _shim.removeEntity(entity).toDart; - } - - @override - Future clearEntities() async { - await _shim.clearEntities().toDart; - } - - @override - Future zoomBegin() async { - await _shim.zoomBegin().toDart; - } - - @override - Future zoomUpdate(double x, double y, double z) async { - await _shim.zoomUpdate(x, y, z).toDart; - } - - @override - Future zoomEnd() async { - await _shim.zoomEnd().toDart; - } - - @override - Future playAnimation(ThermionEntity entity, int index, - {bool loop = false, - bool reverse = false, - bool replaceActive = true, - double crossfade = 0.0, - double startOffset = 0.0}) async { - await _shim - .playAnimation( - entity, index, loop, reverse, replaceActive, crossfade, startOffset) - .toDart; - } - - @override - Future playAnimationByName(ThermionEntity entity, String name, - {bool loop = false, - bool reverse = false, - bool replaceActive = true, - double crossfade = 0.0}) async { - await _shim - .playAnimationByName( - entity, name, loop, reverse, replaceActive, crossfade) - .toDart; - } - - @override - Future setAnimationFrame( - ThermionEntity entity, int index, int animationFrame) async { - await _shim.setAnimationFrame(entity, index, animationFrame).toDart; - } - - @override - Future stopAnimation(ThermionEntity entity, int animationIndex) async { - await _shim.stopAnimation(entity, animationIndex).toDart; - } - - @override - Future stopAnimationByName(ThermionEntity entity, String name) async { - await _shim.stopAnimationByName(entity, name).toDart; - } - - @override - Future setCamera(ThermionEntity entity, String? name) async { - await _shim.setCamera(entity, name).toDart; - } - - @override - Future setMainCamera() async { - await _shim.setMainCamera().toDart; - } - - @override - Future getMainCamera() async { - throw UnimplementedError(); - // final ThermionEntity jsEntity = await _shim.getMainCamera().toDart; - // return ThermionEntity._fromJSObject(jsEntity).toDart; - } - - @override - Future setCameraFov(double degrees, {bool horizontal = true}) async { - await _shim.setCameraFov(degrees, horizontal).toDart; - } - - @override - Future setToneMapping(ToneMapper mapper) async { - await _shim.setToneMapping(mapper.index).toDart; - } - - @override - Future setBloom(double bloom) async { - await _shim.setBloom(bloom).toDart; - } - - @override - Future setCameraFocalLength(double focalLength) async { - await _shim.setCameraFocalLength(focalLength).toDart; - } - - @override - Future setCameraCulling(double near, double far) async { - await _shim.setCameraCulling(near, far).toDart; - } - - @override - Future getCameraCullingNear() async { - return (await _shim.getCameraCullingNear().toDart).toDartDouble; - } - - @override - Future getCameraCullingFar() async { - return (await _shim.getCameraCullingFar().toDart).toDartDouble; - } - - @override - Future setCameraFocusDistance(double focusDistance) async { - await _shim.setCameraFocusDistance(focusDistance).toDart; - } - - @override - Future getCameraPosition() async { - final jsPosition = (await _shim.getCameraPosition().toDart).toDart; - return Vector3(jsPosition[0].toDartDouble, jsPosition[1].toDartDouble, - jsPosition[2].toDartDouble); - } - - @override - Future getCameraModelMatrix() async { - throw UnimplementedError(); - // final JSMatrix4 jsMatrix = await _shim.getCameraModelMatrix().toDart; - // return Matrix4.fromList(jsMatrix.storage).toDart; - } - - @override - Future getCameraViewMatrix() async { - throw UnimplementedError(); - // final JSMatrix4 jsMatrix = await _shim.getCameraViewMatrix().toDart; - // return Matrix4.fromList(jsMatrix.storage).toDart; - } - - @override - Future getCameraProjectionMatrix() async { - throw UnimplementedError(); - // final JSMatrix4 jsMatrix = - // await _shim.getCameraProjectionMatrix().toDart; - // return Matrix4.fromList(jsMatrix.storage).toDart; - } - - @override - Future getCameraCullingProjectionMatrix() async { - throw UnimplementedError(); - // final JSMatrix4 jsMatrix = - // await _shim.getCameraCullingProjectionMatrix().toDart; - // return Matrix4.fromList(jsMatrix.storage).toDart; - } - - @override - Future getCameraFrustum() async { - throw UnimplementedError(); - // final JSObject jsFrustum = await _shim.getCameraFrustum().toDart; - // // Assuming Frustum is a class that can be constructed from the JSObject - // return Frustum._fromJSObject(jsFrustum).toDart; - } - - @override - Future setCameraPosition(double x, double y, double z) async { - await _shim.setCameraPosition(x, y, z).toDart; - } - - @override - Future getCameraRotation() async { - throw UnimplementedError(); - // final JSMatrix3 jsRotation = await _shim.getCameraRotation().toDart; - // return Matrix3.fromList(jsRotation.storage).toDart; - } - - @override - Future moveCameraToAsset(ThermionEntity entity) async { - await _shim.moveCameraToAsset(entity).toDart; - } - - @override - Future setViewFrustumCulling(bool enabled) async { - throw UnimplementedError(); - // await _shim.setViewFrustumCulling(enabled.toJSBoolean()).toDart; - } - - @override - Future setCameraExposure( - double aperture, double shutterSpeed, double sensitivity) async { - await _shim.setCameraExposure(aperture, shutterSpeed, sensitivity).toDart; - } - - @override - Future setCameraRotation(Quaternion quaternion) async { - final values = [ - quaternion.x.toJS, - quaternion.y.toJS, - quaternion.z.toJS, - quaternion.w.toJS - ]; - await _shim.setCameraRotation(values.toJS).toDart; - } - - @override - Future setCameraModelMatrix(List matrix) async { - throw UnimplementedError(); - - // await _shim.setCameraModelMatrix(matrix.toJSBox).toDart; - } - - @override - Future setMaterialColor(ThermionEntity entity, String meshName, - int materialIndex, double r, double g, double b, double a) async { - await _shim - .setMaterialColor(entity, meshName, materialIndex, r, g, b, a) - .toDart; - } - - @override - Future transformToUnitCube(ThermionEntity entity) async { - await _shim.transformToUnitCube(entity).toDart; - } - - @override - Future setPosition( - ThermionEntity entity, double x, double y, double z) async { - await _shim.setPosition(entity, x, y, z).toDart; - } - - @override - Future setScale(ThermionEntity entity, double scale) async { - await _shim.setScale(entity, scale).toDart; - } - - @override - Future setRotation( - ThermionEntity entity, double rads, double x, double y, double z) async { - await _shim.setRotation(entity, rads, x, y, z).toDart; - } - - @override - Future queuePositionUpdate( - ThermionEntity entity, double x, double y, double z, - {bool relative = false}) async { - await _shim.queuePositionUpdate(entity, x, y, z, relative).toDart; - } - - @override - Future queueRotationUpdate( - ThermionEntity entity, double rads, double x, double y, double z, - {bool relative = false}) async { - await _shim.queueRotationUpdate(entity, rads, x, y, z, relative).toDart; - } - - @override - Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat, - {bool relative = false}) async { - throw UnimplementedError(); - - // final JSQuaternion jsQuat = quat.toJSQuaternion().toDart; - // await _shim - // .queueRotationUpdateQuat(entity, jsQuat, relative: relative) - // .toDart; - } - - @override - Future setPostProcessing(bool enabled) async { - await _shim.setPostProcessing(enabled).toDart; - } - - @override - Future setAntiAliasing(bool msaa, bool fxaa, bool taa) async { - await _shim.setAntiAliasing(msaa, fxaa, taa).toDart; - } - - @override - Future setRotationQuat( - ThermionEntity entity, Quaternion rotation) async { - throw UnimplementedError(); - // final JSQuaternion jsRotation = rotation.toJSQuaternion().toDart; - // await _shim.setRotationQuat(entity, jsRotation).toDart; - } - - @override - Future reveal(ThermionEntity entity, String? meshName) async { - throw UnimplementedError(); - // await _shim.reveal(entity, meshName).toDart; - } - - @override - Future hide(ThermionEntity entity, String? meshName) async { - throw UnimplementedError(); - // await _shim.hide(entity, meshName).toDart; - } - - @override - void pick(int x, int y) { - throw UnimplementedError(); - // _shim.pick(x, y).toDart; - } - - @override - String? getNameForEntity(ThermionEntity entity) { - return _shim.getNameForEntity(entity); - } - - @override - Future setCameraManipulatorOptions( - {ManipulatorMode mode = ManipulatorMode.ORBIT, - double orbitSpeedX = 0.01, - double orbitSpeedY = 0.01, - double zoomSpeed = 0.01}) async { - await _shim - .setCameraManipulatorOptions( - mode.index, orbitSpeedX, orbitSpeedY, zoomSpeed) - .toDart; - } - - @override - Future> getChildEntities( - ThermionEntity parent, bool renderableOnly) async { - final children = - await _shim.getChildEntities(parent, renderableOnly).toDart; - return children.toDart - .map((js) => js.toDartInt) - .cast() - .toList(); - } - - @override - Future getChildEntity( - ThermionEntity parent, String childName) async { - return (await _shim.getChildEntity(parent, childName).toDart).toDartInt; - } - - @override - Future> getChildEntityNames(ThermionEntity entity, - {bool renderableOnly = true}) async { - var names = await _shim.getChildEntityNames(entity, renderableOnly).toDart; - return names.toDart.map((x) => x.toDart).toList(); - } - - @override - Future setRecording(bool recording) async { - throw UnimplementedError(); - // await _shim.setRecording(recording.toJSBoolean()).toDart; - } - - @override - Future setRecordingOutputDirectory(String outputDirectory) async { - await _shim.setRecordingOutputDirectory(outputDirectory).toDart; - } - - @override - Future addAnimationComponent(ThermionEntity entity) async { - await _shim.addAnimationComponent(entity).toDart; - } - - @override - Future addCollisionComponent(ThermionEntity entity, - {void Function(int entityId1, int entityId2)? callback, - bool affectsTransform = false}) async { - throw UnimplementedError(); - // final JSFunction? jsCallback = callback != null - // ? allowInterop( - // (int entityId1, int entityId2) => callback(entityId1, entityId2)) - // : null; - // await _shim - // .addCollisionComponent(entity, - // callback: jsCallback, - // affectsTransform: affectsTransform.toJSBoolean()) - // .toDart; - } - - @override - Future removeCollisionComponent(ThermionEntity entity) async { - await _shim.removeCollisionComponent(entity).toDart; - } - - @override - Future createGeometry( - Geometry geometry, - { - bool keepData=false, MaterialInstance? materialInstance, - PrimitiveType primitiveType = PrimitiveType.TRIANGLES}) async { - throw UnimplementedError(); - // final ThermionEntity jsEntity = await _shim - // .createGeometry(vertices, indices, - // materialPath: materialPath, primitiveType: primitiveType.index) - // .toDart; - // return ThermionEntity._fromJSObject(jsEntity).toDart; - } - - @override - Future setParent(ThermionEntity child, ThermionEntity parent, - {bool preserveScaling = false}) async { - await _shim.setParent(child, parent, preserveScaling).toDart; - } - - @override - Future testCollisions(ThermionEntity entity) async { - await _shim.testCollisions(entity).toDart; - } - - @override - Future setPriority(ThermionEntity entityId, int priority) async { - await _shim.setPriority(entityId, priority).toDart; - } - - AbstractGizmo? get gizmo => null; - - @override - Future> getBoneNames(ThermionEntity entity, - {int skinIndex = 0}) async { - var result = await _shim.getBoneNames(entity, skinIndex).toDart; - return result.toDart.map((n) => n.toDart).toList(); - } - - @override - Future getBone(ThermionEntity entity, int boneIndex, - {int skinIndex = 0}) async { - var result = await _shim.getBone(entity, boneIndex, skinIndex).toDart; - return result.toDartInt; - } - - @override - Future getInverseBindMatrix(ThermionEntity parent, int boneIndex, - {int skinIndex = 0}) { - // TODO: implement getInverseBindMatrix - throw UnimplementedError(); - } - - @override - Future getLocalTransform(ThermionEntity entity) async { - var result = await _shim.getLocalTransform(entity).toDart; - return Matrix4.fromList(result.toDart.map((v) => v.toDartDouble).toList()); - } - - @override - Future getParent(ThermionEntity child) async { - var result = await _shim.getParent(child).toDart; - return result.toDartInt; - } - - @override - Future getWorldTransform(ThermionEntity entity) async { - var result = await _shim.getLocalTransform(entity).toDart; - return Matrix4.fromList(result.toDart.map((v) => v.toDartDouble).toList()); - } - - @override - Future removeAnimationComponent(ThermionEntity entity) { - return _shim.removeAnimationComponent(entity).toDart; - } - - @override - Future setBoneTransform( - ThermionEntity entity, int boneIndex, Matrix4 transform, - {int skinIndex = 0}) { - return _shim - .setBoneTransform(entity, boneIndex, - transform.storage.map((v) => v.toJS).toList().toJS, skinIndex) - .toDart; - } - - @override - Future setTransform(ThermionEntity entity, Matrix4 transform) { - return _shim - .setTransform( - entity, transform.storage.map((v) => v.toJS).toList().toJS) - .toDart; - } - - @override - Future updateBoneMatrices(ThermionEntity entity) { - return _shim.updateBoneMatrices(entity).toDart; - } - - final _onDispose = []; - - /// - /// - /// - void onDispose(Future Function() callback) { - _onDispose.add(callback); - } - - @override - Future setShadowType(ShadowType shadowType) { - return _shim.setShadowType(shadowType.index).toDart; - } - - @override - Future setShadowsEnabled(bool enabled) { - return _shim.setShadowsEnabled(enabled).toDart; - } - - @override - Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale) { - return _shim.setSoftShadowOptions(penumbraScale, penumbraRatioScale).toDart; - } - - @override - Future capture() async { - final captured = await _shim.capture().toDart; - return captured.toDart; - } - - @override - late (double, double) viewportDimensions; - - @override - Future getBoundingBox(ThermionEntity entity) { - // return _shim.getBoundingBox(entity); - throw UnimplementedError(); - } - - @override - Future getCameraFov(bool horizontal) { - // TODO: implement getCameraFov - throw UnimplementedError(); - } - - @override - Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity, - double viewportX, double viewportY, double x, double y, double z) { - // TODO: implement queueRelativePositionUpdateWorldAxis - throw UnimplementedError(); - } +// import 'dart:js_interop'; +// import 'dart:js_interop_unsafe'; +// import 'dart:math'; +// import 'dart:typed_data'; + +// import 'package:animation_tools_dart/animation_tools_dart.dart'; +// import 'package:logging/logging.dart'; +// import 'package:vector_math/vector_math_64.dart'; +// import '../../shared_types/internal/gizmo.dart'; +// import '../../../viewer.dart'; +// import '../../events.dart'; +// import '../../shared_types/camera.dart'; +// import 'thermion_viewer_js_shim.dart'; + +// /// +// /// An [ThermionViewer] implementation that forwards calls to +// /// a corresponding Javascript shim implementation (see [ThermionViewerJSShim]). +// /// +// class ThermionViewerJS implements ThermionViewer { +// final _logger = Logger("ThermionViewerJS"); +// late final ThermionViewerJSShim _shim; + +// ThermionViewerJS.fromGlobalProperty(String globalPropertyName) { +// this._shim = globalContext.getProperty(globalPropertyName.toJS) +// as ThermionViewerJSShim; +// } + +// ThermionViewerJS(this._shim); + +// @override +// Future get initialized async { +// var inited = _shim.initialized; +// final JSBoolean result = await inited.toDart; +// return result.toDart; +// } + +// @override +// Stream get pickResult { +// throw UnimplementedError(); +// } + +// @override +// bool get rendering => _shim.rendering; + +// @override +// Future setRendering(bool render) async { +// await _shim.setRendering(render).toDart; +// } + +// @override +// Future render() async { +// await _shim.render().toDart; +// } + +// @override +// Future setFrameRate(int framerate) async { +// await _shim.setFrameRate(framerate).toDart; +// } + +// @override +// Future dispose() async { +// await _shim.dispose().toDart; +// for (final callback in _onDispose) { +// callback.call(); +// } +// } + +// @override +// Future setBackgroundImage(String path, +// {bool fillHeight = false}) async { +// await _shim.setBackgroundImage(path, fillHeight).toDart; +// } + +// @override +// Future setBackgroundImagePosition(double x, double y, +// {bool clamp = false}) async { +// await _shim.setBackgroundImagePosition(x, y, clamp).toDart; +// } + +// @override +// Future clearBackgroundImage() async { +// await _shim.clearBackgroundImage().toDart; +// } + +// @override +// Future setBackgroundColor( +// double r, double g, double b, double alpha) async { +// await _shim.setBackgroundColor(r, g, b, alpha).toDart; +// } + +// @override +// Future loadSkybox(String skyboxPath) async { +// await _shim.loadSkybox(skyboxPath).toDart; +// } + +// @override +// Future removeSkybox() async { +// await _shim.removeSkybox().toDart; +// } + +// @override +// Future loadIbl(String lightingPath, {double intensity = 30000}) async { +// await _shim.loadIbl(lightingPath, intensity).toDart; +// } + +// @override +// Future rotateIbl(Matrix3 rotation) async { +// await _shim +// .rotateIbl(rotation.storage.map((v) => v.toJS).toList().toJS) +// .toDart; +// } + +// @override +// Future removeIbl() async { +// await _shim.removeIbl().toDart; +// } + +// @override +// Future addLight( +// LightType type, +// double colour, +// double intensity, +// double posX, +// double posY, +// double posZ, +// double dirX, +// double dirY, +// double dirZ, +// {double falloffRadius = 1.0, +// double spotLightConeInner = pi / 8, +// double spotLightConeOuter = pi / 4, +// double sunAngularRadius = 0.545, +// double sunHaloSize = 10.0, +// double sunHaloFallof = 80.0, +// bool castShadows = true}) async { +// return (await _shim +// .addLight( +// type.index, +// colour, +// intensity, +// posX, +// posY, +// posZ, +// dirX, +// dirY, +// dirZ, +// falloffRadius, +// spotLightConeInner, +// spotLightConeOuter, +// sunAngularRadius, +// sunHaloSize, +// sunHaloFallof, +// castShadows) +// .toDart) +// .toDartInt; +// } + +// @override +// Future removeLight(ThermionEntity light) async { +// await _shim.removeLight(light).toDart; +// } + +// @override +// Future clearLights() async { +// await _shim.clearLights().toDart; +// } + +// @override +// Future loadGlb(String path, {int numInstances = 1, bool keepData=false}) async { +// var entity = (await _shim.loadGlb(path, numInstances).toDart).toDartInt; +// return entity; +// } + +// @override +// Future createInstance(ThermionEntity entity) async { +// return (await _shim.createInstance(entity).toDart).toDartInt; +// } + +// @override +// Future getInstanceCount(ThermionEntity entity) async { +// return (await _shim.getInstanceCount(entity).toDart).toDartInt; +// } + +// @override +// Future> getInstances(ThermionEntity entity) async { +// throw UnimplementedError(); +// // final List jsInstances = +// // await _shim.getInstances(entity).toDart; +// // return jsInstances +// // .map((js) => ThermionEntity._fromJSObject(js)) +// // .toList() +// // .toDart; +// } + +// @override +// Future loadGltf(String path, String relativeResourcePath, +// {bool keepData = false}) async { +// throw UnimplementedError(); +// // final ThermionEntity jsEntity = await _shim +// // .loadGltf(path, relativeResourcePath, force: force) +// // .toDart; +// // return ThermionEntity._fromJSObject(jsEntity).toDart; +// } + +// @override +// Future panStart(double x, double y) async { +// await _shim.panStart(x, y).toDart; +// } + +// @override +// Future panUpdate(double x, double y) async { +// await _shim.panUpdate(x, y).toDart; +// } + +// @override +// Future panEnd() async { +// await _shim.panEnd().toDart; +// } + +// @override +// Future rotateStart(double x, double y) async { +// await _shim.rotateStart(x, y).toDart; +// } + +// @override +// Future rotateUpdate(double x, double y) async { +// await _shim.rotateUpdate(x, y).toDart; +// } + +// @override +// Future rotateEnd() async { +// await _shim.rotateEnd().toDart; +// } + +// @override +// Future setMorphTargetWeights( +// ThermionEntity entity, List weights) async { +// var jsWeights = weights.map((x) => x.toJS).cast().toList().toJS; +// var promise = _shim.setMorphTargetWeights(entity, jsWeights); +// await promise.toDart; +// } + +// @override +// Future> getMorphTargetNames( +// ThermionEntity entity, ThermionEntity childEntity) async { +// var result = await _shim.getMorphTargetNames(entity, childEntity).toDart; +// return result.toDart.map((r) => r.toDart).toList(); +// } + +// @override +// Future> getAnimationNames(ThermionEntity entity) async { +// var names = (await (_shim.getAnimationNames(entity).toDart)) +// .toDart +// .map((x) => x.toDart) +// .toList(); +// return names; +// } + +// @override +// Future getAnimationDuration( +// ThermionEntity entity, int animationIndex) async { +// return (await _shim.getAnimationDuration(entity, animationIndex).toDart) +// .toDartDouble; +// } + +// @override +// Future clearMorphAnimationData(ThermionEntity entity) async { +// _shim.clearMorphAnimationData(entity); +// } + +// @override +// Future setMorphAnimationData( +// ThermionEntity entity, MorphAnimationData animation, +// {List? targetMeshNames}) async { +// try { +// var animationDataJs = animation.data +// .map((x) => x.map((y) => y.toJS).toList().toJS) +// .toList() +// .toJS; +// var morphTargetsJs = animation.morphTargets +// .map((x) => x.toJS) +// .cast() +// .toList() +// .toJS; +// var targetMeshNamesJS = +// targetMeshNames?.map((x) => x.toJS).cast().toList().toJS; +// await _shim +// .setMorphAnimationData(entity, animationDataJs, morphTargetsJs, +// targetMeshNamesJS, animation.frameLengthInMs) +// .toDart; +// } catch (err, st) { +// _logger.severe(err); +// _logger.severe(st); +// rethrow; +// } +// } + +// @override +// Future resetBones(ThermionEntity entity) async { +// await _shim.resetBones(entity).toDart; +// } + +// @override +// Future addBoneAnimation( +// ThermionEntity entity, BoneAnimationData animation, +// {int skinIndex = 0, +// double fadeInInSecs = 0.0, +// double fadeOutInSecs = 0.0, +// double maxDelta = 1.0}) async { +// var boneNames = animation.bones.map((n) => n.toJS).toList().toJS; +// var frameData = animation.frameData +// .map((frame) => frame +// .map((q) => [ +// q.translation[0].toJS, +// q.translation[1].toJS, +// q.translation[2].toJS, +// q.rotation.x.toJS, +// q.rotation.y.toJS, +// q.rotation.z.toJS, +// q.rotation.w.toJS, +// ].toJS) +// .toList() +// .toJS) +// .toList() +// .toJS; + +// await _shim +// .addBoneAnimation( +// entity, +// boneNames, +// frameData, +// animation.frameLengthInMs.toJS, +// animation.space.index.toJS, +// skinIndex.toJS, +// fadeInInSecs.toJS, +// fadeOutInSecs.toJS, +// maxDelta.toJS) +// .toDart; +// } + +// @override +// Future removeEntity(ThermionEntity entity) async { +// await _shim.removeEntity(entity).toDart; +// } + +// @override +// Future clearEntities() async { +// await _shim.clearEntities().toDart; +// } + +// @override +// Future zoomBegin() async { +// await _shim.zoomBegin().toDart; +// } + +// @override +// Future zoomUpdate(double x, double y, double z) async { +// await _shim.zoomUpdate(x, y, z).toDart; +// } + +// @override +// Future zoomEnd() async { +// await _shim.zoomEnd().toDart; +// } + +// @override +// Future playAnimation(ThermionEntity entity, int index, +// {bool loop = false, +// bool reverse = false, +// bool replaceActive = true, +// double crossfade = 0.0, +// double startOffset = 0.0}) async { +// await _shim +// .playAnimation( +// entity, index, loop, reverse, replaceActive, crossfade, startOffset) +// .toDart; +// } + +// @override +// Future playAnimationByName(ThermionEntity entity, String name, +// {bool loop = false, +// bool reverse = false, +// bool replaceActive = true, +// double crossfade = 0.0}) async { +// await _shim +// .playAnimationByName( +// entity, name, loop, reverse, replaceActive, crossfade) +// .toDart; +// } + +// @override +// Future setAnimationFrame( +// ThermionEntity entity, int index, int animationFrame) async { +// await _shim.setAnimationFrame(entity, index, animationFrame).toDart; +// } + +// @override +// Future stopAnimation(ThermionEntity entity, int animationIndex) async { +// await _shim.stopAnimation(entity, animationIndex).toDart; +// } + +// @override +// Future stopAnimationByName(ThermionEntity entity, String name) async { +// await _shim.stopAnimationByName(entity, name).toDart; +// } + +// @override +// Future setCamera(ThermionEntity entity, String? name) async { +// await _shim.setCamera(entity, name).toDart; +// } + +// @override +// Future setMainCamera() async { +// await _shim.setMainCamera().toDart; +// } + +// @override +// Future getMainCamera() async { +// throw UnimplementedError(); +// // final ThermionEntity jsEntity = await _shim.getMainCamera().toDart; +// // return ThermionEntity._fromJSObject(jsEntity).toDart; +// } + +// @override +// Future setCameraFov(double degrees, {bool horizontal = true}) async { +// await _shim.setCameraFov(degrees, horizontal).toDart; +// } + +// @override +// Future setToneMapping(ToneMapper mapper) async { +// await _shim.setToneMapping(mapper.index).toDart; +// } + +// @override +// Future setBloom(double bloom) async { +// await _shim.setBloom(bloom).toDart; +// } + +// @override +// Future setCameraFocalLength(double focalLength) async { +// await _shim.setCameraFocalLength(focalLength).toDart; +// } + +// @override +// Future setCameraCulling(double near, double far) async { +// await _shim.setCameraCulling(near, far).toDart; +// } + +// @override +// Future getCameraCullingNear() async { +// return (await _shim.getCameraCullingNear().toDart).toDartDouble; +// } + +// @override +// Future getCameraCullingFar() async { +// return (await _shim.getCameraCullingFar().toDart).toDartDouble; +// } + +// @override +// Future setCameraFocusDistance(double focusDistance) async { +// await _shim.setCameraFocusDistance(focusDistance).toDart; +// } + +// @override +// Future getCameraPosition() async { +// final jsPosition = (await _shim.getCameraPosition().toDart).toDart; +// return Vector3(jsPosition[0].toDartDouble, jsPosition[1].toDartDouble, +// jsPosition[2].toDartDouble); +// } + +// @override +// Future getCameraModelMatrix() async { +// throw UnimplementedError(); +// // final JSMatrix4 jsMatrix = await _shim.getCameraModelMatrix().toDart; +// // return Matrix4.fromList(jsMatrix.storage).toDart; +// } + +// @override +// Future getCameraViewMatrix() async { +// throw UnimplementedError(); +// // final JSMatrix4 jsMatrix = await _shim.getCameraViewMatrix().toDart; +// // return Matrix4.fromList(jsMatrix.storage).toDart; +// } + +// @override +// Future getCameraProjectionMatrix() async { +// throw UnimplementedError(); +// // final JSMatrix4 jsMatrix = +// // await _shim.getCameraProjectionMatrix().toDart; +// // return Matrix4.fromList(jsMatrix.storage).toDart; +// } + +// @override +// Future getCameraCullingProjectionMatrix() async { +// throw UnimplementedError(); +// // final JSMatrix4 jsMatrix = +// // await _shim.getCameraCullingProjectionMatrix().toDart; +// // return Matrix4.fromList(jsMatrix.storage).toDart; +// } + +// @override +// Future getCameraFrustum() async { +// throw UnimplementedError(); +// // final JSObject jsFrustum = await _shim.getCameraFrustum().toDart; +// // // Assuming Frustum is a class that can be constructed from the JSObject +// // return Frustum._fromJSObject(jsFrustum).toDart; +// } + +// @override +// Future setCameraPosition(double x, double y, double z) async { +// await _shim.setCameraPosition(x, y, z).toDart; +// } + +// @override +// Future getCameraRotation() async { +// throw UnimplementedError(); +// // final JSMatrix3 jsRotation = await _shim.getCameraRotation().toDart; +// // return Matrix3.fromList(jsRotation.storage).toDart; +// } + +// @override +// Future moveCameraToAsset(ThermionEntity entity) async { +// await _shim.moveCameraToAsset(entity).toDart; +// } + +// @override +// Future setViewFrustumCulling(bool enabled) async { +// throw UnimplementedError(); +// // await _shim.setViewFrustumCulling(enabled.toJSBoolean()).toDart; +// } + +// @override +// Future setCameraExposure( +// double aperture, double shutterSpeed, double sensitivity) async { +// await _shim.setCameraExposure(aperture, shutterSpeed, sensitivity).toDart; +// } + +// @override +// Future setCameraRotation(Quaternion quaternion) async { +// final values = [ +// quaternion.x.toJS, +// quaternion.y.toJS, +// quaternion.z.toJS, +// quaternion.w.toJS +// ]; +// await _shim.setCameraRotation(values.toJS).toDart; +// } + +// @override +// Future setCameraModelMatrix(List matrix) async { +// throw UnimplementedError(); + +// // await _shim.setCameraModelMatrix(matrix.toJSBox).toDart; +// } + +// @override +// Future setMaterialColor(ThermionEntity entity, String meshName, +// int materialIndex, double r, double g, double b, double a) async { +// await _shim +// .setMaterialColor(entity, meshName, materialIndex, r, g, b, a) +// .toDart; +// } + +// @override +// Future transformToUnitCube(ThermionEntity entity) async { +// await _shim.transformToUnitCube(entity).toDart; +// } + +// @override +// Future setPosition( +// ThermionEntity entity, double x, double y, double z) async { +// await _shim.setPosition(entity, x, y, z).toDart; +// } + +// @override +// Future setScale(ThermionEntity entity, double scale) async { +// await _shim.setScale(entity, scale).toDart; +// } + +// @override +// Future setRotation( +// ThermionEntity entity, double rads, double x, double y, double z) async { +// await _shim.setRotation(entity, rads, x, y, z).toDart; +// } + +// @override +// Future queuePositionUpdate( +// ThermionEntity entity, double x, double y, double z, +// {bool relative = false}) async { +// await _shim.queuePositionUpdate(entity, x, y, z, relative).toDart; +// } + +// @override +// Future queueRotationUpdate( +// ThermionEntity entity, double rads, double x, double y, double z, +// {bool relative = false}) async { +// await _shim.queueRotationUpdate(entity, rads, x, y, z, relative).toDart; +// } + +// @override +// Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat, +// {bool relative = false}) async { +// throw UnimplementedError(); + +// // final JSQuaternion jsQuat = quat.toJSQuaternion().toDart; +// // await _shim +// // .queueRotationUpdateQuat(entity, jsQuat, relative: relative) +// // .toDart; +// } + +// @override +// Future setPostProcessing(bool enabled) async { +// await _shim.setPostProcessing(enabled).toDart; +// } + +// @override +// Future setAntiAliasing(bool msaa, bool fxaa, bool taa) async { +// await _shim.setAntiAliasing(msaa, fxaa, taa).toDart; +// } + +// @override +// Future setRotationQuat( +// ThermionEntity entity, Quaternion rotation) async { +// throw UnimplementedError(); +// // final JSQuaternion jsRotation = rotation.toJSQuaternion().toDart; +// // await _shim.setRotationQuat(entity, jsRotation).toDart; +// } + +// @override +// Future reveal(ThermionEntity entity, String? meshName) async { +// throw UnimplementedError(); +// // await _shim.reveal(entity, meshName).toDart; +// } + +// @override +// Future hide(ThermionEntity entity, String? meshName) async { +// throw UnimplementedError(); +// // await _shim.hide(entity, meshName).toDart; +// } + +// @override +// void pick(int x, int y) { +// throw UnimplementedError(); +// // _shim.pick(x, y).toDart; +// } + +// @override +// String? getNameForEntity(ThermionEntity entity) { +// return _shim.getNameForEntity(entity); +// } + +// @override +// Future setCameraManipulatorOptions( +// {ManipulatorMode mode = ManipulatorMode.ORBIT, +// double orbitSpeedX = 0.01, +// double orbitSpeedY = 0.01, +// double zoomSpeed = 0.01}) async { +// await _shim +// .setCameraManipulatorOptions( +// mode.index, orbitSpeedX, orbitSpeedY, zoomSpeed) +// .toDart; +// } + +// @override +// Future> getChildEntities( +// ThermionEntity parent, bool renderableOnly) async { +// final children = +// await _shim.getChildEntities(parent, renderableOnly).toDart; +// return children.toDart +// .map((js) => js.toDartInt) +// .cast() +// .toList(); +// } + +// @override +// Future getChildEntity( +// ThermionEntity parent, String childName) async { +// return (await _shim.getChildEntity(parent, childName).toDart).toDartInt; +// } + +// @override +// Future> getChildEntityNames(ThermionEntity entity, +// {bool renderableOnly = true}) async { +// var names = await _shim.getChildEntityNames(entity, renderableOnly).toDart; +// return names.toDart.map((x) => x.toDart).toList(); +// } + +// @override +// Future setRecording(bool recording) async { +// throw UnimplementedError(); +// // await _shim.setRecording(recording.toJSBoolean()).toDart; +// } + +// @override +// Future setRecordingOutputDirectory(String outputDirectory) async { +// await _shim.setRecordingOutputDirectory(outputDirectory).toDart; +// } + +// @override +// Future addAnimationComponent(ThermionEntity entity) async { +// await _shim.addAnimationComponent(entity).toDart; +// } + +// @override +// Future addCollisionComponent(ThermionEntity entity, +// {void Function(int entityId1, int entityId2)? callback, +// bool affectsTransform = false}) async { +// throw UnimplementedError(); +// // final JSFunction? jsCallback = callback != null +// // ? allowInterop( +// // (int entityId1, int entityId2) => callback(entityId1, entityId2)) +// // : null; +// // await _shim +// // .addCollisionComponent(entity, +// // callback: jsCallback, +// // affectsTransform: affectsTransform.toJSBoolean()) +// // .toDart; +// } + +// @override +// Future removeCollisionComponent(ThermionEntity entity) async { +// await _shim.removeCollisionComponent(entity).toDart; +// } + +// @override +// Future createGeometry( +// Geometry geometry, +// { +// bool keepData=false, MaterialInstance? materialInstance, +// PrimitiveType primitiveType = PrimitiveType.TRIANGLES}) async { +// throw UnimplementedError(); +// // final ThermionEntity jsEntity = await _shim +// // .createGeometry(vertices, indices, +// // materialPath: materialPath, primitiveType: primitiveType.index) +// // .toDart; +// // return ThermionEntity._fromJSObject(jsEntity).toDart; +// } + +// @override +// Future setParent(ThermionEntity child, ThermionEntity parent, +// {bool preserveScaling = false}) async { +// await _shim.setParent(child, parent, preserveScaling).toDart; +// } + +// @override +// Future testCollisions(ThermionEntity entity) async { +// await _shim.testCollisions(entity).toDart; +// } + +// @override +// Future setPriority(ThermionEntity entityId, int priority) async { +// await _shim.setPriority(entityId, priority).toDart; +// } + +// AbstractGizmo? get gizmo => null; + +// @override +// Future> getBoneNames(ThermionEntity entity, +// {int skinIndex = 0}) async { +// var result = await _shim.getBoneNames(entity, skinIndex).toDart; +// return result.toDart.map((n) => n.toDart).toList(); +// } + +// @override +// Future getBone(ThermionEntity entity, int boneIndex, +// {int skinIndex = 0}) async { +// var result = await _shim.getBone(entity, boneIndex, skinIndex).toDart; +// return result.toDartInt; +// } + +// @override +// Future getInverseBindMatrix(ThermionEntity parent, int boneIndex, +// {int skinIndex = 0}) { +// // TODO: implement getInverseBindMatrix +// throw UnimplementedError(); +// } + +// @override +// Future getLocalTransform(ThermionEntity entity) async { +// var result = await _shim.getLocalTransform(entity).toDart; +// return Matrix4.fromList(result.toDart.map((v) => v.toDartDouble).toList()); +// } + +// @override +// Future getParent(ThermionEntity child) async { +// var result = await _shim.getParent(child).toDart; +// return result.toDartInt; +// } + +// @override +// Future getWorldTransform(ThermionEntity entity) async { +// var result = await _shim.getLocalTransform(entity).toDart; +// return Matrix4.fromList(result.toDart.map((v) => v.toDartDouble).toList()); +// } + +// @override +// Future removeAnimationComponent(ThermionEntity entity) { +// return _shim.removeAnimationComponent(entity).toDart; +// } + +// @override +// Future setBoneTransform( +// ThermionEntity entity, int boneIndex, Matrix4 transform, +// {int skinIndex = 0}) { +// return _shim +// .setBoneTransform(entity, boneIndex, +// transform.storage.map((v) => v.toJS).toList().toJS, skinIndex) +// .toDart; +// } + +// @override +// Future setTransform(ThermionEntity entity, Matrix4 transform) { +// return _shim +// .setTransform( +// entity, transform.storage.map((v) => v.toJS).toList().toJS) +// .toDart; +// } + +// @override +// Future updateBoneMatrices(ThermionEntity entity) { +// return _shim.updateBoneMatrices(entity).toDart; +// } + +// final _onDispose = []; + +// /// +// /// +// /// +// void onDispose(Future Function() callback) { +// _onDispose.add(callback); +// } + +// @override +// Future setShadowType(ShadowType shadowType) { +// return _shim.setShadowType(shadowType.index).toDart; +// } + +// @override +// Future setShadowsEnabled(bool enabled) { +// return _shim.setShadowsEnabled(enabled).toDart; +// } + +// @override +// Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale) { +// return _shim.setSoftShadowOptions(penumbraScale, penumbraRatioScale).toDart; +// } + +// @override +// Future capture() async { +// final captured = await _shim.capture().toDart; +// return captured.toDart; +// } + +// @override +// late (double, double) viewportDimensions; + +// @override +// Future getBoundingBox(ThermionEntity entity) { +// // return _shim.getBoundingBox(entity); +// throw UnimplementedError(); +// } + +// @override +// Future getCameraFov(bool horizontal) { +// // TODO: implement getCameraFov +// throw UnimplementedError(); +// } + +// @override +// Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity, +// double viewportX, double viewportY, double x, double y, double z) { +// // TODO: implement queueRelativePositionUpdateWorldAxis +// throw UnimplementedError(); +// } - @override - double pixelRatio = 0.0; +// @override +// double pixelRatio = 0.0; - @override - Future createIbl(double r, double g, double b, double intensity) { - // TODO: implement createIbl - throw UnimplementedError(); - } +// @override +// Future createIbl(double r, double g, double b, double intensity) { +// // TODO: implement createIbl +// throw UnimplementedError(); +// } - @override - // TODO: implement gizmoPickResult - Stream get gizmoPickResult => throw UnimplementedError(); +// @override +// // TODO: implement gizmoPickResult +// Stream get gizmoPickResult => throw UnimplementedError(); - @override - void pickGizmo(int x, int y) { - // TODO: implement pickGizmo - } +// @override +// void pickGizmo(int x, int y) { +// // TODO: implement pickGizmo +// } - @override - Future setGizmoVisibility(bool visible) { - // TODO: implement setGizmoVisibility - throw UnimplementedError(); - } +// @override +// Future setGizmoVisibility(bool visible) { +// // TODO: implement setGizmoVisibility +// throw UnimplementedError(); +// } - @override - Future setLayerEnabled(int layer, bool enabled) { - // TODO: implement setLayerEnabled - throw UnimplementedError(); - } +// @override +// Future setLayerEnabled(int layer, bool enabled) { +// // TODO: implement setLayerEnabled +// throw UnimplementedError(); +// } - @override - // TODO: implement entitiesAdded - Stream get entitiesAdded => throw UnimplementedError(); +// @override +// // TODO: implement entitiesAdded +// Stream get entitiesAdded => throw UnimplementedError(); - @override - // TODO: implement entitiesRemoved - Stream get entitiesRemoved => throw UnimplementedError(); +// @override +// // TODO: implement entitiesRemoved +// Stream get entitiesRemoved => throw UnimplementedError(); - @override - Future getAncestor(ThermionEntity entity) { - // TODO: implement getAncestor - throw UnimplementedError(); - } +// @override +// Future getAncestor(ThermionEntity entity) { +// // TODO: implement getAncestor +// throw UnimplementedError(); +// } - @override - Future getCameraNear() { - // TODO: implement getCameraNear - throw UnimplementedError(); - } +// @override +// Future getCameraNear() { +// // TODO: implement getCameraNear +// throw UnimplementedError(); +// } - @override - Future getViewportBoundingBox(ThermionEntity entity) { - // TODO: implement getViewportBoundingBox - throw UnimplementedError(); - } +// @override +// Future getViewportBoundingBox(ThermionEntity entity) { +// // TODO: implement getViewportBoundingBox +// throw UnimplementedError(); +// } - @override - // TODO: implement lightsAdded - Stream get lightsAdded => throw UnimplementedError(); +// @override +// // TODO: implement lightsAdded +// Stream get lightsAdded => throw UnimplementedError(); - @override - // TODO: implement lightsRemoved - Stream get lightsRemoved => throw UnimplementedError(); +// @override +// // TODO: implement lightsRemoved +// Stream get lightsRemoved => throw UnimplementedError(); - @override - Future loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int layer=4, int priority =4 }) { - // TODO: implement loadGlbFromBuffer - throw UnimplementedError(); - } +// @override +// Future loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int layer=4, int priority =4 }) { +// // TODO: implement loadGlbFromBuffer +// throw UnimplementedError(); +// } - @override - Future queuePositionUpdateFromViewportCoords(ThermionEntity entity, double x, double y) { - // TODO: implement queuePositionUpdateFromViewportCoords - throw UnimplementedError(); - } +// @override +// Future queuePositionUpdateFromViewportCoords(ThermionEntity entity, double x, double y) { +// // TODO: implement queuePositionUpdateFromViewportCoords +// throw UnimplementedError(); +// } - @override - Future removeStencilHighlight(ThermionEntity entity) { - // TODO: implement removeStencilHighlight - throw UnimplementedError(); - } +// @override +// Future removeStencilHighlight(ThermionEntity entity) { +// // TODO: implement removeStencilHighlight +// throw UnimplementedError(); +// } - @override - Future setCameraModelMatrix4(Matrix4 matrix) { - // TODO: implement setCameraModelMatrix4 - throw UnimplementedError(); - } +// @override +// Future setCameraModelMatrix4(Matrix4 matrix) { +// // TODO: implement setCameraModelMatrix4 +// throw UnimplementedError(); +// } - @override - Future setLightDirection(ThermionEntity lightEntity, Vector3 direction) { - // TODO: implement setLightDirection - throw UnimplementedError(); - } +// @override +// Future setLightDirection(ThermionEntity lightEntity, Vector3 direction) { +// // TODO: implement setLightDirection +// throw UnimplementedError(); +// } - @override - Future setLightPosition(ThermionEntity lightEntity, double x, double y, double z) { - // TODO: implement setLightPosition - throw UnimplementedError(); - } +// @override +// Future setLightPosition(ThermionEntity lightEntity, double x, double y, double z) { +// // TODO: implement setLightPosition +// throw UnimplementedError(); +// } - @override - Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, int materialIndex, double value) { - // TODO: implement setMaterialPropertyFloat - throw UnimplementedError(); - } +// @override +// Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, int materialIndex, double value) { +// // TODO: implement setMaterialPropertyFloat +// throw UnimplementedError(); +// } - @override - Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName, int materialIndex, double f1, double f2, double f3, double f4) { - // TODO: implement setMaterialPropertyFloat4 - throw UnimplementedError(); - } +// @override +// Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName, int materialIndex, double f1, double f2, double f3, double f4) { +// // TODO: implement setMaterialPropertyFloat4 +// throw UnimplementedError(); +// } - @override - Future setStencilHighlight(ThermionEntity entity, {double r = 1.0, double g = 0.0, double b = 0.0}) { - // TODO: implement setStencilHighlight - throw UnimplementedError(); - } +// @override +// Future setStencilHighlight(ThermionEntity entity, {double r = 1.0, double g = 0.0, double b = 0.0}) { +// // TODO: implement setStencilHighlight +// throw UnimplementedError(); +// } - @override - Future addDirectLight(DirectLight light) { - // TODO: implement addDirectLight - throw UnimplementedError(); - } +// @override +// Future addDirectLight(DirectLight light) { +// // TODO: implement addDirectLight +// throw UnimplementedError(); +// } - @override - Future applyTexture(covariant ThermionTexture texture, ThermionEntity entity, {int materialIndex = 0, String parameterName = "baseColorMap"}) { - // TODO: implement applyTexture - throw UnimplementedError(); - } +// @override +// Future applyTexture(covariant ThermionTexture texture, ThermionEntity entity, {int materialIndex = 0, String parameterName = "baseColorMap"}) { +// // TODO: implement applyTexture +// throw UnimplementedError(); +// } - @override - Future createTexture(Uint8List data) { - // TODO: implement createTexture - throw UnimplementedError(); - } +// @override +// Future createTexture(Uint8List data) { +// // TODO: implement createTexture +// throw UnimplementedError(); +// } - @override - Future createUbershaderMaterialInstance({bool doubleSided = false, bool unlit = false, bool hasVertexColors = false, bool hasBaseColorTexture = false, bool hasNormalTexture = false, bool hasOcclusionTexture = false, bool hasEmissiveTexture = false, bool useSpecularGlossiness = false, AlphaMode alphaMode = AlphaMode.OPAQUE, bool enableDiagnostics = false, bool hasMetallicRoughnessTexture = false, int metallicRoughnessUV = 0, int baseColorUV = 0, bool hasClearCoatTexture = false, int clearCoatUV = 0, bool hasClearCoatRoughnessTexture = false, int clearCoatRoughnessUV = 0, bool hasClearCoatNormalTexture = false, int clearCoatNormalUV = 0, bool hasClearCoat = false, bool hasTransmission = false, bool hasTextureTransforms = false, int emissiveUV = 0, int aoUV = 0, int normalUV = 0, bool hasTransmissionTexture = false, int transmissionUV = 0, bool hasSheenColorTexture = false, int sheenColorUV = 0, bool hasSheenRoughnessTexture = false, int sheenRoughnessUV = 0, bool hasVolumeThicknessTexture = false, int volumeThicknessUV = 0, bool hasSheen = false, bool hasIOR = false, bool hasVolume = false}) { - // TODO: implement createUbershaderMaterialInstance - throw UnimplementedError(); - } +// @override +// Future createUbershaderMaterialInstance({bool doubleSided = false, bool unlit = false, bool hasVertexColors = false, bool hasBaseColorTexture = false, bool hasNormalTexture = false, bool hasOcclusionTexture = false, bool hasEmissiveTexture = false, bool useSpecularGlossiness = false, AlphaMode alphaMode = AlphaMode.OPAQUE, bool enableDiagnostics = false, bool hasMetallicRoughnessTexture = false, int metallicRoughnessUV = 0, int baseColorUV = 0, bool hasClearCoatTexture = false, int clearCoatUV = 0, bool hasClearCoatRoughnessTexture = false, int clearCoatRoughnessUV = 0, bool hasClearCoatNormalTexture = false, int clearCoatNormalUV = 0, bool hasClearCoat = false, bool hasTransmission = false, bool hasTextureTransforms = false, int emissiveUV = 0, int aoUV = 0, int normalUV = 0, bool hasTransmissionTexture = false, int transmissionUV = 0, bool hasSheenColorTexture = false, int sheenColorUV = 0, bool hasSheenRoughnessTexture = false, int sheenRoughnessUV = 0, bool hasVolumeThicknessTexture = false, int volumeThicknessUV = 0, bool hasSheen = false, bool hasIOR = false, bool hasVolume = false}) { +// // TODO: implement createUbershaderMaterialInstance +// throw UnimplementedError(); +// } - @override - Future createUnlitMaterialInstance() { - // TODO: implement createUnlitMaterialInstance - throw UnimplementedError(); - } +// @override +// Future createUnlitMaterialInstance() { +// // TODO: implement createUnlitMaterialInstance +// throw UnimplementedError(); +// } - @override - Future destroyMaterialInstance(covariant MaterialInstance materialInstance) { - // TODO: implement destroyMaterialInstance - throw UnimplementedError(); - } +// @override +// Future destroyMaterialInstance(covariant MaterialInstance materialInstance) { +// // TODO: implement destroyMaterialInstance +// throw UnimplementedError(); +// } - @override - Future destroyTexture(covariant ThermionTexture texture) { - // TODO: implement destroyTexture - throw UnimplementedError(); - } +// @override +// Future destroyTexture(covariant ThermionTexture texture) { +// // TODO: implement destroyTexture +// throw UnimplementedError(); +// } - @override - Future getMainCameraEntity() { - // TODO: implement getMainCameraEntity - throw UnimplementedError(); - } +// @override +// Future getMainCameraEntity() { +// // TODO: implement getMainCameraEntity +// throw UnimplementedError(); +// } - @override - Future getMaterialInstanceAt(ThermionEntity entity, int index) { - // TODO: implement getMaterialInstanceAt - throw UnimplementedError(); - } +// @override +// Future getMaterialInstanceAt(ThermionEntity entity, int index) { +// // TODO: implement getMaterialInstanceAt +// throw UnimplementedError(); +// } - @override - // TODO: implement sceneUpdated - Stream get sceneUpdated => throw UnimplementedError(); +// @override +// // TODO: implement sceneUpdated +// Stream get sceneUpdated => throw UnimplementedError(); - @override - Future setLayerVisibility(int layer, bool visible) { - // TODO: implement setLayerVisibility - throw UnimplementedError(); - } +// @override +// Future setLayerVisibility(int layer, bool visible) { +// // TODO: implement setLayerVisibility +// throw UnimplementedError(); +// } - @override - Future setMaterialPropertyInt(ThermionEntity entity, String propertyName, int materialIndex, int value) { - // TODO: implement setMaterialPropertyInt - throw UnimplementedError(); - } +// @override +// Future setMaterialPropertyInt(ThermionEntity entity, String propertyName, int materialIndex, int value) { +// // TODO: implement setMaterialPropertyInt +// throw UnimplementedError(); +// } - @override - Future setVisibilityLayer(ThermionEntity entity, int layer) { - // TODO: implement setVisibilityLayer - throw UnimplementedError(); - } +// @override +// Future setVisibilityLayer(ThermionEntity entity, int layer) { +// // TODO: implement setVisibilityLayer +// throw UnimplementedError(); +// } - @override - Future setCameraLensProjection({double near = kNear, double far = kFar, double? aspect, double focalLength = kFocalLength}) { - // TODO: implement setCameraLensProjection - throw UnimplementedError(); - } +// @override +// Future setCameraLensProjection({double near = kNear, double far = kFar, double? aspect, double focalLength = kFocalLength}) { +// // TODO: implement setCameraLensProjection +// throw UnimplementedError(); +// } - @override - Future createCamera() { - // TODO: implement createCamera - throw UnimplementedError(); - } +// @override +// Future createCamera() { +// // TODO: implement createCamera +// throw UnimplementedError(); +// } - @override - Future registerRequestFrameHook(Future Function() hook) { - // TODO: implement registerRequestFrameHook - throw UnimplementedError(); - } +// @override +// Future registerRequestFrameHook(Future Function() hook) { +// // TODO: implement registerRequestFrameHook +// throw UnimplementedError(); +// } - @override - Future requestFrame() { - // TODO: implement requestFrame - throw UnimplementedError(); - } +// @override +// Future requestFrame() { +// // TODO: implement requestFrame +// throw UnimplementedError(); +// } - @override - Future setActiveCamera(covariant Camera camera) { - // TODO: implement setActiveCamera - throw UnimplementedError(); - } +// @override +// Future setActiveCamera(covariant Camera camera) { +// // TODO: implement setActiveCamera +// throw UnimplementedError(); +// } - @override - Future unregisterRequestFrameHook(Future Function() hook) { - // TODO: implement unregisterRequestFrameHook - throw UnimplementedError(); - } -} +// @override +// Future unregisterRequestFrameHook(Future Function() hook) { +// // TODO: implement unregisterRequestFrameHook +// throw UnimplementedError(); +// } +// } diff --git a/thermion_dart/lib/src/viewer/src/web_wasm/src/camera.dart b/thermion_dart/lib/src/viewer/src/web_wasm/src/camera.dart index 1b158caa..4db29392 100644 --- a/thermion_dart/lib/src/viewer/src/web_wasm/src/camera.dart +++ b/thermion_dart/lib/src/viewer/src/web_wasm/src/camera.dart @@ -69,4 +69,10 @@ class ThermionWasmCamera extends Camera { // TODO: implement getViewMatrix throw UnimplementedError(); } + + @override + Future setProjection(Projection projection, double left, double right, double bottom, double top, double near, double far) { + // TODO: implement setProjection + throw UnimplementedError(); + } } diff --git a/thermion_dart/lib/src/viewer/src/web_wasm/src/thermion_viewer_wasm.dart b/thermion_dart/lib/src/viewer/src/web_wasm/src/thermion_viewer_wasm.dart index 88814f29..0bc3eb8e 100644 --- a/thermion_dart/lib/src/viewer/src/web_wasm/src/thermion_viewer_wasm.dart +++ b/thermion_dart/lib/src/viewer/src/web_wasm/src/thermion_viewer_wasm.dart @@ -1,2490 +1,2490 @@ -import 'dart:async'; -import 'dart:js_interop'; -import 'dart:js_interop_unsafe'; -import 'dart:math'; -import 'dart:typed_data' as td; -import 'dart:typed_data'; -import 'package:logging/logging.dart'; -import 'package:web/web.dart'; -import 'package:animation_tools_dart/animation_tools_dart.dart'; - -import 'package:vector_math/vector_math_64.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import '../../shared_types/internal/gizmo.dart'; -import '../../shared_types/internal/gizmo.dart'; -import '../../../viewer.dart'; -import '../../events.dart'; -import '../../shared_types/camera.dart'; -import 'camera.dart'; -import 'material_instance.dart'; - -extension type _EmscriptenModule(JSObject _) implements JSObject { - external JSAny? ccall(String name, String returnType, - JSArray argTypes, JSArray args, JSAny? opts); - - external JSNumber _malloc(int numBytes); - external void _free(JSNumber addr); - external JSNumber stackAlloc(int numBytes); - - external JSAny getValue(JSNumber addr, String llvmType); - external void setValue(JSNumber addr, JSNumber value, String llvmType); - - external JSString intArrayToString(JSAny ptr); - external JSString UTF8ToString(JSAny ptr); - external void stringToUTF8( - JSString str, JSNumber ptr, JSNumber maxBytesToWrite); - external void writeArrayToMemory(JSUint8Array data, JSNumber ptr); - - external JSNumber addFunction(JSFunction f, String signature); - external void removeFunction(JSNumber f); - external JSAny get ALLOC_STACK; - external JSAny get HEAPU32; - external JSAny get HEAP32; -} - -typedef ThermionViewerImpl = ThermionViewerWasm; - -/// -/// A [ThermionViewer] implementation that forwards calls to the -/// (Emscripten-generated) ThermionDart JS module. -/// -class ThermionViewerWasm implements ThermionViewer { - final _logger = Logger("ThermionViewerWasm"); - - _EmscriptenModule? _module; - - bool _initialized = false; - bool _rendering = false; - - String? assetPathPrefix; - - late (double, double) viewportDimensions; - - late double pixelRatio; - - /// - /// Construct an instance of this class by explicitly passing the - /// module instance via the [module] property, or by specifying [moduleName], - /// being the name of the window property where the module has already been - /// loaded. - /// - /// Pass [assetPathPrefix] if you need to prepend a path to all asset paths - /// (e.g. on Flutter where the asset directory /foo is actually shipped under - /// the directory /assets/foo, you would construct this as: - /// - /// final viewer = ThermionViewerWasm(assetPathPrefix:"/assets/") - /// - ThermionViewerWasm({JSObject? module, this.assetPathPrefix}) { - if (module != null) { - _module = module as _EmscriptenModule; - } - } - - void _setAssetPathPrefix(String assetPathPrefix) { - _module!.ccall( - "thermion_dart_web_set_asset_path_prefix", - "void", - ["string".toJS].toJS, - [assetPathPrefix.toJS].toJS, - null); - } - - JSNumber? _viewer; - JSNumber? _sceneManager; - int _width = 0; - int _height = 0; - - Future initialize(double width, double height, double pixelRatio, - {String? uberArchivePath}) async { - if (!_initialized) { - await _initializeModule(); - _initialized = true; - if (assetPathPrefix != null) { - _setAssetPathPrefix(assetPathPrefix!); - } - } - this.pixelRatio = pixelRatio; - - final context = _module!.ccall("thermion_dart_web_create_gl_context", "int", - [].toJS, [].toJS, null); - final loader = _module!.ccall( - "thermion_dart_web_get_resource_loader_wrapper", - "void*", - [].toJS, - [].toJS, - null); - _viewer = _module!.ccall( - "create_filament_viewer", - "void*", - ["void*".toJS, "void*".toJS, "void*".toJS, "string".toJS].toJS, - [context!, loader, null, uberArchivePath?.toJS].toJS, - null) as JSNumber; - await createSwapChain(width.ceil(), height.ceil()); - updateViewportAndCameraProjection(width.ceil(), height.ceil(), 1.0); - _sceneManager = _module!.ccall("get_scene_manager", "void*", - ["void*".toJS].toJS, [_viewer!].toJS, null) as JSNumber; - - _pickCallbackPtr = _module!.addFunction(_onPickCallback.toJS, "viii"); - _pickGizmoCallbackPtr = - _module!.addFunction(_onPickGizmoCallback.toJS, "viii"); - - var gizmoOut = _module!._malloc(4 * 4); - - _module!.ccall("get_gizmo", "void", ["void*".toJS, "void*".toJS].toJS, - [_sceneManager!, gizmoOut].toJS, null); - - var x = _module!.getValue(gizmoOut, "i32") as JSNumber; - var y = _module!.getValue((gizmoOut.toDartInt + 4).toJS, "i32") as JSNumber; - var z = _module!.getValue((gizmoOut.toDartInt + 8).toJS, "i32") as JSNumber; - var center = - _module!.getValue((gizmoOut.toDartInt + 12).toJS, "i32") as JSNumber; - _gizmo = - Gizmo(x.toDartInt, y.toDartInt, z.toDartInt, center.toDartInt, this); - _module!._free(gizmoOut); - _initialized = true; - } - - Future _initializeModule() async { - var moduleScript = document.createElement("script") as HTMLScriptElement; - - globalContext["exports"] = JSObject(); - var module = JSObject(); - globalContext["module"] = module; - var content = await http.get(Uri.parse("thermion_dart.js")); - moduleScript.innerHTML = content.body.toJS; - document.head!.appendChild(moduleScript); - var instantiate = module.getProperty("exports".toJS) as JSFunction; - var moduleInstance = - instantiate.callAsFunction() as JSPromise<_EmscriptenModule>; - _module = await moduleInstance.toDart; - } - - Future createSwapChain(int width, int height) async { - _module!.ccall( - "create_swap_chain", - "void", - ["void*".toJS, "void*".toJS, "uint32_t".toJS, "uint32_t".toJS].toJS, - [_viewer!, null, width.toJS, height.toJS].toJS, - null); - } - - Future destroySwapChain() async { - if (_viewer == null) { - return; - } - _module!.ccall("destroy_swap_chain", "void", ["void*".toJS].toJS, - [_viewer!].toJS, null); - } - - void updateViewportAndCameraProjection( - int width, int height, double scaleFactor) { - if (width == 0 || height == 0) { - throw Exception("Width/height must be greater than zero"); - } - _width = (width * pixelRatio).ceil(); - _height = (height * pixelRatio).ceil(); - viewportDimensions = (_width.toDouble(), _height.toDouble()); - _module!.ccall( - "update_viewport_and_camera_projection", - "void", - ["void*".toJS, "uint32_t".toJS, "uint32_t".toJS, "float".toJS].toJS, - [_viewer!, _width.toJS, _height.toJS, scaleFactor.toJS].toJS, - null); - } - - @override - Future get initialized async { - return _initialized; - } - - /// - /// - /// - final _pickResultController = - StreamController.broadcast(); - - @override - Stream get pickResult { - return _pickResultController.stream; - } - - @override - Stream get gizmoPickResult => - _gizmoPickResultController.stream; - final _gizmoPickResultController = - StreamController.broadcast(); - - @override - bool get rendering => _rendering; - - @override - Future dispose() async { - if (_viewer == null) { - // we've already cleaned everything up, ignore the call to dispose - return; - } - await setRendering(false); - await clearEntities(); - await clearLights(); - _destroyViewer(); - - _sceneManager = null; - _viewer = null; - - for (final callback in _onDispose) { - await callback.call(); - } - _onDispose.clear(); - _module!.removeFunction(_pickCallbackPtr); - _module!.removeFunction(_pickGizmoCallbackPtr); - } - - void _destroyViewer() { - _module!.ccall("destroy_filament_viewer", "void", ["void*".toJS].toJS, - [_viewer].toJS, null); - } - - @override - Future setBackgroundColor(double r, double g, double b, double alpha) async { - _module!.ccall( - "set_background_color", - "void", - ["void*".toJS, "float".toJS, "float".toJS, "float".toJS, "float".toJS] - .toJS, - [_viewer!, r.toJS, g.toJS, b.toJS, alpha.toJS].toJS, - null); - } - - @override - Future addAnimationComponent(ThermionEntity entity) async { - _module!.ccall( - "add_animation_component", - "bool", - ["void*".toJS, "int32_t".toJS].toJS, - [_sceneManager!, entity.toJS].toJS, - null); - } - - Matrix4 _matrixFromPtr(JSNumber matPtr) { - final mat = Matrix4.zero(); - for (int i = 0; i < 16; i++) { - mat[i] = (_module!.getValue((matPtr.toDartInt + (i * 4)).toJS, "float") - as JSNumber) - .toDartDouble; - } - return mat; - } - - @override - Future> getRestLocalTransforms(ThermionEntity entity, - {int skinIndex = 0}) async { - var boneCountJS = _module!.ccall( - "get_bone_count", - "int", - ["void*".toJS, "int".toJS, "int".toJS].toJS, - [_sceneManager!, entity.toJS, skinIndex.toJS].toJS, - null) as JSNumber; - var boneCount = boneCountJS.toDartInt; - var buf = _module!._malloc(boneCount * 16 * 4); - _module!.ccall( - "get_rest_local_transforms", - "void", - ["void*".toJS, "int".toJS, "int".toJS, "float*".toJS, "int".toJS].toJS, - [_sceneManager!, entity.toJS, skinIndex.toJS, buf, boneCount.toJS].toJS, - null); - var transforms = []; - for (int i = 0; i < boneCount; i++) { - var matPtr = (buf.toDartInt + (i * 16 * 4)).toJS; - transforms.add(_matrixFromPtr(matPtr)); - } - _module!._free(buf); - return transforms; - } - - @override - Future getBone(ThermionEntity parent, int boneIndex, - {int skinIndex = 0}) async { - final boneId = _module!.ccall( - "get_bone", - "int", - ["void*".toJS, "int32_t".toJS, "int32_t".toJS, "int32_t".toJS].toJS, - [_sceneManager!, parent.toJS, skinIndex.toJS, boneIndex.toJS].toJS, - null) as JSNumber; - if (boneId.toDartInt == -1) { - throw Exception("Failed to get bone"); - } - return boneId.toDartInt; - } - - Future> getBones(ThermionEntity entity, - {int skinIndex = 0}) async { - final boneNames = await getBoneNames(entity); - final bones = await Future.wait(List.generate( - boneNames.length, (i) => getBone(entity, i, skinIndex: skinIndex))); - return bones; - } - - @override - Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation, - {int skinIndex = 0, - double fadeInInSecs = 0.0, - double fadeOutInSecs = 0.0, - double maxDelta = 1.0}) async { - final boneNames = await getBoneNames(entity); - final bones = await getBones(entity); - - var numBytes = animation.numFrames * 16 * 4; - var floatPtr = _module!._malloc(numBytes); - - var restLocalTransforms = await getRestLocalTransforms(entity); - - for (int i = 0; i < animation.bones.length; i++) { - final boneName = animation.bones[i]; - final entityBoneIndex = boneNames.indexOf(boneName); - - var boneEntity = bones[entityBoneIndex]; - - var baseTransform = restLocalTransforms[entityBoneIndex]; - - var world = Matrix4.identity(); - - // this odd use of ! is intentional, without it, the WASM optimizer gets in trouble - var parentBoneEntity = (await getParent(boneEntity))!; - while (true) { - if (!bones.contains(parentBoneEntity!)) { - break; - } - world = restLocalTransforms[bones.indexOf(parentBoneEntity!)] * world; - parentBoneEntity = (await getParent(parentBoneEntity))!; - } - - world = Matrix4.identity()..setRotation(world.getRotation()); - var worldInverse = Matrix4.identity()..copyInverse(world); - - for (int frameNum = 0; frameNum < animation.numFrames; frameNum++) { - var rotation = animation.frameData[frameNum][i].rotation; - var translation = animation.frameData[frameNum][i].translation; - var frameTransform = - Matrix4.compose(translation, rotation, Vector3.all(1.0)); - var newLocalTransform = frameTransform.clone(); - if (animation.space == Space.Bone) { - newLocalTransform = baseTransform * frameTransform; - } else if (animation.space == Space.ParentWorldRotation) { - newLocalTransform = - baseTransform * (worldInverse * frameTransform * world); - } - for (int j = 0; j < 16; j++) { - var offset = ((frameNum * 16) + j) * 4; - _module!.setValue((floatPtr.toDartInt + offset).toJS, - newLocalTransform.storage[j].toJS, "float"); - } - } - - _module!.ccall( - "add_bone_animation", - "void", - [ - "void*".toJS, - "int".toJS, - "int".toJS, - "int".toJS, - "float*".toJS, - "int".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS - ].toJS, - [ - _sceneManager!, - entity.toJS, - skinIndex.toJS, - entityBoneIndex.toJS, - floatPtr, - animation.numFrames.toJS, - animation.frameLengthInMs.toJS, - fadeOutInSecs.toJS, - fadeInInSecs.toJS, - maxDelta.toJS - ].toJS, - null); - } - _module!._free(floatPtr); - } - - @override - Future addCollisionComponent(ThermionEntity entity, - {void Function(int entityId1, int entityId2)? callback, - bool affectsTransform = false}) { - // TODO: implement addCollisionComponent - throw UnimplementedError(); - } - - @override - Future addLight( - LightType type, - double colour, - double intensity, - double posX, - double posY, - double posZ, - double dirX, - double dirY, - double dirZ, - {double falloffRadius = 1.0, - double spotLightConeInner = pi / 8, - double spotLightConeOuter = pi / 4, - double sunAngularRadius = 0.545, - double sunHaloSize = 10.0, - double sunHaloFallof = 80.0, - bool castShadows = true}) async { - final entityId = _module!.ccall( - "add_light", - "int", - [ - "void*".toJS, - "uint8_t".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "bool".toJS - ].toJS, - [ - _viewer, - type.index.toJS, - colour.toJS, - intensity.toJS, - posX.toJS, - posY.toJS, - posZ.toJS, - dirX.toJS, - dirY.toJS, - dirZ.toJS, - falloffRadius.toJS, - spotLightConeInner.toJS, - spotLightConeOuter.toJS, - sunAngularRadius.toJS, - sunHaloSize.toJS, - sunHaloFallof.toJS, - castShadows.toJS - ].toJS, - null) as JSNumber; - if (entityId.toDartInt == -1) { - throw Exception("Failed to add light"); - } - return entityId.toDartInt; - } - - @override - Future> getBoneNames(ThermionEntity entity, - {int skinIndex = 0}) async { - var boneCountJS = _module!.ccall( - "get_bone_count", - "int", - ["void*".toJS, "int".toJS, "int".toJS].toJS, - [_sceneManager!, entity.toJS, skinIndex.toJS].toJS, - null) as JSNumber; - var boneCount = boneCountJS.toDartInt; - var buf = _module!._malloc(boneCount * 4); - - var empty = " ".toJS; - var ptrs = []; - for (int i = 0; i < boneCount; i++) { - var ptr = _module!._malloc(256); - _module!.stringToUTF8(empty, ptr, 255.toJS); - ptrs.add(ptr); - _module!.setValue((buf.toDartInt + (i * 4)).toJS, ptr, "i32"); - } - _module!.ccall( - "get_bone_names", - "void", - ["void*".toJS, "int".toJS, "char**".toJS, "int".toJS].toJS, - [_sceneManager!, entity.toJS, buf, skinIndex.toJS].toJS, - null); - var names = []; - for (int i = 0; i < boneCount; i++) { - var name = _module!.UTF8ToString(ptrs[i]).toDart; - names.add(name); - } - - return names; - } - - @override - Future> getChildEntities( - ThermionEntity parent, bool renderableOnly) async { - var entityCountJS = _module!.ccall( - "get_entity_count", - "int", - ["void*".toJS, "int".toJS, "bool".toJS].toJS, - [_sceneManager!, parent.toJS, renderableOnly.toJS].toJS, - null) as JSNumber; - var entityCount = entityCountJS.toDartInt; - var entities = []; - var buf = _module!._malloc(entityCount * 4); - - _module!.ccall( - "get_entities", - "void", - ["void*".toJS, "int".toJS, "bool".toJS, "int*".toJS].toJS, - [_sceneManager!, parent.toJS, renderableOnly.toJS, buf].toJS, - null); - for (int i = 0; i < entityCount; i++) { - var entityId = - _module!.getValue((buf.toDartInt + (i * 4)).toJS, "i32") as JSNumber; - entities.add(entityId.toDartInt); - } - _module!._free(buf); - return entities; - } - - @override - Future getChildEntity( - ThermionEntity parent, String childName) async { - final entityId = _module!.ccall( - "find_child_entity_by_name", - "int", - ["void*".toJS, "int".toJS, "string".toJS].toJS, - [_sceneManager!, parent.toJS, childName.toJS].toJS, - null) as JSNumber; - if (entityId.toDartInt == -1) { - throw Exception("Failed to find child entity"); - } - return entityId.toDartInt; - } - - @override - Future> getChildEntityNames(ThermionEntity entity, - {bool renderableOnly = true}) async { - var entityCountJS = _module!.ccall( - "get_entity_count", - "int", - ["void*".toJS, "int".toJS, "bool".toJS].toJS, - [_sceneManager!, entity.toJS, renderableOnly.toJS].toJS, - null) as JSNumber; - var entityCount = entityCountJS.toDartInt; - var names = []; - for (int i = 0; i < entityCount; i++) { - var namePtr = _module!.ccall( - "get_entity_name_at", - "char*", - ["void*".toJS, "int".toJS, "int".toJS, "bool".toJS].toJS, - [_sceneManager!, entity.toJS, i.toJS, renderableOnly.toJS].toJS, - null) as JSNumber; - names.add(_module!.UTF8ToString(namePtr).toDart); - } - return names; - } - - @override - Future getMainCamera() async { - var mainCameraEntity = await getMainCameraEntity(); - return ThermionWasmCamera(mainCameraEntity); - } - - @override - Future> getMorphTargetNames( - ThermionEntity entity, ThermionEntity childEntity) async { - var morphTargetCountJS = _module!.ccall( - "get_morph_target_name_count", - "int", - ["void*".toJS, "int32_t".toJS, "int32_t".toJS].toJS, - [_sceneManager!, entity.toJS, childEntity.toJS].toJS, - null) as JSNumber; - var morphTargetCount = morphTargetCountJS.toDartInt; - var names = []; - for (int i = 0; i < morphTargetCount; i++) { - var buf = _module!._malloc(256); - _module!.ccall( - "get_morph_target_name", - "void", - [ - "void*".toJS, - "int32_t".toJS, - "int32_t".toJS, - "char*".toJS, - "int32_t".toJS - ].toJS, - [_sceneManager!, entity.toJS, childEntity.toJS, buf, i.toJS].toJS, - null); - names.add(_module!.UTF8ToString(buf).toDart); - _module!._free(buf); - } - return names; - } - - @override - String? getNameForEntity(ThermionEntity entity) { - final namePtr = _module!.ccall( - "get_name_for_entity", - "char*", - ["void*".toJS, "int32_t".toJS].toJS, - [_sceneManager!, entity.toJS].toJS, - null) as JSNumber; - if (namePtr.toDartInt == 0) { - return null; - } - return _module!.UTF8ToString(namePtr).toDart; - } - - @override - Future getParent(ThermionEntity child) async { - final parentId = _module!.ccall( - "get_parent", - "int", - ["void*".toJS, "int32_t".toJS].toJS, - [_sceneManager!, child.toJS].toJS, - null) as JSNumber; - if (parentId.toDartInt == -1) { - return null; - } - return parentId.toDartInt; - } - - @override - Future getWorldTransform(ThermionEntity entity) async { - final matrixPtr = _module!._malloc(16 * 4); - _module!.ccall( - "get_world_transform", - "void", - ["void*".toJS, "int32_t".toJS, "float*".toJS].toJS, - [_sceneManager!, entity.toJS, matrixPtr].toJS, - null); - final matrix = _matrixFromPtr(matrixPtr); - _module!._free(matrixPtr); - return matrix; - } - - @override - AbstractGizmo? get gizmo => _gizmo; - Gizmo? _gizmo; - - @override - Future hide(ThermionEntity entity, String? meshName) async { - if (meshName != null) { - final result = _module!.ccall( - "hide_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 hide mesh ${meshName} on entity ${entity.toJS}"); - } - } else { - throw Exception( - "Cannot hide mesh, meshName must be specified when invoking this method"); - } - } - - Future loadGlbFromBuffer(Uint8List data, - {int numInstances = 1, bool keepData= false, int layer=0, int priority=4}) async { - if (numInstances != 1) { - throw Exception("TODO"); - } - final ptr = _module!._malloc(data.length); - _module!.writeArrayToMemory(data.toJS, ptr); - - final result = _module!.ccall( - "load_glb_from_buffer", - "int", - ["void*".toJS, "void*".toJS, "size_t".toJS].toJS, - [_sceneManager!, ptr, data.lengthInBytes.toJS].toJS, - null) as JSNumber; - final entityId = result.toDartInt; - _module!._free(ptr); - if (entityId == -1) { - throw Exception("Failed to load GLB"); - } - return entityId; - } - - @override - Future loadGlb(String path, - {int numInstances = 1, bool keepData = false}) async { - final promise = _module!.ccall( - "load_glb", - "int", - ["void*".toJS, "string".toJS, "int".toJS].toJS, - [_sceneManager!, path.toJS, numInstances.toJS].toJS, - {"async": true}.jsify()) as JSPromise; - final entityId = (await promise.toDart).toDartInt; - if (entityId == -1) { - throw Exception("Failed to load GLB"); - } - return entityId; - } - - @override - Future loadGltf(String path, String relativeResourcePath, - {bool keepData = false}) async { - final promise = _module!.ccall( - "load_gltf", - "int", - ["void*".toJS, "string".toJS, "string".toJS].toJS, - [_sceneManager!, path.toJS, relativeResourcePath.toJS].toJS, - {"async": true}.jsify()) as JSPromise; - final entityId = (await promise.toDart).toDartInt; - if (entityId == -1) { - throw Exception("Failed to load GLTF"); - } - return entityId; - } - - @override - Future loadIbl(String lightingPath, {double intensity = 30000}) async { - var promise = _module!.ccall( - "load_ibl", - "void", - ["void*".toJS, "string".toJS, "float".toJS].toJS, - [_viewer!, lightingPath.toJS, intensity.toJS].toJS, - {"async": true}.jsify()) as JSPromise; - await promise.toDart; - } - - @override - Future loadSkybox(String skyboxPath) async { - var promise = _module!.ccall( - "load_skybox", - "void", - ["void*".toJS, "string".toJS].toJS, - [_viewer!, skyboxPath.toJS].toJS, - {"async": true}.jsify()) as JSPromise; - await promise.toDart; - } - - @override - Future playAnimation(ThermionEntity entity, int index, - {bool loop = false, - bool reverse = false, - bool replaceActive = true, - double crossfade = 0.0, - double startOffset = 0.0}) async { - _module!.ccall( - "play_animation", - "void", - [ - "void*".toJS, - "int32_t".toJS, - "int32_t".toJS, - "bool".toJS, - "bool".toJS, - "bool".toJS, - "float".toJS, - "float".toJS - ].toJS, - [ - _sceneManager!, - entity.toJS, - index.toJS, - loop.toJS, - reverse.toJS, - replaceActive.toJS, - crossfade.toJS - ].toJS, - null); - } - - int _last = 0; - - @override - Future render() async { - _last = DateTime.now().millisecondsSinceEpoch * 1000000; - _module!.ccall( - "render", - "void", - [ - "void*".toJS, - "uint64_t".toJS, - "void*".toJS, - "void*".toJS, - "void*".toJS - ].toJS, - [ - _viewer!, - 0.toJS, - null, // pixelBuffer, - null, // callback - null // data - ].toJS, - null); - } - - Future capture() async { - bool wasRendering = rendering; - await setRendering(false); - final pixelBuffer = _module!._malloc(_width * _height * 4); - final completer = Completer(); - final callback = () { - completer.complete(); - }; - final callbackPtr = _module!.addFunction(callback.toJS, "v"); - - _module!.ccall( - "capture", - "void", - ["void*".toJS, "uint8_t*".toJS, "void*".toJS].toJS, - [_viewer!, pixelBuffer, callbackPtr].toJS, - null); - - int iter = 0; - while (true) { - await Future.delayed(Duration(milliseconds: 5)); - await render(); - if (completer.isCompleted) { - break; - } - iter++; - if (iter > 1000) { - _module!._free(pixelBuffer); - throw Exception("Failed to complete capture"); - } - } - - // Create a Uint8ClampedList to store the pixel data - var data = Uint8List(_width * _height * 4); - for (int i = 0; i < data.length; i++) { - data[i] = (_module!.getValue(((pixelBuffer.toDartInt) + i).toJS, "i8") - as JSNumber) - .toDartInt; - } - _module!._free(pixelBuffer); - await setRendering(wasRendering); - print("Captured to ${data.length} pixel buffer"); - _module!.removeFunction(callbackPtr); - - return data; - } - - @override - Future setAntiAliasing(bool msaa, bool fxaa, bool taa) async { - _module!.ccall( - "set_antialiasing", - "void", - ["void*".toJS, "bool".toJS, "bool".toJS, "bool".toJS].toJS, - [_viewer!, msaa.toJS, fxaa.toJS, taa.toJS].toJS, - null); - } - - @override - Future setCameraPosition(double x, double y, double z) async { - _module!.ccall( - "set_camera_position", - "void", - ["void*".toJS, "float".toJS, "float".toJS, "float".toJS].toJS, - [_viewer!, x.toJS, y.toJS, z.toJS].toJS, - null); - } - - @override - Future setCameraRotation(Quaternion quaternion) async { - _module!.ccall( - "set_camera_rotation", - "void", - ["void*".toJS, "float".toJS, "float".toJS, "float".toJS, "float".toJS] - .toJS, - [ - _viewer!, - quaternion.w.toJS, - quaternion.x.toJS, - quaternion.y.toJS, - quaternion.z.toJS - ].toJS, - null); - } - - @override - Future clearMorphAnimationData(ThermionEntity entity) async { - var meshEntities = await getChildEntities(entity, false); - for (final childEntity in meshEntities) { - _module!.ccall( - "clear_morph_animation", - "void", - [ - "void*".toJS, - "int".toJS, - ].toJS, - [ - _sceneManager!, - childEntity.toJS, - ].toJS, - null); - } - } - - @override - Future setMorphAnimationData( - ThermionEntity entity, MorphAnimationData animation, - {List? targetMeshNames, bool useNextEntity = false}) async { - var meshNames = await getChildEntityNames(entity, renderableOnly: false); - if (targetMeshNames != null) { - for (final targetMeshName in targetMeshNames) { - if (!meshNames.contains(targetMeshName)) { - throw Exception( - "Error: mesh ${targetMeshName} does not exist under the specified entity. Available meshes : ${meshNames}"); - } - } - } - - var meshEntities = await getChildEntities(entity, false); - - // Entities are not guaranteed to have the same morph targets (or share the same order), - // either from each other, or from those specified in [animation]. - // We therefore set morph targets separately for each mesh. - // For each mesh, allocate enough memory to hold FxM 32-bit floats - // (where F is the number of Frames, and M is the number of morph targets in the mesh). - // we call [extract] on [animation] to return frame data only for morph targets that present in both the mesh and the animation - for (int i = 0; i < meshNames.length; i++) { - var meshName = meshNames[i]; - var meshEntity = meshEntities[i]; - - if (targetMeshNames?.contains(meshName) == false) { - // _logger.info("Skipping $meshName, not contained in target"); - continue; - } - - if (useNextEntity) meshEntity += 1; - - var meshMorphTargets = await getMorphTargetNames(entity, meshEntity); - - _logger.info("Got mesh morph targets ${meshMorphTargets}"); - - var intersection = animation.morphTargets - .toSet() - .intersection(meshMorphTargets.toSet()) - .toList(); - - if (intersection.isEmpty) { - throw Exception( - """No morph targets specified in animation are present on mesh $meshName. - If you weren't intending to animate every mesh, specify [targetMeshNames] when invoking this method. - Animation morph targets: ${animation.morphTargets}\n - Mesh morph targets ${meshMorphTargets} - Child meshes: ${meshNames}"""); - } - - var indices = - intersection.map((m) => meshMorphTargets.indexOf(m)).toList(); - - var frameData = animation.extract(morphTargets: intersection); - - assert(frameData.length == animation.numFrames * intersection.length); - - // Allocate memory in WASM for the morph data - var dataPtr = _module!._malloc(frameData.length * 4); - - // Create a Float32List to copy the morph data to - var dataList = td.Float32List.fromList(frameData); - - // Copy the morph data to WASM - _module!.writeArrayToMemory( - dataList.buffer.asUint8List(dataList.offsetInBytes).toJS, dataPtr); - - // Allocate memory in WASM for the morph indices - var idxPtr = _module!._malloc(indices.length * 4); - - // Create an Int32List to copy the morph indices to - var idxList = td.Int32List.fromList(indices); - - // Copy the morph indices to WASM - _module!.writeArrayToMemory( - idxList.buffer.asUint8List(idxList.offsetInBytes).toJS, idxPtr); - bool result = false; - try { - var jsResult = _module!.ccall( - "set_morph_animation", - "bool", - [ - "void*".toJS, - "int".toJS, - "float*".toJS, - "int*".toJS, - "int".toJS, - "int".toJS, - "float".toJS - ].toJS, - [ - _sceneManager!, - meshEntity.toJS, - dataPtr, - idxPtr, - indices.length.toJS, - animation.numFrames.toJS, - animation.frameLengthInMs.toJS - ].toJS, - null); - _logger.info("Got jsResult $jsResult"); - result = (jsResult as JSNumber).toDartInt == 1; - } catch (err, st) { - _logger.severe(err); - _logger.severe(st); - } - - // Free the memory allocated in WASM - _module!._free(dataPtr); - _module!._free(idxPtr); - - if (!result) { - throw Exception("Failed to set morph animation data for ${meshName}"); - } - } - } - - @override - Future setPosition( - ThermionEntity entity, double x, double y, double z) async { - _module!.ccall( - "set_position", - "void", - ["void*".toJS, "int".toJS, "float".toJS, "float".toJS, "float".toJS] - .toJS, - [_sceneManager!, entity.toJS, x.toJS, y.toJS, z.toJS].toJS, - null); - } - - @override - Future setPostProcessing(bool enabled) async { - _module!.ccall("set_post_processing", "void", - ["void*".toJS, "bool".toJS].toJS, [_viewer!, enabled.toJS].toJS, null); - } - - @override - Future setRotation( - ThermionEntity entity, double rads, double x, double y, double z) async { - var quaternion = Quaternion.axisAngle(Vector3(x, y, z), rads); - _module!.ccall( - "set_rotation", - "void", - [ - "void*".toJS, - "int".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS - ].toJS, - [ - _sceneManager!, - entity.toJS, - quaternion.radians.toJS, - quaternion.x.toJS, - quaternion.y.toJS, - quaternion.z.toJS, - quaternion.w.toJS - ].toJS, - null); - } - - @override - Future setRotationQuat(ThermionEntity entity, Quaternion rotation) async { - _module!.ccall( - "set_rotation", - "void", - [ - "void*".toJS, - "int".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS - ].toJS, - [ - _sceneManager!, - entity.toJS, - rotation.radians.toJS, - rotation.x.toJS, - rotation.y.toJS, - rotation.z.toJS, - rotation.w.toJS - ].toJS, - null); - } - - final _onDispose = []; - - /// - /// - /// - void onDispose(Future Function() callback) { - _onDispose.add(callback); - } - - @override - 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(Geometry geometry, - {MaterialInstance? materialInstance, - bool keepData = false, - PrimitiveType primitiveType = PrimitiveType.TRIANGLES}) async { - final verticesData = td.Float32List.fromList(geometry.vertices); - final indicesData = Uint16List.fromList(geometry.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, - verticesData.length.toJS, - indicesPtr, - indicesData.length.toJS, - primitiveType.index.toJS, - (materialInstance as ThermionWasmMaterialInstance?)?.pointer.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); - _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); - _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); - _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!.ccall("get_camera_model_matrix", "void*", - ["void*".toJS].toJS, [_viewer!].toJS, null) as JSNumber; - final matrix = _matrixFromPtr(ptr); - _module!.ccall( - "thermion_flutter_free", "void", ["void*".toJS].toJS, [ptr].toJS, null); - - return matrix; - } - - @override - Future getCameraPosition() async { - final ptr = _module!._malloc(3 * 8); - _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); - _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); - _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); - _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); - _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); - _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() async { - _module! - .ccall("grab_end", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); - } - - @override - Future panStart(double x, double y) async { - _module!.ccall( - "grab_begin", - "void", - ["void*".toJS, "float".toJS, "float".toJS, "bool".toJS].toJS, - [_viewer!, x.toJS, y.toJS, true.toJS].toJS, - null); - } - - @override - Future panUpdate(double x, double y) async { - _module!.ccall( - "grab_update", - "void", - ["void*".toJS, "float".toJS, "float".toJS].toJS, - [_viewer!, x.toJS, y.toJS].toJS, - null); - } - - late JSNumber _pickCallbackPtr; - - void _onPickCallback(ThermionEntity entity, int x, int y) { - _pickResultController - .add((entity: entity, x: x.toDouble(), y: y.toDouble())); - } - - @override - void pick(int x, int y) async { - x = (x * pixelRatio).ceil(); - y = (viewportDimensions.$2 - (y * pixelRatio)).ceil(); - _module!.ccall( - "filament_pick", - "void", - ["void*".toJS, "int".toJS, "int".toJS, "void*".toJS].toJS, - [_viewer!, x.toJS, y.toJS, _pickCallbackPtr].toJS, - null); - } - - @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 { - 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}"); - } - } - - @override - Future rotateIbl(Matrix3 rotation) async { - final ptr = _module!._malloc(9 * 4); - 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) async { - _module!.ccall( - "grab_begin", - "void", - ["void*".toJS, "float".toJS, "float".toJS, "bool".toJS].toJS, - [_viewer!, x.toJS, y.toJS, false.toJS].toJS, - null); - } - - @override - Future rotateUpdate(double x, double y) async { - _module!.ccall( - "grab_update", - "void", - ["void*".toJS, "float".toJS, "float".toJS].toJS, - [_viewer!, x.toJS, y.toJS].toJS, - null); - } - - @override - Future rotateEnd() async { - _module! - .ccall("grab_end", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); - } - - @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); - 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, {bool horizontal = true}) async { - _module!.ccall( - "set_camera_fov", - "void", - ["void*".toJS, "float".toJS, "bool".toJS].toJS, - [_viewer!, degrees.toJS, horizontal.toJS].toJS, - null); - } - - - @override - Future setCameraModelMatrix(List matrix) async { - assert(matrix.length == 16, "Matrix must have 16 elements"); - final ptr = _module!._malloc(16 * 8); - 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); - 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, - {bool preserveScaling = false}) async { - _module!.ccall( - "set_parent", - "void", - ["void*".toJS, "int".toJS, "int".toJS, "bool".toJS].toJS, - [_sceneManager!, child.toJS, parent.toJS, preserveScaling.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); - 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) async { - final namePtr = _allocateString(name); - _module!.ccall( - "stop_animation_by_name", - "void", - ["void*".toJS, "int".toJS, "char*".toJS].toJS, - [_sceneManager!, entity.toJS, namePtr].toJS, - null); - _module!._free(namePtr); - } - - @override - Future testCollisions(ThermionEntity entity) async { - final result = _module!.ccall( - "test_collisions", - "bool", - ["void*".toJS, "int".toJS].toJS, - [_sceneManager!, entity.toJS].toJS, - null) as JSBoolean; - return result.toDart; - } - - @override - Future transformToUnitCube(ThermionEntity entity) async { - _module!.ccall( - "transform_to_unit_cube", - "void", - ["void*".toJS, "int".toJS].toJS, - [_sceneManager!, entity.toJS].toJS, - null); - } - - @override - Future updateBoneMatrices(ThermionEntity entity) async { - _module!.ccall( - "update_bone_matrices", - "void", - ["void*".toJS, "int".toJS].toJS, - [_sceneManager!, entity.toJS].toJS, - null); - } - - @override - Future zoomBegin() async { - _module!.ccall( - "scroll_begin", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); - } - - @override - Future zoomEnd() async { - _module!.ccall( - "scroll_end", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); - } - - @override - Future zoomUpdate(double x, double y, double z) async { - _module!.ccall( - "scroll_update", - "void", - ["void*".toJS, "float".toJS, "float".toJS, "float".toJS].toJS, - [_viewer!, x.toJS, y.toJS, z.toJS].toJS, - null); - } - -// Helper method to allocate a string in the WASM memory - JSNumber _allocateString(String str) { - final bytes = utf8.encode(str); - final ptr = _module!._malloc(bytes.length + 1); - for (var i = 0; i < bytes.length; i++) { - _module!.setValue((ptr.toDartInt + i).toJS, bytes[i].toJS, "i8"); - } - _module!.setValue( - (ptr.toDartInt + bytes.length).toJS, 0.toJS, "i8"); // Null terminator - return ptr; - } - - @override - Future setShadowType(ShadowType shadowType) async { - _module!.ccall("set_shadow_type", "void", ["void*".toJS, "int".toJS].toJS, - [_viewer!, shadowType.index.toJS].toJS, null); - } - - @override - Future setShadowsEnabled(bool enabled) async { - _module!.ccall("set_shadows_enabled", "void", - ["void*".toJS, "bool".toJS].toJS, [_viewer!, enabled.toJS].toJS, null); - } - - @override - Future setSoftShadowOptions( - double penumbraScale, double penumbraRatioScale) async { - _module!.ccall( - "set_soft_shadow_options", - "void", - ["void*".toJS, "float".toJS, "float".toJS].toJS, - [_viewer!, penumbraScale.toJS, penumbraRatioScale.toJS].toJS, - null); - } - - @override - Future getBoundingBox(ThermionEntity entity) { - var minX = _module!._malloc(4); - var minY = _module!._malloc(4); - var maxX = _module!._malloc(4); - var maxY = _module!._malloc(4); - _module!.ccall( - "get_bounding_box_to_out", - "void", - [ - "void*".toJS, - "int".toJS, - "float*".toJS, - "float*".toJS, - "float*".toJS, - "float*".toJS - ].toJS, - [_sceneManager!, entity.toJS, minX, minY, maxX, maxY].toJS, - null); - - final min = Vector2( - (_module!.getValue(minX, "float") as JSNumber).toDartDouble, - (_module!.getValue(minY, "float") as JSNumber).toDartDouble); - final max = Vector2( - (_module!.getValue(maxX, "float") as JSNumber).toDartDouble, - (_module!.getValue(maxY, "float") as JSNumber).toDartDouble); - - final box = Aabb2.minMax(min, max); - _module!._free(minX); - _module!._free(minY); - _module!._free(maxX); - _module!._free(maxY); - - return Future.value(box); - } - - @override - Future getCameraFov(bool horizontal) async { - var fov = _module!.ccall( - "get_camera_fov", - "float", - ["void*".toJS, "bool".toJS].toJS, - [_viewer!, horizontal.toJS].toJS, - null); - return (fov as JSNumber).toDartDouble; - } - - @override - Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity, - double viewportX, double viewportY, double x, double y, double z) async { - _module!.ccall( - "queue_relative_position_update_world_axis", - "void", - [ - "void*".toJS, - "int".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS, - "float".toJS - ].toJS, - [ - _sceneManager!, - entity.toJS, - viewportX.toJS, - viewportY.toJS, - x.toJS, - y.toJS, - z.toJS - ].toJS, - null); - } - - @override - Future setLayerEnabled(int layer, bool enabled) async { - _module!.ccall( - "set_layer_visibility", - "void", - [ - "void*".toJS, - "int".toJS, - "bool".toJS, - ].toJS, - [ - _sceneManager!, - layer.toJS, - enabled.toJS, - ].toJS, - null); - } - - @override - Future createIbl(double r, double g, double b, double intensity) async { - _module!.ccall( - "create_ibl", - "void", - [ - "void*".toJS, - "double".toJS, - "double".toJS, - "double".toJS, - "double".toJS, - ].toJS, - [_sceneManager!, r.toJS, g.toJS, b.toJS, intensity.toJS].toJS, - null); - } - - late JSNumber _pickGizmoCallbackPtr; - - void _onPickGizmoCallback(ThermionEntity entity, int x, int y) { - _gizmoPickResultController - .add((entity: entity, x: x.toDouble(), y: y.toDouble())); - } - - @override - void pickGizmo(int x, int y) { - x = (x * pixelRatio).ceil(); - y = (viewportDimensions.$2 - (y * pixelRatio)).ceil(); - - _module!.ccall( - "pick_gizmo", - "void", - [ - "void*".toJS, - "int".toJS, - "int".toJS, - "void*".toJS, - ].toJS, - [_sceneManager!, x.toJS, y.toJS, _pickGizmoCallbackPtr].toJS, - null); - } - - @override - Future setGizmoVisibility(bool visible) async { - _module!.ccall( - "set_gizmo_visibility", - "void", - [ - "void*".toJS, - "bool".toJS, - ].toJS, - [_sceneManager!, visible.toJS].toJS, - null); - } - - @override - Future setLightDirection( - ThermionEntity lightEntity, Vector3 direction) async { - direction.normalize(); - _module!.ccall( - "set_light_direction", - "void", - ["void*".toJS, "double".toJS, "double".toJS, "double".toJS].toJS, - [_viewer!, direction.x.toJS, direction.y.toJS, direction.z.toJS].toJS, - null); - } - - @override - Future setLightPosition( - ThermionEntity lightEntity, double x, double y, double z) async { - _module!.ccall( - "set_light_position", - "void", - ["void*".toJS, "double".toJS, "double".toJS, "double".toJS].toJS, - [_viewer!, x.toJS, y.toJS, z.toJS].toJS, - null); - } - - @override - Future getAncestor(ThermionEntity entity) { - // TODO: implement getAncestor - throw UnimplementedError(); - } - - @override - Future queuePositionUpdateFromViewportCoords( - ThermionEntity entity, double x, double y) { - // TODO: implement queuePositionUpdateFromViewportCoords - throw UnimplementedError(); - } - - @override - Future removeStencilHighlight(ThermionEntity entity) { - // TODO: implement removeStencilHighlight - throw UnimplementedError(); - } - - @override - Future setStencilHighlight(ThermionEntity entity, - {double r = 1.0, double g = 0.0, double b = 0.0}) { - // TODO: implement setStencilHighlight - throw UnimplementedError(); - } - - @override - // TODO: implement entitiesAdded - Stream get entitiesAdded => throw UnimplementedError(); - - @override - // TODO: implement entitiesRemoved - Stream get entitiesRemoved => throw UnimplementedError(); - - @override - Future getCameraNear() { - // TODO: implement getCameraNear - throw UnimplementedError(); - } - - @override - Future getViewportBoundingBox(ThermionEntity entity) { - // TODO: implement getViewportBoundingBox - throw UnimplementedError(); - } - - @override - // TODO: implement lightsAdded - Stream get lightsAdded => throw UnimplementedError(); - - @override - // TODO: implement lightsRemoved - Stream get lightsRemoved => throw UnimplementedError(); - - @override - Future setCameraModelMatrix4(Matrix4 matrix) { - // TODO: implement setCameraModelMatrix4 - throw UnimplementedError(); - } - - @override - Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, - int materialIndex, double value) { - // TODO: implement setMaterialPropertyFloat - throw UnimplementedError(); - } - - @override - Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName, - int materialIndex, double f1, double f2, double f3, double f4) { - // TODO: implement setMaterialPropertyFloat4 - throw UnimplementedError(); - } - - @override - Future addDirectLight(DirectLight light) { - // TODO: implement addDirectLight - throw UnimplementedError(); - } - - @override - Future applyTexture(covariant ThermionTexture texture, ThermionEntity entity, - {int materialIndex = 0, String parameterName = "baseColorMap"}) { - // TODO: implement applyTexture - throw UnimplementedError(); - } - - @override - Future createTexture(td.Uint8List data) { - // TODO: implement createTexture - throw UnimplementedError(); - } - - @override - Future createUbershaderMaterialInstance( - {bool doubleSided = false, - bool unlit = false, - bool hasVertexColors = false, - bool hasBaseColorTexture = false, - bool hasNormalTexture = false, - bool hasOcclusionTexture = false, - bool hasEmissiveTexture = false, - bool useSpecularGlossiness = false, - AlphaMode alphaMode = AlphaMode.OPAQUE, - bool enableDiagnostics = false, - bool hasMetallicRoughnessTexture = false, - int metallicRoughnessUV = 0, - int baseColorUV = 0, - bool hasClearCoatTexture = false, - int clearCoatUV = 0, - bool hasClearCoatRoughnessTexture = false, - int clearCoatRoughnessUV = 0, - bool hasClearCoatNormalTexture = false, - int clearCoatNormalUV = 0, - bool hasClearCoat = false, - bool hasTransmission = false, - bool hasTextureTransforms = false, - int emissiveUV = 0, - int aoUV = 0, - int normalUV = 0, - bool hasTransmissionTexture = false, - int transmissionUV = 0, - bool hasSheenColorTexture = false, - int sheenColorUV = 0, - bool hasSheenRoughnessTexture = false, - int sheenRoughnessUV = 0, - bool hasVolumeThicknessTexture = false, - int volumeThicknessUV = 0, - bool hasSheen = false, - bool hasIOR = false, - bool hasVolume = false}) { - // TODO: implement createUbershaderMaterialInstance - throw UnimplementedError(); - } - - @override - Future createUnlitMaterialInstance() { - // TODO: implement createUnlitMaterialInstance - throw UnimplementedError(); - } - - @override - Future destroyMaterialInstance(covariant MaterialInstance materialInstance) { - // TODO: implement destroyMaterialInstance - throw UnimplementedError(); - } - - @override - Future destroyTexture(covariant ThermionTexture texture) { - // TODO: implement destroyTexture - throw UnimplementedError(); - } - - @override - Future getMainCameraEntity() async { - final entityId = _module!.ccall( - "get_main_camera", "int", ["void*".toJS].toJS, [_viewer].toJS, null) - as JSNumber; - if (entityId.toDartInt == -1) { - throw Exception("Failed to get main camera"); - } - return entityId.toDartInt; - } - - @override - Future getMaterialInstanceAt( - ThermionEntity entity, int index) { - // TODO: implement getMaterialInstanceAt - throw UnimplementedError(); - } - - @override - Future requestFrame() async { - // TODO: implement requestFrame - } - - @override - // TODO: implement sceneUpdated - Stream get sceneUpdated => throw UnimplementedError(); - - @override - Future setLayerVisibility(int layer, bool visible) { - // TODO: implement setLayerVisibility - throw UnimplementedError(); - } - - @override - Future setMaterialPropertyInt(ThermionEntity entity, String propertyName, - int materialIndex, int value) { - // TODO: implement setMaterialPropertyInt - throw UnimplementedError(); - } - - @override - Future setVisibilityLayer(ThermionEntity entity, int layer) { - // TODO: implement setVisibilityLayer - throw UnimplementedError(); - } +// import 'dart:async'; +// import 'dart:js_interop'; +// import 'dart:js_interop_unsafe'; +// import 'dart:math'; +// import 'dart:typed_data' as td; +// import 'dart:typed_data'; +// import 'package:logging/logging.dart'; +// import 'package:web/web.dart'; +// import 'package:animation_tools_dart/animation_tools_dart.dart'; + +// import 'package:vector_math/vector_math_64.dart'; +// import 'package:http/http.dart' as http; +// import 'dart:convert'; +// import '../../shared_types/internal/gizmo.dart'; +// import '../../shared_types/internal/gizmo.dart'; +// import '../../../viewer.dart'; +// import '../../events.dart'; +// import '../../shared_types/camera.dart'; +// import 'camera.dart'; +// import 'material_instance.dart'; + +// extension type _EmscriptenModule(JSObject _) implements JSObject { +// external JSAny? ccall(String name, String returnType, +// JSArray argTypes, JSArray args, JSAny? opts); + +// external JSNumber _malloc(int numBytes); +// external void _free(JSNumber addr); +// external JSNumber stackAlloc(int numBytes); + +// external JSAny getValue(JSNumber addr, String llvmType); +// external void setValue(JSNumber addr, JSNumber value, String llvmType); + +// external JSString intArrayToString(JSAny ptr); +// external JSString UTF8ToString(JSAny ptr); +// external void stringToUTF8( +// JSString str, JSNumber ptr, JSNumber maxBytesToWrite); +// external void writeArrayToMemory(JSUint8Array data, JSNumber ptr); + +// external JSNumber addFunction(JSFunction f, String signature); +// external void removeFunction(JSNumber f); +// external JSAny get ALLOC_STACK; +// external JSAny get HEAPU32; +// external JSAny get HEAP32; +// } + +// typedef ThermionViewerImpl = ThermionViewerWasm; + +// /// +// /// A [ThermionViewer] implementation that forwards calls to the +// /// (Emscripten-generated) ThermionDart JS module. +// /// +// class ThermionViewerWasm implements ThermionViewer { +// final _logger = Logger("ThermionViewerWasm"); + +// _EmscriptenModule? _module; + +// bool _initialized = false; +// bool _rendering = false; + +// String? assetPathPrefix; + +// late (double, double) viewportDimensions; + +// late double pixelRatio; + +// /// +// /// Construct an instance of this class by explicitly passing the +// /// module instance via the [module] property, or by specifying [moduleName], +// /// being the name of the window property where the module has already been +// /// loaded. +// /// +// /// Pass [assetPathPrefix] if you need to prepend a path to all asset paths +// /// (e.g. on Flutter where the asset directory /foo is actually shipped under +// /// the directory /assets/foo, you would construct this as: +// /// +// /// final viewer = ThermionViewerWasm(assetPathPrefix:"/assets/") +// /// +// ThermionViewerWasm({JSObject? module, this.assetPathPrefix}) { +// if (module != null) { +// _module = module as _EmscriptenModule; +// } +// } + +// void _setAssetPathPrefix(String assetPathPrefix) { +// _module!.ccall( +// "thermion_dart_web_set_asset_path_prefix", +// "void", +// ["string".toJS].toJS, +// [assetPathPrefix.toJS].toJS, +// null); +// } + +// JSNumber? _viewer; +// JSNumber? _sceneManager; +// int _width = 0; +// int _height = 0; + +// Future initialize(double width, double height, double pixelRatio, +// {String? uberArchivePath}) async { +// if (!_initialized) { +// await _initializeModule(); +// _initialized = true; +// if (assetPathPrefix != null) { +// _setAssetPathPrefix(assetPathPrefix!); +// } +// } +// this.pixelRatio = pixelRatio; + +// final context = _module!.ccall("thermion_dart_web_create_gl_context", "int", +// [].toJS, [].toJS, null); +// final loader = _module!.ccall( +// "thermion_dart_web_get_resource_loader_wrapper", +// "void*", +// [].toJS, +// [].toJS, +// null); +// _viewer = _module!.ccall( +// "create_filament_viewer", +// "void*", +// ["void*".toJS, "void*".toJS, "void*".toJS, "string".toJS].toJS, +// [context!, loader, null, uberArchivePath?.toJS].toJS, +// null) as JSNumber; +// await createSwapChain(width.ceil(), height.ceil()); +// updateViewportAndCameraProjection(width.ceil(), height.ceil(), 1.0); +// _sceneManager = _module!.ccall("get_scene_manager", "void*", +// ["void*".toJS].toJS, [_viewer!].toJS, null) as JSNumber; + +// _pickCallbackPtr = _module!.addFunction(_onPickCallback.toJS, "viii"); +// _pickGizmoCallbackPtr = +// _module!.addFunction(_onPickGizmoCallback.toJS, "viii"); + +// var gizmoOut = _module!._malloc(4 * 4); + +// _module!.ccall("get_gizmo", "void", ["void*".toJS, "void*".toJS].toJS, +// [_sceneManager!, gizmoOut].toJS, null); + +// var x = _module!.getValue(gizmoOut, "i32") as JSNumber; +// var y = _module!.getValue((gizmoOut.toDartInt + 4).toJS, "i32") as JSNumber; +// var z = _module!.getValue((gizmoOut.toDartInt + 8).toJS, "i32") as JSNumber; +// var center = +// _module!.getValue((gizmoOut.toDartInt + 12).toJS, "i32") as JSNumber; +// _gizmo = +// Gizmo(x.toDartInt, y.toDartInt, z.toDartInt, center.toDartInt, this); +// _module!._free(gizmoOut); +// _initialized = true; +// } + +// Future _initializeModule() async { +// var moduleScript = document.createElement("script") as HTMLScriptElement; + +// globalContext["exports"] = JSObject(); +// var module = JSObject(); +// globalContext["module"] = module; +// var content = await http.get(Uri.parse("thermion_dart.js")); +// moduleScript.innerHTML = content.body.toJS; +// document.head!.appendChild(moduleScript); +// var instantiate = module.getProperty("exports".toJS) as JSFunction; +// var moduleInstance = +// instantiate.callAsFunction() as JSPromise<_EmscriptenModule>; +// _module = await moduleInstance.toDart; +// } + +// Future createSwapChain(int width, int height) async { +// _module!.ccall( +// "create_swap_chain", +// "void", +// ["void*".toJS, "void*".toJS, "uint32_t".toJS, "uint32_t".toJS].toJS, +// [_viewer!, null, width.toJS, height.toJS].toJS, +// null); +// } + +// Future destroySwapChain() async { +// if (_viewer == null) { +// return; +// } +// _module!.ccall("destroy_swap_chain", "void", ["void*".toJS].toJS, +// [_viewer!].toJS, null); +// } + +// void updateViewportAndCameraProjection( +// int width, int height, double scaleFactor) { +// if (width == 0 || height == 0) { +// throw Exception("Width/height must be greater than zero"); +// } +// _width = (width * pixelRatio).ceil(); +// _height = (height * pixelRatio).ceil(); +// viewportDimensions = (_width.toDouble(), _height.toDouble()); +// _module!.ccall( +// "update_viewport_and_camera_projection", +// "void", +// ["void*".toJS, "uint32_t".toJS, "uint32_t".toJS, "float".toJS].toJS, +// [_viewer!, _width.toJS, _height.toJS, scaleFactor.toJS].toJS, +// null); +// } + +// @override +// Future get initialized async { +// return _initialized; +// } + +// /// +// /// +// /// +// final _pickResultController = +// StreamController.broadcast(); + +// @override +// Stream get pickResult { +// return _pickResultController.stream; +// } + +// @override +// Stream get gizmoPickResult => +// _gizmoPickResultController.stream; +// final _gizmoPickResultController = +// StreamController.broadcast(); + +// @override +// bool get rendering => _rendering; + +// @override +// Future dispose() async { +// if (_viewer == null) { +// // we've already cleaned everything up, ignore the call to dispose +// return; +// } +// await setRendering(false); +// await clearEntities(); +// await clearLights(); +// _destroyViewer(); + +// _sceneManager = null; +// _viewer = null; + +// for (final callback in _onDispose) { +// await callback.call(); +// } +// _onDispose.clear(); +// _module!.removeFunction(_pickCallbackPtr); +// _module!.removeFunction(_pickGizmoCallbackPtr); +// } + +// void _destroyViewer() { +// _module!.ccall("destroy_filament_viewer", "void", ["void*".toJS].toJS, +// [_viewer].toJS, null); +// } + +// @override +// Future setBackgroundColor(double r, double g, double b, double alpha) async { +// _module!.ccall( +// "set_background_color", +// "void", +// ["void*".toJS, "float".toJS, "float".toJS, "float".toJS, "float".toJS] +// .toJS, +// [_viewer!, r.toJS, g.toJS, b.toJS, alpha.toJS].toJS, +// null); +// } + +// @override +// Future addAnimationComponent(ThermionEntity entity) async { +// _module!.ccall( +// "add_animation_component", +// "bool", +// ["void*".toJS, "int32_t".toJS].toJS, +// [_sceneManager!, entity.toJS].toJS, +// null); +// } + +// Matrix4 _matrixFromPtr(JSNumber matPtr) { +// final mat = Matrix4.zero(); +// for (int i = 0; i < 16; i++) { +// mat[i] = (_module!.getValue((matPtr.toDartInt + (i * 4)).toJS, "float") +// as JSNumber) +// .toDartDouble; +// } +// return mat; +// } + +// @override +// Future> getRestLocalTransforms(ThermionEntity entity, +// {int skinIndex = 0}) async { +// var boneCountJS = _module!.ccall( +// "get_bone_count", +// "int", +// ["void*".toJS, "int".toJS, "int".toJS].toJS, +// [_sceneManager!, entity.toJS, skinIndex.toJS].toJS, +// null) as JSNumber; +// var boneCount = boneCountJS.toDartInt; +// var buf = _module!._malloc(boneCount * 16 * 4); +// _module!.ccall( +// "get_rest_local_transforms", +// "void", +// ["void*".toJS, "int".toJS, "int".toJS, "float*".toJS, "int".toJS].toJS, +// [_sceneManager!, entity.toJS, skinIndex.toJS, buf, boneCount.toJS].toJS, +// null); +// var transforms = []; +// for (int i = 0; i < boneCount; i++) { +// var matPtr = (buf.toDartInt + (i * 16 * 4)).toJS; +// transforms.add(_matrixFromPtr(matPtr)); +// } +// _module!._free(buf); +// return transforms; +// } + +// @override +// Future getBone(ThermionEntity parent, int boneIndex, +// {int skinIndex = 0}) async { +// final boneId = _module!.ccall( +// "get_bone", +// "int", +// ["void*".toJS, "int32_t".toJS, "int32_t".toJS, "int32_t".toJS].toJS, +// [_sceneManager!, parent.toJS, skinIndex.toJS, boneIndex.toJS].toJS, +// null) as JSNumber; +// if (boneId.toDartInt == -1) { +// throw Exception("Failed to get bone"); +// } +// return boneId.toDartInt; +// } + +// Future> getBones(ThermionEntity entity, +// {int skinIndex = 0}) async { +// final boneNames = await getBoneNames(entity); +// final bones = await Future.wait(List.generate( +// boneNames.length, (i) => getBone(entity, i, skinIndex: skinIndex))); +// return bones; +// } + +// @override +// Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation, +// {int skinIndex = 0, +// double fadeInInSecs = 0.0, +// double fadeOutInSecs = 0.0, +// double maxDelta = 1.0}) async { +// final boneNames = await getBoneNames(entity); +// final bones = await getBones(entity); + +// var numBytes = animation.numFrames * 16 * 4; +// var floatPtr = _module!._malloc(numBytes); + +// var restLocalTransforms = await getRestLocalTransforms(entity); + +// for (int i = 0; i < animation.bones.length; i++) { +// final boneName = animation.bones[i]; +// final entityBoneIndex = boneNames.indexOf(boneName); + +// var boneEntity = bones[entityBoneIndex]; + +// var baseTransform = restLocalTransforms[entityBoneIndex]; + +// var world = Matrix4.identity(); + +// // this odd use of ! is intentional, without it, the WASM optimizer gets in trouble +// var parentBoneEntity = (await getParent(boneEntity))!; +// while (true) { +// if (!bones.contains(parentBoneEntity!)) { +// break; +// } +// world = restLocalTransforms[bones.indexOf(parentBoneEntity!)] * world; +// parentBoneEntity = (await getParent(parentBoneEntity))!; +// } + +// world = Matrix4.identity()..setRotation(world.getRotation()); +// var worldInverse = Matrix4.identity()..copyInverse(world); + +// for (int frameNum = 0; frameNum < animation.numFrames; frameNum++) { +// var rotation = animation.frameData[frameNum][i].rotation; +// var translation = animation.frameData[frameNum][i].translation; +// var frameTransform = +// Matrix4.compose(translation, rotation, Vector3.all(1.0)); +// var newLocalTransform = frameTransform.clone(); +// if (animation.space == Space.Bone) { +// newLocalTransform = baseTransform * frameTransform; +// } else if (animation.space == Space.ParentWorldRotation) { +// newLocalTransform = +// baseTransform * (worldInverse * frameTransform * world); +// } +// for (int j = 0; j < 16; j++) { +// var offset = ((frameNum * 16) + j) * 4; +// _module!.setValue((floatPtr.toDartInt + offset).toJS, +// newLocalTransform.storage[j].toJS, "float"); +// } +// } + +// _module!.ccall( +// "add_bone_animation", +// "void", +// [ +// "void*".toJS, +// "int".toJS, +// "int".toJS, +// "int".toJS, +// "float*".toJS, +// "int".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS +// ].toJS, +// [ +// _sceneManager!, +// entity.toJS, +// skinIndex.toJS, +// entityBoneIndex.toJS, +// floatPtr, +// animation.numFrames.toJS, +// animation.frameLengthInMs.toJS, +// fadeOutInSecs.toJS, +// fadeInInSecs.toJS, +// maxDelta.toJS +// ].toJS, +// null); +// } +// _module!._free(floatPtr); +// } + +// @override +// Future addCollisionComponent(ThermionEntity entity, +// {void Function(int entityId1, int entityId2)? callback, +// bool affectsTransform = false}) { +// // TODO: implement addCollisionComponent +// throw UnimplementedError(); +// } + +// @override +// Future addLight( +// LightType type, +// double colour, +// double intensity, +// double posX, +// double posY, +// double posZ, +// double dirX, +// double dirY, +// double dirZ, +// {double falloffRadius = 1.0, +// double spotLightConeInner = pi / 8, +// double spotLightConeOuter = pi / 4, +// double sunAngularRadius = 0.545, +// double sunHaloSize = 10.0, +// double sunHaloFallof = 80.0, +// bool castShadows = true}) async { +// final entityId = _module!.ccall( +// "add_light", +// "int", +// [ +// "void*".toJS, +// "uint8_t".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "bool".toJS +// ].toJS, +// [ +// _viewer, +// type.index.toJS, +// colour.toJS, +// intensity.toJS, +// posX.toJS, +// posY.toJS, +// posZ.toJS, +// dirX.toJS, +// dirY.toJS, +// dirZ.toJS, +// falloffRadius.toJS, +// spotLightConeInner.toJS, +// spotLightConeOuter.toJS, +// sunAngularRadius.toJS, +// sunHaloSize.toJS, +// sunHaloFallof.toJS, +// castShadows.toJS +// ].toJS, +// null) as JSNumber; +// if (entityId.toDartInt == -1) { +// throw Exception("Failed to add light"); +// } +// return entityId.toDartInt; +// } + +// @override +// Future> getBoneNames(ThermionEntity entity, +// {int skinIndex = 0}) async { +// var boneCountJS = _module!.ccall( +// "get_bone_count", +// "int", +// ["void*".toJS, "int".toJS, "int".toJS].toJS, +// [_sceneManager!, entity.toJS, skinIndex.toJS].toJS, +// null) as JSNumber; +// var boneCount = boneCountJS.toDartInt; +// var buf = _module!._malloc(boneCount * 4); + +// var empty = " ".toJS; +// var ptrs = []; +// for (int i = 0; i < boneCount; i++) { +// var ptr = _module!._malloc(256); +// _module!.stringToUTF8(empty, ptr, 255.toJS); +// ptrs.add(ptr); +// _module!.setValue((buf.toDartInt + (i * 4)).toJS, ptr, "i32"); +// } +// _module!.ccall( +// "get_bone_names", +// "void", +// ["void*".toJS, "int".toJS, "char**".toJS, "int".toJS].toJS, +// [_sceneManager!, entity.toJS, buf, skinIndex.toJS].toJS, +// null); +// var names = []; +// for (int i = 0; i < boneCount; i++) { +// var name = _module!.UTF8ToString(ptrs[i]).toDart; +// names.add(name); +// } + +// return names; +// } + +// @override +// Future> getChildEntities( +// ThermionEntity parent, bool renderableOnly) async { +// var entityCountJS = _module!.ccall( +// "get_entity_count", +// "int", +// ["void*".toJS, "int".toJS, "bool".toJS].toJS, +// [_sceneManager!, parent.toJS, renderableOnly.toJS].toJS, +// null) as JSNumber; +// var entityCount = entityCountJS.toDartInt; +// var entities = []; +// var buf = _module!._malloc(entityCount * 4); + +// _module!.ccall( +// "get_entities", +// "void", +// ["void*".toJS, "int".toJS, "bool".toJS, "int*".toJS].toJS, +// [_sceneManager!, parent.toJS, renderableOnly.toJS, buf].toJS, +// null); +// for (int i = 0; i < entityCount; i++) { +// var entityId = +// _module!.getValue((buf.toDartInt + (i * 4)).toJS, "i32") as JSNumber; +// entities.add(entityId.toDartInt); +// } +// _module!._free(buf); +// return entities; +// } + +// @override +// Future getChildEntity( +// ThermionEntity parent, String childName) async { +// final entityId = _module!.ccall( +// "find_child_entity_by_name", +// "int", +// ["void*".toJS, "int".toJS, "string".toJS].toJS, +// [_sceneManager!, parent.toJS, childName.toJS].toJS, +// null) as JSNumber; +// if (entityId.toDartInt == -1) { +// throw Exception("Failed to find child entity"); +// } +// return entityId.toDartInt; +// } + +// @override +// Future> getChildEntityNames(ThermionEntity entity, +// {bool renderableOnly = true}) async { +// var entityCountJS = _module!.ccall( +// "get_entity_count", +// "int", +// ["void*".toJS, "int".toJS, "bool".toJS].toJS, +// [_sceneManager!, entity.toJS, renderableOnly.toJS].toJS, +// null) as JSNumber; +// var entityCount = entityCountJS.toDartInt; +// var names = []; +// for (int i = 0; i < entityCount; i++) { +// var namePtr = _module!.ccall( +// "get_entity_name_at", +// "char*", +// ["void*".toJS, "int".toJS, "int".toJS, "bool".toJS].toJS, +// [_sceneManager!, entity.toJS, i.toJS, renderableOnly.toJS].toJS, +// null) as JSNumber; +// names.add(_module!.UTF8ToString(namePtr).toDart); +// } +// return names; +// } + +// @override +// Future getMainCamera() async { +// var mainCameraEntity = await getMainCameraEntity(); +// return ThermionWasmCamera(mainCameraEntity); +// } + +// @override +// Future> getMorphTargetNames( +// ThermionEntity entity, ThermionEntity childEntity) async { +// var morphTargetCountJS = _module!.ccall( +// "get_morph_target_name_count", +// "int", +// ["void*".toJS, "int32_t".toJS, "int32_t".toJS].toJS, +// [_sceneManager!, entity.toJS, childEntity.toJS].toJS, +// null) as JSNumber; +// var morphTargetCount = morphTargetCountJS.toDartInt; +// var names = []; +// for (int i = 0; i < morphTargetCount; i++) { +// var buf = _module!._malloc(256); +// _module!.ccall( +// "get_morph_target_name", +// "void", +// [ +// "void*".toJS, +// "int32_t".toJS, +// "int32_t".toJS, +// "char*".toJS, +// "int32_t".toJS +// ].toJS, +// [_sceneManager!, entity.toJS, childEntity.toJS, buf, i.toJS].toJS, +// null); +// names.add(_module!.UTF8ToString(buf).toDart); +// _module!._free(buf); +// } +// return names; +// } + +// @override +// String? getNameForEntity(ThermionEntity entity) { +// final namePtr = _module!.ccall( +// "get_name_for_entity", +// "char*", +// ["void*".toJS, "int32_t".toJS].toJS, +// [_sceneManager!, entity.toJS].toJS, +// null) as JSNumber; +// if (namePtr.toDartInt == 0) { +// return null; +// } +// return _module!.UTF8ToString(namePtr).toDart; +// } + +// @override +// Future getParent(ThermionEntity child) async { +// final parentId = _module!.ccall( +// "get_parent", +// "int", +// ["void*".toJS, "int32_t".toJS].toJS, +// [_sceneManager!, child.toJS].toJS, +// null) as JSNumber; +// if (parentId.toDartInt == -1) { +// return null; +// } +// return parentId.toDartInt; +// } + +// @override +// Future getWorldTransform(ThermionEntity entity) async { +// final matrixPtr = _module!._malloc(16 * 4); +// _module!.ccall( +// "get_world_transform", +// "void", +// ["void*".toJS, "int32_t".toJS, "float*".toJS].toJS, +// [_sceneManager!, entity.toJS, matrixPtr].toJS, +// null); +// final matrix = _matrixFromPtr(matrixPtr); +// _module!._free(matrixPtr); +// return matrix; +// } + +// @override +// AbstractGizmo? get gizmo => _gizmo; +// Gizmo? _gizmo; + +// @override +// Future hide(ThermionEntity entity, String? meshName) async { +// if (meshName != null) { +// final result = _module!.ccall( +// "hide_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 hide mesh ${meshName} on entity ${entity.toJS}"); +// } +// } else { +// throw Exception( +// "Cannot hide mesh, meshName must be specified when invoking this method"); +// } +// } + +// Future loadGlbFromBuffer(Uint8List data, +// {int numInstances = 1, bool keepData= false, int layer=0, int priority=4}) async { +// if (numInstances != 1) { +// throw Exception("TODO"); +// } +// final ptr = _module!._malloc(data.length); +// _module!.writeArrayToMemory(data.toJS, ptr); + +// final result = _module!.ccall( +// "load_glb_from_buffer", +// "int", +// ["void*".toJS, "void*".toJS, "size_t".toJS].toJS, +// [_sceneManager!, ptr, data.lengthInBytes.toJS].toJS, +// null) as JSNumber; +// final entityId = result.toDartInt; +// _module!._free(ptr); +// if (entityId == -1) { +// throw Exception("Failed to load GLB"); +// } +// return entityId; +// } + +// @override +// Future loadGlb(String path, +// {int numInstances = 1, bool keepData = false}) async { +// final promise = _module!.ccall( +// "load_glb", +// "int", +// ["void*".toJS, "string".toJS, "int".toJS].toJS, +// [_sceneManager!, path.toJS, numInstances.toJS].toJS, +// {"async": true}.jsify()) as JSPromise; +// final entityId = (await promise.toDart).toDartInt; +// if (entityId == -1) { +// throw Exception("Failed to load GLB"); +// } +// return entityId; +// } + +// @override +// Future loadGltf(String path, String relativeResourcePath, +// {bool keepData = false}) async { +// final promise = _module!.ccall( +// "load_gltf", +// "int", +// ["void*".toJS, "string".toJS, "string".toJS].toJS, +// [_sceneManager!, path.toJS, relativeResourcePath.toJS].toJS, +// {"async": true}.jsify()) as JSPromise; +// final entityId = (await promise.toDart).toDartInt; +// if (entityId == -1) { +// throw Exception("Failed to load GLTF"); +// } +// return entityId; +// } + +// @override +// Future loadIbl(String lightingPath, {double intensity = 30000}) async { +// var promise = _module!.ccall( +// "load_ibl", +// "void", +// ["void*".toJS, "string".toJS, "float".toJS].toJS, +// [_viewer!, lightingPath.toJS, intensity.toJS].toJS, +// {"async": true}.jsify()) as JSPromise; +// await promise.toDart; +// } + +// @override +// Future loadSkybox(String skyboxPath) async { +// var promise = _module!.ccall( +// "load_skybox", +// "void", +// ["void*".toJS, "string".toJS].toJS, +// [_viewer!, skyboxPath.toJS].toJS, +// {"async": true}.jsify()) as JSPromise; +// await promise.toDart; +// } + +// @override +// Future playAnimation(ThermionEntity entity, int index, +// {bool loop = false, +// bool reverse = false, +// bool replaceActive = true, +// double crossfade = 0.0, +// double startOffset = 0.0}) async { +// _module!.ccall( +// "play_animation", +// "void", +// [ +// "void*".toJS, +// "int32_t".toJS, +// "int32_t".toJS, +// "bool".toJS, +// "bool".toJS, +// "bool".toJS, +// "float".toJS, +// "float".toJS +// ].toJS, +// [ +// _sceneManager!, +// entity.toJS, +// index.toJS, +// loop.toJS, +// reverse.toJS, +// replaceActive.toJS, +// crossfade.toJS +// ].toJS, +// null); +// } + +// int _last = 0; + +// @override +// Future render() async { +// _last = DateTime.now().millisecondsSinceEpoch * 1000000; +// _module!.ccall( +// "render", +// "void", +// [ +// "void*".toJS, +// "uint64_t".toJS, +// "void*".toJS, +// "void*".toJS, +// "void*".toJS +// ].toJS, +// [ +// _viewer!, +// 0.toJS, +// null, // pixelBuffer, +// null, // callback +// null // data +// ].toJS, +// null); +// } + +// Future capture() async { +// bool wasRendering = rendering; +// await setRendering(false); +// final pixelBuffer = _module!._malloc(_width * _height * 4); +// final completer = Completer(); +// final callback = () { +// completer.complete(); +// }; +// final callbackPtr = _module!.addFunction(callback.toJS, "v"); + +// _module!.ccall( +// "capture", +// "void", +// ["void*".toJS, "uint8_t*".toJS, "void*".toJS].toJS, +// [_viewer!, pixelBuffer, callbackPtr].toJS, +// null); + +// int iter = 0; +// while (true) { +// await Future.delayed(Duration(milliseconds: 5)); +// await render(); +// if (completer.isCompleted) { +// break; +// } +// iter++; +// if (iter > 1000) { +// _module!._free(pixelBuffer); +// throw Exception("Failed to complete capture"); +// } +// } + +// // Create a Uint8ClampedList to store the pixel data +// var data = Uint8List(_width * _height * 4); +// for (int i = 0; i < data.length; i++) { +// data[i] = (_module!.getValue(((pixelBuffer.toDartInt) + i).toJS, "i8") +// as JSNumber) +// .toDartInt; +// } +// _module!._free(pixelBuffer); +// await setRendering(wasRendering); +// print("Captured to ${data.length} pixel buffer"); +// _module!.removeFunction(callbackPtr); + +// return data; +// } + +// @override +// Future setAntiAliasing(bool msaa, bool fxaa, bool taa) async { +// _module!.ccall( +// "set_antialiasing", +// "void", +// ["void*".toJS, "bool".toJS, "bool".toJS, "bool".toJS].toJS, +// [_viewer!, msaa.toJS, fxaa.toJS, taa.toJS].toJS, +// null); +// } + +// @override +// Future setCameraPosition(double x, double y, double z) async { +// _module!.ccall( +// "set_camera_position", +// "void", +// ["void*".toJS, "float".toJS, "float".toJS, "float".toJS].toJS, +// [_viewer!, x.toJS, y.toJS, z.toJS].toJS, +// null); +// } + +// @override +// Future setCameraRotation(Quaternion quaternion) async { +// _module!.ccall( +// "set_camera_rotation", +// "void", +// ["void*".toJS, "float".toJS, "float".toJS, "float".toJS, "float".toJS] +// .toJS, +// [ +// _viewer!, +// quaternion.w.toJS, +// quaternion.x.toJS, +// quaternion.y.toJS, +// quaternion.z.toJS +// ].toJS, +// null); +// } + +// @override +// Future clearMorphAnimationData(ThermionEntity entity) async { +// var meshEntities = await getChildEntities(entity, false); +// for (final childEntity in meshEntities) { +// _module!.ccall( +// "clear_morph_animation", +// "void", +// [ +// "void*".toJS, +// "int".toJS, +// ].toJS, +// [ +// _sceneManager!, +// childEntity.toJS, +// ].toJS, +// null); +// } +// } + +// @override +// Future setMorphAnimationData( +// ThermionEntity entity, MorphAnimationData animation, +// {List? targetMeshNames, bool useNextEntity = false}) async { +// var meshNames = await getChildEntityNames(entity, renderableOnly: false); +// if (targetMeshNames != null) { +// for (final targetMeshName in targetMeshNames) { +// if (!meshNames.contains(targetMeshName)) { +// throw Exception( +// "Error: mesh ${targetMeshName} does not exist under the specified entity. Available meshes : ${meshNames}"); +// } +// } +// } + +// var meshEntities = await getChildEntities(entity, false); + +// // Entities are not guaranteed to have the same morph targets (or share the same order), +// // either from each other, or from those specified in [animation]. +// // We therefore set morph targets separately for each mesh. +// // For each mesh, allocate enough memory to hold FxM 32-bit floats +// // (where F is the number of Frames, and M is the number of morph targets in the mesh). +// // we call [extract] on [animation] to return frame data only for morph targets that present in both the mesh and the animation +// for (int i = 0; i < meshNames.length; i++) { +// var meshName = meshNames[i]; +// var meshEntity = meshEntities[i]; + +// if (targetMeshNames?.contains(meshName) == false) { +// // _logger.info("Skipping $meshName, not contained in target"); +// continue; +// } + +// if (useNextEntity) meshEntity += 1; + +// var meshMorphTargets = await getMorphTargetNames(entity, meshEntity); + +// _logger.info("Got mesh morph targets ${meshMorphTargets}"); + +// var intersection = animation.morphTargets +// .toSet() +// .intersection(meshMorphTargets.toSet()) +// .toList(); + +// if (intersection.isEmpty) { +// throw Exception( +// """No morph targets specified in animation are present on mesh $meshName. +// If you weren't intending to animate every mesh, specify [targetMeshNames] when invoking this method. +// Animation morph targets: ${animation.morphTargets}\n +// Mesh morph targets ${meshMorphTargets} +// Child meshes: ${meshNames}"""); +// } + +// var indices = +// intersection.map((m) => meshMorphTargets.indexOf(m)).toList(); + +// var frameData = animation.extract(morphTargets: intersection); + +// assert(frameData.length == animation.numFrames * intersection.length); + +// // Allocate memory in WASM for the morph data +// var dataPtr = _module!._malloc(frameData.length * 4); + +// // Create a Float32List to copy the morph data to +// var dataList = td.Float32List.fromList(frameData); + +// // Copy the morph data to WASM +// _module!.writeArrayToMemory( +// dataList.buffer.asUint8List(dataList.offsetInBytes).toJS, dataPtr); + +// // Allocate memory in WASM for the morph indices +// var idxPtr = _module!._malloc(indices.length * 4); + +// // Create an Int32List to copy the morph indices to +// var idxList = td.Int32List.fromList(indices); + +// // Copy the morph indices to WASM +// _module!.writeArrayToMemory( +// idxList.buffer.asUint8List(idxList.offsetInBytes).toJS, idxPtr); +// bool result = false; +// try { +// var jsResult = _module!.ccall( +// "set_morph_animation", +// "bool", +// [ +// "void*".toJS, +// "int".toJS, +// "float*".toJS, +// "int*".toJS, +// "int".toJS, +// "int".toJS, +// "float".toJS +// ].toJS, +// [ +// _sceneManager!, +// meshEntity.toJS, +// dataPtr, +// idxPtr, +// indices.length.toJS, +// animation.numFrames.toJS, +// animation.frameLengthInMs.toJS +// ].toJS, +// null); +// _logger.info("Got jsResult $jsResult"); +// result = (jsResult as JSNumber).toDartInt == 1; +// } catch (err, st) { +// _logger.severe(err); +// _logger.severe(st); +// } + +// // Free the memory allocated in WASM +// _module!._free(dataPtr); +// _module!._free(idxPtr); + +// if (!result) { +// throw Exception("Failed to set morph animation data for ${meshName}"); +// } +// } +// } + +// @override +// Future setPosition( +// ThermionEntity entity, double x, double y, double z) async { +// _module!.ccall( +// "set_position", +// "void", +// ["void*".toJS, "int".toJS, "float".toJS, "float".toJS, "float".toJS] +// .toJS, +// [_sceneManager!, entity.toJS, x.toJS, y.toJS, z.toJS].toJS, +// null); +// } + +// @override +// Future setPostProcessing(bool enabled) async { +// _module!.ccall("set_post_processing", "void", +// ["void*".toJS, "bool".toJS].toJS, [_viewer!, enabled.toJS].toJS, null); +// } + +// @override +// Future setRotation( +// ThermionEntity entity, double rads, double x, double y, double z) async { +// var quaternion = Quaternion.axisAngle(Vector3(x, y, z), rads); +// _module!.ccall( +// "set_rotation", +// "void", +// [ +// "void*".toJS, +// "int".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS +// ].toJS, +// [ +// _sceneManager!, +// entity.toJS, +// quaternion.radians.toJS, +// quaternion.x.toJS, +// quaternion.y.toJS, +// quaternion.z.toJS, +// quaternion.w.toJS +// ].toJS, +// null); +// } + +// @override +// Future setRotationQuat(ThermionEntity entity, Quaternion rotation) async { +// _module!.ccall( +// "set_rotation", +// "void", +// [ +// "void*".toJS, +// "int".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS +// ].toJS, +// [ +// _sceneManager!, +// entity.toJS, +// rotation.radians.toJS, +// rotation.x.toJS, +// rotation.y.toJS, +// rotation.z.toJS, +// rotation.w.toJS +// ].toJS, +// null); +// } + +// final _onDispose = []; + +// /// +// /// +// /// +// void onDispose(Future Function() callback) { +// _onDispose.add(callback); +// } + +// @override +// 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(Geometry geometry, +// {MaterialInstance? materialInstance, +// bool keepData = false, +// PrimitiveType primitiveType = PrimitiveType.TRIANGLES}) async { +// final verticesData = td.Float32List.fromList(geometry.vertices); +// final indicesData = Uint16List.fromList(geometry.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, +// verticesData.length.toJS, +// indicesPtr, +// indicesData.length.toJS, +// primitiveType.index.toJS, +// (materialInstance as ThermionWasmMaterialInstance?)?.pointer.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); +// _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); +// _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); +// _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!.ccall("get_camera_model_matrix", "void*", +// ["void*".toJS].toJS, [_viewer!].toJS, null) as JSNumber; +// final matrix = _matrixFromPtr(ptr); +// _module!.ccall( +// "thermion_flutter_free", "void", ["void*".toJS].toJS, [ptr].toJS, null); + +// return matrix; +// } + +// @override +// Future getCameraPosition() async { +// final ptr = _module!._malloc(3 * 8); +// _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); +// _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); +// _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); +// _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); +// _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); +// _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() async { +// _module! +// .ccall("grab_end", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); +// } + +// @override +// Future panStart(double x, double y) async { +// _module!.ccall( +// "grab_begin", +// "void", +// ["void*".toJS, "float".toJS, "float".toJS, "bool".toJS].toJS, +// [_viewer!, x.toJS, y.toJS, true.toJS].toJS, +// null); +// } + +// @override +// Future panUpdate(double x, double y) async { +// _module!.ccall( +// "grab_update", +// "void", +// ["void*".toJS, "float".toJS, "float".toJS].toJS, +// [_viewer!, x.toJS, y.toJS].toJS, +// null); +// } + +// late JSNumber _pickCallbackPtr; + +// void _onPickCallback(ThermionEntity entity, int x, int y) { +// _pickResultController +// .add((entity: entity, x: x.toDouble(), y: y.toDouble())); +// } + +// @override +// void pick(int x, int y) async { +// x = (x * pixelRatio).ceil(); +// y = (viewportDimensions.$2 - (y * pixelRatio)).ceil(); +// _module!.ccall( +// "filament_pick", +// "void", +// ["void*".toJS, "int".toJS, "int".toJS, "void*".toJS].toJS, +// [_viewer!, x.toJS, y.toJS, _pickCallbackPtr].toJS, +// null); +// } + +// @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 { +// 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}"); +// } +// } + +// @override +// Future rotateIbl(Matrix3 rotation) async { +// final ptr = _module!._malloc(9 * 4); +// 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) async { +// _module!.ccall( +// "grab_begin", +// "void", +// ["void*".toJS, "float".toJS, "float".toJS, "bool".toJS].toJS, +// [_viewer!, x.toJS, y.toJS, false.toJS].toJS, +// null); +// } + +// @override +// Future rotateUpdate(double x, double y) async { +// _module!.ccall( +// "grab_update", +// "void", +// ["void*".toJS, "float".toJS, "float".toJS].toJS, +// [_viewer!, x.toJS, y.toJS].toJS, +// null); +// } + +// @override +// Future rotateEnd() async { +// _module! +// .ccall("grab_end", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); +// } + +// @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); +// 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, {bool horizontal = true}) async { +// _module!.ccall( +// "set_camera_fov", +// "void", +// ["void*".toJS, "float".toJS, "bool".toJS].toJS, +// [_viewer!, degrees.toJS, horizontal.toJS].toJS, +// null); +// } + + +// @override +// Future setCameraModelMatrix(List matrix) async { +// assert(matrix.length == 16, "Matrix must have 16 elements"); +// final ptr = _module!._malloc(16 * 8); +// 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); +// 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, +// {bool preserveScaling = false}) async { +// _module!.ccall( +// "set_parent", +// "void", +// ["void*".toJS, "int".toJS, "int".toJS, "bool".toJS].toJS, +// [_sceneManager!, child.toJS, parent.toJS, preserveScaling.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); +// 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) async { +// final namePtr = _allocateString(name); +// _module!.ccall( +// "stop_animation_by_name", +// "void", +// ["void*".toJS, "int".toJS, "char*".toJS].toJS, +// [_sceneManager!, entity.toJS, namePtr].toJS, +// null); +// _module!._free(namePtr); +// } + +// @override +// Future testCollisions(ThermionEntity entity) async { +// final result = _module!.ccall( +// "test_collisions", +// "bool", +// ["void*".toJS, "int".toJS].toJS, +// [_sceneManager!, entity.toJS].toJS, +// null) as JSBoolean; +// return result.toDart; +// } + +// @override +// Future transformToUnitCube(ThermionEntity entity) async { +// _module!.ccall( +// "transform_to_unit_cube", +// "void", +// ["void*".toJS, "int".toJS].toJS, +// [_sceneManager!, entity.toJS].toJS, +// null); +// } + +// @override +// Future updateBoneMatrices(ThermionEntity entity) async { +// _module!.ccall( +// "update_bone_matrices", +// "void", +// ["void*".toJS, "int".toJS].toJS, +// [_sceneManager!, entity.toJS].toJS, +// null); +// } + +// @override +// Future zoomBegin() async { +// _module!.ccall( +// "scroll_begin", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); +// } + +// @override +// Future zoomEnd() async { +// _module!.ccall( +// "scroll_end", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); +// } + +// @override +// Future zoomUpdate(double x, double y, double z) async { +// _module!.ccall( +// "scroll_update", +// "void", +// ["void*".toJS, "float".toJS, "float".toJS, "float".toJS].toJS, +// [_viewer!, x.toJS, y.toJS, z.toJS].toJS, +// null); +// } + +// // Helper method to allocate a string in the WASM memory +// JSNumber _allocateString(String str) { +// final bytes = utf8.encode(str); +// final ptr = _module!._malloc(bytes.length + 1); +// for (var i = 0; i < bytes.length; i++) { +// _module!.setValue((ptr.toDartInt + i).toJS, bytes[i].toJS, "i8"); +// } +// _module!.setValue( +// (ptr.toDartInt + bytes.length).toJS, 0.toJS, "i8"); // Null terminator +// return ptr; +// } + +// @override +// Future setShadowType(ShadowType shadowType) async { +// _module!.ccall("set_shadow_type", "void", ["void*".toJS, "int".toJS].toJS, +// [_viewer!, shadowType.index.toJS].toJS, null); +// } + +// @override +// Future setShadowsEnabled(bool enabled) async { +// _module!.ccall("set_shadows_enabled", "void", +// ["void*".toJS, "bool".toJS].toJS, [_viewer!, enabled.toJS].toJS, null); +// } + +// @override +// Future setSoftShadowOptions( +// double penumbraScale, double penumbraRatioScale) async { +// _module!.ccall( +// "set_soft_shadow_options", +// "void", +// ["void*".toJS, "float".toJS, "float".toJS].toJS, +// [_viewer!, penumbraScale.toJS, penumbraRatioScale.toJS].toJS, +// null); +// } + +// @override +// Future getBoundingBox(ThermionEntity entity) { +// var minX = _module!._malloc(4); +// var minY = _module!._malloc(4); +// var maxX = _module!._malloc(4); +// var maxY = _module!._malloc(4); +// _module!.ccall( +// "get_bounding_box_to_out", +// "void", +// [ +// "void*".toJS, +// "int".toJS, +// "float*".toJS, +// "float*".toJS, +// "float*".toJS, +// "float*".toJS +// ].toJS, +// [_sceneManager!, entity.toJS, minX, minY, maxX, maxY].toJS, +// null); + +// final min = Vector2( +// (_module!.getValue(minX, "float") as JSNumber).toDartDouble, +// (_module!.getValue(minY, "float") as JSNumber).toDartDouble); +// final max = Vector2( +// (_module!.getValue(maxX, "float") as JSNumber).toDartDouble, +// (_module!.getValue(maxY, "float") as JSNumber).toDartDouble); + +// final box = Aabb2.minMax(min, max); +// _module!._free(minX); +// _module!._free(minY); +// _module!._free(maxX); +// _module!._free(maxY); + +// return Future.value(box); +// } + +// @override +// Future getCameraFov(bool horizontal) async { +// var fov = _module!.ccall( +// "get_camera_fov", +// "float", +// ["void*".toJS, "bool".toJS].toJS, +// [_viewer!, horizontal.toJS].toJS, +// null); +// return (fov as JSNumber).toDartDouble; +// } + +// @override +// Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity, +// double viewportX, double viewportY, double x, double y, double z) async { +// _module!.ccall( +// "queue_relative_position_update_world_axis", +// "void", +// [ +// "void*".toJS, +// "int".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS, +// "float".toJS +// ].toJS, +// [ +// _sceneManager!, +// entity.toJS, +// viewportX.toJS, +// viewportY.toJS, +// x.toJS, +// y.toJS, +// z.toJS +// ].toJS, +// null); +// } + +// @override +// Future setLayerEnabled(int layer, bool enabled) async { +// _module!.ccall( +// "set_layer_visibility", +// "void", +// [ +// "void*".toJS, +// "int".toJS, +// "bool".toJS, +// ].toJS, +// [ +// _sceneManager!, +// layer.toJS, +// enabled.toJS, +// ].toJS, +// null); +// } + +// @override +// Future createIbl(double r, double g, double b, double intensity) async { +// _module!.ccall( +// "create_ibl", +// "void", +// [ +// "void*".toJS, +// "double".toJS, +// "double".toJS, +// "double".toJS, +// "double".toJS, +// ].toJS, +// [_sceneManager!, r.toJS, g.toJS, b.toJS, intensity.toJS].toJS, +// null); +// } + +// late JSNumber _pickGizmoCallbackPtr; + +// void _onPickGizmoCallback(ThermionEntity entity, int x, int y) { +// _gizmoPickResultController +// .add((entity: entity, x: x.toDouble(), y: y.toDouble())); +// } + +// @override +// void pickGizmo(int x, int y) { +// x = (x * pixelRatio).ceil(); +// y = (viewportDimensions.$2 - (y * pixelRatio)).ceil(); + +// _module!.ccall( +// "pick_gizmo", +// "void", +// [ +// "void*".toJS, +// "int".toJS, +// "int".toJS, +// "void*".toJS, +// ].toJS, +// [_sceneManager!, x.toJS, y.toJS, _pickGizmoCallbackPtr].toJS, +// null); +// } + +// @override +// Future setGizmoVisibility(bool visible) async { +// _module!.ccall( +// "set_gizmo_visibility", +// "void", +// [ +// "void*".toJS, +// "bool".toJS, +// ].toJS, +// [_sceneManager!, visible.toJS].toJS, +// null); +// } + +// @override +// Future setLightDirection( +// ThermionEntity lightEntity, Vector3 direction) async { +// direction.normalize(); +// _module!.ccall( +// "set_light_direction", +// "void", +// ["void*".toJS, "double".toJS, "double".toJS, "double".toJS].toJS, +// [_viewer!, direction.x.toJS, direction.y.toJS, direction.z.toJS].toJS, +// null); +// } + +// @override +// Future setLightPosition( +// ThermionEntity lightEntity, double x, double y, double z) async { +// _module!.ccall( +// "set_light_position", +// "void", +// ["void*".toJS, "double".toJS, "double".toJS, "double".toJS].toJS, +// [_viewer!, x.toJS, y.toJS, z.toJS].toJS, +// null); +// } + +// @override +// Future getAncestor(ThermionEntity entity) { +// // TODO: implement getAncestor +// throw UnimplementedError(); +// } + +// @override +// Future queuePositionUpdateFromViewportCoords( +// ThermionEntity entity, double x, double y) { +// // TODO: implement queuePositionUpdateFromViewportCoords +// throw UnimplementedError(); +// } + +// @override +// Future removeStencilHighlight(ThermionEntity entity) { +// // TODO: implement removeStencilHighlight +// throw UnimplementedError(); +// } + +// @override +// Future setStencilHighlight(ThermionEntity entity, +// {double r = 1.0, double g = 0.0, double b = 0.0}) { +// // TODO: implement setStencilHighlight +// throw UnimplementedError(); +// } + +// @override +// // TODO: implement entitiesAdded +// Stream get entitiesAdded => throw UnimplementedError(); + +// @override +// // TODO: implement entitiesRemoved +// Stream get entitiesRemoved => throw UnimplementedError(); + +// @override +// Future getCameraNear() { +// // TODO: implement getCameraNear +// throw UnimplementedError(); +// } + +// @override +// Future getViewportBoundingBox(ThermionEntity entity) { +// // TODO: implement getViewportBoundingBox +// throw UnimplementedError(); +// } + +// @override +// // TODO: implement lightsAdded +// Stream get lightsAdded => throw UnimplementedError(); + +// @override +// // TODO: implement lightsRemoved +// Stream get lightsRemoved => throw UnimplementedError(); + +// @override +// Future setCameraModelMatrix4(Matrix4 matrix) { +// // TODO: implement setCameraModelMatrix4 +// throw UnimplementedError(); +// } + +// @override +// Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, +// int materialIndex, double value) { +// // TODO: implement setMaterialPropertyFloat +// throw UnimplementedError(); +// } + +// @override +// Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName, +// int materialIndex, double f1, double f2, double f3, double f4) { +// // TODO: implement setMaterialPropertyFloat4 +// throw UnimplementedError(); +// } + +// @override +// Future addDirectLight(DirectLight light) { +// // TODO: implement addDirectLight +// throw UnimplementedError(); +// } + +// @override +// Future applyTexture(covariant ThermionTexture texture, ThermionEntity entity, +// {int materialIndex = 0, String parameterName = "baseColorMap"}) { +// // TODO: implement applyTexture +// throw UnimplementedError(); +// } + +// @override +// Future createTexture(td.Uint8List data) { +// // TODO: implement createTexture +// throw UnimplementedError(); +// } + +// @override +// Future createUbershaderMaterialInstance( +// {bool doubleSided = false, +// bool unlit = false, +// bool hasVertexColors = false, +// bool hasBaseColorTexture = false, +// bool hasNormalTexture = false, +// bool hasOcclusionTexture = false, +// bool hasEmissiveTexture = false, +// bool useSpecularGlossiness = false, +// AlphaMode alphaMode = AlphaMode.OPAQUE, +// bool enableDiagnostics = false, +// bool hasMetallicRoughnessTexture = false, +// int metallicRoughnessUV = 0, +// int baseColorUV = 0, +// bool hasClearCoatTexture = false, +// int clearCoatUV = 0, +// bool hasClearCoatRoughnessTexture = false, +// int clearCoatRoughnessUV = 0, +// bool hasClearCoatNormalTexture = false, +// int clearCoatNormalUV = 0, +// bool hasClearCoat = false, +// bool hasTransmission = false, +// bool hasTextureTransforms = false, +// int emissiveUV = 0, +// int aoUV = 0, +// int normalUV = 0, +// bool hasTransmissionTexture = false, +// int transmissionUV = 0, +// bool hasSheenColorTexture = false, +// int sheenColorUV = 0, +// bool hasSheenRoughnessTexture = false, +// int sheenRoughnessUV = 0, +// bool hasVolumeThicknessTexture = false, +// int volumeThicknessUV = 0, +// bool hasSheen = false, +// bool hasIOR = false, +// bool hasVolume = false}) { +// // TODO: implement createUbershaderMaterialInstance +// throw UnimplementedError(); +// } + +// @override +// Future createUnlitMaterialInstance() { +// // TODO: implement createUnlitMaterialInstance +// throw UnimplementedError(); +// } + +// @override +// Future destroyMaterialInstance(covariant MaterialInstance materialInstance) { +// // TODO: implement destroyMaterialInstance +// throw UnimplementedError(); +// } + +// @override +// Future destroyTexture(covariant ThermionTexture texture) { +// // TODO: implement destroyTexture +// throw UnimplementedError(); +// } + +// @override +// Future getMainCameraEntity() async { +// final entityId = _module!.ccall( +// "get_main_camera", "int", ["void*".toJS].toJS, [_viewer].toJS, null) +// as JSNumber; +// if (entityId.toDartInt == -1) { +// throw Exception("Failed to get main camera"); +// } +// return entityId.toDartInt; +// } + +// @override +// Future getMaterialInstanceAt( +// ThermionEntity entity, int index) { +// // TODO: implement getMaterialInstanceAt +// throw UnimplementedError(); +// } + +// @override +// Future requestFrame() async { +// // TODO: implement requestFrame +// } + +// @override +// // TODO: implement sceneUpdated +// Stream get sceneUpdated => throw UnimplementedError(); + +// @override +// Future setLayerVisibility(int layer, bool visible) { +// // TODO: implement setLayerVisibility +// throw UnimplementedError(); +// } + +// @override +// Future setMaterialPropertyInt(ThermionEntity entity, String propertyName, +// int materialIndex, int value) { +// // TODO: implement setMaterialPropertyInt +// throw UnimplementedError(); +// } + +// @override +// Future setVisibilityLayer(ThermionEntity entity, int layer) { +// // TODO: implement setVisibilityLayer +// throw UnimplementedError(); +// } - @override - Future setCameraLensProjection({double near = kNear, double far = kFar, double? aspect, double focalLength = kFocalLength}) { - // TODO: implement setCameraLensProjection - throw UnimplementedError(); - } +// @override +// Future setCameraLensProjection({double near = kNear, double far = kFar, double? aspect, double focalLength = kFocalLength}) { +// // TODO: implement setCameraLensProjection +// throw UnimplementedError(); +// } - @override - Future createCamera() { - // TODO: implement createCamera - throw UnimplementedError(); - } +// @override +// Future createCamera() { +// // TODO: implement createCamera +// throw UnimplementedError(); +// } - @override - Future setActiveCamera(covariant Camera camera) { - // TODO: implement setActiveCamera - throw UnimplementedError(); - } +// @override +// Future setActiveCamera(covariant Camera camera) { +// // TODO: implement setActiveCamera +// throw UnimplementedError(); +// } - final _hooks = []; +// final _hooks = []; - @override - Future registerRequestFrameHook(Future Function() hook) async { - if (!_hooks.contains(hook)) { - _hooks.add(hook); - } - } +// @override +// Future registerRequestFrameHook(Future Function() hook) async { +// if (!_hooks.contains(hook)) { +// _hooks.add(hook); +// } +// } - @override - Future unregisterRequestFrameHook(Future Function() hook) async { - if (_hooks.contains(hook)) { - _hooks.remove(hook); - } - } -} +// @override +// Future unregisterRequestFrameHook(Future Function() hook) async { +// if (_hooks.contains(hook)) { +// _hooks.remove(hook); +// } +// } +// }