From 82f533e6b2f2e594e3d6cb7b1b04f2f70e5ca92b Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Sun, 26 May 2024 12:11:11 +0800 Subject: [PATCH] expose methods for getting bone names --- .../abstract_filament_viewer.dart | 9 +++++ .../compatibility/native/dart_filament.g.dart | 21 ++++++++++ .../dart_filament/filament_viewer_impl.dart | 38 +++++++++++++++++-- dart_filament/native/src/DartFilamentApi.cpp | 13 +++++++ dart_filament/native/src/SceneManager.cpp | 38 +++++++++++++++++++ 5 files changed, 115 insertions(+), 4 deletions(-) diff --git a/dart_filament/lib/dart_filament/abstract_filament_viewer.dart b/dart_filament/lib/dart_filament/abstract_filament_viewer.dart index 5bcbd84e..761278d1 100644 --- a/dart_filament/lib/dart_filament/abstract_filament_viewer.dart +++ b/dart_filament/lib/dart_filament/abstract_filament_viewer.dart @@ -236,6 +236,15 @@ abstract class AbstractFilamentViewer { Future> getMorphTargetNames( FilamentEntity entity, FilamentEntity childEntity); + /// + /// Gets the names of all bones for the armature at [skinIndex] under the specified [entity]. + /// + Future> getBoneNames( + FilamentEntity entity, { int skinIndex = 0}); + + /// + /// Gets the names of all glTF animations embedded in the specified entity. + /// Future> getAnimationNames(FilamentEntity entity); /// diff --git a/dart_filament/lib/dart_filament/compatibility/native/dart_filament.g.dart b/dart_filament/lib/dart_filament/compatibility/native/dart_filament.g.dart index fa3da1ea..858c0f2a 100644 --- a/dart_filament/lib/dart_filament/compatibility/native/dart_filament.g.dart +++ b/dart_filament/lib/dart_filament/compatibility/native/dart_filament.g.dart @@ -565,6 +565,27 @@ external double get_animation_duration( int index, ); +@ffi.Native, EntityId, ffi.Int)>( + symbol: 'get_bone_count', + assetId: 'package:dart_filament/dart_filament.dart') +external int get_bone_count( + ffi.Pointer sceneManager, + int assetEntity, + int skinIndex, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, EntityId, + ffi.Pointer>, ffi.Int)>( + symbol: 'get_bone_names', + assetId: 'package:dart_filament/dart_filament.dart') +external void get_bone_names( + ffi.Pointer sceneManager, + int assetEntity, + ffi.Pointer> outPtr, + int skinIndex, +); + @ffi.Native< ffi.Void Function(ffi.Pointer, EntityId, EntityId, ffi.Pointer, ffi.Int)>( diff --git a/dart_filament/lib/dart_filament/filament_viewer_impl.dart b/dart_filament/lib/dart_filament/filament_viewer_impl.dart index cf33f4fc..b149df2e 100644 --- a/dart_filament/lib/dart_filament/filament_viewer_impl.dart +++ b/dart_filament/lib/dart_filament/filament_viewer_impl.dart @@ -3,6 +3,7 @@ import 'dart:ffi'; import 'dart:io'; import 'dart:math'; import 'package:animation_tools_dart/animation_tools_dart.dart'; +import 'package:dart_filament/dart_filament/compatibility/native/compatibility.dart'; import 'package:dart_filament/dart_filament/entities/filament_entity.dart'; import 'package:dart_filament/dart_filament/entities/gizmo.dart'; @@ -124,7 +125,7 @@ class FilamentViewer extends AbstractFilamentViewer { _scene = SceneImpl(this); await setCameraManipulatorOptions(zoomSpeed: 10.0); - + final out = allocator(3); get_gizmo(_sceneManager!, out); _gizmo = Gizmo(out[0], out[1], out[2], this); @@ -422,6 +423,23 @@ class FilamentViewer extends AbstractFilamentViewer { return names.cast(); } + Future> getBoneNames(FilamentEntity entity, + {int skinIndex = 0}) async { + var count = get_bone_count(_sceneManager!, entity, skinIndex); + var out = allocator>(count); + for (int i = 0; i < count; i++) { + out[i] = allocator(255); + } + + get_bone_names(_sceneManager!, entity, out, skinIndex); + var names = []; + for (int i = 0; i < count; i++) { + var namePtr = out[i]; + names.add(namePtr.cast().toDartString()); + } + return names; + } + @override Future> getAnimationNames(FilamentEntity entity) async { var animationCount = get_animation_count(_sceneManager!, entity); @@ -461,6 +479,14 @@ class FilamentViewer extends AbstractFilamentViewer { FilamentEntity entity, MorphAnimationData animation, {List? targetMeshNames}) async { var meshNames = await getChildEntityNames(entity, renderableOnly: true); + if (targetMeshNames != null) { + for (final targetMeshName in targetMeshNames) { + if (!meshNames.contains(targetMeshName)) { + throw Exception( + "Error: mesh ${targetMeshName} does not exist under the specified entity. Available meshes : ${meshNames}"); + } + } + } var meshEntities = await getChildEntities(entity, true); @@ -481,6 +507,8 @@ class FilamentViewer extends AbstractFilamentViewer { var meshMorphTargets = await getMorphTargetNames(entity, meshEntity); + print("Got mesh morph targets ${meshMorphTargets}"); + var intersection = animation.morphTargets .toSet() .intersection(meshMorphTargets.toSet()) @@ -488,7 +516,11 @@ class FilamentViewer extends AbstractFilamentViewer { 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.\nAnimation morph targets: ${animation.morphTargets}\nMesh morph targets ${meshMorphTargets}"); + """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 = @@ -1168,6 +1200,4 @@ class FilamentViewer extends AbstractFilamentViewer { Future setPriority(FilamentEntity entityId, int priority) async { set_priority(_sceneManager!, entityId, priority); } - - } diff --git a/dart_filament/native/src/DartFilamentApi.cpp b/dart_filament/native/src/DartFilamentApi.cpp index 29142371..21eeedc8 100644 --- a/dart_filament/native/src/DartFilamentApi.cpp +++ b/dart_filament/native/src/DartFilamentApi.cpp @@ -510,6 +510,19 @@ extern "C" strcpy(outPtr, name.c_str()); } + EMSCRIPTEN_KEEPALIVE int get_bone_count(void *sceneManager, EntityId assetEntity, int skinIndex) { + auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex); + return names->size(); + } + + EMSCRIPTEN_KEEPALIVE void get_bone_names(void *sceneManager, EntityId assetEntity, const char** out, int skinIndex) { + auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex); + + for(int i = 0; i < names->size(); i++) { + memcpy((void*)out[i], names->at(i).c_str(), names->at(i).length()); + } + } + EMSCRIPTEN_KEEPALIVE int get_morph_target_name_count(void *sceneManager, EntityId assetEntity, EntityId childEntity) { auto names = ((SceneManager *)sceneManager)->getMorphTargetNames(assetEntity, childEntity); diff --git a/dart_filament/native/src/SceneManager.cpp b/dart_filament/native/src/SceneManager.cpp index f599c631..5d49d6c5 100644 --- a/dart_filament/native/src/SceneManager.cpp +++ b/dart_filament/native/src/SceneManager.cpp @@ -1239,6 +1239,44 @@ namespace flutter_filament return names; } + unique_ptr> SceneManager::getBoneNames(EntityId assetEntityId, int skinIndex) { + + unique_ptr> names = std::make_unique>(); + + auto *instance = getInstanceByEntityId(assetEntityId); + + if (!instance) + { + auto *asset = getAssetByEntityId(assetEntityId); + if (asset) + { + instance = asset->getInstance(); + } + else + { + Log("ERROR: failed to find instance for entity %d", assetEntityId); + return names; + } + } + + size_t skinCount = instance->getSkinCount(); + + if (skinCount > 1) + { + Log("WARNING - skin count > 1 not currently implemented. This will probably not work"); + } + + size_t numJoints = instance->getJointCountAt(skinIndex); + auto joints = instance->getJointsAt(skinIndex); + for (int i = 0; i < numJoints; i++) + { + const char *jointName = _ncm->getName(_ncm->getInstance(joints[i])); + names->push_back(jointName); + } + return names; + } + + void SceneManager::transformToUnitCube(EntityId entityId) { const auto *instance = getInstanceByEntityId(entityId);