diff --git a/thermion_dart/lib/src/filament/src/implementation/ffi_filament_app.dart b/thermion_dart/lib/src/filament/src/implementation/ffi_filament_app.dart index b04585be..119570b9 100644 --- a/thermion_dart/lib/src/filament/src/implementation/ffi_filament_app.dart +++ b/thermion_dart/lib/src/filament/src/implementation/ffi_filament_app.dart @@ -10,6 +10,7 @@ import 'package:thermion_dart/src/filament/src/implementation/ffi_scene.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_swapchain.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_texture.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_view.dart'; +import 'package:thermion_dart/src/utils/src/matrix.dart'; import 'package:thermion_dart/thermion_dart.dart'; import 'package:logging/logging.dart'; import 'resource_loader.dart'; @@ -1092,4 +1093,23 @@ class FFIFilamentApp extends FilamentApp { void onDestroy(Future Function() callback) { _onDestroy.add(callback); } + + /// + /// + /// + Future createEntity( + {bool createTransformComponent = true}) async { + final entity = EntityManager_createEntity(Engine_getEntityManager(engine)); + if (createTransformComponent) { + TransformManager_createComponent(transformManager, entity); + } + return entity; + } + + /// + /// + /// + Future setTransform(ThermionEntity entity, Matrix4 transform) async { + TransformManager_setTransform(transformManager, entity, matrix4ToDouble4x4(transform)); + } } diff --git a/thermion_dart/lib/src/filament/src/interface/filament_app.dart b/thermion_dart/lib/src/filament/src/interface/filament_app.dart index 130c1016..3116e09d 100644 --- a/thermion_dart/lib/src/filament/src/interface/filament_app.dart +++ b/thermion_dart/lib/src/filament/src/interface/filament_app.dart @@ -320,4 +320,14 @@ abstract class FilamentApp { /// /// void onDestroy(Future Function() callback); + + /// + /// + /// + Future createEntity({bool createTransformComponent = true}); + + /// + /// + /// + Future setTransform(ThermionEntity entity, Matrix4 transform); } diff --git a/thermion_dart/native/src/c_api/TEngine.cpp b/thermion_dart/native/src/c_api/TEngine.cpp index 8bd193ee..6586d4cd 100644 --- a/thermion_dart/native/src/c_api/TEngine.cpp +++ b/thermion_dart/native/src/c_api/TEngine.cpp @@ -183,6 +183,12 @@ namespace thermion return reinterpret_cast(&lightManager); } + EMSCRIPTEN_KEEPALIVE TEntityManager *Engine_getEntityManager(TEngine *tEngine) { + auto *engine = reinterpret_cast(tEngine); + auto &entityManager = engine->getEntityManager(); + return reinterpret_cast(&entityManager); + } + EMSCRIPTEN_KEEPALIVE TCamera *Engine_createCamera(TEngine *tEngine) { auto *engine = reinterpret_cast(tEngine); @@ -404,6 +410,11 @@ namespace thermion engine->destroy(indirectLight); } + EMSCRIPTEN_KEEPALIVE EntityId EntityManager_createEntity(TEntityManager *tEntityManager) { + auto entityManager = reinterpret_cast(tEntityManager); + auto entity = entityManager->create(); + } + #ifdef __cplusplus } } diff --git a/thermion_dart/native/src/c_api/TTransformManager.cpp b/thermion_dart/native/src/c_api/TTransformManager.cpp index 8335847e..0f5ac3d8 100644 --- a/thermion_dart/native/src/c_api/TTransformManager.cpp +++ b/thermion_dart/native/src/c_api/TTransformManager.cpp @@ -168,4 +168,14 @@ extern "C" return Entity::smuggle(parent); } + + EMSCRIPTEN_KEEPALIVE void TransformManager_createComponent(TTransformManager *tTransformManager, EntityId entityId) { + auto tm = reinterpret_cast(tTransformManager); + auto entity = Entity::import(entityId); + if(tm->hasComponent(entity)) { + Log("Entity already has transform component"); + return; + } + tm->create(entity); + } } \ No newline at end of file diff --git a/thermion_dart/test/transform_tests.dart b/thermion_dart/test/transform_tests.dart index 50dd6927..3cde628f 100644 --- a/thermion_dart/test/transform_tests.dart +++ b/thermion_dart/test/transform_tests.dart @@ -8,45 +8,60 @@ import 'helpers.dart'; void main() async { final testHelper = TestHelper("transforms"); await testHelper.setup(); - group("transforms", () { - test('set/unset parent geometry', () async { - await testHelper.withViewer((viewer) async { - var blueMaterialInstance = - await FilamentApp.instance!.createUnlitMaterialInstance(); - final blueCube = await viewer.createGeometry( - GeometryHelper.cube(normals: false, uvs: false), - materialInstances: [blueMaterialInstance]); - await blueMaterialInstance.setParameterFloat4( - "baseColorFactor", 0.0, 0.0, 1.0, 1.0); - // Position blue cube slightly behind and to the right - await blueCube - .setTransform(Matrix4.translation(Vector3(1.0, 0.0, -1.0))); + test('create entity and set as parent', () async { + await testHelper.withViewer((viewer) async { + final cube = await viewer + .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); - var greenMaterialInstance = - await FilamentApp.instance!.createUnlitMaterialInstance(); - final greenCube = await viewer.createGeometry( - GeometryHelper.cube(normals: false, uvs: false), - materialInstances: [greenMaterialInstance]); - await greenMaterialInstance.setParameterFloat4( - "baseColorFactor", 0.0, 1.0, 0.0, 1.0); + await testHelper.capture(viewer.view, "create_entity_before_parent"); + + final entity = await FilamentApp.instance!.createEntity(); - await viewer.addToScene(blueCube); - await viewer.addToScene(greenCube); + await FilamentApp.instance!.setParent(cube.entity, entity); - await testHelper.capture(viewer.view, "before_parent"); + await FilamentApp.instance!.setTransform(entity, Matrix4.translation(Vector3.all(-1))); - await FilamentApp.instance!.setParent(blueCube.entity, greenCube.entity); + await testHelper.capture(viewer.view, "create_entity_after_parent"); - await greenCube.setTransform(Matrix4.translation(Vector3.all(-1))); + }); + }); - await testHelper.capture(viewer.view, "after_parent"); + test('set/unset parent geometry', () async { + await testHelper.withViewer((viewer) async { + var blueMaterialInstance = + await FilamentApp.instance!.createUnlitMaterialInstance(); + final blueCube = await viewer.createGeometry( + GeometryHelper.cube(normals: false, uvs: false), + materialInstances: [blueMaterialInstance]); + await blueMaterialInstance.setParameterFloat4( + "baseColorFactor", 0.0, 0.0, 1.0, 1.0); - await FilamentApp.instance!.setParent(blueCube.entity, null); + // Position blue cube slightly behind and to the right + await blueCube.setTransform(Matrix4.translation(Vector3(1.0, 0.0, -1.0))); - await testHelper.capture(viewer.view, "unparent"); - }); + var greenMaterialInstance = + await FilamentApp.instance!.createUnlitMaterialInstance(); + final greenCube = await viewer.createGeometry( + GeometryHelper.cube(normals: false, uvs: false), + materialInstances: [greenMaterialInstance]); + await greenMaterialInstance.setParameterFloat4( + "baseColorFactor", 0.0, 1.0, 0.0, 1.0); + + await viewer.addToScene(blueCube); + await viewer.addToScene(greenCube); + + await testHelper.capture(viewer.view, "before_parent"); + + await FilamentApp.instance!.setParent(blueCube.entity, greenCube.entity); + + await greenCube.setTransform(Matrix4.translation(Vector3.all(-1))); + + await testHelper.capture(viewer.view, "after_parent"); + + await FilamentApp.instance!.setParent(blueCube.entity, null); + + await testHelper.capture(viewer.view, "unparent"); }); }); } -