restructure viewer/types/helper folders, remove old WASM/web FFI interop, add SceneUpdated stream

This commit is contained in:
Nick Fisher
2024-09-16 11:07:54 +08:00
parent 285c9016d7
commit 475f90d224
37 changed files with 1675 additions and 3381 deletions

View File

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

View File

@@ -0,0 +1,89 @@
import 'dart:async';
import 'dart:ffi';
import 'package:ffi/ffi.dart';
export 'package:ffi/ffi.dart';
export 'dart:ffi';
export 'thermion_dart.g.dart';
final allocator = calloc;
void using(Pointer ptr, Future Function(Pointer ptr) function) async {
await function.call(ptr);
allocator.free(ptr);
}
Future<void> withVoidCallback(
Function(Pointer<NativeFunction<Void Function()>>) func) async {
final completer = Completer();
// ignore: prefer_function_declarations_over_variables
void Function() callback = () {
completer.complete();
};
final nativeCallable = NativeCallable<Void Function()>.listener(callback);
func.call(nativeCallable.nativeFunction);
await completer.future;
nativeCallable.close();
}
Future<int> withVoidPointerCallback(
Function(Pointer<NativeFunction<Void Function(Pointer<Void>)>>)
func) async {
final completer = Completer<Pointer<Void>>();
// ignore: prefer_function_declarations_over_variables
void Function(Pointer<Void>) callback = (Pointer<Void> ptr) {
completer.complete(ptr);
};
final nativeCallable =
NativeCallable<Void Function(Pointer<Void>)>.listener(callback);
func.call(nativeCallable.nativeFunction);
var ptr = await completer.future;
nativeCallable.close();
return ptr.address;
}
Future<bool> withBoolCallback(
Function(Pointer<NativeFunction<Void Function(Bool)>>) func) async {
final completer = Completer<bool>();
// ignore: prefer_function_declarations_over_variables
void Function(bool) callback = (bool result) {
completer.complete(result);
};
final nativeCallable = NativeCallable<Void Function(Bool)>.listener(callback);
func.call(nativeCallable.nativeFunction);
await completer.future;
nativeCallable.close();
return completer.future;
}
Future<int> withIntCallback(
Function(Pointer<NativeFunction<Void Function(Int32)>>) func) async {
final completer = Completer<int>();
// ignore: prefer_function_declarations_over_variables
void Function(int) callback = (int result) {
completer.complete(result);
};
final nativeCallable =
NativeCallable<Void Function(Int32)>.listener(callback);
func.call(nativeCallable.nativeFunction);
await completer.future;
nativeCallable.close();
return completer.future;
}
Future<String> withCharPtrCallback(
Function(Pointer<NativeFunction<Void Function(Pointer<Char>)>>)
func) async {
final completer = Completer<String>();
// ignore: prefer_function_declarations_over_variables
void Function(Pointer<Char>) callback = (Pointer<Char> result) {
completer.complete(result.cast<Utf8>().toDartString());
};
final nativeCallable =
NativeCallable<Void Function(Pointer<Char>)>.listener(callback);
func.call(nativeCallable.nativeFunction);
await completer.future;
nativeCallable.close();
return completer.future;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
library;
export 'geometry.dart';
export 'gltf.dart';
export 'light_options.dart';
// a handle that can be safely passed back to the rendering layer to manipulate an Entity
typedef ThermionEntity = int;

View File

@@ -0,0 +1,19 @@
import 'package:thermion_dart/thermion_dart/viewer/thermion_viewer_base.dart';
class Geometry {
final List<double> vertices;
final List<int> indices;
final List<double>? normals;
final List<(double, double)>? uvs;
final PrimitiveType primitiveType;
final String? materialPath;
Geometry(this.vertices, this.indices, { this.normals=null, this.uvs=null,
this.primitiveType = PrimitiveType.TRIANGLES, this.materialPath = null});
void scale(double factor) {
for (int i = 0; i < vertices.length; i++) {
vertices[i] = vertices[i] * factor;
}
}
}

View File

@@ -0,0 +1,6 @@
class GLTF {
final String uri;
final int numInstances;
GLTF(this.uri, this.numInstances);
}

View File

@@ -0,0 +1,7 @@
enum LightType {
SUN, //!< Directional light that also draws a sun's disk in the sky.
DIRECTIONAL, //!< Directional light, emits light in a given direction.
POINT, //!< Point light, emits light from a position, in all directions.
FOCUSED_SPOT, //!< Physically correct spot light.
SPOT,
}

View File

@@ -0,0 +1,56 @@
import 'dart:math';
import 'package:vector_math/vector_math_64.dart' as v;
import 'package:vector_math/vector_math_64.dart';
import 'light.dart';
class IBL {
String? iblPath;
final double iblIntensity;
IBL(this.iblIntensity);
}
class DirectLight {
final LightType type;
final double color;
final double intensity;
final bool castShadows;
late final v.Vector3 position;
late final v.Vector3 direction;
final double falloffRadius;
final double spotLightConeInner;
final double spotLightConeOuter;
final double sunAngularRadius;
final double sunHaloSize;
final double sunHaloFallof;
DirectLight({
required this.type,
required this.color,
required this.intensity,
this.castShadows = false,
required this.direction,
required this.position,
this.falloffRadius = 1.0,
this.spotLightConeInner = pi / 8,
this.spotLightConeOuter = pi / 4,
this.sunAngularRadius = 0.545,
this.sunHaloSize = 10.0,
this.sunHaloFallof = 80.0,
});
DirectLight.point({
double color = 6500,
double intensity = 100000,
bool castShadows = false,
Vector3? position,
double falloffRadius = 1.0,
}) : this(
type: LightType.POINT,
color: color,
intensity: intensity,
castShadows: castShadows,
position: position ?? Vector3(0, 1, 0),
direction: Vector3.zero(),
falloffRadius: falloffRadius,
);
}

View File

@@ -0,0 +1,4 @@
// see filament Manipulator.h for more details
@Deprecated(
"This is used the native pointer manipulator Prefer ThermionGestureHandler instead")
enum ManipulatorMode { ORBIT, MAP, FREE_FLIGHT }

View File

@@ -0,0 +1,4 @@
// "picking" means clicking/tapping on the viewport, and unprojecting the X/Y coordinate to determine whether any renderable entities were present at those coordinates.
import 'package:thermion_dart/thermion_dart/viewer/shared_types/shared_types.dart';
typedef FilamentPickResult = ({ThermionEntity entity, double x, double y});

View File

@@ -0,0 +1,10 @@
// copied from filament/backened/DriverEnums.h
enum PrimitiveType {
// don't change the enums values (made to match GL)
POINTS, //!< points
LINES, //!< lines
UNUSED1,
LINE_STRIP, //!< line strip
TRIANGLES, //!< triangles
TRIANGLE_STRIP, //!< triangle strip
}

View File

@@ -0,0 +1,6 @@
enum ShadowType {
PCF, //!< percentage-closer filtered shadows (default)
VSM, //!< variance shadows
DPCF, //!< PCF with contact hardening simulation
PCSS, //!< PCF with soft shadows and contact hardening
}

View File

@@ -0,0 +1,10 @@
library shared_types;
export 'entities.dart';
export 'light.dart';
export 'shadow.dart';
export 'manipulator.dart';
export 'pick_result.dart';
export 'primitive.dart';
export 'texture_details.dart';
export 'tone_mapper.dart';

View File

@@ -0,0 +1,14 @@
///
/// This represents the backing "surface" that we render into.
/// "Texture" here is a misnomer as it is only a render target texture on certain platforms.
///
class TextureDetails {
final int textureId;
// both width and height are in physical, not logical pixels
final int width;
final int height;
TextureDetails(
{required this.textureId, required this.width, required this.height});
}

View File

@@ -0,0 +1 @@
enum ToneMapper { ACES, FILMIC, LINEAR }

View File

@@ -0,0 +1,856 @@
import 'package:thermion_dart/thermion_dart/viewer/events.dart';
import 'shared_types/shared_types.dart';
export 'shared_types/shared_types.dart';
import 'dart:math';
import 'dart:typed_data';
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
import 'package:vector_math/vector_math_64.dart';
import 'dart:async';
import 'package:animation_tools_dart/animation_tools_dart.dart';
abstract class ThermionViewer {
///
/// A Future that resolves when the underlying rendering context has been successfully created.
///
Future<bool> get initialized;
///
/// The current dimensions of the viewport (in physical pixels).
///
var viewportDimensions = (0.0, 0.0);
///
/// The current ratio of logical to physical pixels.
///
late double pixelRatio;
///
/// The result(s) of calling [pick] (see below).
/// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick].
/// If [pick] is called without an active subscription to this stream, the results will be silently discarded.
///
Stream<FilamentPickResult> get pickResult;
///
/// The result(s) of calling [pickGizmo] (see below).
///
Stream<FilamentPickResult> get gizmoPickResult;
///
/// A Stream containing entities added/removed to/from to the scene.
///
Stream<SceneUpdateEvent> get sceneUpdated;
///
/// Whether the controller is currently rendering at [framerate].
///
bool get rendering;
///
/// Set to true to continuously render the scene at the framerate specified by [setFrameRate] (60 fps by default).
///
Future setRendering(bool render);
///
/// Render a single frame.
///
Future render();
///
/// Render a single frame to the viewport and copy the pixel buffer to [out].
///
Future<Uint8List> capture();
///
/// Sets the framerate for continuous rendering when [setRendering] is enabled.
///
Future setFrameRate(int framerate);
///
/// Destroys/disposes the viewer (including the entire scene). You cannot use the viewer after calling this method.
///
Future dispose();
///
/// Set the background image to [path] (which should have a file extension .png, .jpg, or .ktx).
/// This will be rendered at the maximum depth (i.e. behind all other objects including the skybox).
/// If [fillHeight] is false, the image will be rendered at its original size. Note this may cause issues with pixel density so be sure to specify the correct resolution
/// If [fillHeight] is true, the image will be stretched/compressed to fit the height of the viewport.
///
Future setBackgroundImage(String path, {bool fillHeight = false});
///
/// Moves the background image to the relative offset from the origin (bottom-left) specified by [x] and [y].
/// If [clamp] is true, the image cannot be positioned outside the bounds of the viewport.
///
Future setBackgroundImagePosition(double x, double y, {bool clamp = false});
///
/// Removes the background image.
///
Future clearBackgroundImage();
///
/// Sets the color for the background plane (positioned at the maximum depth, i.e. behind all other objects including the skybox).
///
Future setBackgroundColor(double r, double g, double b, double alpha);
///
/// Load a skybox from [skyboxPath] (which must be a .ktx file)
///
Future loadSkybox(String skyboxPath);
///
/// Removes the skybox from the scene.
///
Future removeSkybox();
///
/// Creates an indirect light by loading the reflections/irradiance from the KTX file.
/// Only one indirect light can be active at any given time; if an indirect light has already been loaded, it will be replaced.
///
Future loadIbl(String lightingPath, {double intensity = 30000});
///
/// Creates a indirect light with the given color.
/// Only one indirect light can be active at any given time; if an indirect light has already been loaded, it will be replaced.
///
Future createIbl(double r, double g, double b, double intensity);
///
/// Rotates the IBL & skybox.
///
Future rotateIbl(Matrix3 rotation);
///
/// Removes the image-based light from the scene.
///
Future removeIbl();
///
/// Add a light to the scene.
/// See LightManager.h for details
/// Note that [sunAngularRadius] is in degrees,
/// whereas [spotLightConeInner] and [spotLightConeOuter] are in radians
///
@Deprecated("This will be removed in future versions. Use addDirectLight instead.")
Future<ThermionEntity> 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});
///
/// Adds a direct light to the scene.
/// See LightManager.h for details
/// Note that [sunAngularRadius] is in degrees,
/// whereas [spotLightConeInner] and [spotLightConeOuter] are in radians
///
Future<ThermionEntity> addDirectLight(
DirectLight light);
///
/// Remove a light from the scene.
///
Future removeLight(ThermionEntity light);
///
/// Remove all lights (excluding IBL) from the scene.
///
Future clearLights();
///
/// Load the .glb asset at the given path and insert into the scene.
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
///
Future<ThermionEntity> loadGlb(String path,
{int numInstances = 1, bool keepData = false});
///
/// Load the .glb asset from the specified buffer and insert into the scene.
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
///
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data,
{int numInstances = 1, bool keepData = false});
///
/// Create a new instance of [entity].
///
Future<ThermionEntity> createInstance(ThermionEntity entity);
///
/// Returns the number of instances of the asset associated with [entity].
///
Future<int> getInstanceCount(ThermionEntity entity);
///
/// Returns all instances of [entity].
///
Future<List<ThermionEntity>> getInstances(ThermionEntity entity);
///
/// Load the .gltf asset at the given path and insert into the scene.
/// [relativeResourcePath] is the folder path where the glTF resources are stored;
/// this is usually the parent directory of the .gltf file itself.
///
/// See [loadGlb] for an explanation of [keepData].
///
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
{bool keepData = false});
///
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
///
Future panStart(double x, double y);
///
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
///
Future panUpdate(double x, double y);
///
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
///
Future panEnd();
///
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
///
Future rotateStart(double x, double y);
///
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
///
Future rotateUpdate(double x, double y);
///
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
///
Future rotateEnd();
///
/// Set the weights for all morph targets in [entity] to [weights].
/// Note that [weights] must contain values for ALL morph targets, but no exception will be thrown if you don't do so (you'll just get incorrect results).
/// If you only want to set one value, set all others to zero (check [getMorphTargetNames] if you need the get a list of all morph targets).
/// IMPORTANT - this accepts the actual ThermionEntity with the relevant morph targets (unlike [getMorphTargetNames], which uses the parent entity and the child mesh name).
/// Use [getChildEntityByName] if you are setting the weights for a child mesh.
///
Future setMorphTargetWeights(ThermionEntity entity, List<double> weights);
///
/// Gets the names of all morph targets for the child renderable [childEntity] under [entity].
///
Future<List<String>> getMorphTargetNames(
ThermionEntity entity, ThermionEntity childEntity);
///
/// Gets the names of all bones for the armature at [skinIndex] under the specified [entity].
///
Future<List<String>> getBoneNames(ThermionEntity entity, {int skinIndex = 0});
///
/// Gets the names of all glTF animations embedded in the specified entity.
///
Future<List<String>> getAnimationNames(ThermionEntity entity);
///
/// Returns the length (in seconds) of the animation at the given index.
///
Future<double> getAnimationDuration(
ThermionEntity entity, int animationIndex);
///
/// Animate the morph targets in [entity]. See [MorphTargetAnimation] for an explanation as to how to construct the animation frame data.
/// This method will check the morph target names specified in [animation] against the morph target names that actually exist exist under [meshName] in [entity],
/// throwing an exception if any cannot be found.
/// It is permissible for [animation] to omit any targets that do exist under [meshName]; these simply won't be animated.
///
Future setMorphAnimationData(
ThermionEntity entity, MorphAnimationData animation,
{List<String>? targetMeshNames});
///
/// Clear all current morph animations for [entity].
///
Future clearMorphAnimationData(ThermionEntity entity);
///
/// Resets all bones in the given entity to their rest pose.
/// This should be done before every call to addBoneAnimation.
///
Future resetBones(ThermionEntity entity);
///
/// Enqueues and plays the [animation] for the specified bone(s).
/// By default, frame data is interpreted as being in *parent* bone space;
/// a 45 degree around Y means the bone will rotate 45 degrees around the
/// Y axis of the parent bone *in its current orientation*.
/// (i.e NOT the parent bone's rest position!).
/// Currently, only [Space.ParentBone] and [Space.Model] are supported; if you want
/// to transform to another space, you will need to do so manually.
///
/// [fadeInInSecs]/[fadeOutInSecs]/[maxDelta] are used to cross-fade between
/// the current active glTF animation ("animation1") and the animation you
/// set via this method ("animation2"). The bone orientations will be
/// linearly interpolated between animation1 and animation2; at time 0,
/// the orientation will be 100% animation1, at time [fadeInInSecs], the
/// animation will be ((1 - maxDelta) * animation1) + (maxDelta * animation2).
/// This will be applied in reverse after [fadeOutInSecs].
///
///
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
{int skinIndex = 0,
double fadeInInSecs = 0.0,
double fadeOutInSecs = 0.0,
double maxDelta = 1.0});
///
/// Gets the entity representing the bone at [boneIndex]/[skinIndex].
/// The returned entity is only intended for use with [getWorldTransform].
///
Future<ThermionEntity> getBone(ThermionEntity parent, int boneIndex,
{int skinIndex = 0});
///
/// Gets the local (relative to parent) transform for [entity].
///
Future<Matrix4> getLocalTransform(ThermionEntity entity);
///
/// Gets the world transform for [entity].
///
Future<Matrix4> getWorldTransform(ThermionEntity entity);
///
/// Gets the inverse bind (pose) matrix for the bone.
/// Note that [parent] must be the ThermionEntity returned by [loadGlb/loadGltf], not any other method ([getChildEntity] etc).
/// This is because all joint information is internally stored with the parent entity.
///
Future<Matrix4> getInverseBindMatrix(ThermionEntity parent, int boneIndex,
{int skinIndex = 0});
///
/// Sets the transform (relative to its parent) for [entity].
///
Future setTransform(ThermionEntity entity, Matrix4 transform);
///
/// Updates the bone matrices for [entity] (which must be the ThermionEntity
/// returned by [loadGlb/loadGltf]).
/// Under the hood, this just calls [updateBoneMatrices] on the Animator
/// instance of the relevant FilamentInstance (which uses the local
/// bone transform and the inverse bind matrix to set the bone matrix).
///
Future updateBoneMatrices(ThermionEntity entity);
///
/// Directly set the bone matrix for the bone at the given index.
/// Don't call this manually unless you know what you're doing.
///
Future setBoneTransform(
ThermionEntity entity, int boneIndex, Matrix4 transform,
{int skinIndex = 0});
///
/// Removes/destroys the specified entity from the scene.
/// [entity] will no longer be a valid handle after this method is called; ensure you immediately discard all references once this method is complete.
///
Future removeEntity(ThermionEntity entity);
///
/// Removes/destroys all renderable entities from the scene (including cameras).
/// All [ThermionEntity] handles will no longer be valid after this method is called; ensure you immediately discard all references to all entities once this method is complete.
///
Future clearEntities();
///
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
///
Future zoomBegin();
///
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
///
Future zoomUpdate(double x, double y, double z);
///
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
///
Future zoomEnd();
///
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
///
Future playAnimation(ThermionEntity entity, int index,
{bool loop = false,
bool reverse = false,
bool replaceActive = true,
double crossfade = 0.0,
double startOffset = 0.0});
///
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
///
Future playAnimationByName(ThermionEntity entity, String name,
{bool loop = false,
bool reverse = false,
bool replaceActive = true,
double crossfade = 0.0});
Future setAnimationFrame(
ThermionEntity entity, int index, int animationFrame);
Future stopAnimation(ThermionEntity entity, int animationIndex);
Future stopAnimationByName(ThermionEntity entity, String name);
///
/// Sets the current scene camera to the glTF camera under [name] in [entity].
///
Future setCamera(ThermionEntity entity, String? name);
///
/// Sets the current scene camera to the main camera (which is always available and added to every scene by default).
///
Future setMainCamera();
///
/// Returns the entity associated with the main camera.
///
Future<ThermionEntity> getMainCamera();
///
/// Sets the horizontal field of view (if [horizontal] is true) or vertical field of view for the currently active camera to [degrees].
/// The aspect ratio of the current viewport is used.
///
Future setCameraFov(double degrees, {bool horizontal = true});
///
/// Gets the field of view (in degrees).
///
Future<double> getCameraFov(bool horizontal);
///
/// Sets the tone mapping (requires postprocessing).
///
Future setToneMapping(ToneMapper mapper);
///
/// Sets the strength of the bloom.
///
Future setBloom(double bloom);
///
/// Sets the focal length of the camera. Default value is 28.0.
///
Future setCameraFocalLength(double focalLength);
///
/// Sets the distance (in world units) to the near/far planes for the active camera. Default values are 0.05/1000.0. See Camera.h for details.
///
Future setCameraCulling(double near, double far);
///
/// Get the distance (in world units) to the near plane for the active camera.
///
@Deprecated("Use getCameraNear")
Future<double> getCameraCullingNear();
///
/// Get the distance (in world units) to the near plane for the active camera.
///
Future<double> getCameraNear();
///
/// Get the distance (in world units) to the far culling plane for the active camera.
///
Future<double> getCameraCullingFar();
///
///
///
Future setCameraLensProjection(
double near, double far, double aspect, double focalLength);
///
/// Sets the focus distance for the camera.
///
Future setCameraFocusDistance(double focusDistance);
///
/// Get the camera position in world space.
///
Future<Vector3> getCameraPosition();
///
/// Get the camera's model matrix.
///
Future<Matrix4> getCameraModelMatrix();
///
/// Get the camera's view matrix. See Camera.h for more details.
///
Future<Matrix4> getCameraViewMatrix();
///
/// Get the camera's projection matrix. See Camera.h for more details.
///
Future<Matrix4> getCameraProjectionMatrix();
///
/// Get the camera's culling projection matrix. See Camera.h for more details.
///
Future<Matrix4> getCameraCullingProjectionMatrix();
///
/// Get the camera's culling frustum in world space. Returns a (vector_math) [Frustum] instance where plane0-plane6 define the left, right, bottom, top, far and near planes respectively.
/// See Camera.h and (filament) Frustum.h for more details.
///
Future<Frustum> getCameraFrustum();
///
/// Set the camera position in world space. Note this is not persistent - any viewport navigation will reset the camera transform.
///
Future setCameraPosition(double x, double y, double z);
///
/// Get the camera rotation matrix.
///
Future<Matrix3> getCameraRotation();
///
/// Repositions the camera to the last vertex of the bounding box of [entity], looking at the penultimate vertex.
///
Future moveCameraToAsset(ThermionEntity entity);
///
/// Enables/disables frustum culling. Currently we don't expose a method for manipulating the camera projection/culling matrices so this is your only option to deal with unwanted near/far clipping.
///
Future setViewFrustumCulling(bool enabled);
///
/// Sets the camera exposure.
///
Future setCameraExposure(
double aperture, double shutterSpeed, double sensitivity);
///
/// Rotate the camera by [rads] around the given axis.
///
Future setCameraRotation(Quaternion quaternion);
///
/// Sets the camera model matrix.
///
@Deprecated("Will be superseded by setCameraModelMatrix4")
Future setCameraModelMatrix(List<double> matrix);
///
/// Sets the camera model matrix.
///
Future setCameraModelMatrix4(Matrix4 matrix);
///
/// Sets the `baseColorFactor` property for the material at index [materialIndex] in [entity] under node [meshName] to [color].
///
@Deprecated("Use setMaterialPropertyFloat4 instead")
Future setMaterialColor(ThermionEntity entity, String meshName,
int materialIndex, double r, double g, double b, double a);
///
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
/// [entity] must have a Renderable attached.
///
Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName,
int materialIndex, double f1, double f2, double f3, double f4);
///
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
/// [entity] must have a Renderable attached.
///
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName,
int materialIndex, double value);
///
/// Scale [entity] to fit within the unit cube.
///
Future transformToUnitCube(ThermionEntity entity);
///
/// Directly sets the world space position for [entity] to the given coordinates.
///
Future setPosition(ThermionEntity entity, double x, double y, double z);
///
/// Set the world space position for [lightEntity] to the given coordinates.
///
Future setLightPosition(
ThermionEntity lightEntity, double x, double y, double z);
///
/// Sets the world space direction for [lightEntity] to the given vector.
///
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction);
///
/// Directly sets the scale for [entity], skipping all collision detection.
///
Future setScale(ThermionEntity entity, double scale);
///
/// Directly sets the rotation for [entity] to [rads] around the axis {x,y,z}, skipping all collision detection.
///
Future setRotation(
ThermionEntity entity, double rads, double x, double y, double z);
///
/// Queues an update to the worldspace position for [entity] to {x,y,z}.
/// The actual update will occur on the next frame, and will be subject to collision detection.
///
Future queuePositionUpdate(
ThermionEntity entity, double x, double y, double z,
{bool relative = false});
///
/// TODO
///
Future queuePositionUpdateFromViewportCoords(
ThermionEntity entity, double x, double y);
///
/// TODO
///
Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity,
double viewportX, double viewportY, double x, double y, double z);
///
/// Queues an update to the worldspace rotation for [entity].
/// The actual update will occur on the next frame, and will be subject to collision detection.
///
Future queueRotationUpdate(
ThermionEntity entity, double rads, double x, double y, double z,
{bool relative = false});
///
/// Same as [queueRotationUpdate].
///
Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat,
{bool relative = false});
///
/// Enable/disable postprocessing (disabled by default).
///
Future setPostProcessing(bool enabled);
///
/// Enable/disable shadows (disabled by default).
///
Future setShadowsEnabled(bool enabled);
///
/// Set shadow type.
///
Future setShadowType(ShadowType shadowType);
///
/// Set soft shadow options (ShadowType DPCF and PCSS)
///
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale);
///
/// Set antialiasing options.
///
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
///
/// Sets the rotation for [entity] to the specified quaternion.
///
Future setRotationQuat(ThermionEntity entity, Quaternion rotation);
///
/// Reveal the node [meshName] under [entity]. Only applicable if [hide] had previously been called; this is a no-op otherwise.
///
Future reveal(ThermionEntity entity, String? meshName);
///
/// If [meshName] is provided, hide the node [meshName] under [entity], otherwise hide the root node for [entity].
/// The entity still exists in memory, but is no longer being rendered into the scene. Call [reveal] to re-commence rendering.
///
Future hide(ThermionEntity entity, String? meshName);
///
/// Used to select the entity in the scene at the given viewport coordinates.
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [pickResult] stream to receive the results of this method.
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
///
void pick(int x, int y);
///
/// Used to test whether a Gizmo is at the given viewport coordinates.
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [gizmoPickResult] stream to receive the results of this method.
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
///
void pickGizmo(int x, int y);
///
/// Retrieves the name assigned to the given ThermionEntity (usually corresponds to the glTF mesh name).
///
String? getNameForEntity(ThermionEntity entity);
///
/// Sets the options for manipulating the camera via the viewport.
/// ManipulatorMode.FREE_FLIGHT and ManipulatorMode.MAP are currently unsupported and will throw an exception.
///
@Deprecated("Use ThermionGestureHandler instead")
Future setCameraManipulatorOptions(
{ManipulatorMode mode = ManipulatorMode.ORBIT,
double orbitSpeedX = 0.01,
double orbitSpeedY = 0.01,
double zoomSpeed = 0.01});
///
/// Returns all child entities under [parent].
///
Future<List<ThermionEntity>> getChildEntities(
ThermionEntity parent, bool renderableOnly);
///
/// Finds the child entity named [childName] associated with the given parent.
/// Usually, [parent] will be the return value from [loadGlb]/[loadGltf] and [childName] will be the name of a node/mesh.
///
Future<ThermionEntity> getChildEntity(
ThermionEntity parent, String childName);
///
/// List the name of all child entities under the given entity.
///
Future<List<String>> getChildEntityNames(ThermionEntity entity,
{bool renderableOnly = true});
///
/// If [recording] is set to true, each frame the framebuffer/texture will be written to /tmp/output_*.png.
/// This will impact performance; handle with care.
///
Future setRecording(bool recording);
///
/// Sets the output directory where recorded PNGs will be placed.
///
Future setRecordingOutputDirectory(String outputDirectory);
///
/// An [entity] will only be animatable after an animation component is attached.
/// Any calls to [playAnimation]/[setBoneAnimation]/[setMorphAnimation] will have no visual effect until [addAnimationComponent] has been called on the instance.
///
Future addAnimationComponent(ThermionEntity entity);
///
/// Removes an animation component from [entity].
///
Future removeAnimationComponent(ThermionEntity entity);
///
/// Makes [entity] collidable.
/// This allows you to call [testCollisions] with any other entity ("entity B") to see if [entity] has collided with entity B. The callback will be invoked if so.
/// Alternatively, if [affectsTransform] is true and this entity collides with another entity, any queued position updates to the latter entity will be ignored.
///
Future addCollisionComponent(ThermionEntity entity,
{void Function(int entityId1, int entityId2)? callback,
bool affectsTransform = false});
///
/// Removes the collision component from [entity], meaning this will no longer be tested when [testCollisions] or [queuePositionUpdate] is called with another entity.
///
Future removeCollisionComponent(ThermionEntity entity);
///
/// Creates a (renderable) entity with the specified geometry and adds to the scene.
/// If [keepData] is true, the source data will not be released.
///
Future createGeometry(Geometry geometry, { bool keepData= false});
///
/// Gets the parent entity of [entity]. Returns null if the entity has no parent.
///
Future<ThermionEntity?> getParent(ThermionEntity entity);
///
/// Gets the ancestor (ultimate parent) entity of [entity]. Returns null if the entity has no parent.
///
Future<ThermionEntity?> getAncestor(ThermionEntity entity);
///
/// Sets the parent transform of [child] to [parent].
///
Future setParent(ThermionEntity child, ThermionEntity parent,
{bool preserveScaling});
///
/// Test all collidable entities against this entity to see if any have collided.
/// This method returns void; the relevant callback passed to [addCollisionComponent] will be fired if a collision is detected.
///
Future testCollisions(ThermionEntity entity);
///
/// Sets the draw priority for the given entity. See RenderableManager.h for more details.
///
Future setPriority(ThermionEntity entityId, int priority);
///
/// The gizmo for translating/rotating objects. Only one gizmo is present in the scene.
///
AbstractGizmo? get gizmo;
///
/// Register a callback to be invoked when this viewer is disposed.
///
void onDispose(Future Function() callback);
///
/// Gets the 2D bounding box (in viewport coordinates) for the given entity.
///
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity);
///
/// Filament assigns renderables to a numeric layer.
/// We place all scene assets in layer 0 (enabled by default), gizmos in layer 1 (enabled by default), world grid in layer 2 (disabled by default).
/// Use this method to toggle visibility of the respective layer.
///
Future setLayerEnabled(int layer, bool enabled);
///
/// Show/hide the translation gizmo.
///
Future setGizmoVisibility(bool visible);
///
/// Renders an outline around [entity] with the given color.
///
Future setStencilHighlight(ThermionEntity entity,
{double r = 1.0, double g = 0.0, double b = 0.0});
///
/// Removes the outline around [entity]. Noop if there was no highlight.
///
Future removeStencilHighlight(ThermionEntity entity);
}

View File

@@ -0,0 +1,890 @@
import 'dart:math';
import 'dart:typed_data';
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
import 'package:thermion_dart/thermion_dart/viewer/events.dart';
import 'package:thermion_dart/thermion_dart/viewer/thermion_viewer_base.dart';
import 'package:vector_math/vector_math_64.dart';
import 'dart:async';
import 'package:animation_tools_dart/animation_tools_dart.dart';
class ThermionViewerStub extends ThermionViewer {
@override
Future addAnimationComponent(ThermionEntity entity) {
// TODO: implement addAnimationComponent
throw UnimplementedError();
}
@override
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
{int skinIndex = 0,
double fadeInInSecs = 0.0,
double fadeOutInSecs = 0.0,
double maxDelta = 1.0}) {
// TODO: implement addBoneAnimation
throw UnimplementedError();
}
@override
Future addCollisionComponent(ThermionEntity entity,
{void Function(int entityId1, int entityId2)? callback,
bool affectsTransform = false}) {
// TODO: implement addCollisionComponent
throw UnimplementedError();
}
@override
Future<ThermionEntity> 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}) {
// TODO: implement addLight
throw UnimplementedError();
}
@override
Future clearBackgroundImage() {
// TODO: implement clearBackgroundImage
throw UnimplementedError();
}
@override
Future clearEntities() {
// TODO: implement clearEntities
throw UnimplementedError();
}
@override
Future clearLights() {
// TODO: implement clearLights
throw UnimplementedError();
}
@override
Future<ThermionEntity> createInstance(ThermionEntity entity) {
// TODO: implement createInstance
throw UnimplementedError();
}
@override
Future dispose() {
// TODO: implement dispose
throw UnimplementedError();
}
@override
Future<double> getAnimationDuration(
ThermionEntity entity, int animationIndex) {
// TODO: implement getAnimationDuration
throw UnimplementedError();
}
@override
Future<List<String>> getAnimationNames(ThermionEntity entity) {
// TODO: implement getAnimationNames
throw UnimplementedError();
}
@override
Future<ThermionEntity> getBone(ThermionEntity parent, int boneIndex,
{int skinIndex = 0}) {
// TODO: implement getBone
throw UnimplementedError();
}
@override
Future<List<String>> getBoneNames(ThermionEntity entity,
{int skinIndex = 0}) {
// TODO: implement getBoneNames
throw UnimplementedError();
}
@override
Future<double> getCameraCullingFar() {
// TODO: implement getCameraCullingFar
throw UnimplementedError();
}
@override
Future<double> getCameraCullingNear() {
// TODO: implement getCameraCullingNear
throw UnimplementedError();
}
@override
Future<Matrix4> getCameraCullingProjectionMatrix() {
// TODO: implement getCameraCullingProjectionMatrix
throw UnimplementedError();
}
@override
Future<Frustum> getCameraFrustum() {
// TODO: implement getCameraFrustum
throw UnimplementedError();
}
@override
Future<Matrix4> getCameraModelMatrix() {
// TODO: implement getCameraModelMatrix
throw UnimplementedError();
}
@override
Future<Vector3> getCameraPosition() {
// TODO: implement getCameraPosition
throw UnimplementedError();
}
@override
Future<Matrix4> getCameraProjectionMatrix() {
// TODO: implement getCameraProjectionMatrix
throw UnimplementedError();
}
@override
Future<Matrix3> getCameraRotation() {
// TODO: implement getCameraRotation
throw UnimplementedError();
}
@override
Future<Matrix4> getCameraViewMatrix() {
// TODO: implement getCameraViewMatrix
throw UnimplementedError();
}
@override
Future<List<ThermionEntity>> getChildEntities(
ThermionEntity parent, bool renderableOnly) {
// TODO: implement getChildEntities
throw UnimplementedError();
}
@override
Future<ThermionEntity> getChildEntity(
ThermionEntity parent, String childName) {
// TODO: implement getChildEntity
throw UnimplementedError();
}
@override
Future<List<String>> getChildEntityNames(ThermionEntity entity,
{bool renderableOnly = true}) {
// TODO: implement getChildEntityNames
throw UnimplementedError();
}
@override
Future<int> getInstanceCount(ThermionEntity entity) {
// TODO: implement getInstanceCount
throw UnimplementedError();
}
@override
Future<List<ThermionEntity>> getInstances(ThermionEntity entity) {
// TODO: implement getInstances
throw UnimplementedError();
}
@override
Future<Matrix4> getInverseBindMatrix(ThermionEntity parent, int boneIndex,
{int skinIndex = 0}) {
// TODO: implement getInverseBindMatrix
throw UnimplementedError();
}
@override
Future<Matrix4> getLocalTransform(ThermionEntity entity) {
// TODO: implement getLocalTransform
throw UnimplementedError();
}
@override
Future<ThermionEntity> getMainCamera() {
// TODO: implement getMainCamera
throw UnimplementedError();
}
@override
Future<List<String>> getMorphTargetNames(
ThermionEntity entity, ThermionEntity childEntity) {
// TODO: implement getMorphTargetNames
throw UnimplementedError();
}
@override
String? getNameForEntity(ThermionEntity entity) {
// TODO: implement getNameForEntity
throw UnimplementedError();
}
@override
Future<ThermionEntity?> getParent(ThermionEntity child) {
// TODO: implement getParent
throw UnimplementedError();
}
@override
Future<Matrix4> getWorldTransform(ThermionEntity entity) {
// TODO: implement getWorldTransform
throw UnimplementedError();
}
@override
// TODO: implement gizmo
AbstractGizmo? get gizmo => throw UnimplementedError();
@override
Future hide(ThermionEntity entity, String? meshName) {
// TODO: implement hide
throw UnimplementedError();
}
@override
// TODO: implement initialized
Future<bool> get initialized => throw UnimplementedError();
@override
Future loadIbl(String lightingPath, {double intensity = 30000}) {
// TODO: implement loadIbl
throw UnimplementedError();
}
@override
Future loadSkybox(String skyboxPath) {
// TODO: implement loadSkybox
throw UnimplementedError();
}
@override
Future moveCameraToAsset(ThermionEntity entity) {
// TODO: implement moveCameraToAsset
throw UnimplementedError();
}
@override
void onDispose(Future Function() callback) {
// TODO: implement onDispose
}
@override
Future panEnd() {
// TODO: implement panEnd
throw UnimplementedError();
}
@override
Future panStart(double x, double y) {
// TODO: implement panStart
throw UnimplementedError();
}
@override
Future panUpdate(double x, double y) {
// TODO: implement panUpdate
throw UnimplementedError();
}
@override
void pick(int x, int y) {
// TODO: implement pick
}
@override
// TODO: implement pickResult
Stream<FilamentPickResult> get pickResult => throw UnimplementedError();
@override
Future playAnimation(ThermionEntity entity, int index,
{bool loop = false,
bool reverse = false,
bool replaceActive = true,
double crossfade = 0.0,
double startOffset=0.0}) {
// TODO: implement playAnimation
throw UnimplementedError();
}
@override
Future playAnimationByName(ThermionEntity entity, String name,
{bool loop = false,
bool reverse = false,
bool replaceActive = true,
double crossfade = 0.0}) {
// TODO: implement playAnimationByName
throw UnimplementedError();
}
@override
Future queuePositionUpdate(
ThermionEntity entity, double x, double y, double z,
{bool relative = false}) {
// TODO: implement queuePositionUpdate
throw UnimplementedError();
}
@override
Future queueRotationUpdate(
ThermionEntity entity, double rads, double x, double y, double z,
{bool relative = false}) {
// TODO: implement queueRotationUpdate
throw UnimplementedError();
}
@override
Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat,
{bool relative = false}) {
// TODO: implement queueRotationUpdateQuat
throw UnimplementedError();
}
@override
Future removeAnimationComponent(ThermionEntity entity) {
// TODO: implement removeAnimationComponent
throw UnimplementedError();
}
@override
Future removeCollisionComponent(ThermionEntity entity) {
// TODO: implement removeCollisionComponent
throw UnimplementedError();
}
@override
Future removeEntity(ThermionEntity entity) {
// TODO: implement removeEntity
throw UnimplementedError();
}
@override
Future removeIbl() {
// TODO: implement removeIbl
throw UnimplementedError();
}
@override
Future removeLight(ThermionEntity light) {
// TODO: implement removeLight
throw UnimplementedError();
}
@override
Future removeSkybox() {
// TODO: implement removeSkybox
throw UnimplementedError();
}
@override
Future render() {
// TODO: implement render
throw UnimplementedError();
}
@override
// TODO: implement rendering
bool get rendering => throw UnimplementedError();
@override
Future resetBones(ThermionEntity entity) {
// TODO: implement resetBones
throw UnimplementedError();
}
@override
Future reveal(ThermionEntity entity, String? meshName) {
// TODO: implement reveal
throw UnimplementedError();
}
@override
Future rotateEnd() {
// TODO: implement rotateEnd
throw UnimplementedError();
}
@override
Future rotateIbl(Matrix3 rotation) {
// TODO: implement rotateIbl
throw UnimplementedError();
}
@override
Future rotateStart(double x, double y) {
// TODO: implement rotateStart
throw UnimplementedError();
}
@override
Future rotateUpdate(double x, double y) {
// TODO: implement rotateUpdate
throw UnimplementedError();
}
@override
Future setAnimationFrame(
ThermionEntity entity, int index, int animationFrame) {
// TODO: implement setAnimationFrame
throw UnimplementedError();
}
@override
Future setAntiAliasing(bool msaa, bool fxaa, bool taa) {
// TODO: implement setAntiAliasing
throw UnimplementedError();
}
@override
Future setBackgroundColor(double r, double g, double b, double alpha) {
// TODO: implement setBackgroundColor
throw UnimplementedError();
}
@override
Future setBackgroundImage(String path, {bool fillHeight = false}) {
// TODO: implement setBackgroundImage
throw UnimplementedError();
}
@override
Future setBackgroundImagePosition(double x, double y, {bool clamp = false}) {
// TODO: implement setBackgroundImagePosition
throw UnimplementedError();
}
@override
Future setBloom(double bloom) {
// TODO: implement setBloom
throw UnimplementedError();
}
@override
Future setBoneTransform(
ThermionEntity entity, int boneIndex, Matrix4 transform,
{int skinIndex = 0}) {
// TODO: implement setBoneTransform
throw UnimplementedError();
}
@override
Future setCamera(ThermionEntity entity, String? name) {
// TODO: implement setCamera
throw UnimplementedError();
}
@override
Future setCameraCulling(double near, double far) {
// TODO: implement setCameraCulling
throw UnimplementedError();
}
@override
Future setCameraExposure(
double aperture, double shutterSpeed, double sensitivity) {
// TODO: implement setCameraExposure
throw UnimplementedError();
}
@override
Future setCameraFocalLength(double focalLength) {
// TODO: implement setCameraFocalLength
throw UnimplementedError();
}
@override
Future setCameraFocusDistance(double focusDistance) {
// TODO: implement setCameraFocusDistance
throw UnimplementedError();
}
@override
Future setCameraFov(double degrees, {bool horizontal=true}) {
// TODO: implement setCameraFov
throw UnimplementedError();
}
@override
Future setCameraManipulatorOptions(
{ManipulatorMode mode = ManipulatorMode.ORBIT,
double orbitSpeedX = 0.01,
double orbitSpeedY = 0.01,
double zoomSpeed = 0.01}) {
// TODO: implement setCameraManipulatorOptions
throw UnimplementedError();
}
@override
Future setCameraModelMatrix(List<double> matrix) {
// TODO: implement setCameraModelMatrix
throw UnimplementedError();
}
@override
Future setCameraPosition(double x, double y, double z) {
// TODO: implement setCameraPosition
throw UnimplementedError();
}
@override
Future setCameraRotation(Quaternion quaternion) {
// TODO: implement setCameraRotation
throw UnimplementedError();
}
@override
Future setFrameRate(int framerate) {
// TODO: implement setFrameRate
throw UnimplementedError();
}
@override
Future setMainCamera() {
// TODO: implement setMainCamera
throw UnimplementedError();
}
@override
Future setMaterialColor(ThermionEntity entity, String meshName,
int materialIndex, double r, double g, double b, double a) {
// TODO: implement setMaterialColor
throw UnimplementedError();
}
@override
Future clearMorphAnimationData(ThermionEntity entity) {
throw UnimplementedError();
}
@override
Future setMorphAnimationData(
ThermionEntity entity, MorphAnimationData animation,
{List<String>? targetMeshNames}) {
// TODO: implement setMorphAnimationData
throw UnimplementedError();
}
@override
Future setMorphTargetWeights(ThermionEntity entity, List<double> weights) {
// TODO: implement setMorphTargetWeights
throw UnimplementedError();
}
@override
Future setParent(ThermionEntity child, ThermionEntity parent, { bool preserveScaling = false}) {
// TODO: implement setParent
throw UnimplementedError();
}
@override
Future setPosition(ThermionEntity entity, double x, double y, double z) {
// TODO: implement setPosition
throw UnimplementedError();
}
@override
Future setPostProcessing(bool enabled) {
// TODO: implement setPostProcessing
throw UnimplementedError();
}
@override
Future setPriority(ThermionEntity entityId, int priority) {
// TODO: implement setPriority
throw UnimplementedError();
}
@override
Future setRecording(bool recording) {
// TODO: implement setRecording
throw UnimplementedError();
}
@override
Future setRecordingOutputDirectory(String outputDirectory) {
// TODO: implement setRecordingOutputDirectory
throw UnimplementedError();
}
@override
Future setRendering(bool render) {
// TODO: implement setRendering
throw UnimplementedError();
}
@override
Future setRotation(
ThermionEntity entity, double rads, double x, double y, double z) {
// TODO: implement setRotation
throw UnimplementedError();
}
@override
Future setRotationQuat(ThermionEntity entity, Quaternion rotation) {
// TODO: implement setRotationQuat
throw UnimplementedError();
}
@override
Future setScale(ThermionEntity entity, double scale) {
// TODO: implement setScale
throw UnimplementedError();
}
@override
Future setToneMapping(ToneMapper mapper) {
// TODO: implement setToneMapping
throw UnimplementedError();
}
@override
Future setTransform(ThermionEntity entity, Matrix4 transform) {
// TODO: implement setTransform
throw UnimplementedError();
}
@override
Future setViewFrustumCulling(bool enabled) {
// TODO: implement setViewFrustumCulling
throw UnimplementedError();
}
@override
Future stopAnimation(ThermionEntity entity, int animationIndex) {
// TODO: implement stopAnimation
throw UnimplementedError();
}
@override
Future stopAnimationByName(ThermionEntity entity, String name) {
// TODO: implement stopAnimationByName
throw UnimplementedError();
}
@override
Future testCollisions(ThermionEntity entity) {
// TODO: implement testCollisions
throw UnimplementedError();
}
@override
Future transformToUnitCube(ThermionEntity entity) {
// TODO: implement transformToUnitCube
throw UnimplementedError();
}
@override
Future updateBoneMatrices(ThermionEntity entity) {
// TODO: implement updateBoneMatrices
throw UnimplementedError();
}
@override
Future zoomBegin() {
// TODO: implement zoomBegin
throw UnimplementedError();
}
@override
Future zoomEnd() {
// TODO: implement zoomEnd
throw UnimplementedError();
}
@override
Future zoomUpdate(double x, double y, double z) {
// TODO: implement zoomUpdate
throw UnimplementedError();
}
@override
Future setShadowType(ShadowType shadowType) {
// TODO: implement setShadowType
throw UnimplementedError();
}
@override
Future setShadowsEnabled(bool enabled) {
// TODO: implement setShadowsEnabled
throw UnimplementedError();
}
@override
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale) {
// TODO: implement setSoftShadowOptions
throw UnimplementedError();
}
@override
Future<Uint8List> capture() {
// TODO: implement capture
throw UnimplementedError();
}
@override
Future<Aabb2> getBoundingBox(ThermionEntity entity) {
// TODO: implement getBoundingBox
throw UnimplementedError();
}
@override
Future<double> 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
Future setLayerEnabled(int layer, bool enabled) {
// TODO: implement setLayerEnabled
throw UnimplementedError();
}
@override
Future createIbl(double r, double g, double b, double intensity) {
// TODO: implement createIbl
throw UnimplementedError();
}
@override
// TODO: implement gizmoPickResult
Stream<FilamentPickResult> get gizmoPickResult => throw UnimplementedError();
@override
void pickGizmo(int x, int y) {
// TODO: implement pickGizmo
}
@override
Future setGizmoVisibility(bool visible) {
// TODO: implement setGizmoVisibility
throw UnimplementedError();
}
@override
Future<ThermionEntity?> getAncestor(ThermionEntity entity) {
// TODO: implement getAncestor
throw UnimplementedError();
}
@override
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false}) {
// TODO: implement loadGlbFromBuffer
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 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 setStencilHighlight(ThermionEntity entity, {double r = 1.0, double g = 0.0, double b = 0.0}) {
// TODO: implement setStencilHighlight
throw UnimplementedError();
}
@override
Future<double> getCameraNear() {
// TODO: implement getCameraNear
throw UnimplementedError();
}
@override
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity) {
// TODO: implement getViewportBoundingBox
throw UnimplementedError();
}
@override
Future setCameraLensProjection(double near, double far, double aspect, double focalLength) {
// TODO: implement setCameraLensProjection
throw UnimplementedError();
}
@override
Future setCameraModelMatrix4(Matrix4 matrix) {
// TODO: implement setCameraModelMatrix4
throw UnimplementedError();
}
@override
Future<ThermionEntity> loadGlb(String path, {int numInstances = 1, bool keepData = false}) {
// TODO: implement loadGlb
throw UnimplementedError();
}
@override
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath, {bool keepData = false}) {
// TODO: implement loadGltf
throw UnimplementedError();
}
@override
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, int materialIndex, double value) {
// 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 createGeometry(Geometry geometry, {bool keepData=false}) {
// TODO: implement createGeometry
throw UnimplementedError();
}
@override
// TODO: implement sceneUpdated
Stream<SceneUpdateEvent> get sceneUpdated => throw UnimplementedError();
@override
Future<ThermionEntity> addDirectLight(DirectLight light) {
// TODO: implement addDirectLight
throw UnimplementedError();
}
}

View File

@@ -0,0 +1,760 @@
@JS()
library thermion_flutter_js;
import 'dart:js_interop';
import 'package:logging/logging.dart';
import 'package:thermion_dart/thermion_dart/viewer/web/thermion_viewer_js_shim.dart';
import 'package:vector_math/vector_math_64.dart' as v64;
import 'package:animation_tools_dart/animation_tools_dart.dart';
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
import 'dart:js_interop_unsafe';
import 'package:vector_math/vector_math_64.dart';
///
/// A (Dart) class that wraps a (Dart) instance of [ThermionViewer],
/// but exported to JS by binding to a global property.
/// This is effectively an implementation of [ThermionViewerJSShim];
/// allowing users to interact with an instance of [ThermionViewer]
/// (presumably compiled to WASM) from any Javascript context (including
/// the browser console).
///
@JSExport()
class ThermionViewerJSDartBridge {
final _logger = Logger("ThermionViewerJSDartBridge");
final ThermionViewer viewer;
ThermionViewerJSDartBridge(this.viewer);
void bind({String globalPropertyName = "thermionViewer"}) {
var wrapper = createJSInteropWrapper<ThermionViewerJSDartBridge>(this)
as ThermionViewerJSShim;
globalContext.setProperty(globalPropertyName.toJS, wrapper);
}
JSPromise<JSBoolean> 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<JSUint8Array> 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<JSNumber> 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<JSNumber> 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<JSNumber> 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<JSNumber> createInstance(ThermionEntity entity) {
return viewer.createInstance(entity).then((instance) => instance.toJS).toJS;
}
@JSExport()
JSPromise<JSNumber> getInstanceCount(ThermionEntity entity) =>
viewer.getInstanceCount(entity).then((v) => v.toJS).toJS;
@JSExport()
JSPromise<JSArray<JSNumber>> getInstances(ThermionEntity entity) {
return viewer
.getInstances(entity)
.then((instances) =>
instances.map((instance) => instance.toJS).toList().toJS)
.toJS;
}
@JSExport()
JSPromise<JSNumber> 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<JSNumber> weights) {
var dartWeights = weights.toDart.map((w) => w.toDartDouble).toList();
return viewer.setMorphTargetWeights(entity, dartWeights).toJS;
}
@JSExport()
JSPromise<JSArray<JSString>> 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<JSArray<JSString>> getBoneNames(
ThermionEntity entity, int skinIndex) {
return viewer
.getBoneNames(entity, skinIndex: skinIndex)
.then((v) => v.map((s) => s.toJS).toList().toJS)
.toJS;
}
@JSExport()
JSPromise<JSArray<JSString>> getAnimationNames(ThermionEntity entity) =>
viewer
.getAnimationNames(entity)
.then((v) => v.map((s) => s.toJS).toList().toJS)
.toJS;
@JSExport()
JSPromise<JSNumber> 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<JSArray<JSNumber>> animation,
JSArray<JSString> morphTargets,
JSArray<JSString>? 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<JSString> bones,
JSArray<JSArray<JSArray<JSNumber>>> 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<BoneAnimationFrame>()
.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<JSNumber> getMainCamera() {
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<JSNumber> getCameraCullingNear() =>
viewer.getCameraCullingNear().then((v) => v.toJS).toJS;
@JSExport()
JSPromise<JSNumber> getCameraCullingFar() =>
viewer.getCameraCullingFar().then((v) => v.toJS).toJS;
@JSExport()
JSPromise setCameraFocusDistance(double focusDistance) =>
viewer.setCameraFocusDistance(focusDistance).toJS;
@JSExport()
JSPromise<JSArray<JSNumber>> getCameraPosition() {
throw UnimplementedError();
// return viewer.getCameraPosition().then((position) => position.toJS).toJS;
}
@JSExport()
JSPromise<JSArray<JSNumber>> getCameraModelMatrix() {
throw UnimplementedError();
// return viewer.getCameraModelMatrix().then((matrix) => matrix.toJSArray<JSNumber>()).toJS;
}
@JSExport()
JSPromise<JSArray<JSNumber>> getCameraViewMatrix() {
throw UnimplementedError();
// return viewer.getCameraViewMatrix().then((matrix) => matrix.toJSArray<JSNumber>()).toJS;
}
@JSExport()
JSPromise<JSArray<JSNumber>> getCameraProjectionMatrix() {
throw UnimplementedError();
// return viewer.getCameraProjectionMatrix().then((matrix) => matrix.toJSArray<JSNumber>()).toJS;
}
@JSExport()
JSPromise<JSArray<JSNumber>> getCameraCullingProjectionMatrix() {
throw UnimplementedError();
// return viewer.getCameraCullingProjectionMatrix().then((matrix) => matrix.toJSArray<JSNumber>()).toJS;
}
@JSExport()
JSPromise<JSNumber> 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<JSArray<JSNumber>> 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<JSNumber> 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<JSNumber> 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<JSNumber> 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<JSNumber> 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<JSArray<JSNumber>> 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 <JSNumber>[].toJS;
}).toJS;
}
@JSExport()
JSPromise<JSNumber> 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<JSArray<JSString>> 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<JSArray<JSNumber>> getLocalTransform(ThermionEntity entity) {
return viewer
.getLocalTransform(entity)
.then((t) => t.storage.map((v) => v.toJS).toList().toJS)
.toJS;
}
@JSExport()
JSPromise<JSArray<JSNumber>> getWorldTransform(ThermionEntity entity) {
return viewer
.getWorldTransform(entity)
.then((t) => t.storage.map((v) => v.toJS).toList().toJS)
.toJS;
}
@JSExport()
JSPromise setTransform(ThermionEntity entity, JSArray<JSNumber> 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<JSNumber> 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;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,424 @@
@JS()
library thermion_flutter_js;
import 'dart:js_interop';
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
///
/// An extension type on [JSObject] that represents a
/// Javascript shim implementation of the [ThermionViewer] interface.
///
extension type ThermionViewerJSShim(JSObject _) implements JSObject {
@JS('initialized')
external JSPromise<JSBoolean> get initialized;
@JS('rendering')
external bool get rendering;
@JS('setRendering')
external JSPromise setRendering(bool render);
@JS('render')
external JSPromise render();
@JS('capture')
external JSPromise<JSUint8Array> capture();
@JS('setFrameRate')
external JSPromise setFrameRate(int framerate);
@JS('dispose')
external JSPromise dispose();
@JS('setBackgroundImage')
external JSPromise setBackgroundImage(String path, bool fillHeight);
@JS('setBackgroundImagePosition')
external JSPromise setBackgroundImagePosition(double x, double y, bool clamp);
@JS('clearBackgroundImage')
external JSPromise clearBackgroundImage();
@JS('setBackgroundColor')
external JSPromise setBackgroundColor(
double r, double g, double b, double alpha);
@JS('loadSkybox')
external JSPromise loadSkybox(String skyboxPath);
@JS('removeSkybox')
external JSPromise removeSkybox();
@JS('loadIbl')
external JSPromise loadIbl(String lightingPath, double intensity);
@JS('rotateIbl')
external JSPromise rotateIbl(JSArray<JSNumber> rotationMatrix);
@JS('removeIbl')
external JSPromise removeIbl();
@JS('addLight')
external JSPromise<JSNumber> addLight(
int type,
double colour,
double intensity,
double posX,
double posY,
double posZ,
double dirX,
double dirY,
double dirZ,
double falloffRadius,
double spotLightConeInner,
double spotLightConeOuter,
double sunAngularRadius,
double sunHaloSize,
double sunHaloFallof,
bool castShadows);
@JS('removeLight')
external JSPromise removeLight(ThermionEntity light);
@JS('clearLights')
external JSPromise clearLights();
@JS('loadGlb')
external JSPromise<JSNumber> loadGlb(String path, int numInstances);
@JS('createInstance')
external JSPromise<JSNumber> createInstance(ThermionEntity entity);
@JS('getInstanceCount')
external JSPromise<JSNumber> getInstanceCount(ThermionEntity entity);
@JS('getInstances')
external JSPromise<JSArray<JSNumber>> getInstances(ThermionEntity entity);
@JS('loadGltf')
external JSPromise<JSNumber> loadGltf(
String path, String relativeResourcePath);
@JS('panStart')
external JSPromise panStart(double x, double y);
@JS('panUpdate')
external JSPromise panUpdate(double x, double y);
@JS('panEnd')
external JSPromise panEnd();
@JS('rotateStart')
external JSPromise rotateStart(double x, double y);
@JS('rotateUpdate')
external JSPromise rotateUpdate(double x, double y);
@JS('rotateEnd')
external JSPromise rotateEnd();
@JS('setMorphTargetWeights')
external JSPromise setMorphTargetWeights(
ThermionEntity entity, JSArray<JSNumber> weights);
@JS('getMorphTargetNames')
external JSPromise<JSArray<JSString>> getMorphTargetNames(
ThermionEntity entity, ThermionEntity childEntity);
@JS('getBoneNames')
external JSPromise<JSArray<JSString>> getBoneNames(
ThermionEntity entity, int skinIndex);
@JS('getAnimationNames')
external JSPromise<JSArray<JSString>> getAnimationNames(
ThermionEntity entity);
@JS('getAnimationDuration')
external JSPromise<JSNumber> getAnimationDuration(
ThermionEntity entity, int animationIndex);
@JS('clearMorphAnimationData')
external void clearMorphAnimationData(ThermionEntity entity);
@JS('setMorphAnimationData')
external JSPromise setMorphAnimationData(
ThermionEntity entity,
JSArray<JSArray<JSNumber>> animation,
JSArray<JSString> morphTargets,
JSArray<JSString>? targetMeshNames,
double frameLengthInMs);
@JS('resetBones')
external JSPromise resetBones(ThermionEntity entity);
@JS('addBoneAnimation')
external JSPromise addBoneAnimation(
ThermionEntity entity,
JSArray<JSString> bones,
JSArray<JSArray<JSArray<JSNumber>>> frameData,
JSNumber frameLengthInMs,
JSNumber spaceEnum,
JSNumber skinIndex,
JSNumber fadeInInSecs,
JSNumber fadeOutInSecs,
JSNumber maxDelta);
@JS('removeEntity')
external JSPromise removeEntity(ThermionEntity entity);
@JS('clearEntities')
external JSPromise clearEntities();
@JS('zoomBegin')
external JSPromise zoomBegin();
@JS('zoomUpdate')
external JSPromise zoomUpdate(double x, double y, double z);
@JS('zoomEnd')
external JSPromise zoomEnd();
@JS('playAnimation')
external JSPromise playAnimation(
ThermionEntity entity,
int index,
bool loop,
bool reverse,
bool replaceActive,
double crossfade,
double startOffset,
);
@JS('playAnimationByName')
external JSPromise playAnimationByName(
ThermionEntity entity,
String name,
bool loop,
bool reverse,
bool replaceActive,
double crossfade,
);
@JS('setAnimationFrame')
external JSPromise setAnimationFrame(
ThermionEntity entity, int index, int animationFrame);
@JS('stopAnimation')
external JSPromise stopAnimation(ThermionEntity entity, int animationIndex);
@JS('stopAnimationByName')
external JSPromise stopAnimationByName(ThermionEntity entity, String name);
@JS('setCamera')
external JSPromise setCamera(ThermionEntity entity, String? name);
@JS('setMainCamera')
external JSPromise setMainCamera();
@JS('getMainCamera')
external JSPromise<JSNumber> getMainCamera();
@JS('setCameraFov')
external JSPromise setCameraFov(double degrees, bool horizontal);
@JS('setToneMapping')
external JSPromise setToneMapping(int mapper);
@JS('setBloom')
external JSPromise setBloom(double bloom);
@JS('setCameraFocalLength')
external JSPromise setCameraFocalLength(double focalLength);
@JS('setCameraCulling')
external JSPromise setCameraCulling(double near, double far);
@JS('getCameraCullingNear')
external JSPromise<JSNumber> getCameraCullingNear();
@JS('getCameraCullingFar')
external JSPromise<JSNumber> getCameraCullingFar();
@JS('setCameraFocusDistance')
external JSPromise setCameraFocusDistance(double focusDistance);
@JS('getCameraPosition')
external JSPromise<JSArray<JSNumber>> getCameraPosition();
@JS('getCameraModelMatrix')
external JSPromise<JSArray<JSNumber>> getCameraModelMatrix();
@JS('getCameraViewMatrix')
external JSPromise<JSArray<JSNumber>> getCameraViewMatrix();
@JS('getCameraProjectionMatrix')
external JSPromise<JSArray<JSNumber>> getCameraProjectionMatrix();
@JS('getCameraCullingProjectionMatrix')
external JSPromise<JSArray<JSNumber>> getCameraCullingProjectionMatrix();
@JS('getCameraFrustum')
external JSPromise<JSObject> getCameraFrustum();
@JS('setCameraPosition')
external JSPromise setCameraPosition(double x, double y, double z);
@JS('getCameraRotation')
external JSPromise<JSArray<JSNumber>> getCameraRotation();
@JS('moveCameraToAsset')
external JSPromise moveCameraToAsset(ThermionEntity entity);
@JS('setViewFrustumCulling')
external JSPromise setViewFrustumCulling(JSBoolean enabled);
@JS('setCameraExposure')
external JSPromise setCameraExposure(
double aperture, double shutterSpeed, double sensitivity);
@JS('setCameraRotation')
external JSPromise setCameraRotation(JSArray<JSNumber> quaternion);
@JS('setCameraModelMatrix')
external JSPromise setCameraModelMatrix(JSArray<JSNumber> matrix);
@JS('setMaterialColor')
external JSPromise setMaterialColor(ThermionEntity entity, String meshName,
int materialIndex, double r, double g, double b, double a);
@JS('transformToUnitCube')
external JSPromise transformToUnitCube(ThermionEntity entity);
@JS('setPosition')
external JSPromise setPosition(
ThermionEntity entity, double x, double y, double z);
@JS('setScale')
external JSPromise setScale(ThermionEntity entity, double scale);
@JS('setRotation')
external JSPromise setRotation(
ThermionEntity entity, double rads, double x, double y, double z);
@JS('queuePositionUpdate')
external JSPromise queuePositionUpdate(
ThermionEntity entity, double x, double y, double z, bool relative);
@JS('queueRotationUpdate')
external JSPromise queueRotationUpdate(ThermionEntity entity, double rads,
double x, double y, double z, bool relative);
@JS('queueRotationUpdateQuat')
external JSPromise queueRotationUpdateQuat(
ThermionEntity entity, JSArray<JSNumber> quat, bool relative);
@JS('setPostProcessing')
external JSPromise setPostProcessing(bool enabled);
@JS('setAntiAliasing')
external JSPromise setAntiAliasing(bool msaa, bool fxaa, bool taa);
@JS('setRotationQuat')
external JSPromise setRotationQuat(
ThermionEntity entity, JSArray<JSNumber> rotation);
@JS('reveal')
external JSPromise reveal(ThermionEntity entity, String? meshName);
@JS('hide')
external JSPromise hide(ThermionEntity entity, String? meshName);
@JS('pick')
external void pick(int x, int y);
@JS('getNameForEntity')
external String? getNameForEntity(ThermionEntity entity);
@JS('setCameraManipulatorOptions')
external JSPromise setCameraManipulatorOptions(
int mode,
double orbitSpeedX,
double orbitSpeedY,
double zoomSpeed,
);
@JS('getChildEntities')
external JSPromise<JSArray<JSNumber>> getChildEntities(
ThermionEntity parent, bool renderableOnly);
@JS('getChildEntity')
external JSPromise<JSNumber> getChildEntity(
ThermionEntity parent, String childName);
@JS('getChildEntityNames')
external JSPromise<JSArray<JSString>> getChildEntityNames(
ThermionEntity entity, bool renderableOnly);
@JS('setRecording')
external JSPromise setRecording(JSBoolean recording);
@JS('setRecordingOutputDirectory')
external JSPromise setRecordingOutputDirectory(String outputDirectory);
@JS('addAnimationComponent')
external JSPromise addAnimationComponent(ThermionEntity entity);
@JS('removeAnimationComponent')
external JSPromise removeAnimationComponent(ThermionEntity entity);
@JS('addCollisionComponent')
external JSPromise addCollisionComponent(ThermionEntity entity);
@JS('removeCollisionComponent')
external JSPromise removeCollisionComponent(ThermionEntity entity);
@JS('createGeometry')
external JSPromise<JSNumber> createGeometry(JSArray<JSNumber> vertices,
JSArray<JSNumber> indices, String? materialPath, int primitiveType);
@JS('setParent')
external JSPromise setParent(ThermionEntity child, ThermionEntity parent, bool preserveScaling);
@JS('getParent')
external JSPromise<JSNumber> getParent(ThermionEntity child);
@JS('getParent')
external JSPromise<JSNumber> getBone(
ThermionEntity child, int boneIndex, int skinIndex);
@JS('testCollisions')
external JSPromise testCollisions(ThermionEntity entity);
@JS('setPriority')
external JSPromise setPriority(ThermionEntity entityId, int priority);
@JS('getLocalTransform')
external JSPromise<JSArray<JSNumber>> getLocalTransform(
ThermionEntity entity);
@JS('getWorldTransform')
external JSPromise<JSArray<JSNumber>> getWorldTransform(
ThermionEntity entity);
@JS('updateBoneMatrices')
external JSPromise updateBoneMatrices(ThermionEntity entity);
@JS('setTransform')
external JSPromise setTransform(
ThermionEntity entity, JSArray<JSNumber> transform);
@JS('setBoneTransform')
external JSPromise setBoneTransform(ThermionEntity entity, int boneIndex,
JSArray<JSNumber> transform, int skinIndex);
@JS('setShadowsEnabled')
external JSPromise setShadowsEnabled(bool enabled);
@JS('setShadowType')
external JSPromise setShadowType(int shadowType);
@JS('setSoftShadowOptions')
external JSPromise setSoftShadowOptions(
double penumbraScale, double penumbraRatioScale);
}

File diff suppressed because it is too large Load Diff