refactoring
This commit is contained in:
262
thermion_dart/lib/src/viewer/src/ffi/src/background_image.dart
Normal file
262
thermion_dart/lib/src/viewer/src/ffi/src/background_image.dart
Normal file
@@ -0,0 +1,262 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:animation_tools_dart/src/bone_animation_data.dart';
|
||||
import 'package:animation_tools_dart/src/morph_animation_data.dart';
|
||||
import 'package:thermion_dart/src/filament/src/layers.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
class BackgroundImage extends ThermionAsset {
|
||||
final ThermionAsset asset;
|
||||
ThermionEntity get entity => asset.entity;
|
||||
|
||||
Texture? _backgroundImageTexture;
|
||||
FFIMaterial? _imageMaterial;
|
||||
FFITextureSampler? _imageSampler;
|
||||
|
||||
final FFIScene scene;
|
||||
final FilamentApp app;
|
||||
|
||||
BackgroundImage._(this.asset, this.scene, this.app,
|
||||
this._backgroundImageTexture, this._imageMaterial, this._imageSampler);
|
||||
|
||||
Future destroy() async {
|
||||
Scene_removeEntity(scene.scene, entity);
|
||||
await _backgroundImageTexture!.dispose();
|
||||
await _imageSampler!.dispose();
|
||||
}
|
||||
|
||||
static Future<BackgroundImage> create(
|
||||
FFIFilamentApp app, FFIScene scene, Uint8List imageData) async {
|
||||
final image = await app.decodeImage(imageData);
|
||||
var backgroundImageTexture = await app.createTexture(
|
||||
await image.getWidth(), await image.getHeight());
|
||||
var imageMaterial = FFIMaterial(Material_createImageMaterial(), app);
|
||||
var imageSampler = await app.createTextureSampler() as FFITextureSampler;
|
||||
|
||||
var imageMaterialInstance =
|
||||
await imageMaterial!.createInstance() as FFIMaterialInstance;
|
||||
await imageMaterialInstance.setParameterTexture(
|
||||
"image",
|
||||
backgroundImageTexture as FFITexture,
|
||||
imageSampler as FFITextureSampler);
|
||||
var backgroundImage =
|
||||
await app.createGeometry(GeometryHelper.fullscreenQuad()) as FFIAsset;
|
||||
backgroundImage.setMaterialInstanceAt(imageMaterialInstance);
|
||||
await scene.add(backgroundImage);
|
||||
return BackgroundImage._(backgroundImage, scene, app,
|
||||
backgroundImageTexture, imageMaterial, imageSampler);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionAsset> createInstance(
|
||||
{covariant List<MaterialInstance>? materialInstances = null}) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ThermionEntity>> getChildEntities() async {
|
||||
return [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionAsset> getInstance(int index) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> getInstanceCount() async {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ThermionAsset>> getInstances() async {
|
||||
return [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future removeStencilHighlight() {
|
||||
// TODO: implement removeStencilHighlight
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setBoundingBoxVisibility(bool visible) {
|
||||
// TODO: implement setBoundingBoxVisibility
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setCastShadows(bool castShadows) {
|
||||
// TODO: implement setCastShadows
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMaterialInstanceAt(covariant MaterialInstance instance) {
|
||||
// TODO: implement setMaterialInstanceAt
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setReceiveShadows(bool castShadows) {
|
||||
// TODO: implement setReceiveShadows
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setStencilHighlight(
|
||||
{double r = 1.0, double g = 0.0, double b = 0.0, int? entityIndex}) {
|
||||
// TODO: implement setStencilHighlight
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setVisibilityLayer(ThermionEntity entity, VisibilityLayers layer) {
|
||||
// TODO: implement setVisibilityLayer
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future addAnimationComponent(ThermionEntity entity) {
|
||||
// TODO: implement addAnimationComponent
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future addBoneAnimation(ThermionAsset asset, BoneAnimationData animation, {int skinIndex = 0, double fadeInInSecs = 0.0, double fadeOutInSecs = 0.0, double maxDelta = 1.0}) {
|
||||
// TODO: implement addBoneAnimation
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future clearMorphAnimationData(ThermionEntity entity) {
|
||||
// TODO: implement clearMorphAnimationData
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getAnimationDuration(covariant ThermionAsset asset, int animationIndex) {
|
||||
// TODO: implement getAnimationDuration
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getAnimationNames(covariant ThermionAsset asset) {
|
||||
// TODO: implement getAnimationNames
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> getBone(covariant ThermionAsset asset, int boneIndex, {int skinIndex = 0}) {
|
||||
// TODO: implement getBone
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getBoneNames(covariant ThermionAsset asset, {int skinIndex = 0}) {
|
||||
// TODO: implement getBoneNames
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Matrix4> getInverseBindMatrix(covariant ThermionAsset asset, int boneIndex, {int skinIndex = 0}) {
|
||||
// TODO: implement getInverseBindMatrix
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Matrix4> getLocalTransform(ThermionEntity entity) {
|
||||
// TODO: implement getLocalTransform
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getMorphTargetNames(covariant ThermionAsset asset, ThermionEntity childEntity) {
|
||||
// TODO: implement getMorphTargetNames
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Matrix4> getWorldTransform(ThermionEntity entity) {
|
||||
// TODO: implement getWorldTransform
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future playAnimation(ThermionAsset asset, int index, {bool loop = false, bool reverse = false, bool replaceActive = true, double crossfade = 0.0, double startOffset = 0.0}) {
|
||||
// TODO: implement playAnimation
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future playAnimationByName(covariant ThermionAsset asset, String name, {bool loop = false, bool reverse = false, bool replaceActive = true, double crossfade = 0.0}) {
|
||||
// TODO: implement playAnimationByName
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future removeAnimationComponent(ThermionEntity entity) {
|
||||
// TODO: implement removeAnimationComponent
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future resetBones(ThermionAsset asset) {
|
||||
// TODO: implement resetBones
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setBoneTransform(ThermionEntity entity, int boneIndex, Matrix4 transform, {int skinIndex = 0}) {
|
||||
// TODO: implement setBoneTransform
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setGltfAnimationFrame(covariant ThermionAsset asset, int index, int animationFrame) {
|
||||
// TODO: implement setGltfAnimationFrame
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMorphAnimationData(covariant ThermionAsset asset, 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 setTransform(ThermionEntity entity, Matrix4 transform) {
|
||||
// TODO: implement setTransform
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future stopAnimation(covariant ThermionAsset asset, int animationIndex) {
|
||||
// TODO: implement stopAnimation
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future stopAnimationByName(covariant ThermionAsset asset, String name) {
|
||||
// TODO: implement stopAnimationByName
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future updateBoneMatrices(ThermionEntity entity) {
|
||||
// TODO: implement updateBoneMatrices
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:thermion_dart/src/filament/src/layers.dart';
|
||||
import 'package:thermion_dart/src/utils/src/matrix.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:vector_math/vector_math_64.dart' as v64;
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
class FFIAsset extends ThermionAsset {
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -389,7 +393,477 @@ class FFIAsset extends ThermionAsset {
|
||||
return RenderableManager_isShadowReceiver(app.renderableManager, entity);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future transformToUnitCube() async {
|
||||
SceneAsset_transformToUnitCube(asset);
|
||||
TransformManager_transformToUnitCube(app.transformManager, entity, SceneAsset_getBoundingBox(asset));
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setVisibilityLayer(
|
||||
ThermionEntity entity, VisibilityLayers layer) async {
|
||||
RenderableManager_setVisibilityLayer(
|
||||
app.renderableManager, entity, layer.value);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future setMorphTargetWeights(
|
||||
ThermionEntity entity, List<double> weights) async {
|
||||
if (weights.isEmpty) {
|
||||
throw Exception("Weights must not be empty");
|
||||
}
|
||||
var weightsPtr = allocator<Float>(weights.length);
|
||||
|
||||
for (int i = 0; i < weights.length; i++) {
|
||||
weightsPtr[i] = weights[i];
|
||||
}
|
||||
var success = await withBoolCallback((cb) {
|
||||
AnimationManager_setMorphTargetWeightsRenderThread(
|
||||
animationManager, entity, weightsPtr, weights.length, cb);
|
||||
});
|
||||
allocator.free(weightsPtr);
|
||||
|
||||
if (!success) {
|
||||
throw Exception(
|
||||
"Failed to set morph target weights, check logs for details");
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future<List<String>> getMorphTargetNames(
|
||||
covariant FFIAsset asset, ThermionEntity childEntity) async {
|
||||
var names = <String>[];
|
||||
|
||||
var count = AnimationManager_getMorphTargetNameCount(
|
||||
animationManager, asset.asset, childEntity);
|
||||
var outPtr = allocator<Char>(255);
|
||||
for (int i = 0; i < count; i++) {
|
||||
AnimationManager_getMorphTargetName(
|
||||
animationManager, asset.asset, childEntity, outPtr, i);
|
||||
names.add(outPtr.cast<Utf8>().toDartString());
|
||||
}
|
||||
allocator.free(outPtr);
|
||||
return names.cast<String>();
|
||||
}
|
||||
|
||||
Future<List<String>> getBoneNames(covariant FFIAsset asset,
|
||||
{int skinIndex = 0}) async {
|
||||
var count =
|
||||
AnimationManager_getBoneCount(animationManager, asset.asset, skinIndex);
|
||||
var out = allocator<Pointer<Char>>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
out[i] = allocator<Char>(255);
|
||||
}
|
||||
|
||||
AnimationManager_getBoneNames(
|
||||
animationManager, asset.asset, out, skinIndex);
|
||||
var names = <String>[];
|
||||
for (int i = 0; i < count; i++) {
|
||||
var namePtr = out[i];
|
||||
names.add(namePtr.cast<Utf8>().toDartString());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future<List<String>> getAnimationNames(covariant FFIAsset asset) async {
|
||||
var animationCount =
|
||||
AnimationManager_getAnimationCount(animationManager, asset.asset);
|
||||
var names = <String>[];
|
||||
var outPtr = allocator<Char>(255);
|
||||
for (int i = 0; i < animationCount; i++) {
|
||||
AnimationManager_getAnimationName(
|
||||
animationManager, asset.asset, outPtr, i);
|
||||
names.add(outPtr.cast<Utf8>().toDartString());
|
||||
}
|
||||
allocator.free(outPtr);
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future<double> getAnimationDuration(
|
||||
FFIAsset asset, int animationIndex) async {
|
||||
return AnimationManager_getAnimationDuration(
|
||||
animationManager, asset.asset, animationIndex);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<double> getAnimationDurationByName(FFIAsset asset, String name) async {
|
||||
var animations = await getAnimationNames(asset);
|
||||
var index = animations.indexOf(name);
|
||||
if (index == -1) {
|
||||
throw Exception("Failed to find animation $name");
|
||||
}
|
||||
return getAnimationDuration(asset, index);
|
||||
}
|
||||
|
||||
Future clearMorphAnimationData(ThermionEntity entity) async {
|
||||
if (!AnimationManager_clearMorphAnimation(animationManager, entity)) {
|
||||
throw Exception("Failed to clear morph animation");
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future setMorphAnimationData(FFIAsset asset, MorphAnimationData animation,
|
||||
{List<String>? targetMeshNames}) async {
|
||||
var meshEntities = await getChildEntities(asset);
|
||||
|
||||
var meshNames = meshEntities.map((e) => getNameForEntity(e)).toList();
|
||||
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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
var meshMorphTargets = await getMorphTargetNames(asset, meshEntity);
|
||||
|
||||
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 = Uint32List.fromList(
|
||||
intersection.map((m) => meshMorphTargets.indexOf(m)).toList());
|
||||
|
||||
// var frameData = animation.data;
|
||||
var frameData = animation.subset(intersection);
|
||||
|
||||
assert(
|
||||
frameData.data.length == animation.numFrames * intersection.length);
|
||||
|
||||
var result = AnimationManager_setMorphAnimation(
|
||||
animationManager,
|
||||
meshEntity,
|
||||
frameData.data.address,
|
||||
indices.address,
|
||||
indices.length,
|
||||
animation.numFrames,
|
||||
animation.frameLengthInMs);
|
||||
|
||||
if (!result) {
|
||||
throw Exception("Failed to set morph animation data for ${meshName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Currently, scale is not supported.
|
||||
///
|
||||
@override
|
||||
Future addBoneAnimation(covariant FFIAsset asset, BoneAnimationData animation,
|
||||
{int skinIndex = 0,
|
||||
double fadeOutInSecs = 0.0,
|
||||
double fadeInInSecs = 0.0,
|
||||
double maxDelta = 1.0}) async {
|
||||
if (animation.space != Space.Bone &&
|
||||
animation.space != Space.ParentWorldRotation) {
|
||||
throw UnimplementedError("TODO - support ${animation.space}");
|
||||
}
|
||||
if (skinIndex != 0) {
|
||||
throw UnimplementedError("TODO - support skinIndex != 0 ");
|
||||
}
|
||||
var boneNames = await getBoneNames(asset);
|
||||
var restLocalTransformsRaw = allocator<Float>(boneNames.length * 16);
|
||||
AnimationManager_getRestLocalTransforms(animationManager, asset.asset,
|
||||
skinIndex, restLocalTransformsRaw, boneNames.length);
|
||||
|
||||
var restLocalTransforms = <Matrix4>[];
|
||||
for (int i = 0; i < boneNames.length; i++) {
|
||||
var values = <double>[];
|
||||
for (int j = 0; j < 16; j++) {
|
||||
values.add(restLocalTransformsRaw[(i * 16) + j]);
|
||||
}
|
||||
restLocalTransforms.add(Matrix4.fromList(values));
|
||||
}
|
||||
allocator.free(restLocalTransformsRaw);
|
||||
|
||||
var numFrames = animation.frameData.length;
|
||||
|
||||
var data = allocator<Float>(numFrames * 16);
|
||||
|
||||
var bones = await Future.wait(List<Future<ThermionEntity>>.generate(
|
||||
boneNames.length, (i) => getBone(asset, i)));
|
||||
|
||||
for (int i = 0; i < animation.bones.length; i++) {
|
||||
var boneName = animation.bones[i];
|
||||
var entityBoneIndex = boneNames.indexOf(boneName);
|
||||
if (entityBoneIndex == -1) {
|
||||
_logger.warning("Bone $boneName not found, skipping");
|
||||
continue;
|
||||
}
|
||||
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 < 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++) {
|
||||
data.elementAt((frameNum * 16) + j).value =
|
||||
newLocalTransform.storage[j];
|
||||
}
|
||||
}
|
||||
|
||||
AnimationManager_addBoneAnimation(
|
||||
animationManager,
|
||||
asset.asset,
|
||||
skinIndex,
|
||||
entityBoneIndex,
|
||||
data,
|
||||
numFrames,
|
||||
animation.frameLengthInMs,
|
||||
fadeOutInSecs,
|
||||
fadeInInSecs,
|
||||
maxDelta);
|
||||
}
|
||||
allocator.free(data);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Matrix4> getLocalTransform(ThermionEntity entity) async {
|
||||
return double4x4ToMatrix4(
|
||||
TransformManager_getLocalTransform(app.transformManager, entity));
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Matrix4> getWorldTransform(ThermionEntity entity) async {
|
||||
return double4x4ToMatrix4(
|
||||
TransformManager_getWorldTransform(app.transformManager, entity));
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setTransform(ThermionEntity entity, Matrix4 transform) async {
|
||||
TransformManager_setTransform(
|
||||
app.transformManager, entity, matrix4ToDouble4x4(transform));
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future updateBoneMatrices(ThermionEntity entity) async {
|
||||
throw UnimplementedError();
|
||||
|
||||
// var result = await withBoolCallback((cb) {
|
||||
// update_bone_matrices_render_thread(_sceneManager!, entity, cb);
|
||||
// });
|
||||
// if (!result) {
|
||||
// throw Exception("Failed to update bone matrices");
|
||||
// }
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Matrix4> getInverseBindMatrix(FFIAsset asset, int boneIndex,
|
||||
{int skinIndex = 0}) async {
|
||||
var matrix = Float32List(16);
|
||||
AnimationManager_getInverseBindMatrix(
|
||||
animationManager, asset.asset, skinIndex, boneIndex, matrix.address);
|
||||
return Matrix4.fromList(matrix);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<ThermionEntity> getBone(FFIAsset asset, int boneIndex,
|
||||
{int skinIndex = 0}) async {
|
||||
if (skinIndex != 0) {
|
||||
throw UnimplementedError("TOOD");
|
||||
}
|
||||
return AnimationManager_getBone(
|
||||
animationManager, asset.asset, skinIndex, boneIndex);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future setBoneTransform(
|
||||
ThermionEntity entity, int boneIndex, Matrix4 transform,
|
||||
{int skinIndex = 0}) async {
|
||||
if (skinIndex != 0) {
|
||||
throw UnimplementedError("TOOD");
|
||||
}
|
||||
final ptr = allocator<Float>(16);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
ptr[i] = transform.storage[i];
|
||||
}
|
||||
var result = await withBoolCallback((cb) {
|
||||
AnimationManager_setBoneTransformRenderThread(
|
||||
animationManager, entity, skinIndex, boneIndex, ptr, cb);
|
||||
});
|
||||
|
||||
allocator.free(ptr);
|
||||
if (!result) {
|
||||
throw Exception("Failed to set bone transform");
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future resetBones(covariant FFIAsset asset) async {
|
||||
AnimationManager_resetToRestPose(animationManager, asset.asset);
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future playAnimation(covariant FFIAsset asset, int index,
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0,
|
||||
double startOffset = 0.0}) async {
|
||||
AnimationManager_playAnimation(animationManager, asset.asset, index, loop,
|
||||
reverse, replaceActive, crossfade, startOffset);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future stopAnimation(FFIAsset asset, int animationIndex) async {
|
||||
AnimationManager_stopAnimation(
|
||||
animationManager, asset.asset, animationIndex);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future stopAnimationByName(FFIAsset asset, String name) async {
|
||||
var animations = await getAnimationNames(asset);
|
||||
await stopAnimation(asset, animations.indexOf(name));
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future playAnimationByName(FFIAsset asset, String name,
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0,
|
||||
bool wait = false}) async {
|
||||
var animations = await getAnimationNames(asset);
|
||||
var index = animations.indexOf(name);
|
||||
var duration = await getAnimationDuration(asset, index);
|
||||
await playAnimation(asset, index,
|
||||
loop: loop,
|
||||
reverse: reverse,
|
||||
replaceActive: replaceActive,
|
||||
crossfade: crossfade);
|
||||
if (wait) {
|
||||
await Future.delayed(Duration(milliseconds: (duration * 1000).toInt()));
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future setGltfAnimationFrame(
|
||||
FFIAsset asset, int index, int animationFrame) async {
|
||||
AnimationManager_setGltfAnimationFrame(
|
||||
animationManager, asset.asset, index, animationFrame);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future addAnimationComponent(ThermionEntity entity) async {
|
||||
AnimationManager_addAnimationComponent(animationManager, entity);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future removeAnimationComponent(ThermionEntity entity) async {
|
||||
AnimationManager_removeAnimationComponent(animationManager, entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ import 'dart:typed_data';
|
||||
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/layers.dart';
|
||||
import 'package:thermion_dart/src/filament/src/layers.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import '../../../../utils/src/matrix.dart';
|
||||
import '../../thermion_viewer_base.dart';
|
||||
|
||||
class FFICamera extends Camera {
|
||||
final Pointer<TCamera> camera;
|
||||
@@ -150,4 +150,12 @@ class FFICamera extends Camera {
|
||||
Future destroy() async {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
Future setCameraExposure(
|
||||
double aperture, double shutterSpeed, double sensitivity) async {
|
||||
Camera_setExposure(camera, aperture, shutterSpeed, sensitivity);
|
||||
}
|
||||
|
||||
Future<double> getFocusDistance() async => Camera_getFocusDistance(camera);
|
||||
Future setFocusDistance(double focusDistance) async => Camera_setFocusDistance(camera, focusDistance);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/filament/filament.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_view.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
typedef RenderCallback = Pointer<NativeFunction<Void Function(Pointer<Void>)>>;
|
||||
@@ -11,12 +16,13 @@ class FFIFilamentConfig extends FilamentConfig<RenderCallback, Pointer<Void>> {
|
||||
FFIFilamentConfig(
|
||||
{required super.backend,
|
||||
required super.resourceLoader,
|
||||
required super.driver,
|
||||
required super.platform,
|
||||
required super.sharedContext,
|
||||
required super.uberArchivePath});
|
||||
}
|
||||
|
||||
class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
static FFIFilamentApp? _instance;
|
||||
|
||||
final Pointer<TEngine> engine;
|
||||
final Pointer<TGltfAssetLoader> gltfAssetLoader;
|
||||
final Pointer<TGltfResourceLoader> gltfResourceLoader;
|
||||
@@ -47,53 +53,82 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
transformManager: transformManager,
|
||||
lightManager: lightManager,
|
||||
renderableManager: renderableManager,
|
||||
ubershaderMaterialProvider: ubershaderMaterialProvider);
|
||||
ubershaderMaterialProvider: ubershaderMaterialProvider) {}
|
||||
|
||||
Future<FFIFilamentApp> create(FFIFilamentConfig config) async {
|
||||
if (_instance == null) {
|
||||
RenderLoop_destroy();
|
||||
RenderLoop_create();
|
||||
|
||||
final engine = await withPointerCallback<TEngine>((cb) =>
|
||||
Engine_createRenderThread(
|
||||
TBackend.values[config.backend.index].index,
|
||||
config.platform ?? nullptr,
|
||||
config.sharedContext ?? nullptr,
|
||||
config.stereoscopicEyeCount,
|
||||
config.disableHandleUseAfterFreeCheck,
|
||||
cb));
|
||||
|
||||
final gltfResourceLoader = await withPointerCallback<TGltfResourceLoader>(
|
||||
(cb) => GltfResourceLoader_createRenderThread(engine, cb));
|
||||
final gltfAssetLoader = await withPointerCallback<TGltfAssetLoader>(
|
||||
(cb) => GltfAssetLoader_createRenderThread(engine, nullptr, cb));
|
||||
final renderer = await withPointerCallback<TRenderer>(
|
||||
(cb) => Engine_createRendererRenderThread(engine, cb));
|
||||
final ubershaderMaterialProvider =
|
||||
await withPointerCallback<TMaterialProvider>(
|
||||
(cb) => GltfAssetLoader_getMaterialProvider(gltfAssetLoader));
|
||||
|
||||
final transformManager = Engine_getTransformManager(engine);
|
||||
final lightManager = Engine_getLightManager(engine);
|
||||
final renderableManager = Engine_getRenderableManager(engine);
|
||||
|
||||
final renderTicker = await withPointerCallback<TRenderTicker>(
|
||||
(cb) => RenderTicker_create(renderer));
|
||||
|
||||
final nameComponentManager = NameComponentManager_create();
|
||||
|
||||
_instance = FFIFilamentApp(
|
||||
engine,
|
||||
gltfAssetLoader,
|
||||
gltfResourceLoader,
|
||||
renderer,
|
||||
transformManager,
|
||||
lightManager,
|
||||
renderableManager,
|
||||
ubershaderMaterialProvider,
|
||||
renderTicker, nameComponentManager);
|
||||
static Future create(FFIFilamentConfig config) async {
|
||||
if (FilamentApp.instance != null) {
|
||||
await FilamentApp.instance!.destroy();
|
||||
}
|
||||
return _instance!;
|
||||
|
||||
RenderLoop_destroy();
|
||||
RenderLoop_create();
|
||||
|
||||
final engine = await withPointerCallback<TEngine>((cb) =>
|
||||
Engine_createRenderThread(
|
||||
TBackend.values[config.backend.index].index,
|
||||
config.platform ?? nullptr,
|
||||
config.sharedContext ?? nullptr,
|
||||
config.stereoscopicEyeCount,
|
||||
config.disableHandleUseAfterFreeCheck,
|
||||
cb));
|
||||
|
||||
final gltfResourceLoader = await withPointerCallback<TGltfResourceLoader>(
|
||||
(cb) => GltfResourceLoader_createRenderThread(engine, cb));
|
||||
final gltfAssetLoader = await withPointerCallback<TGltfAssetLoader>(
|
||||
(cb) => GltfAssetLoader_createRenderThread(engine, nullptr, cb));
|
||||
final renderer = await withPointerCallback<TRenderer>(
|
||||
(cb) => Engine_createRendererRenderThread(engine, cb));
|
||||
final ubershaderMaterialProvider =
|
||||
await withPointerCallback<TMaterialProvider>(
|
||||
(cb) => GltfAssetLoader_getMaterialProvider(gltfAssetLoader));
|
||||
|
||||
final transformManager = Engine_getTransformManager(engine);
|
||||
final lightManager = Engine_getLightManager(engine);
|
||||
final renderableManager = Engine_getRenderableManager(engine);
|
||||
|
||||
final renderTicker = await withPointerCallback<TRenderTicker>(
|
||||
(cb) => RenderTicker_create(renderer));
|
||||
|
||||
final nameComponentManager = NameComponentManager_create();
|
||||
|
||||
FilamentApp.instance = FFIFilamentApp(
|
||||
engine,
|
||||
gltfAssetLoader,
|
||||
gltfResourceLoader,
|
||||
renderer,
|
||||
transformManager,
|
||||
lightManager,
|
||||
renderableManager,
|
||||
ubershaderMaterialProvider,
|
||||
renderTicker,
|
||||
nameComponentManager);
|
||||
|
||||
}
|
||||
|
||||
final _views = <FFISwapChain, List<FFIView>>{};
|
||||
final _viewMappings = <FFIView, FFISwapChain>{};
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setRenderable(covariant FFIView view, bool renderable) async {
|
||||
final swapChain = _viewMappings[view]!;
|
||||
if (renderable && !_views[swapChain]!.contains(view)) {
|
||||
_views[swapChain]!.add(view);
|
||||
} else if (!renderable && _views[swapChain]!.contains(view)) {
|
||||
_views[swapChain]!.remove(view);
|
||||
}
|
||||
|
||||
final views = calloc<Pointer<TView>>(255);
|
||||
for (final swapChain in _views.keys) {
|
||||
var numViews = _views[swapChain]!.length;
|
||||
for (int i = 0; i < numViews; i++) {
|
||||
views[i] = _views[swapChain]![i].view;
|
||||
}
|
||||
RenderTicker_setRenderable(
|
||||
renderTicker, swapChain.swapChain, views, numViews);
|
||||
}
|
||||
calloc.free(views);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -136,8 +171,12 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
}
|
||||
|
||||
@override
|
||||
Future destroy() {
|
||||
throw UnimplementedError();
|
||||
Future destroy() async {
|
||||
for (final swapChain in _views.keys) {
|
||||
for (final view in _views[swapChain]!) {
|
||||
await setRenderable(view, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@@ -153,16 +192,316 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
return FFIRenderTarget(renderTarget, this);
|
||||
}
|
||||
|
||||
// ///
|
||||
// ///
|
||||
// ///
|
||||
// Future<RenderTarget> createRenderTarget(int width, int height,
|
||||
// {covariant FFITexture? color, covariant FFITexture? depth}) async {
|
||||
// final renderTarget = await withPointerCallback<TRenderTarget>((cb) {
|
||||
// RenderTarget_createRenderThread(app.engine, width, height,
|
||||
// color?.pointer ?? nullptr, depth?.pointer ?? nullptr, cb);
|
||||
// });
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Texture> createTexture(int width, int height,
|
||||
{int depth = 1,
|
||||
int levels = 1,
|
||||
Set<TextureUsage> flags = const {TextureUsage.TEXTURE_USAGE_SAMPLEABLE},
|
||||
TextureSamplerType textureSamplerType = TextureSamplerType.SAMPLER_2D,
|
||||
TextureFormat textureFormat = TextureFormat.RGBA16F,
|
||||
int? importedTextureHandle}) async {
|
||||
var bitmask = flags.fold(0, (a, b) => a | b.index);
|
||||
final texturePtr = await withPointerCallback<TTexture>((cb) {
|
||||
Texture_buildRenderThread(
|
||||
engine!,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
levels,
|
||||
importedTextureHandle ?? 0,
|
||||
bitmask,
|
||||
TTextureSamplerType.values[textureSamplerType.index],
|
||||
TTextureFormat.values[textureFormat.index],
|
||||
cb);
|
||||
});
|
||||
if (texturePtr == nullptr) {
|
||||
throw Exception("Failed to create texture");
|
||||
}
|
||||
return FFITexture(
|
||||
engine!,
|
||||
texturePtr,
|
||||
);
|
||||
}
|
||||
|
||||
// return FFIRenderTarget(renderTarget, app);
|
||||
// }
|
||||
Future<TextureSampler> createTextureSampler(
|
||||
{TextureMinFilter minFilter = TextureMinFilter.LINEAR,
|
||||
TextureMagFilter magFilter = TextureMagFilter.LINEAR,
|
||||
TextureWrapMode wrapS = TextureWrapMode.CLAMP_TO_EDGE,
|
||||
TextureWrapMode wrapT = TextureWrapMode.CLAMP_TO_EDGE,
|
||||
TextureWrapMode wrapR = TextureWrapMode.CLAMP_TO_EDGE,
|
||||
double anisotropy = 0.0,
|
||||
TextureCompareMode compareMode = TextureCompareMode.NONE,
|
||||
TextureCompareFunc compareFunc = TextureCompareFunc.LESS_EQUAL}) async {
|
||||
final samplerPtr = TextureSampler_create();
|
||||
TextureSampler_setMinFilter(
|
||||
samplerPtr, TSamplerMinFilter.values[minFilter.index]);
|
||||
TextureSampler_setMagFilter(
|
||||
samplerPtr, TSamplerMagFilter.values[magFilter.index]);
|
||||
TextureSampler_setWrapModeS(
|
||||
samplerPtr, TSamplerWrapMode.values[wrapS.index]);
|
||||
TextureSampler_setWrapModeT(
|
||||
samplerPtr, TSamplerWrapMode.values[wrapT.index]);
|
||||
TextureSampler_setWrapModeR(
|
||||
samplerPtr, TSamplerWrapMode.values[wrapR.index]);
|
||||
if (anisotropy > 0) {
|
||||
TextureSampler_setAnisotropy(samplerPtr, anisotropy);
|
||||
}
|
||||
|
||||
TextureSampler_setCompareMode(
|
||||
samplerPtr,
|
||||
TSamplerCompareMode.values[compareMode.index],
|
||||
TSamplerCompareFunc.values[compareFunc.index]);
|
||||
|
||||
return FFITextureSampler(samplerPtr);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<LinearImage> decodeImage(Uint8List data) async {
|
||||
final name = "image";
|
||||
var ptr = Image_decode(
|
||||
data.address,
|
||||
data.length,
|
||||
name.toNativeUtf8().cast<Char>(),
|
||||
);
|
||||
if (ptr == nullptr) {
|
||||
throw Exception("Failed to decode image");
|
||||
}
|
||||
return FFILinearImage(ptr);
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates an (empty) imge with the given dimensions.
|
||||
///
|
||||
Future<LinearImage> createImage(int width, int height, int channels) async {
|
||||
final ptr = Image_createEmpty(width, height, channels);
|
||||
return FFILinearImage(ptr);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Material> createMaterial(Uint8List data) async {
|
||||
var ptr = await withPointerCallback<TMaterial>((cb) {
|
||||
Engine_buildMaterialRenderThread(engine!, data.address, data.length, cb);
|
||||
});
|
||||
return FFIMaterial(ptr, this);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance> 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}) async {
|
||||
final key = Struct.create<TMaterialKey>();
|
||||
|
||||
key.doubleSided = doubleSided;
|
||||
key.unlit = unlit;
|
||||
key.hasVertexColors = hasVertexColors;
|
||||
key.hasBaseColorTexture = hasBaseColorTexture;
|
||||
key.hasNormalTexture = hasNormalTexture;
|
||||
key.hasOcclusionTexture = hasOcclusionTexture;
|
||||
key.hasEmissiveTexture = hasEmissiveTexture;
|
||||
key.useSpecularGlossiness = useSpecularGlossiness;
|
||||
key.alphaMode = alphaMode.index;
|
||||
key.enableDiagnostics = enableDiagnostics;
|
||||
key.unnamed.unnamed.hasMetallicRoughnessTexture =
|
||||
hasMetallicRoughnessTexture;
|
||||
key.unnamed.unnamed.metallicRoughnessUV = 0;
|
||||
key.baseColorUV = baseColorUV;
|
||||
key.hasClearCoatTexture = hasClearCoatTexture;
|
||||
key.clearCoatUV = clearCoatUV;
|
||||
key.hasClearCoatRoughnessTexture = hasClearCoatRoughnessTexture;
|
||||
key.clearCoatRoughnessUV = clearCoatRoughnessUV;
|
||||
key.hasClearCoatNormalTexture = hasClearCoatNormalTexture;
|
||||
key.clearCoatNormalUV = clearCoatNormalUV;
|
||||
key.hasClearCoat = hasClearCoat;
|
||||
key.hasTransmission = hasTransmission;
|
||||
key.hasTextureTransforms = hasTextureTransforms;
|
||||
key.emissiveUV = emissiveUV;
|
||||
key.aoUV = aoUV;
|
||||
key.normalUV = normalUV;
|
||||
key.hasTransmissionTexture = hasTransmissionTexture;
|
||||
key.transmissionUV = transmissionUV;
|
||||
key.hasSheenColorTexture = hasSheenColorTexture;
|
||||
key.sheenColorUV = sheenColorUV;
|
||||
key.hasSheenRoughnessTexture = hasSheenRoughnessTexture;
|
||||
key.sheenRoughnessUV = sheenRoughnessUV;
|
||||
key.hasVolumeThicknessTexture = hasVolumeThicknessTexture;
|
||||
key.volumeThicknessUV = volumeThicknessUV;
|
||||
key.hasSheen = hasSheen;
|
||||
key.hasIOR = hasIOR;
|
||||
key.hasVolume = hasVolume;
|
||||
|
||||
final materialInstance = await withPointerCallback<TMaterialInstance>((cb) {
|
||||
MaterialProvider_createMaterialInstanceRenderThread(
|
||||
ubershaderMaterialProvider, key.address, cb);
|
||||
});
|
||||
if (materialInstance == nullptr) {
|
||||
throw Exception("Failed to create material instance");
|
||||
}
|
||||
|
||||
var instance = FFIMaterialInstance(materialInstance, this);
|
||||
return instance;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<FFIMaterialInstance> createUnlitMaterialInstance() async {
|
||||
final instance = await createUbershaderMaterialInstance(unlit: true);
|
||||
return instance as FFIMaterialInstance;
|
||||
}
|
||||
|
||||
FFIMaterial? _gridMaterial;
|
||||
Future<FFIMaterial> get gridMaterial async {
|
||||
_gridMaterial ??= FFIMaterial(Material_createGridMaterial(), this);
|
||||
return _gridMaterial!;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future<ThermionAsset> createGeometry(Geometry geometry,
|
||||
{List<MaterialInstance>? materialInstances,
|
||||
bool keepData = false}) async {
|
||||
var assetPtr = await withPointerCallback<TSceneAsset>((callback) {
|
||||
var ptrList = Int64List(materialInstances?.length ?? 0);
|
||||
if (materialInstances != null && materialInstances.isNotEmpty) {
|
||||
ptrList.setRange(
|
||||
0,
|
||||
materialInstances.length,
|
||||
materialInstances
|
||||
.cast<FFIMaterialInstance>()
|
||||
.map((mi) => mi.pointer.address)
|
||||
.toList());
|
||||
}
|
||||
|
||||
return SceneAsset_createGeometryRenderThread(
|
||||
engine,
|
||||
geometry.vertices.address,
|
||||
geometry.vertices.length,
|
||||
geometry.normals.address,
|
||||
geometry.normals.length,
|
||||
geometry.uvs.address,
|
||||
geometry.uvs.length,
|
||||
geometry.indices.address,
|
||||
geometry.indices.length,
|
||||
geometry.primitiveType.index,
|
||||
ptrList.address.cast<Pointer<TMaterialInstance>>(),
|
||||
ptrList.length,
|
||||
callback);
|
||||
});
|
||||
if (assetPtr == nullptr) {
|
||||
throw Exception("Failed to create geometry");
|
||||
}
|
||||
|
||||
var asset = FFIAsset(assetPtr, this);
|
||||
|
||||
return asset;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance> getMaterialInstanceAt(
|
||||
ThermionEntity entity, int index) async {
|
||||
final instancePtr = RenderableManager_getMaterialInstanceAt(
|
||||
renderableManager, entity, index);
|
||||
|
||||
final instance = FFIMaterialInstance(instancePtr, this);
|
||||
return instance;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future render() async {
|
||||
RenderTicker_renderRenderThread(renderTicker, 0);
|
||||
}
|
||||
|
||||
@override
|
||||
Future register(
|
||||
covariant FFISwapChain swapChain, covariant FFIView view) async {
|
||||
_viewMappings[view] = swapChain;
|
||||
}
|
||||
|
||||
final _hooks = <Future Function()>[];
|
||||
|
||||
@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 requestFrame() async {
|
||||
for (final hook in _hooks) {
|
||||
await hook.call();
|
||||
}
|
||||
final completer = Completer();
|
||||
|
||||
final callback = NativeCallable<Void Function()>.listener(() {
|
||||
completer.complete(true);
|
||||
});
|
||||
|
||||
RenderLoop_requestAnimationFrame(callback.nativeFunction.cast());
|
||||
|
||||
try {
|
||||
await completer.future.timeout(Duration(seconds: 1));
|
||||
} catch (err) {
|
||||
print("WARNING - render call timed out");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import 'dart:async';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/entities.dart';
|
||||
import 'thermion_dart.g.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'ffi_view.dart';
|
||||
|
||||
class FFIGizmo extends FFIAsset implements GizmoAsset {
|
||||
|
||||
final Set<ThermionEntity> gizmoEntities;
|
||||
late NativeCallable<GizmoPickCallbackFunction> _nativeCallback;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/scene.dart';
|
||||
import 'package:thermion_dart/src/filament/src/scene.dart';
|
||||
import 'callbacks.dart';
|
||||
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/layers.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/shared_types.dart';
|
||||
import 'package:thermion_dart/src/filament/src/layers.dart';
|
||||
import 'package:thermion_dart/src/filament/src/shared_types.dart';
|
||||
import 'callbacks.dart';
|
||||
import 'ffi_camera.dart';
|
||||
|
||||
@@ -66,10 +66,6 @@ class FFIView extends View {
|
||||
View_setPostProcessing(view, enabled);
|
||||
}
|
||||
|
||||
Future setRenderable(bool renderable, FFISwapChain swapChain) async {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setFrustumCullingEnabled(bool enabled) async {
|
||||
View_setFrustumCullingEnabled(view, enabled);
|
||||
@@ -84,7 +80,8 @@ class FFIView extends View {
|
||||
|
||||
@override
|
||||
Future setToneMapper(ToneMapper mapper) async {
|
||||
View_setToneMappingRenderThread(view, app.engine, TToneMapping.values[mapper.index].value);
|
||||
View_setToneMappingRenderThread(
|
||||
view, app.engine, TToneMapping.values[mapper.index].value);
|
||||
}
|
||||
|
||||
Future setStencilBufferEnabled(bool enabled) async {
|
||||
@@ -111,7 +108,7 @@ class FFIView extends View {
|
||||
Future setScene(covariant FFIScene scene) async {
|
||||
await withVoidCallback((cb) => View_setScene(view, scene.scene));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future setLayerVisibility(VisibilityLayers layer, bool visible) async {
|
||||
View_setLayerEnabled(view, layer.value, visible);
|
||||
|
||||
13
thermion_dart/lib/src/viewer/src/ffi/src/grid_overlay.dart
Normal file
13
thermion_dart/lib/src/viewer/src/ffi/src/grid_overlay.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
|
||||
class GridOverlay extends FFIAsset {
|
||||
GridOverlay(super.asset, super.app);
|
||||
|
||||
static Future<GridOverlay> create(FFIFilamentApp app) async {
|
||||
final gridMaterial = await app.gridMaterial;
|
||||
final asset = SceneAsset_createGrid(app.engine, gridMaterial.pointer);
|
||||
return GridOverlay(asset, app);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,12 @@ external ffi.Pointer<TMaterialInstance> Material_createInstance(
|
||||
ffi.Pointer<TMaterial> tMaterial,
|
||||
);
|
||||
|
||||
@ffi.Native<ffi.Pointer<TMaterial> Function()>(isLeaf: true)
|
||||
external ffi.Pointer<TMaterial> Material_createImageMaterial();
|
||||
|
||||
@ffi.Native<ffi.Pointer<TMaterial> Function()>(isLeaf: true)
|
||||
external ffi.Pointer<TMaterial> Material_createGridMaterial();
|
||||
|
||||
@ffi.Native<ffi.Bool Function(ffi.Pointer<TMaterial>, ffi.Pointer<ffi.Char>)>(
|
||||
isLeaf: true)
|
||||
external bool Material_hasParameter(
|
||||
@@ -1227,6 +1233,11 @@ external double Camera_getFov(
|
||||
bool horizontal,
|
||||
);
|
||||
|
||||
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
|
||||
external double Camera_getFocusDistance(
|
||||
ffi.Pointer<TCamera> camera,
|
||||
);
|
||||
|
||||
@ffi.Native<ffi.Void Function(ffi.Pointer<TCamera>, ffi.Float)>(isLeaf: true)
|
||||
external void Camera_setFocusDistance(
|
||||
ffi.Pointer<TCamera> camera,
|
||||
@@ -1324,11 +1335,12 @@ external void TransformManager_setTransform(
|
||||
double4x4 transform,
|
||||
);
|
||||
|
||||
@ffi.Native<ffi.Void Function(ffi.Pointer<TTransformManager>, EntityId)>(
|
||||
@ffi.Native<ffi.Void Function(ffi.Pointer<TTransformManager>, EntityId, Aabb3)>(
|
||||
isLeaf: true)
|
||||
external void TransformManager_transformToUnitCube(
|
||||
ffi.Pointer<TTransformManager> tTransformManager,
|
||||
int entityId,
|
||||
Aabb3 boundingBox,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
@@ -1458,7 +1470,7 @@ external void RenderTicker_render(
|
||||
ffi.Void Function(ffi.Pointer<TRenderTicker>, ffi.Pointer<TSwapChain>,
|
||||
ffi.Pointer<ffi.Pointer<TView>>, ffi.Uint8)>(isLeaf: true)
|
||||
external void RenderTicker_setRenderable(
|
||||
ffi.Pointer<TRenderTicker> tFilamentRender,
|
||||
ffi.Pointer<TRenderTicker> tRenderTicker,
|
||||
ffi.Pointer<TSwapChain> swapChain,
|
||||
ffi.Pointer<ffi.Pointer<TView>> views,
|
||||
int numViews,
|
||||
@@ -2719,15 +2731,15 @@ external void TextureSampler_destroyRenderThread(
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TSceneManager>,
|
||||
ffi.Pointer<TAnimationManager>,
|
||||
EntityId,
|
||||
ffi.Int,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Bool)>>)>(
|
||||
isLeaf: true)
|
||||
external void set_bone_transform_render_thread(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
external void AnimationManager_setBoneTransformRenderThread(
|
||||
ffi.Pointer<TAnimationManager> tAnimationManager,
|
||||
int asset,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
@@ -2736,10 +2748,10 @@ external void set_bone_transform_render_thread(
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(ffi.Pointer<TSceneManager>, EntityId,
|
||||
ffi.Void Function(ffi.Pointer<TAnimationManager>, EntityId,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
|
||||
external void reset_to_rest_pose_render_thread(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
external void AnimationManager_resetToRestPoseRenderThread(
|
||||
ffi.Pointer<TAnimationManager> tAnimationManager,
|
||||
int entityId,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> callback,
|
||||
);
|
||||
@@ -3181,6 +3193,14 @@ external ffi.Pointer<TSceneAsset> SceneAsset_loadGltf(
|
||||
int numInstances,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Pointer<TSceneAsset> Function(
|
||||
ffi.Pointer<TEngine>, ffi.Pointer<TMaterial>)>(isLeaf: true)
|
||||
external ffi.Pointer<TSceneAsset> SceneAsset_createGrid(
|
||||
ffi.Pointer<TEngine> tEngine,
|
||||
ffi.Pointer<TMaterial> tMaterial,
|
||||
);
|
||||
|
||||
@ffi.Native<ffi.Void Function(ffi.Pointer<TSceneAsset>)>(isLeaf: true)
|
||||
external void SceneAsset_destroy(
|
||||
ffi.Pointer<TSceneAsset> tSceneAsset,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
||||
library;
|
||||
|
||||
export 'src/thermion_viewer_ffi.dart' show ThermionViewerFFI;
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/engine.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
class FilamentConfig<T, U> {
|
||||
final Backend backend;
|
||||
final T? renderCallback;
|
||||
final U? renderCallbackOwner;
|
||||
final U resourceLoader;
|
||||
final U? platform;
|
||||
final U? driver;
|
||||
final U? sharedContext;
|
||||
final String uberArchivePath;
|
||||
final int stereoscopicEyeCount;
|
||||
final bool disableHandleUseAfterFreeCheck;
|
||||
|
||||
FilamentConfig(
|
||||
{required this.backend,
|
||||
required this.resourceLoader,
|
||||
required this.uberArchivePath,
|
||||
this.renderCallback,
|
||||
this.renderCallbackOwner,
|
||||
this.platform,
|
||||
this.driver,
|
||||
this.sharedContext,
|
||||
this.stereoscopicEyeCount = 1,
|
||||
this.disableHandleUseAfterFreeCheck = false});
|
||||
}
|
||||
|
||||
abstract class FilamentApp<T> {
|
||||
final T engine;
|
||||
final T gltfAssetLoader;
|
||||
final T gltfResourceLoader;
|
||||
final T renderer;
|
||||
final T transformManager;
|
||||
final T lightManager;
|
||||
final T renderableManager;
|
||||
final T ubershaderMaterialProvider;
|
||||
|
||||
FilamentApp(
|
||||
{required this.engine,
|
||||
required this.gltfAssetLoader,
|
||||
required this.gltfResourceLoader,
|
||||
required this.renderer,
|
||||
required this.transformManager,
|
||||
required this.lightManager,
|
||||
required this.renderableManager,
|
||||
required this.ubershaderMaterialProvider
|
||||
});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createHeadlessSwapChain(int width, int height,
|
||||
{bool hasStencilBuffer = false});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createSwapChain(T handle, {bool hasStencilBuffer = false});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroySwapChain(SwapChain swapChain);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroy();
|
||||
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<RenderTarget> createRenderTarget(
|
||||
int width, int height, { covariant Texture? color, covariant Texture? depth });
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/layers.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import '../thermion_viewer_base.dart';
|
||||
|
||||
enum Projection { Perspective, Orthographic }
|
||||
|
||||
abstract class Camera {
|
||||
Future lookAt(Vector3 position, {Vector3? focus, Vector3? up}) async {
|
||||
focus ??= Vector3.zero();
|
||||
up ??= Vector3(0, 1, 0);
|
||||
final viewMatrix = makeViewMatrix(position, focus, up);
|
||||
viewMatrix.invert();
|
||||
await setModelMatrix(viewMatrix);
|
||||
}
|
||||
|
||||
Future setProjection(Projection projection, double left, double right,
|
||||
double bottom, double top, double near, double far);
|
||||
Future setProjectionMatrixWithCulling(
|
||||
Matrix4 projectionMatrix, double near, double far);
|
||||
|
||||
Future setLensProjection(
|
||||
{double near = kNear,
|
||||
double far = kFar,
|
||||
double aspect = 1.0,
|
||||
double focalLength = kFocalLength});
|
||||
|
||||
Future<Matrix4> getViewMatrix();
|
||||
Future<Matrix4> getModelMatrix();
|
||||
Future<Matrix4> getProjectionMatrix();
|
||||
Future<Matrix4> getCullingProjectionMatrix();
|
||||
Future setModelMatrix(Matrix4 matrix);
|
||||
|
||||
ThermionEntity getEntity();
|
||||
|
||||
Future setTransform(Matrix4 transform);
|
||||
|
||||
Future<double> getNear();
|
||||
Future<double> getCullingFar();
|
||||
Future<double> getFocalLength();
|
||||
|
||||
Future destroy();
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
enum Backend {
|
||||
/// !< Automatically selects an appropriate driver for the platform.
|
||||
DEFAULT(0),
|
||||
|
||||
/// !< Selects the OpenGL/ES driver (default on Android)
|
||||
OPENGL(1),
|
||||
|
||||
/// !< Selects the Vulkan driver if the platform supports it (default on Linux/Windows)
|
||||
VULKAN(2),
|
||||
|
||||
/// !< Selects the Metal driver if the platform supports it (default on MacOS/iOS).
|
||||
METAL(3),
|
||||
|
||||
/// !< Selects the no-op driver for testing purposes.
|
||||
NOOP(4);
|
||||
|
||||
final int value;
|
||||
const Backend(this.value);
|
||||
|
||||
static Backend fromValue(int value) => switch (value) {
|
||||
0 => DEFAULT,
|
||||
1 => OPENGL,
|
||||
2 => VULKAN,
|
||||
3 => METAL,
|
||||
4 => NOOP,
|
||||
_ => throw ArgumentError("Unknown value for TBackend: $value"),
|
||||
};
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
library;
|
||||
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
export 'geometry.dart';
|
||||
export 'gltf.dart';
|
||||
|
||||
export 'light_options.dart';
|
||||
|
||||
// handle manipulate an Entity
|
||||
typedef ThermionEntity = int;
|
||||
|
||||
abstract class ThermionAsset {
|
||||
///
|
||||
///
|
||||
///
|
||||
ThermionEntity get entity;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<List<ThermionEntity>> getChildEntities();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setMaterialInstanceAt(covariant MaterialInstance instance);
|
||||
|
||||
///
|
||||
/// Renders an outline around [entity] with the given color.
|
||||
///
|
||||
Future setStencilHighlight(
|
||||
{double r = 1.0, double g = 0.0, double b = 0.0, int? entityIndex});
|
||||
|
||||
///
|
||||
/// Removes the outline around [entity]. Noop if there was no highlight.
|
||||
///
|
||||
Future removeStencilHighlight();
|
||||
|
||||
///
|
||||
/// When visible is [true], renders the bounding box.
|
||||
///
|
||||
Future setBoundingBoxVisibility(bool visible);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<ThermionAsset> getInstance(int index);
|
||||
|
||||
///
|
||||
/// Create a new instance of [entity].
|
||||
/// Instances are not automatically added to the scene; you must
|
||||
/// call [addToScene].
|
||||
///
|
||||
Future<ThermionAsset> createInstance(
|
||||
{covariant List<MaterialInstance>? materialInstances = null});
|
||||
|
||||
///
|
||||
/// Returns the number of instances associated with this asset.
|
||||
///
|
||||
Future<int> getInstanceCount();
|
||||
|
||||
///
|
||||
/// Returns all instances of associated with this asset.
|
||||
///
|
||||
Future<List<ThermionAsset>> getInstances();
|
||||
|
||||
Future setCastShadows(bool castShadows);
|
||||
Future setReceiveShadows(bool castShadows);
|
||||
}
|
||||
|
||||
enum Axis {
|
||||
X(const [1.0, 0.0, 0.0]),
|
||||
Y(const [0.0, 1.0, 0.0]),
|
||||
Z(const [0.0, 0.0, 1.0]);
|
||||
|
||||
const Axis(this.vector);
|
||||
|
||||
final List<double> vector;
|
||||
|
||||
Vector3 asVector() => Vector3(vector[0], vector[1], vector[2]);
|
||||
}
|
||||
|
||||
enum GizmoPickResultType { AxisX, AxisY, AxisZ, Parent, None }
|
||||
|
||||
enum GizmoType { translation, rotation }
|
||||
|
||||
abstract class GizmoAsset extends ThermionAsset {
|
||||
Future pick(int x, int y,
|
||||
{Future Function(GizmoPickResultType axis, Vector3 coords)? handler});
|
||||
Future highlight(Axis axis);
|
||||
Future unhighlight();
|
||||
bool isNonPickable(ThermionEntity entity);
|
||||
bool isGizmoEntity(ThermionEntity entity);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
final ThermionEntity FILAMENT_ENTITY_NULL = 0;
|
||||
@@ -1,32 +0,0 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import '../../viewer.dart';
|
||||
|
||||
class Geometry {
|
||||
final Float32List vertices;
|
||||
final Uint16List indices;
|
||||
final Float32List normals;
|
||||
final Float32List uvs;
|
||||
final PrimitiveType primitiveType;
|
||||
|
||||
Geometry(
|
||||
this.vertices,
|
||||
List<int> indices, {
|
||||
Float32List? normals,
|
||||
Float32List? uvs,
|
||||
this.primitiveType = PrimitiveType.TRIANGLES,
|
||||
}) : indices = Uint16List.fromList(indices),
|
||||
normals = normals ?? Float32List(0),
|
||||
uvs = uvs ?? Float32List(0) {
|
||||
assert(this.uvs.length == 0 || this.uvs.length == (vertices.length ~/ 3 * 2), "Expected either zero or ${indices.length * 2} UVs, got ${this.uvs.length}");
|
||||
}
|
||||
|
||||
void scale(double factor) {
|
||||
for (int i = 0; i < vertices.length; i++) {
|
||||
vertices[i] = vertices[i] * factor;
|
||||
}
|
||||
}
|
||||
|
||||
bool get hasNormals => normals.isNotEmpty;
|
||||
bool get hasUVs => uvs.isNotEmpty;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
class GLTF {
|
||||
final String uri;
|
||||
final int numInstances;
|
||||
|
||||
GLTF(this.uri, this.numInstances);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
const double kNear = 0.05;
|
||||
const double kFar = 1000.0;
|
||||
const double kFocalLength = 28.0;
|
||||
|
||||
enum VisibilityLayers {
|
||||
DEFAULT_ASSET(0),
|
||||
LAYER_1(1),
|
||||
LAYER_2(2),
|
||||
LAYER_3(3),
|
||||
LAYER_4(4),
|
||||
LAYER_5(5),
|
||||
BACKGROUND(6),
|
||||
OVERLAY(7);
|
||||
|
||||
final int value;
|
||||
const VisibilityLayers(this.value);
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
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,
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
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,
|
||||
);
|
||||
|
||||
DirectLight.sun({
|
||||
double color = 6500,
|
||||
double intensity = 100000,
|
||||
bool castShadows = true,
|
||||
Vector3? direction,
|
||||
double sunAngularRadius = 0.545,
|
||||
double sunHaloSize = 10.0,
|
||||
double sunHaloFalloff = 80.0,
|
||||
}) : this(
|
||||
type: LightType.DIRECTIONAL,
|
||||
color: color,
|
||||
intensity: intensity,
|
||||
castShadows: castShadows,
|
||||
position: Vector3(0, 0, 0),
|
||||
direction: direction ?? Vector3(0, -1, 0),
|
||||
sunAngularRadius: sunAngularRadius,
|
||||
sunHaloSize: sunHaloSize,
|
||||
sunHaloFallof: sunHaloFalloff,
|
||||
);
|
||||
|
||||
DirectLight.spot({
|
||||
double color = 6500,
|
||||
double intensity = 100000,
|
||||
bool castShadows = true,
|
||||
Vector3? position,
|
||||
Vector3? direction,
|
||||
double falloffRadius = 1.0,
|
||||
double spotLightConeInner = pi / 8,
|
||||
double spotLightConeOuter = pi / 4,
|
||||
}) : this(
|
||||
type: LightType.SPOT,
|
||||
color: color,
|
||||
intensity: intensity,
|
||||
castShadows: castShadows,
|
||||
position: position ?? Vector3(0, 1, 0),
|
||||
direction: direction ?? Vector3(0, -1, 0),
|
||||
falloffRadius: falloffRadius,
|
||||
spotLightConeInner: spotLightConeInner,
|
||||
spotLightConeOuter: spotLightConeOuter,
|
||||
);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// see filament Manipulator.h for more details
|
||||
@Deprecated(
|
||||
"This is used the native pointer manipulator Prefer InputHandler instead")
|
||||
enum ManipulatorMode { ORBIT, MAP, FREE_FLIGHT }
|
||||
@@ -1,150 +0,0 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
enum SamplerCompareFunction {
|
||||
/// !< Less or equal
|
||||
LE,
|
||||
|
||||
/// !< Greater or equal
|
||||
GE,
|
||||
|
||||
/// !< Strictly less than
|
||||
L,
|
||||
|
||||
/// !< Strictly greater than
|
||||
G,
|
||||
|
||||
/// !< Equal
|
||||
E,
|
||||
|
||||
/// !< Not equal
|
||||
NE,
|
||||
|
||||
/// !< Always. Depth / stencil testing is deactivated.
|
||||
A,
|
||||
|
||||
/// !< Never. The depth / stencil test always fails.
|
||||
N;
|
||||
}
|
||||
|
||||
/// Defines stencil operations
|
||||
enum StencilOperation {
|
||||
/// Keep the current value
|
||||
KEEP,
|
||||
|
||||
/// Set the value to zero
|
||||
ZERO,
|
||||
|
||||
/// Set the value to reference value
|
||||
REPLACE,
|
||||
|
||||
/// Increment the current value with saturation
|
||||
INCR,
|
||||
|
||||
/// Increment the current value without saturation
|
||||
INCR_WRAP,
|
||||
|
||||
/// Decrement the current value with saturation
|
||||
DECR,
|
||||
|
||||
/// Decrement the current value without saturation
|
||||
DECR_WRAP,
|
||||
|
||||
/// Invert the current value
|
||||
INVERT
|
||||
}
|
||||
|
||||
enum CullingMode {
|
||||
NONE, // No culling
|
||||
FRONT, // Cull front faces
|
||||
BACK, // Cull back faces
|
||||
FRONT_AND_BACK // Cull both front and back faces
|
||||
}
|
||||
|
||||
/// Defines which face(s) the stencil operation affects
|
||||
enum StencilFace {
|
||||
/// Front face only
|
||||
FRONT,
|
||||
|
||||
/// Back face only
|
||||
BACK,
|
||||
|
||||
/// Both front and back faces
|
||||
FRONT_AND_BACK
|
||||
}
|
||||
|
||||
enum AlphaMode { OPAQUE, MASK, BLEND }
|
||||
|
||||
enum TransparencyMode {
|
||||
//! the transparent object is drawn honoring the raster state
|
||||
DEFAULT,
|
||||
/**
|
||||
* the transparent object is first drawn in the depth buffer,
|
||||
* then in the color buffer, honoring the culling mode, but ignoring the depth test function
|
||||
*/
|
||||
TWO_PASSES_ONE_SIDE,
|
||||
|
||||
/**
|
||||
* the transparent object is drawn twice in the color buffer,
|
||||
* first with back faces only, then with front faces; the culling
|
||||
* mode is ignored. Can be combined with two-sided lighting
|
||||
*/
|
||||
TWO_PASSES_TWO_SIDES
|
||||
}
|
||||
|
||||
abstract class Material {
|
||||
Future<MaterialInstance> createInstance();
|
||||
Future<bool> hasParameter(String propertyName);
|
||||
Future destroy();
|
||||
}
|
||||
|
||||
abstract class MaterialInstance {
|
||||
Future<bool> isStencilWriteEnabled();
|
||||
Future setDepthWriteEnabled(bool enabled);
|
||||
Future setDepthFunc(SamplerCompareFunction depthFunc);
|
||||
Future setDepthCullingEnabled(bool enabled);
|
||||
Future setParameterFloat(String name, double x);
|
||||
Future setParameterFloat2(String name, double x, double y);
|
||||
Future setParameterFloat3(String name, double x, double y, double z);
|
||||
Future setParameterFloat3Array(String name, List<Vector3> data);
|
||||
Future setParameterFloat4(
|
||||
String name, double x, double y, double z, double w);
|
||||
|
||||
Future setParameterInt(String name, int value);
|
||||
Future setParameterBool(String name, bool value);
|
||||
Future setParameterTexture(
|
||||
String name, covariant Texture texture, covariant TextureSampler sampler);
|
||||
|
||||
/// Sets the stencil operation to be performed when the stencil test fails
|
||||
Future setStencilOpStencilFail(StencilOperation op,
|
||||
[StencilFace face = StencilFace.FRONT_AND_BACK]);
|
||||
|
||||
/// Sets the stencil operation to be performed when the depth test fails
|
||||
Future setStencilOpDepthFail(StencilOperation op,
|
||||
[StencilFace face = StencilFace.FRONT_AND_BACK]);
|
||||
|
||||
/// Sets the stencil operation to be performed when both depth and stencil tests pass
|
||||
Future setStencilOpDepthStencilPass(StencilOperation op,
|
||||
[StencilFace face = StencilFace.FRONT_AND_BACK]);
|
||||
|
||||
/// Sets the stencil test comparison function
|
||||
Future setStencilCompareFunction(SamplerCompareFunction func,
|
||||
[StencilFace face = StencilFace.FRONT_AND_BACK]);
|
||||
|
||||
/// Sets the reference value used for stencil testing
|
||||
Future setStencilReferenceValue(int value,
|
||||
[StencilFace face = StencilFace.FRONT_AND_BACK]);
|
||||
|
||||
Future setStencilWriteEnabled(bool enabled);
|
||||
|
||||
Future setCullingMode(CullingMode cullingMode);
|
||||
|
||||
Future setStencilReadMask(int mask);
|
||||
Future setStencilWriteMask(int mask);
|
||||
|
||||
Future setTransparencyMode(TransparencyMode mode);
|
||||
|
||||
Future destroy();
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import '../../viewer.dart';
|
||||
|
||||
/// The result of a picking operation (see [ThermionViewer.pick] for more details).
|
||||
/// [x] and [y] refer to the original screen coordinates used to call [pick]; this should
|
||||
/// match the values of [fragX] and [fragY]. [fragZ] is the depth value in screen coordinates,
|
||||
/// [depth] is the value in the depth buffer (i.e. fragZ = 1.0 - depth).
|
||||
///
|
||||
typedef FilamentPickResult = ({
|
||||
ThermionEntity entity,
|
||||
int x,
|
||||
int y,
|
||||
double depth,
|
||||
double fragX,
|
||||
double fragY,
|
||||
double fragZ
|
||||
});
|
||||
typedef PickResult = FilamentPickResult;
|
||||
@@ -1,10 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
abstract class RenderTarget {
|
||||
Future<Texture> getColorTexture();
|
||||
Future<Texture> getDepthTexture();
|
||||
Future destroy();
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import 'package:thermion_dart/src/viewer/src/thermion_viewer_base.dart';
|
||||
|
||||
abstract class Scene {
|
||||
Future add(covariant ThermionAsset asset);
|
||||
Future remove(covariant ThermionAsset asset);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
library shared_types;
|
||||
|
||||
export 'swap_chain.dart';
|
||||
export 'view.dart';
|
||||
export 'render_target.dart';
|
||||
export 'camera.dart';
|
||||
export 'material.dart';
|
||||
export 'texture.dart';
|
||||
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';
|
||||
@@ -1,3 +0,0 @@
|
||||
abstract class SwapChain {
|
||||
|
||||
}
|
||||
@@ -1,455 +0,0 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
/// Defines the type of sampler to use with a texture
|
||||
enum TextureSamplerType {
|
||||
SAMPLER_2D,
|
||||
SAMPLER_2D_ARRAY,
|
||||
SAMPLER_CUBEMAP,
|
||||
SAMPLER_EXTERNAL,
|
||||
SAMPLER_3D,
|
||||
SAMPLER_CUBEMAP_ARRAY
|
||||
}
|
||||
|
||||
/// Defines internal texture formats
|
||||
enum TextureFormat {
|
||||
// 8-bits per element
|
||||
R8, // R 8-bits
|
||||
R8_SNORM, // R 8-bits (signed normalized)
|
||||
R8UI, // R 8-bits (unsigned integer)
|
||||
R8I, // R 8-bits (signed integer)
|
||||
STENCIL8, // Stencil 8-bits
|
||||
|
||||
// 16-bits per element
|
||||
R16F, // R 16-bits (float)
|
||||
R16UI, // R 16-bits (unsigned integer)
|
||||
R16I, // R 16-bits (signed integer)
|
||||
RG8, // RG 8-bits each
|
||||
RG8_SNORM, // RG 8-bits each (signed normalized)
|
||||
RG8UI, // RG 8-bits each (unsigned integer)
|
||||
RG8I, // RG 8-bits each (signed integer)
|
||||
RGB565, // RGB 5-6-5 bits
|
||||
RGB9_E5, // RGB9_E5 format
|
||||
RGB5_A1, // RGB 5 bits each, A 1 bit
|
||||
RGBA4, // RGBA 4 bits each
|
||||
DEPTH16, // Depth 16-bits
|
||||
|
||||
// 24-bits per element
|
||||
RGB8, // RGB 8-bits each
|
||||
SRGB8, // RGB 8-bits each (sRGB color space)
|
||||
RGB8_SNORM, // RGB 8-bits each (signed normalized)
|
||||
RGB8UI, // RGB 8-bits each (unsigned integer)
|
||||
RGB8I, // RGB 8-bits each (signed integer)
|
||||
DEPTH24, // Depth 24-bits
|
||||
|
||||
// 32-bits per element
|
||||
R32F, // R 32-bits (float)
|
||||
R32UI, // R 32-bits (unsigned integer)
|
||||
R32I, // R 32-bits (signed integer)
|
||||
RG16F, // RG 16-bits each (float)
|
||||
RG16UI, // RG 16-bits each (unsigned integer)
|
||||
RG16I, // RG 16-bits each (signed integer)
|
||||
R11F_G11F_B10F, // R11F_G11F_B10F format
|
||||
RGBA8, // RGBA 8-bits each
|
||||
SRGB8_A8, // RGB 8-bits each (sRGB), A 8-bits
|
||||
RGBA8_SNORM, // RGBA 8-bits each (signed normalized)
|
||||
UNUSED, // used to be rgbm
|
||||
RGB10_A2, // RGB 10-bits each, A 2-bits
|
||||
RGBA8UI, // RGBA 8-bits each (unsigned integer)
|
||||
RGBA8I, // RGBA 8-bits each (signed integer)
|
||||
DEPTH32F, // Depth 32-bits (float)
|
||||
DEPTH24_STENCIL8, // Depth 24-bits, Stencil 8-bits
|
||||
DEPTH32F_STENCIL8, // Depth 32-bits (float), Stencil 8-bits
|
||||
|
||||
// 48-bits per element
|
||||
RGB16F, // RGB 16-bits each (float)
|
||||
RGB16UI, // RGB 16-bits each (unsigned integer)
|
||||
RGB16I, // RGB 16-bits each (signed integer)
|
||||
|
||||
// 64-bits per element
|
||||
RG32F, // RG 32-bits each (float)
|
||||
RG32UI, // RG 32-bits each (unsigned integer)
|
||||
RG32I, // RG 32-bits each (signed integer)
|
||||
RGBA16F, // RGBA 16-bits each (float)
|
||||
RGBA16UI, // RGBA 16-bits each (unsigned integer)
|
||||
RGBA16I, // RGBA 16-bits each (signed integer)
|
||||
|
||||
// 96-bits per element
|
||||
RGB32F, // RGB 32-bits each (float)
|
||||
RGB32UI, // RGB 32-bits each (unsigned integer)
|
||||
RGB32I, // RGB 32-bits each (signed integer)
|
||||
|
||||
// 128-bits per element
|
||||
RGBA32F, // RGBA 32-bits each (float)
|
||||
RGBA32UI, // RGBA 32-bits each (unsigned integer)
|
||||
RGBA32I, // RGBA 32-bits each (signed integer)
|
||||
|
||||
// Compressed formats
|
||||
EAC_R11, // EAC R11 (compressed)
|
||||
EAC_R11_SIGNED, // EAC R11 (compressed, signed)
|
||||
EAC_RG11, // EAC RG11 (compressed)
|
||||
EAC_RG11_SIGNED, // EAC RG11 (compressed, signed)
|
||||
ETC2_RGB8, // ETC2 RGB8 (compressed)
|
||||
ETC2_SRGB8, // ETC2 RGB8 (compressed, sRGB)
|
||||
ETC2_RGB8_A1, // ETC2 RGB8A1 (compressed)
|
||||
ETC2_SRGB8_A1, // ETC2 RGB8A1 (compressed, sRGB)
|
||||
ETC2_EAC_RGBA8, // ETC2 RGBA8 (compressed)
|
||||
ETC2_EAC_SRGBA8, // ETC2 RGBA8 (compressed, sRGB)
|
||||
|
||||
// DXT formats
|
||||
DXT1_RGB, // DXT1 RGB (compressed)
|
||||
DXT1_RGBA, // DXT1 RGBA (compressed)
|
||||
DXT3_RGBA, // DXT3 RGBA (compressed)
|
||||
DXT5_RGBA, // DXT5 RGBA (compressed)
|
||||
DXT1_SRGB, // DXT1 sRGB (compressed)
|
||||
DXT1_SRGBA, // DXT1 sRGBA (compressed)
|
||||
DXT3_SRGBA, // DXT3 sRGBA (compressed)
|
||||
DXT5_SRGBA, // DXT5 sRGBA (compressed)
|
||||
|
||||
// ASTC formats
|
||||
RGBA_ASTC_4x4, // ASTC 4x4 RGBA (compressed)
|
||||
RGBA_ASTC_5x4, // ASTC 5x4 RGBA (compressed)
|
||||
RGBA_ASTC_5x5, // ASTC 5x5 RGBA (compressed)
|
||||
RGBA_ASTC_6x5, // ASTC 6x5 RGBA (compressed)
|
||||
RGBA_ASTC_6x6, // ASTC 6x6 RGBA (compressed)
|
||||
RGBA_ASTC_8x5, // ASTC 8x5 RGBA (compressed)
|
||||
RGBA_ASTC_8x6, // ASTC 8x6 RGBA (compressed)
|
||||
RGBA_ASTC_8x8, // ASTC 8x8 RGBA (compressed)
|
||||
RGBA_ASTC_10x5, // ASTC 10x5 RGBA (compressed)
|
||||
RGBA_ASTC_10x6, // ASTC 10x6 RGBA (compressed)
|
||||
RGBA_ASTC_10x8, // ASTC 10x8 RGBA (compressed)
|
||||
RGBA_ASTC_10x10, // ASTC 10x10 RGBA (compressed)
|
||||
RGBA_ASTC_12x10, // ASTC 12x10 RGBA (compressed)
|
||||
RGBA_ASTC_12x12, // ASTC 12x12 RGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_4x4, // ASTC 4x4 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_5x4, // ASTC 5x4 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_5x5, // ASTC 5x5 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_6x5, // ASTC 6x5 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_6x6, // ASTC 6x6 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_8x5, // ASTC 8x5 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_8x6, // ASTC 8x6 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_8x8, // ASTC 8x8 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_10x5, // ASTC 10x5 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_10x6, // ASTC 10x6 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_10x8, // ASTC 10x8 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_10x10, // ASTC 10x10 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_12x10, // ASTC 12x10 sRGBA (compressed)
|
||||
SRGB8_ALPHA8_ASTC_12x12, // ASTC 12x12 sRGBA (compressed)
|
||||
|
||||
// RGTC formats
|
||||
RED_RGTC1, // BC4 unsigned
|
||||
SIGNED_RED_RGTC1, // BC4 signed
|
||||
RED_GREEN_RGTC2, // BC5 unsigned
|
||||
SIGNED_RED_GREEN_RGTC2, // BC5 signed
|
||||
|
||||
// BPTC formats
|
||||
RGB_BPTC_SIGNED_FLOAT, // BC6H signed
|
||||
RGB_BPTC_UNSIGNED_FLOAT, // BC6H unsigned
|
||||
RGBA_BPTC_UNORM, // BC7
|
||||
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
|
||||
}
|
||||
|
||||
enum TextureUsage {
|
||||
TEXTURE_USAGE_NONE(0),
|
||||
|
||||
/// !< Texture can be used as a color attachment
|
||||
TEXTURE_USAGE_COLOR_ATTACHMENT(1),
|
||||
|
||||
/// !< Texture can be used as a depth attachment
|
||||
TEXTURE_USAGE_DEPTH_ATTACHMENT(2),
|
||||
|
||||
/// !< Texture can be used as a stencil attachment
|
||||
TEXTURE_USAGE_STENCIL_ATTACHMENT(4),
|
||||
|
||||
/// !< Data can be uploaded into this texture (default)
|
||||
TEXTURE_USAGE_UPLOADABLE(8),
|
||||
|
||||
/// !< Texture can be sampled (default)
|
||||
TEXTURE_USAGE_SAMPLEABLE(16),
|
||||
|
||||
/// !< Texture can be used as a subpass input
|
||||
TEXTURE_USAGE_SUBPASS_INPUT(32),
|
||||
|
||||
/// !< Texture can be used the source of a blit()
|
||||
TEXTURE_USAGE_BLIT_SRC(64),
|
||||
|
||||
/// !< Texture can be used the destination of a blit()
|
||||
TEXTURE_USAGE_BLIT_DST(128),
|
||||
|
||||
/// !< Texture can be used the destination of a blit()
|
||||
TEXTURE_USAGE_PROTECTED(256),
|
||||
|
||||
/// !< Default texture usage
|
||||
TEXTURE_USAGE_DEFAULT(24);
|
||||
|
||||
final int value;
|
||||
const TextureUsage(this.value);
|
||||
|
||||
static TextureUsage fromValue(int value) => switch (value) {
|
||||
0 => TEXTURE_USAGE_NONE,
|
||||
1 => TEXTURE_USAGE_COLOR_ATTACHMENT,
|
||||
2 => TEXTURE_USAGE_DEPTH_ATTACHMENT,
|
||||
4 => TEXTURE_USAGE_STENCIL_ATTACHMENT,
|
||||
8 => TEXTURE_USAGE_UPLOADABLE,
|
||||
16 => TEXTURE_USAGE_SAMPLEABLE,
|
||||
32 => TEXTURE_USAGE_SUBPASS_INPUT,
|
||||
64 => TEXTURE_USAGE_BLIT_SRC,
|
||||
128 => TEXTURE_USAGE_BLIT_DST,
|
||||
256 => TEXTURE_USAGE_PROTECTED,
|
||||
24 => TEXTURE_USAGE_DEFAULT,
|
||||
_ => throw ArgumentError("Unknown value for TTextureUsage: $value"),
|
||||
};
|
||||
}
|
||||
|
||||
/// Defines texture wrapping modes for texture coordinates
|
||||
enum TextureWrapMode {
|
||||
/// Clamps texture coordinates to edge, extending edge pixels
|
||||
CLAMP_TO_EDGE,
|
||||
|
||||
/// Repeats the texture (tiles)
|
||||
REPEAT,
|
||||
|
||||
/// Mirrors the texture at each repeat
|
||||
MIRRORED_REPEAT
|
||||
}
|
||||
|
||||
/// Defines texture minification filter types
|
||||
enum TextureMinFilter {
|
||||
/// Nearest neighbor sampling (pixelated look)
|
||||
NEAREST,
|
||||
|
||||
/// Linear interpolation between texels
|
||||
LINEAR,
|
||||
|
||||
/// Nearest neighbor filtering with nearest mipmap
|
||||
NEAREST_MIPMAP_NEAREST,
|
||||
|
||||
/// Linear filtering with nearest mipmap
|
||||
LINEAR_MIPMAP_NEAREST,
|
||||
|
||||
/// Nearest filtering with linear mipmap interpolation
|
||||
NEAREST_MIPMAP_LINEAR,
|
||||
|
||||
/// Linear filtering with linear mipmap interpolation (best quality)
|
||||
LINEAR_MIPMAP_LINEAR
|
||||
}
|
||||
|
||||
/// Defines texture magnification filter types
|
||||
enum TextureMagFilter {
|
||||
/// Nearest neighbor sampling (pixelated look)
|
||||
NEAREST,
|
||||
|
||||
/// Linear interpolation between texels
|
||||
LINEAR
|
||||
}
|
||||
|
||||
/// Defines texture comparison modes
|
||||
enum TextureCompareMode {
|
||||
/// No comparison is performed
|
||||
NONE,
|
||||
|
||||
/// Compare texture values to reference value
|
||||
COMPARE_TO_TEXTURE
|
||||
}
|
||||
|
||||
/// Defines texture comparison functions
|
||||
enum TextureCompareFunc {
|
||||
/// Less than or equal
|
||||
LESS_EQUAL,
|
||||
|
||||
/// Greater than or equal
|
||||
GREATER_EQUAL,
|
||||
|
||||
/// Less than
|
||||
LESS,
|
||||
|
||||
/// Greater than
|
||||
GREATER,
|
||||
|
||||
/// Equal
|
||||
EQUAL,
|
||||
|
||||
/// Not equal
|
||||
NOT_EQUAL,
|
||||
|
||||
/// Always passes
|
||||
ALWAYS,
|
||||
|
||||
/// Never passes
|
||||
NEVER
|
||||
}
|
||||
|
||||
/// Defines swizzle operations for texture components
|
||||
enum TextureSwizzle {
|
||||
/// Use the component as is
|
||||
CHANNEL_0,
|
||||
|
||||
/// Use the red channel
|
||||
CHANNEL_R,
|
||||
|
||||
/// Use the green channel
|
||||
CHANNEL_G,
|
||||
|
||||
/// Use the blue channel
|
||||
CHANNEL_B,
|
||||
|
||||
/// Use the alpha channel
|
||||
CHANNEL_A,
|
||||
|
||||
/// Use value 0
|
||||
ZERO,
|
||||
|
||||
/// Use value 1
|
||||
ONE
|
||||
}
|
||||
|
||||
/// Defines the texture sampler configuration
|
||||
abstract class TextureSampler {
|
||||
/// Disposes the sampler resources
|
||||
Future dispose();
|
||||
}
|
||||
|
||||
/// Defines a texture object
|
||||
abstract class Texture {
|
||||
/// Returns the width of the texture at the specified mipmap level
|
||||
Future<int> getWidth([int level = 0]);
|
||||
|
||||
/// Returns the height of the texture at the specified mipmap level
|
||||
Future<int> getHeight([int level = 0]);
|
||||
|
||||
/// Returns the depth of the texture at the specified mipmap level (for 3D textures)
|
||||
Future<int> getDepth([int level = 0]);
|
||||
|
||||
/// Returns the number of mipmap levels this texture has
|
||||
Future<int> getLevels();
|
||||
|
||||
/// Returns the sampler type of this texture
|
||||
Future<TextureSamplerType> getTarget();
|
||||
|
||||
/// Returns the internal format of this texture
|
||||
Future<TextureFormat> getFormat();
|
||||
|
||||
Future setLinearImage(
|
||||
covariant LinearImage image, PixelDataFormat format, PixelDataType type);
|
||||
|
||||
/// Sets the image data for a 2D texture or a texture level
|
||||
Future setImage(int level, Uint8List buffer, int width, int height,
|
||||
int channels, PixelDataFormat format, PixelDataType type);
|
||||
|
||||
/// Sets the image data for a region of a 2D texture
|
||||
Future setSubImage(int level, int xOffset, int yOffset, int width, int height,
|
||||
Uint8List buffer, PixelDataFormat format, PixelDataType type);
|
||||
|
||||
/// Sets the image data for a 3D texture or cubemap
|
||||
Future setImage3D(
|
||||
int level,
|
||||
int xOffset,
|
||||
int yOffset,
|
||||
int zOffset,
|
||||
int width,
|
||||
int height,
|
||||
int channels,
|
||||
int depth,
|
||||
Uint8List buffer,
|
||||
PixelDataFormat format,
|
||||
PixelDataType type);
|
||||
|
||||
/// Sets an external image (like a video or camera frame) as the texture source
|
||||
Future setExternalImage(dynamic externalImage);
|
||||
|
||||
/// Generates mipmaps automatically for the texture
|
||||
Future generateMipmaps();
|
||||
|
||||
/// Disposes the texture resources
|
||||
Future dispose();
|
||||
}
|
||||
|
||||
enum PixelDataFormat {
|
||||
R,
|
||||
|
||||
/// One Red channel, float
|
||||
R_INTEGER,
|
||||
|
||||
/// One Red channel, integer
|
||||
RG,
|
||||
|
||||
/// Two Red and Green channels, float
|
||||
RG_INTEGER,
|
||||
|
||||
/// Two Red and Green channels, integer
|
||||
RGB,
|
||||
|
||||
/// Three Red, Green and Blue channels, float
|
||||
RGB_INTEGER,
|
||||
|
||||
/// Three Red, Green and Blue channels, integer
|
||||
RGBA,
|
||||
|
||||
/// Four Red, Green, Blue and Alpha channels, float
|
||||
RGBA_INTEGER,
|
||||
|
||||
/// Four Red, Green, Blue and Alpha channels, integer
|
||||
UNUSED,
|
||||
|
||||
/// Used to be rgbm
|
||||
DEPTH_COMPONENT,
|
||||
|
||||
/// Depth, 16-bit or 24-bits usually
|
||||
DEPTH_STENCIL,
|
||||
|
||||
/// Two Depth (24-bits) + Stencil (8-bits) channels
|
||||
ALPHA
|
||||
|
||||
/// One Alpha channel, float
|
||||
}
|
||||
|
||||
/// Pixel Data Type
|
||||
enum PixelDataType {
|
||||
UBYTE,
|
||||
|
||||
/// Unsigned byte
|
||||
BYTE,
|
||||
|
||||
/// Signed byte
|
||||
USHORT,
|
||||
|
||||
/// Unsigned short (16-bit)
|
||||
SHORT,
|
||||
|
||||
/// Signed short (16-bit)
|
||||
UINT,
|
||||
|
||||
/// Unsigned int (32-bit)
|
||||
INT,
|
||||
|
||||
/// Signed int (32-bit)
|
||||
HALF,
|
||||
|
||||
/// Half-float (16-bit float)
|
||||
FLOAT,
|
||||
|
||||
/// Float (32-bits float)
|
||||
COMPRESSED,
|
||||
|
||||
/// Compressed pixels, see CompressedPixelDataType
|
||||
UINT_10F_11F_11F_REV,
|
||||
|
||||
/// Three low precision floating-point numbers
|
||||
USHORT_565,
|
||||
|
||||
/// Unsigned int (16-bit), encodes 3 RGB channels
|
||||
UINT_2_10_10_10_REV,
|
||||
|
||||
/// Unsigned normalized 10 bits RGB, 2 bits alpha
|
||||
}
|
||||
|
||||
@deprecated
|
||||
typedef ThermionTexture = Texture;
|
||||
|
||||
abstract class LinearImage {
|
||||
Future destroy();
|
||||
Future<Float32List> getData();
|
||||
Future<int> getWidth();
|
||||
Future<int> getHeight();
|
||||
Future<int> getChannels();
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
///
|
||||
/// 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});
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
enum ToneMapper { ACES, FILMIC, LINEAR }
|
||||
@@ -1,39 +0,0 @@
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/layers.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
///
|
||||
/// The viewport currently attached to a [View].
|
||||
///
|
||||
/// The dimensions here are guaranteed to be in physical pixels.
|
||||
///
|
||||
class Viewport {
|
||||
final int left;
|
||||
final int bottom;
|
||||
final int width;
|
||||
final int height;
|
||||
|
||||
Viewport(this.left, this.bottom, this.width, this.height);
|
||||
}
|
||||
|
||||
enum QualityLevel { LOW, MEDIUM, HIGH, ULTRA }
|
||||
|
||||
abstract class View {
|
||||
Future<Viewport> getViewport();
|
||||
Future setViewport(int width, int height);
|
||||
Future<RenderTarget?> getRenderTarget();
|
||||
Future setRenderTarget(covariant RenderTarget? renderTarget);
|
||||
Future setCamera(covariant Camera camera);
|
||||
Future<Camera> getCamera();
|
||||
Future setPostProcessing(bool enabled);
|
||||
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
|
||||
Future setRenderable(bool renderable, covariant SwapChain swapChain);
|
||||
Future setFrustumCullingEnabled(bool enabled);
|
||||
Future setToneMapper(ToneMapper mapper);
|
||||
Future setStencilBufferEnabled(bool enabled);
|
||||
Future<bool> isStencilBufferEnabled();
|
||||
Future setDithering(bool enabled);
|
||||
Future<bool> isDitheringEnabled();
|
||||
Future setBloom(bool enabled, double strength);
|
||||
Future setRenderQuality(QualityLevel quality);
|
||||
Future setLayerVisibility(VisibilityLayers layer, bool visible);
|
||||
}
|
||||
@@ -1,23 +1,28 @@
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/layers.dart';
|
||||
|
||||
import '../../utils/src/gizmo.dart';
|
||||
import 'shared_types/shared_types.dart';
|
||||
export 'shared_types/shared_types.dart';
|
||||
|
||||
import 'dart:math';
|
||||
import 'package:thermion_dart/src/filament/src/filament_app.dart';
|
||||
import '../../filament/src/shared_types.dart';
|
||||
import 'dart:typed_data';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'dart:async';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
|
||||
///
|
||||
/// A high-level interface for interacting with a 3D scene.
|
||||
/// This broadly maps to a single scene/view
|
||||
/// A (high-level) interface for a 3D scene.
|
||||
///
|
||||
/// Use this to add/remove assets, lights and cameras.
|
||||
///
|
||||
/// Multiple instances can be created; each will correspond
|
||||
/// broadly to a single Filament Scene/View.
|
||||
///
|
||||
/// If you know yhat you are doing, you can use a lower level interface by
|
||||
/// using the methods directly via FilamentApp.instance;
|
||||
///
|
||||
abstract class ThermionViewer {
|
||||
|
||||
///
|
||||
/// Whether the controller is currently rendering at [framerate].
|
||||
///
|
||||
///
|
||||
View get view;
|
||||
|
||||
///
|
||||
/// If [true], this Viewer should render itself
|
||||
///
|
||||
bool get rendering;
|
||||
|
||||
@@ -31,29 +36,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future render();
|
||||
|
||||
///
|
||||
/// Requests a single frame to be rendered. This is only intended to be used internally.
|
||||
///
|
||||
Future requestFrame();
|
||||
|
||||
///
|
||||
/// Render a single frame and return the captured image as a pixel buffer.
|
||||
///
|
||||
Future<List<Uint8List>> capture(
|
||||
covariant List<
|
||||
({View view, SwapChain? swapChain, RenderTarget? renderTarget})>
|
||||
targets);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<View> createView();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<View> getViewAt(int index);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -119,32 +101,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
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
|
||||
@@ -198,139 +154,6 @@ abstract class ThermionViewer {
|
||||
Future<ThermionAsset> loadGltf(String path, String relativeResourcePath,
|
||||
{bool keepData = false});
|
||||
|
||||
///
|
||||
/// 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(
|
||||
covariant ThermionAsset asset, ThermionEntity childEntity);
|
||||
|
||||
///
|
||||
/// Gets the names of all bones for the armature at [skinIndex] under the specified [entity].
|
||||
///
|
||||
Future<List<String>> getBoneNames(covariant ThermionAsset asset,
|
||||
{int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Gets the names of all glTF animations embedded in the specified entity.
|
||||
///
|
||||
Future<List<String>> getAnimationNames(covariant ThermionAsset asset);
|
||||
|
||||
///
|
||||
/// Returns the length (in seconds) of the animation at the given index.
|
||||
///
|
||||
Future<double> getAnimationDuration(
|
||||
covariant ThermionAsset asset, int animationIndex);
|
||||
|
||||
///
|
||||
/// Construct animation(s) for every entity under [asset]. If [targetMeshNames] is provided, only entities with matching names will be animated.
|
||||
/// [MorphTargetAnimation] for an explanation as to how to construct the animation frame data.
|
||||
/// This method will check the morph target names specified in [animation] against the morph target names that actually exist exist under [meshName] in [entity],
|
||||
/// throwing an exception if any cannot be found.
|
||||
/// It is permissible for [animation] to omit any targets that do exist under [meshName]; these simply won't be animated.
|
||||
///
|
||||
Future setMorphAnimationData(
|
||||
covariant ThermionAsset asset, 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(ThermionAsset asset);
|
||||
|
||||
///
|
||||
/// 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(ThermionAsset asset, 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(covariant ThermionAsset asset, 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(
|
||||
covariant ThermionAsset asset, int boneIndex,
|
||||
{int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Sets the transform (relative to its parent) for [entity].
|
||||
///
|
||||
Future setTransform(ThermionEntity entity, Matrix4 transform);
|
||||
|
||||
///
|
||||
/// Sets multiple transforms (relative to parent) simultaneously for [entity].
|
||||
/// Uses mutex to ensure that transform updates aren't split across frames.
|
||||
///
|
||||
Future queueTransformUpdates(
|
||||
List<ThermionEntity> entities, List<Matrix4> transforms);
|
||||
|
||||
///
|
||||
/// 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});
|
||||
|
||||
///
|
||||
/// Destroys [asset] and all underlying resources
|
||||
/// (including instances, but excluding any manually created material instances).
|
||||
@@ -343,72 +166,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future destroyAssets();
|
||||
|
||||
///
|
||||
/// Schedules the glTF animation at [index] in [asset] to start playing on the next frame.
|
||||
///
|
||||
Future playAnimation(ThermionAsset asset, 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(covariant ThermionAsset asset, String name,
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setGltfAnimationFrame(
|
||||
covariant ThermionAsset asset, int index, int animationFrame);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future stopAnimation(covariant ThermionAsset asset, int animationIndex);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future stopAnimationByName(covariant ThermionAsset asset, String name);
|
||||
|
||||
///
|
||||
/// Sets the current scene camera to the glTF camera under [name] in [entity].
|
||||
///
|
||||
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. You probably never need this; use getMainCamera instead.
|
||||
///
|
||||
Future<ThermionEntity> getMainCameraEntity();
|
||||
|
||||
///
|
||||
/// Returns the Camera instance for the main camera.
|
||||
///
|
||||
Future<Camera> 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).
|
||||
///
|
||||
@@ -419,115 +176,11 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future setBloom(bool enabled, double strength);
|
||||
|
||||
///
|
||||
/// 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();
|
||||
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
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);
|
||||
|
||||
///
|
||||
/// Scale [entity] to fit within the unit cube.
|
||||
///
|
||||
Future transformToUnitCube(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Set the world space position for [lightEntity] to the given coordinates.
|
||||
///
|
||||
@@ -539,18 +192,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction);
|
||||
|
||||
///
|
||||
/// TODO
|
||||
///
|
||||
Future queuePositionUpdateFromViewportCoords(
|
||||
ThermionEntity entity, double x, double y);
|
||||
|
||||
///
|
||||
/// TODO
|
||||
///
|
||||
Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity,
|
||||
double viewportX, double viewportY, double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Enable/disable postprocessing effects (anti-aliasing, tone mapping, bloom). Disabled by default.
|
||||
///
|
||||
@@ -576,16 +217,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
|
||||
|
||||
///
|
||||
/// Adds a single [entity] to the scene.
|
||||
///
|
||||
Future addEntityToScene(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Removes a single [entity] from the scene.
|
||||
///
|
||||
Future removeAssetFromScene(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Hit test the viewport at the given coordinates. If the coordinates intersect
|
||||
/// with a renderable entity, [resultHandler] will be called.
|
||||
@@ -599,37 +230,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
String? getNameForEntity(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Returns all child entities under [asset].
|
||||
///
|
||||
Future<List<ThermionEntity>> getChildEntities(covariant ThermionAsset asset);
|
||||
|
||||
///
|
||||
/// Finds the child entity named [childName] associated with the given parent.
|
||||
/// Usually, [parent] will be the return value from [loadGlb]/[loadGltf] and [childName] will be the name of a node/mesh.
|
||||
///
|
||||
Future<ThermionEntity?> getChildEntity(
|
||||
covariant ThermionAsset asset, String childName);
|
||||
|
||||
///
|
||||
/// 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);
|
||||
|
||||
///
|
||||
/// 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<ThermionAsset> createGeometry(Geometry geometry,
|
||||
{covariant List<MaterialInstance>? materialInstances,
|
||||
bool keepData = false});
|
||||
|
||||
///
|
||||
/// Gets the parent entity of [entity]. Returns null if the entity has no parent.
|
||||
///
|
||||
@@ -672,131 +272,15 @@ abstract class ThermionViewer {
|
||||
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Toggles the visibility of the respective layer.
|
||||
///
|
||||
Future setLayerVisibility(VisibilityLayers layer, bool visible);
|
||||
|
||||
///
|
||||
/// All renderable entities are assigned a layer mask.
|
||||
///
|
||||
/// By calling [setLayerVisibility], all renderable entities allocated to
|
||||
/// the given layer can be efficiently hidden/revealed.
|
||||
///
|
||||
/// By default, all renderable entities are assigned to layer 0 (and this
|
||||
/// layer is enabled by default). Call [setVisibilityLayer] to change the
|
||||
/// layer for the specified entity.
|
||||
///
|
||||
/// Note that we currently also assign gizmos to layer 1 (enabled by default)
|
||||
/// and the world grid to layer 2 (disabled by default). We suggest you avoid
|
||||
/// using these layers.
|
||||
///
|
||||
Future setVisibilityLayer(ThermionEntity entity, VisibilityLayers layer);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future showGridOverlay({covariant Material? material});
|
||||
Future showGridOverlay();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future removeGridOverlay();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Texture> createTexture(int width, int height,
|
||||
{int depth = 1,
|
||||
int levels = 1,
|
||||
TextureSamplerType textureSamplerType = TextureSamplerType.SAMPLER_2D,
|
||||
TextureFormat textureFormat = TextureFormat.RGBA32F});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<TextureSampler> createTextureSampler(
|
||||
{TextureMinFilter minFilter = TextureMinFilter.LINEAR,
|
||||
TextureMagFilter magFilter = TextureMagFilter.LINEAR,
|
||||
TextureWrapMode wrapS = TextureWrapMode.CLAMP_TO_EDGE,
|
||||
TextureWrapMode wrapT = TextureWrapMode.CLAMP_TO_EDGE,
|
||||
TextureWrapMode wrapR = TextureWrapMode.CLAMP_TO_EDGE,
|
||||
double anisotropy = 0.0,
|
||||
TextureCompareMode compareMode = TextureCompareMode.NONE,
|
||||
TextureCompareFunc compareFunc = TextureCompareFunc.LESS_EQUAL});
|
||||
|
||||
///
|
||||
/// Decodes the specified image data.
|
||||
///
|
||||
Future<LinearImage> decodeImage(Uint8List data);
|
||||
|
||||
///
|
||||
/// Creates an (empty) imge with the given dimensions.
|
||||
///
|
||||
Future<LinearImage> createImage(int width, int height, int channels);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Material> createMaterial(Uint8List data);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance> 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 = -1,
|
||||
int baseColorUV = -1,
|
||||
bool hasClearCoatTexture = false,
|
||||
int clearCoatUV = -1,
|
||||
bool hasClearCoatRoughnessTexture = false,
|
||||
int clearCoatRoughnessUV = -1,
|
||||
bool hasClearCoatNormalTexture = false,
|
||||
int clearCoatNormalUV = -1,
|
||||
bool hasClearCoat = false,
|
||||
bool hasTransmission = false,
|
||||
bool hasTextureTransforms = false,
|
||||
int emissiveUV = -1,
|
||||
int aoUV = -1,
|
||||
int normalUV = -1,
|
||||
bool hasTransmissionTexture = false,
|
||||
int transmissionUV = -1,
|
||||
bool hasSheenColorTexture = false,
|
||||
int sheenColorUV = -1,
|
||||
bool hasSheenRoughnessTexture = false,
|
||||
int sheenRoughnessUV = -1,
|
||||
bool hasVolumeThicknessTexture = false,
|
||||
int volumeThicknessUV = -1,
|
||||
bool hasSheen = false,
|
||||
bool hasIOR = false,
|
||||
bool hasVolume = false,
|
||||
});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroyMaterialInstance(covariant MaterialInstance materialInstance);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance> createUnlitMaterialInstance();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance> getMaterialInstanceAt(
|
||||
ThermionEntity entity, int index);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -817,52 +301,8 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future<Camera> getActiveCamera();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future registerRequestFrameHook(Future Function() hook);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future unregisterRequestFrameHook(Future Function() hook);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
int getCameraCount();
|
||||
|
||||
///
|
||||
/// Returns the camera specified by the given index. Note that the camera at
|
||||
/// index 0 is always the main camera; this cannot be destroyed.
|
||||
///
|
||||
/// Throws an exception if the index is out-of-bounds.
|
||||
///
|
||||
Camera getCameraAt(int index);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setCastShadows(ThermionEntity entity, bool castShadows);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<bool> isCastShadowsEnabled(ThermionEntity entity);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setReceiveShadows(ThermionEntity entity, bool receiveShadows);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<bool> isReceiveShadowsEnabled(ThermionEntity entity);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setClearOptions(
|
||||
Vector4 clearColor, int clearStencil, bool clear, bool discard);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ library thermion_flutter_js;
|
||||
|
||||
import 'dart:js_interop';
|
||||
|
||||
import '../../shared_types/shared_types.dart';
|
||||
import '../../../../filament/src/shared_types.dart';
|
||||
|
||||
///
|
||||
/// An extension type on [JSObject] that represents a
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
library thermion_viewer;
|
||||
|
||||
export 'src/thermion_viewer_base.dart';
|
||||
export '../filament/src/filament_app.dart';
|
||||
export 'src/thermion_viewer_stub.dart'
|
||||
if (dart.library.io) 'src/ffi/thermion_viewer_ffi.dart'
|
||||
if (dart.library.js_interop) 'src/web_wasm/thermion_viewer_web_wasm.dart';
|
||||
export 'src/shared_types/shared_types.dart';
|
||||
export '../filament/src/shared_types.dart';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user