From 4e64c4976f4c19429cb8deab3f6df1173982684e Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Sat, 4 Jan 2025 15:56:05 +0800 Subject: [PATCH] refactor!: rename removeAsset to destroyAsset use render thread methods for lights --- .../implementations/gizmo_input_handler.dart | 2 +- .../picking_camera_gesture_handler.dart | 2 +- .../viewer/src/ffi/src/thermion_dart.g.dart | 318 ++++--- .../src/ffi/src/thermion_viewer_ffi.dart | 58 +- .../src/viewer/src/thermion_viewer_base.dart | 6 +- .../src/viewer/src/thermion_viewer_stub.dart | 15 +- .../src/thermion_viewer_dart_bridge.dart | 4 +- .../src/web_js/src/thermion_viewer_js.dart | 4 +- .../web_js/src/thermion_viewer_js_shim.dart | 4 +- .../web_wasm/src/thermion_viewer_wasm.dart | 10 +- .../native/include/c_api/ThermionDartApi.h | 7 +- .../c_api/ThermionDartRenderThreadApi.h | 48 +- .../native/src/c_api/ThermionDartApi.cpp | 13 +- .../src/c_api/ThermionDartRenderThreadApi.cpp | 77 +- thermion_dart/test/asset_tests.dart | 7 +- thermion_dart/test/camera_tests.dart | 18 + thermion_dart/test/geometry_tests.dart | 22 +- thermion_dart/test/gizmo_tests.dart | 4 +- thermion_dart/test/gltf_tests.dart | 8 +- thermion_dart/test/helpers.dart | 1 + thermion_dart/test/input_handlers.mocks.dart | 12 +- thermion_dart/test/light_tests.dart | 12 + thermion_dart/test/material_tests.dart | 12 +- thermion_dart/test/old/integration_test.dart | 782 ++++++++++++++++++ thermion_dart/test/overlay_tests.dart | 6 +- 25 files changed, 1233 insertions(+), 219 deletions(-) create mode 100644 thermion_dart/test/old/integration_test.dart diff --git a/thermion_dart/lib/src/input/src/implementations/gizmo_input_handler.dart b/thermion_dart/lib/src/input/src/implementations/gizmo_input_handler.dart index 59b5ed23..562b6f8a 100644 --- a/thermion_dart/lib/src/input/src/implementations/gizmo_input_handler.dart +++ b/thermion_dart/lib/src/input/src/implementations/gizmo_input_handler.dart @@ -22,7 +22,7 @@ class _Gizmo { Future dispose() async { await transformUpdates.close(); - await viewer.removeAsset(_gizmo); + await viewer.destroyAsset(_gizmo); } Future hide() async { diff --git a/thermion_dart/lib/src/input/src/implementations/picking_camera_gesture_handler.dart b/thermion_dart/lib/src/input/src/implementations/picking_camera_gesture_handler.dart index fb99708e..67252c44 100644 --- a/thermion_dart/lib/src/input/src/implementations/picking_camera_gesture_handler.dart +++ b/thermion_dart/lib/src/input/src/implementations/picking_camera_gesture_handler.dart @@ -23,7 +23,7 @@ // } // Future dispose() async { -// await viewer.removeAsset(_translationGizmo); +// await viewer.destroyAsset(_translationGizmo); // } // @override diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart index 55b4a8b3..52ca1a92 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_dart.g.dart @@ -246,6 +246,28 @@ void MaterialInstance_setTransparencyMode( transparencyMode.value, ); +@ffi.Native< + ffi.Void Function(ffi.Pointer, EntityId, ffi.Double, + ffi.Double, ffi.Double)>(isLeaf: true) +external void LightManager_setPosition( + ffi.Pointer tLightManager, + int light, + double x, + double y, + double z, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, EntityId, ffi.Double, + ffi.Double, ffi.Double)>(isLeaf: true) +external void LightManager_setDirection( + ffi.Pointer tLightManager, + int light, + double x, + double y, + double z, +); + @ffi.Native< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(isLeaf: true) @@ -406,6 +428,12 @@ external ffi.Pointer Engine_getRenderableManager( ffi.Pointer engine, ); +@ffi.Native Function(ffi.Pointer)>( + isLeaf: true) +external ffi.Pointer Engine_getLightManager( + ffi.Pointer engine, +); + @ffi.Native Function(ffi.Pointer)>( isLeaf: true) external ffi.Pointer Engine_getEntityManager( @@ -465,11 +493,16 @@ external void set_background_color( @ffi.Native, ffi.Pointer)>( isLeaf: true) -external void load_skybox( +external void Viewer_loadSkybox( ffi.Pointer viewer, ffi.Pointer skyboxPath, ); +@ffi.Native)>(isLeaf: true) +external void Viewer_removeSkybox( + ffi.Pointer viewer, +); + @ffi.Native< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Float)>(isLeaf: true) @@ -479,6 +512,11 @@ external void Viewer_loadIbl( double intensity, ); +@ffi.Native)>(isLeaf: true) +external void Viewer_removeIbl( + ffi.Pointer viewer, +); + @ffi.Native< ffi.Void Function(ffi.Pointer, ffi.Float, ffi.Float, ffi.Float, ffi.Float)>(isLeaf: true) @@ -497,88 +535,6 @@ external void rotate_ibl( ffi.Pointer rotationMatrix, ); -@ffi.Native)>(isLeaf: true) -external void remove_skybox( - ffi.Pointer viewer, -); - -@ffi.Native)>(isLeaf: true) -external void remove_ibl( - ffi.Pointer viewer, -); - -@ffi.Native< - EntityId Function( - ffi.Pointer, - ffi.Uint8, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Float, - ffi.Bool)>(isLeaf: true) -external int add_light( - ffi.Pointer viewer, - int type, - double colour, - double intensity, - double posX, - double posY, - double posZ, - double dirX, - double dirY, - double dirZ, - double falloffRadius, - double spotLightConeInner, - double spotLightConeOuter, - double sunAngularRadius, - double sunHaloSize, - double sunHaloFallof, - bool shadows, -); - -@ffi.Native, EntityId)>(isLeaf: true) -external void remove_light( - ffi.Pointer viewer, - int entityId, -); - -@ffi.Native)>(isLeaf: true) -external void clear_lights( - ffi.Pointer viewer, -); - -@ffi.Native< - ffi.Void Function(ffi.Pointer, EntityId, ffi.Float, ffi.Float, - ffi.Float)>(isLeaf: true) -external void set_light_position( - ffi.Pointer viewer, - int light, - double x, - double y, - double z, -); - -@ffi.Native< - ffi.Void Function(ffi.Pointer, EntityId, ffi.Float, ffi.Float, - ffi.Float)>(isLeaf: true) -external void set_light_direction( - ffi.Pointer viewer, - int light, - double x, - double y, - double z, -); - @ffi.Native)>(isLeaf: true) external int get_main_camera( ffi.Pointer viewer, @@ -1314,6 +1270,14 @@ external void Viewer_loadIblRenderThread( ffi.Pointer> onComplete, ); +@ffi.Native< + ffi.Void Function(ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void Viewer_removeIblRenderThread( + ffi.Pointer viewer, + ffi.Pointer> onComplete, +); + @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -1341,6 +1305,23 @@ external void Viewer_destroyRenderTargetRenderThread( ffi.Pointer> onComplete, ); +@ffi.Native< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void Viewer_loadSkyboxRenderThread( + ffi.Pointer viewer, + ffi.Pointer skyboxPath, + ffi.Pointer> onComplete, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void Viewer_removeSkyboxRenderThread( + ffi.Pointer viewer, + ffi.Pointer> onComplete, +); + @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -1462,20 +1443,6 @@ external void set_background_image_position_render_thread( bool clamp, ); -@ffi.Native< - ffi.Void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>)>(isLeaf: true) -external void load_skybox_render_thread( - ffi.Pointer viewer, - ffi.Pointer skyboxPath, - ffi.Pointer> onComplete, -); - -@ffi.Native)>(isLeaf: true) -external void remove_skybox_render_thread( - ffi.Pointer viewer, -); - @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -1656,24 +1623,89 @@ external void SceneManager_loadGltfRenderThread( ); @ffi.Native< - ffi.Pointer Function(ffi.Pointer, + ffi.Void Function(ffi.Pointer, ffi.Pointer>)>(isLeaf: true) -external ffi.Pointer SceneManager_destroyAllRenderThread( +external void SceneManager_destroyAllRenderThread( ffi.Pointer tSceneManager, ffi.Pointer> callback, ); @ffi.Native< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, + ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer>)>(isLeaf: true) -external ffi.Pointer SceneManager_destroyAssetRenderThread( +external void SceneManager_destroyAssetRenderThread( ffi.Pointer tSceneManager, ffi.Pointer sceneAsset, ffi.Pointer> callback, ); +@ffi.Native< + ffi.Void Function(ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void SceneManager_destroyAssetsRenderThread( + ffi.Pointer tSceneManager, + ffi.Pointer> callback, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void SceneManager_destroyLightsRenderThread( + ffi.Pointer tSceneManager, + ffi.Pointer> callback, +); + +@ffi.Native< + EntityId Function( + ffi.Pointer, + ffi.Uint8, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Bool, + ffi.Pointer>)>( + isLeaf: true) +external int SceneManager_addLightRenderThread( + ffi.Pointer tSceneManager, + int type, + double colour, + double intensity, + double posX, + double posY, + double posZ, + double dirX, + double dirY, + double dirZ, + double falloffRadius, + double spotLightConeInner, + double spotLightConeOuter, + double sunAngularRadius, + double sunHaloSize, + double sunHaloFallof, + bool shadows, + ffi.Pointer> callback, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, EntityId, + ffi.Pointer>)>(isLeaf: true) +external void SceneManager_removeLightRenderThread( + ffi.Pointer tSceneManager, + int entityId, + ffi.Pointer> callback, +); + @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -2012,6 +2044,7 @@ external void SceneManager_transformToUnitCube( ffi.Pointer, ffi.Pointer, ffi.Size, + ffi.Int, ffi.Bool, ffi.Int, ffi.Int, @@ -2020,6 +2053,7 @@ external ffi.Pointer SceneManager_loadGlbFromBuffer( ffi.Pointer tSceneManager, ffi.Pointer arg1, int length, + int numInstances, bool keepData, int priority, int layer, @@ -2047,26 +2081,81 @@ external ffi.Pointer SceneManager_loadGltf( ); @ffi.Native< - ffi.Pointer Function( - ffi.Pointer)>(isLeaf: true) -external ffi.Pointer SceneManager_getAnimationManager( + EntityId Function( + ffi.Pointer, + ffi.Uint8, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Float, + ffi.Bool)>(isLeaf: true) +external int SceneManager_addLight( ffi.Pointer tSceneManager, + int type, + double colour, + double intensity, + double posX, + double posY, + double posZ, + double dirX, + double dirY, + double dirZ, + double falloffRadius, + double spotLightConeInner, + double spotLightConeOuter, + double sunAngularRadius, + double sunHaloSize, + double sunHaloFallof, + bool shadows, ); -@ffi.Native Function(ffi.Pointer)>( +@ffi.Native, EntityId)>( isLeaf: true) -external ffi.Pointer SceneManager_destroyAll( +external void SceneManager_removeLight( + ffi.Pointer tSceneManager, + int entityId, +); + +@ffi.Native)>(isLeaf: true) +external void SceneManager_destroyLights( ffi.Pointer tSceneManager, ); @ffi.Native< - ffi.Pointer Function( + ffi.Void Function( ffi.Pointer, ffi.Pointer)>(isLeaf: true) -external ffi.Pointer SceneManager_destroyAsset( +external void SceneManager_destroyAsset( ffi.Pointer tSceneManager, ffi.Pointer sceneAsset, ); +@ffi.Native)>(isLeaf: true) +external void SceneManager_destroyAssets( + ffi.Pointer tSceneManager, +); + +@ffi.Native)>(isLeaf: true) +external void SceneManager_destroyAll( + ffi.Pointer tSceneManager, +); + +@ffi.Native< + ffi.Pointer Function( + ffi.Pointer)>(isLeaf: true) +external ffi.Pointer SceneManager_getAnimationManager( + ffi.Pointer tSceneManager, +); + @ffi.Native< ffi.Pointer Function( ffi.Pointer)>(isLeaf: true) @@ -2118,6 +2207,13 @@ external ffi.Pointer RenderableManager_getMaterialInstanceAt( int primitiveIndex, ); +@ffi.Native, EntityId)>( + isLeaf: true) +external bool RenderableManager_isRenderable( + ffi.Pointer tRenderableManager, + int entityId, +); + @ffi.Native, ffi.Pointer)>( isLeaf: true) external void SceneAsset_addToScene( @@ -2425,6 +2521,8 @@ final class TViewer extends ffi.Opaque {} final class TSceneManager extends ffi.Opaque {} +final class TLightManager extends ffi.Opaque {} + final class TRenderTarget extends ffi.Opaque {} final class TSwapChain extends ffi.Opaque {} diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart index c8f7fc8e..da63623a 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart @@ -356,7 +356,7 @@ class ThermionViewerFFI extends ThermionViewer { final pathPtr = skyboxPath.toNativeUtf8(allocator: allocator).cast(); await withVoidCallback((cb) { - load_skybox_render_thread(_viewer!, pathPtr, cb); + Viewer_loadSkyboxRenderThread(_viewer!, pathPtr, cb); }); allocator.free(pathPtr); @@ -401,7 +401,9 @@ class ThermionViewerFFI extends ThermionViewer { /// @override Future removeSkybox() async { - remove_skybox_render_thread(_viewer!); + await withVoidCallback((cb) { + Viewer_removeSkyboxRenderThread(_viewer!, cb); + }); } /// @@ -454,25 +456,27 @@ class ThermionViewerFFI extends ThermionViewer { /// @override Future addDirectLight(DirectLight directLight) async { - var entity = SceneManager_addLight( - _sceneManager!, - directLight.type.index, - directLight.color, - directLight.intensity, - directLight.position.x, - directLight.position.y, - directLight.position.z, - directLight.direction.x, - directLight.direction.y, - directLight.direction.z, - directLight.falloffRadius, - directLight.spotLightConeInner, - directLight.spotLightConeOuter, - directLight.sunAngularRadius, - directLight.sunHaloSize, - directLight.sunHaloFallof, - directLight.castShadows, - ); + var entity = await withIntCallback((cb) { + SceneManager_addLightRenderThread( + _sceneManager!, + directLight.type.index, + directLight.color, + directLight.intensity, + directLight.position.x, + directLight.position.y, + directLight.position.z, + directLight.direction.x, + directLight.direction.y, + directLight.direction.z, + directLight.falloffRadius, + directLight.spotLightConeInner, + directLight.spotLightConeOuter, + directLight.sunAngularRadius, + directLight.sunHaloSize, + directLight.sunHaloFallof, + directLight.castShadows, + cb); + }); if (entity == FILAMENT_ASSET_ERROR) { throw Exception("Failed to add light to scene"); } @@ -484,7 +488,9 @@ class ThermionViewerFFI extends ThermionViewer { /// @override Future removeLight(ThermionEntity entity) async { - SceneManager_removeLight(_sceneManager!, entity); + await withVoidCallback((cb) { + SceneManager_removeLightRenderThread(_sceneManager!, entity, cb); + }); } /// @@ -492,7 +498,9 @@ class ThermionViewerFFI extends ThermionViewer { /// @override Future destroyLights() async { - SceneManager_destroyLights(_sceneManager!); + await withVoidCallback((cb) { + SceneManager_destroyLightsRenderThread(_sceneManager!, cb); + }); } /// @@ -976,7 +984,7 @@ class ThermionViewerFFI extends ThermionViewer { /// /// @override - Future removeAsset(covariant FFIAsset asset) async { + Future destroyAsset(covariant FFIAsset asset) async { if (asset.boundingBoxAsset != null) { await asset.setBoundingBoxVisibility(false); await withVoidCallback((callback) => @@ -993,7 +1001,7 @@ class ThermionViewerFFI extends ThermionViewer { @override Future destroyAssets() async { await withVoidCallback((callback) { - SceneManager_destroyAllRenderThread(_sceneManager!, callback); + SceneManager_destroyAssetsRenderThread(_sceneManager!, callback); }); } diff --git a/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart b/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart index 19f34a65..7a622f2a 100644 --- a/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart +++ b/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart @@ -377,10 +377,10 @@ abstract class ThermionViewer { {int skinIndex = 0}); /// - /// Removes/destroys the specified entity from the scene. - /// [entity] will no longer be a valid handle after this method is called; ensure you immediately discard all references once this method is complete. + /// Destroys [asset] and all underlying resources + /// (including instances, but excluding any manually created material instances). /// - Future removeAsset(ThermionAsset asset); + Future destroyAsset(ThermionAsset asset); /// /// Removes/destroys all renderable entities from the scene (including cameras). diff --git a/thermion_dart/lib/src/viewer/src/thermion_viewer_stub.dart b/thermion_dart/lib/src/viewer/src/thermion_viewer_stub.dart index ebc01fc6..8ab78532 100644 --- a/thermion_dart/lib/src/viewer/src/thermion_viewer_stub.dart +++ b/thermion_dart/lib/src/viewer/src/thermion_viewer_stub.dart @@ -410,13 +410,6 @@ class ThermionViewerStub extends ThermionViewer { throw UnimplementedError(); } - - @override - Future setParent(ThermionEntity child, ThermionEntity parent, { bool preserveScaling = false}) { - // TODO: implement setParent - throw UnimplementedError(); - } - @override Future setPosition(ThermionEntity entity, double x, double y, double z) { // TODO: implement setPosition @@ -1008,7 +1001,7 @@ class ThermionViewerStub extends ThermionViewer { } @override - Future removeAsset(ThermionAsset asset) { + Future destroyAsset(ThermionAsset asset) { // TODO: implement removeAsset throw UnimplementedError(); } @@ -1102,6 +1095,12 @@ class ThermionViewerStub extends ThermionViewer { // TODO: implement showGridOverlay throw UnimplementedError(); } + + @override + Future setParent(ThermionEntity child, ThermionEntity? parent, {bool preserveScaling=false}) { + // TODO: implement setParent + throw UnimplementedError(); + } } diff --git a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_dart_bridge.dart b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_dart_bridge.dart index 0a25e7bb..70e2b061 100644 --- a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_dart_bridge.dart +++ b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_dart_bridge.dart @@ -319,8 +319,8 @@ // } // @JSExport() -// JSPromise removeAsset(ThermionEntity entity) => -// viewer.removeAsset(entity).toJS; +// JSPromise destroyAsset(ThermionEntity entity) => +// viewer.destroyAsset(entity).toJS; // @JSExport() // JSPromise destroyAssets() { diff --git a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js.dart b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js.dart index b9380135..d53a67c8 100644 --- a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js.dart +++ b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js.dart @@ -339,8 +339,8 @@ // } // @override -// Future removeAsset(ThermionEntity entity) async { -// await _shim.removeAsset(entity).toDart; +// Future destroyAsset(ThermionEntity entity) async { +// await _shim.destroyAsset(entity).toDart; // } // @override diff --git a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js_shim.dart b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js_shim.dart index 30ee6bb5..a594854f 100644 --- a/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js_shim.dart +++ b/thermion_dart/lib/src/viewer/src/web_js/src/thermion_viewer_js_shim.dart @@ -164,8 +164,8 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject { JSNumber fadeOutInSecs, JSNumber maxDelta); - @JS('removeAsset') - external JSPromise removeAsset(ThermionEntity entity); + @JS('destroyAsset') + external JSPromise destroyAsset(ThermionEntity entity); @JS('destroyAssets') external JSPromise destroyAssets(); diff --git a/thermion_dart/lib/src/viewer/src/web_wasm/src/thermion_viewer_wasm.dart b/thermion_dart/lib/src/viewer/src/web_wasm/src/thermion_viewer_wasm.dart index 54497cdc..0779c135 100644 --- a/thermion_dart/lib/src/viewer/src/web_wasm/src/thermion_viewer_wasm.dart +++ b/thermion_dart/lib/src/viewer/src/web_wasm/src/thermion_viewer_wasm.dart @@ -225,8 +225,8 @@ // return; // } // await setRendering(false); -// await clearEntities(); -// await clearLights(); +// await destroyAssets(); +// await destroyLights(); // _destroyViewer(); // _sceneManager = null; @@ -1130,13 +1130,13 @@ // } // @override -// Future clearEntities() async { +// Future destroyAssets() async { // _module!.ccall( // "clear_entities", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); // } // @override -// Future clearLights() async { +// Future destroyLights() async { // _module!.ccall( // "clear_lights", "void", ["void*".toJS].toJS, [_viewer!].toJS, null); // } @@ -1585,7 +1585,7 @@ // } // @override -// Future removeEntity(ThermionEntity entity) async { +// Future destroyAsset(ThermionEntity entity) async { // _module!.ccall("remove_entity", "void", ["void*".toJS, "int".toJS].toJS, // [_viewer!, entity.toJS].toJS, null); // } diff --git a/thermion_dart/native/include/c_api/ThermionDartApi.h b/thermion_dart/native/include/c_api/ThermionDartApi.h index 843e9342..c699defc 100644 --- a/thermion_dart/native/include/c_api/ThermionDartApi.h +++ b/thermion_dart/native/include/c_api/ThermionDartApi.h @@ -60,14 +60,13 @@ extern "C" EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp); EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a); - EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath); + EMSCRIPTEN_KEEPALIVE void Viewer_loadSkybox(TViewer *viewer, const char *skyboxPath); + EMSCRIPTEN_KEEPALIVE void Viewer_removeSkybox(TViewer *viewer); EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity); EMSCRIPTEN_KEEPALIVE void Viewer_removeIbl(TViewer *viewer); EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity); EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix); - EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer); - - + EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer); EMSCRIPTEN_KEEPALIVE void set_frame_interval(TViewer *viewer, float interval); diff --git a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h index 3a7ac7ac..18d0a7a9 100644 --- a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h +++ b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h @@ -41,11 +41,13 @@ namespace thermion EMSCRIPTEN_KEEPALIVE void Viewer_removeIblRenderThread(TViewer *viewer, void (*onComplete)()); EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height, void (*onComplete)(TRenderTarget *)); EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTargetRenderThread(TViewer *viewer, TRenderTarget *tRenderTarget, void (*onComplete)()); + EMSCRIPTEN_KEEPALIVE void Viewer_loadSkyboxRenderThread(TViewer *viewer, const char *skyboxPath, void (*onComplete)()); + EMSCRIPTEN_KEEPALIVE void Viewer_removeSkyboxRenderThread(TViewer *viewer, void (*onComplete)()); - EMSCRIPTEN_KEEPALIVE void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t* materialData, size_t length, void (*onComplete)(TMaterial *)); - EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, void (*onComplete)()); + EMSCRIPTEN_KEEPALIVE void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t *materialData, size_t length, void (*onComplete)(TMaterial *)); + EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, void (*onComplete)()); - EMSCRIPTEN_KEEPALIVE void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance*)); + EMSCRIPTEN_KEEPALIVE void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance *)); EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping); EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom); @@ -59,18 +61,15 @@ namespace thermion EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer); EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer, const char *path, bool fillHeight, void (*onComplete)()); EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer, float x, float y, bool clamp); - EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer, const char *skyboxPath, void (*onComplete)()); - EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer); EMSCRIPTEN_KEEPALIVE void SceneManager_createGridRenderThread(TSceneManager *tSceneManager, TMaterial *tMaterial, void (*callback)(TSceneAsset *)); EMSCRIPTEN_KEEPALIVE TGizmo *SceneManager_createGizmoRenderThread( - TSceneManager *tSceneManager, - TView *tView, + TSceneManager *tSceneManager, + TView *tView, TScene *tScene, TGizmoType tGizmoType, - void (*onComplete)(TGizmo*) - ); + void (*onComplete)(TGizmo *)); EMSCRIPTEN_KEEPALIVE void SceneManager_createGeometryRenderThread( TSceneManager *sceneManager, @@ -92,13 +91,36 @@ namespace thermion EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance *)); EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbRenderThread(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(TSceneAsset *)); EMSCRIPTEN_KEEPALIVE void SceneManager_loadGltfRenderThread(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(TSceneAsset *)); - EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAllRenderThread(TSceneManager *tSceneManager, void (*callback)()); - EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAssetRenderThread(TSceneManager *tSceneManager, TSceneAsset *sceneAsset, void (*callback)()); - EMSCRIPTEN_KEEPALIVE void SceneManager_createCameraRenderThread(TSceneManager *tSceneManager, void (*callback)(TCamera*)); + EMSCRIPTEN_KEEPALIVE void SceneManager_destroyAllRenderThread(TSceneManager *tSceneManager, void (*callback)()); + EMSCRIPTEN_KEEPALIVE void SceneManager_destroyAssetRenderThread(TSceneManager *tSceneManager, TSceneAsset *sceneAsset, void (*callback)()); + EMSCRIPTEN_KEEPALIVE void SceneManager_destroyAssetsRenderThread(TSceneManager *tSceneManager, void (*callback)()); + EMSCRIPTEN_KEEPALIVE void SceneManager_destroyLightsRenderThread(TSceneManager *tSceneManager, void (*callback)()); + EMSCRIPTEN_KEEPALIVE EntityId SceneManager_addLightRenderThread( + TSceneManager *tSceneManager, + uint8_t type, + float colour, + float intensity, + float posX, + float posY, + float posZ, + float dirX, + float dirY, + float dirZ, + float falloffRadius, + float spotLightConeInner, + float spotLightConeOuter, + float sunAngularRadius, + float sunHaloSize, + float sunHaloFallof, + bool shadows, + void (*callback)(EntityId)); + EMSCRIPTEN_KEEPALIVE void SceneManager_removeLightRenderThread(TSceneManager *tSceneManager, EntityId entityId, void (*callback)()); + + EMSCRIPTEN_KEEPALIVE void SceneManager_createCameraRenderThread(TSceneManager *tSceneManager, void (*callback)(TCamera *)); EMSCRIPTEN_KEEPALIVE void SceneAsset_createInstanceRenderThread(TSceneAsset *asset, TMaterialInstance **tMaterialInstances, int materialInstanceCount, void (*callback)(TSceneAsset *)); - EMSCRIPTEN_KEEPALIVE void MaterialProvider_createMaterialInstanceRenderThread(TMaterialProvider *tMaterialProvider, TMaterialKey *tKey, void (*callback)(TMaterialInstance*)); + EMSCRIPTEN_KEEPALIVE void MaterialProvider_createMaterialInstanceRenderThread(TMaterialProvider *tMaterialProvider, TMaterialKey *tKey, void (*callback)(TMaterialInstance *)); EMSCRIPTEN_KEEPALIVE void SceneManager_destroyMaterialInstanceRenderThread(TSceneManager *tSceneManager, TMaterialInstance *tMaterialInstance, void (*callback)()); EMSCRIPTEN_KEEPALIVE void AnimationManager_updateBoneMatricesRenderThread( diff --git a/thermion_dart/native/src/c_api/ThermionDartApi.cpp b/thermion_dart/native/src/c_api/ThermionDartApi.cpp index 30c2fe15..58ea8a50 100644 --- a/thermion_dart/native/src/c_api/ThermionDartApi.cpp +++ b/thermion_dart/native/src/c_api/ThermionDartApi.cpp @@ -74,11 +74,16 @@ extern "C" ((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp, 100, 100); } - EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath) + EMSCRIPTEN_KEEPALIVE void Viewer_loadSkybox(TViewer *viewer, const char *skyboxPath) { ((FilamentViewer *)viewer)->loadSkybox(skyboxPath); } + EMSCRIPTEN_KEEPALIVE void Viewer_removeSkybox(TViewer *viewer) + { + ((FilamentViewer *)viewer)->removeSkybox(); + } + EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity) { ((FilamentViewer *)viewer)->createIbl(r, g, b, intensity); @@ -108,12 +113,6 @@ extern "C" ((FilamentViewer *)viewer)->rotateIbl(matrix); } - EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer) - { - ((FilamentViewer *)viewer)->removeSkybox(); - } - - EMSCRIPTEN_KEEPALIVE int get_instance_count(TSceneManager *sceneManager, EntityId entityId) { return ((SceneManager *)sceneManager)->getInstanceCount(entityId); diff --git a/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp b/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp index 20e976c3..b57f0924 100644 --- a/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp +++ b/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp @@ -542,21 +542,24 @@ extern "C" auto fut = _rl->add_task(lambda); } - EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer, + EMSCRIPTEN_KEEPALIVE void Viewer_loadSkyboxRenderThread(TViewer *viewer, const char *skyboxPath, void (*onComplete)()) { std::packaged_task lambda([=] { - load_skybox(viewer, skyboxPath); + Viewer_loadSkybox(viewer, skyboxPath); onComplete(); }); auto fut = _rl->add_task(lambda); } - EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer) + EMSCRIPTEN_KEEPALIVE void Viewer_removeSkyboxRenderThread(TViewer *viewer, void (*onComplete)()) { std::packaged_task lambda([=] - { remove_skybox(viewer); }); + { + Viewer_removeSkybox(viewer); + onComplete(); + }); auto fut = _rl->add_task(lambda); } @@ -591,7 +594,7 @@ extern "C" auto fut = _rl->add_task(lambda); } - EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAllRenderThread(TSceneManager *tSceneManager, void (*callback)()) + EMSCRIPTEN_KEEPALIVE void SceneManager_destroyAllRenderThread(TSceneManager *tSceneManager, void (*callback)()) { std::packaged_task lambda( [=]() mutable @@ -600,7 +603,6 @@ extern "C" callback(); }); auto fut = _rl->add_task(lambda); - return nullptr; } EMSCRIPTEN_KEEPALIVE TGizmo *SceneManager_createGizmoRenderThread( @@ -620,7 +622,45 @@ extern "C" return nullptr; } - EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAssetRenderThread(TSceneManager *tSceneManager, TSceneAsset *tSceneAsset, void (*callback)()) + EMSCRIPTEN_KEEPALIVE EntityId SceneManager_addLightRenderThread( + TSceneManager *tSceneManager, + uint8_t type, + float colour, + float intensity, + float posX, + float posY, + float posZ, + float dirX, + float dirY, + float dirZ, + float falloffRadius, + float spotLightConeInner, + float spotLightConeOuter, + float sunAngularRadius, + float sunHaloSize, + float sunHaloFallof, + bool shadows, + void (*callback)(EntityId entityId)) { +std::packaged_task lambda( + [=]() mutable + { + auto light = SceneManager_addLight(tSceneManager, type, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, falloffRadius, spotLightConeInner, spotLightConeOuter, sunAngularRadius, sunHaloSize, sunHaloFallof, shadows); + callback(light); + }); + auto fut = _rl->add_task(lambda); + } + + EMSCRIPTEN_KEEPALIVE void SceneManager_removeLightRenderThread(TSceneManager *tSceneManager, EntityId entityId, void (*callback)()) { + std::packaged_task lambda( + [=]() mutable + { + SceneManager_removeLight(tSceneManager, entityId); + callback(); + }); + auto fut = _rl->add_task(lambda); + } + + EMSCRIPTEN_KEEPALIVE void SceneManager_destroyAssetRenderThread(TSceneManager *tSceneManager, TSceneAsset *tSceneAsset, void (*callback)()) { std::packaged_task lambda( [=]() mutable @@ -629,7 +669,28 @@ extern "C" callback(); }); auto fut = _rl->add_task(lambda); - return nullptr; + } + + EMSCRIPTEN_KEEPALIVE void SceneManager_destroyAssetsRenderThread(TSceneManager *tSceneManager, void (*callback)()) + { + std::packaged_task lambda( + [=]() mutable + { + SceneManager_destroyAssets(tSceneManager); + callback(); + }); + auto fut = _rl->add_task(lambda); + } + + EMSCRIPTEN_KEEPALIVE void SceneManager_destroyLightsRenderThread(TSceneManager *tSceneManager, void (*callback)()) + { + std::packaged_task lambda( + [=]() mutable + { + SceneManager_destroyLights(tSceneManager); + callback(); + }); + auto fut = _rl->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void SceneManager_createCameraRenderThread(TSceneManager *tSceneManager, void (*callback)(TCamera *)) diff --git a/thermion_dart/test/asset_tests.dart b/thermion_dart/test/asset_tests.dart index cda5dbd4..3c8a8339 100644 --- a/thermion_dart/test/asset_tests.dart +++ b/thermion_dart/test/asset_tests.dart @@ -1,6 +1,4 @@ -import 'package:thermion_dart/thermion_dart.dart'; import 'package:test/test.dart'; -import 'package:vector_math/vector_math_64.dart'; import 'helpers.dart'; void main() async { @@ -11,7 +9,12 @@ void main() async { var asset = await viewer.loadGlb("file://${testHelper.testDir}/assets/cube.glb"); await testHelper.capture(viewer, "asset_loaded"); await viewer.destroyAssets(); + await viewer.destroyLights(); + await viewer.removeSkybox(); + await viewer.removeIbl(); await testHelper.capture(viewer, "assets_cleared"); + asset = await viewer.loadGlb("file://${testHelper.testDir}/assets/cube.glb"); + await testHelper.capture(viewer, "asset_reloaded"); }, bg: kRed); }); }); diff --git a/thermion_dart/test/camera_tests.dart b/thermion_dart/test/camera_tests.dart index 2926710d..04db60f7 100644 --- a/thermion_dart/test/camera_tests.dart +++ b/thermion_dart/test/camera_tests.dart @@ -187,6 +187,24 @@ void main() async { }); }); + test( + 'when a camera is the parent of another entity, setting the model matrix updates the parent transform ', + () async { + await testHelper.withViewer((viewer) async { + var camera = await viewer.createCamera(); + + var child = await viewer + .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); + await viewer.setParent(child.entity, camera.getEntity()); + + await testHelper.capture(viewer, "camera_as_parent1"); + + await camera.setModelMatrix(Matrix4.translation(Vector3(1, 0, 0))); + + await testHelper.capture(viewer, "camera_as_parent2"); + }, bg: kRed, cameraPosition: Vector3(0, 0, 10)); + }); + test('create camera', () async { await testHelper.withViewer((viewer) async { await viewer.setCameraPosition(0, 0, 5); diff --git a/thermion_dart/test/geometry_tests.dart b/thermion_dart/test/geometry_tests.dart index cf16c2dc..77d45009 100644 --- a/thermion_dart/test/geometry_tests.dart +++ b/thermion_dart/test/geometry_tests.dart @@ -22,7 +22,7 @@ void main() async { final cube = await viewer .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); await testHelper.capture(viewer, "geometry_cube_no_normals_uvs"); - await viewer.removeAsset(cube); + await viewer.destroyAsset(cube); await testHelper.capture(viewer, "geometry_remove_cube"); }); }); @@ -86,7 +86,7 @@ void main() async { instance.entity, Matrix4.translation(Vector3.all(1))); await testHelper.capture(viewer, "geometry_instanced"); - await viewer.removeAsset(instance); + await viewer.destroyAsset(instance); await testHelper.capture(viewer, "geometry_instance_removed"); }); }); @@ -169,7 +169,7 @@ void main() async { "baseColorFactor", 0.0, 1.0, 0.0, 0.0); await testHelper.capture( viewer, "geometry_cube_with_custom_material_ubershader"); - await viewer.removeAsset(cube); + await viewer.destroyAsset(cube); }); }); @@ -193,7 +193,7 @@ void main() async { await viewer.applyTexture(texture as ThermionFFITexture, cube.entity); await testHelper.capture( viewer, "geometry_cube_with_custom_material_ubershader_texture"); - await viewer.removeAsset(cube); + await viewer.destroyAsset(cube); await viewer.destroyTexture(texture); }); @@ -223,7 +223,7 @@ void main() async { var texture = await viewer.createTexture(textureData); await viewer.applyTexture(texture, cube.entity); await testHelper.capture(viewer, "unlit_material_texture_only"); - await viewer.removeAsset(cube); + await viewer.destroyAsset(cube); }); }); @@ -258,6 +258,18 @@ void main() async { await testHelper.capture(viewer, "geometry_sphere_no_normals"); }); + test('create multiple (non-instanced) geometry', () async { + await testHelper.withViewer((viewer) async { + final cube1 = await viewer + .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); + final cube2 = await viewer + .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); + await viewer.setTransform( + cube2.entity, Matrix4.translation(Vector3(0, 1.5, 0))); + await testHelper.capture(viewer, "multiple_geometry"); + }, bg: kRed); + }); + test('create camera geometry', () async { await testHelper.withViewer((viewer) async { final camera = await viewer.createGeometry( diff --git a/thermion_dart/test/gizmo_tests.dart b/thermion_dart/test/gizmo_tests.dart index 7de211b0..df7d65bd 100644 --- a/thermion_dart/test/gizmo_tests.dart +++ b/thermion_dart/test/gizmo_tests.dart @@ -225,7 +225,7 @@ void main() async { // await testHelper.capture(viewer, "texture_applied_to_geometry"); - // await viewer.removeEntity(cube); + // await viewer.destroyAsset(cube); // await viewer.destroyTexture(texture); // await viewer.dispose(); // }); @@ -334,7 +334,7 @@ void main() async { // await viewer.setToneMapping(ToneMapper.LINEAR); // final unlit = await viewer.createUnlitMaterialInstance(); - // await viewer.removeEntity(cube); + // await viewer.destroyAsset(cube); // cube = await viewer.createGeometry(GeometryHelper.cube(), // materialInstance: unlit); // var reconstructedTexture = await viewer.createTexture(pixelBufferPng); diff --git a/thermion_dart/test/gltf_tests.dart b/thermion_dart/test/gltf_tests.dart index dd288e39..6afb533c 100644 --- a/thermion_dart/test/gltf_tests.dart +++ b/thermion_dart/test/gltf_tests.dart @@ -16,7 +16,7 @@ void main() async { var model = await viewer .loadGlb("file://${testHelper.testDir}/assets/cube.glb"); await testHelper.capture(viewer, "load_glb_from_file"); - await viewer.removeAsset(model); + await viewer.destroyAsset(model); }); }); @@ -41,11 +41,11 @@ void main() async { await testHelper.capture(viewer, "load_glb_from_buffer_with_instances"); - await viewer.removeAsset(instance); + await viewer.destroyAsset(instance); await testHelper.capture(viewer, "load_glb_from_buffer_instance_removed"); - await viewer.removeAsset(model); + await viewer.destroyAsset(model); await testHelper.capture(viewer, "load_glb_from_buffer_original_removed"); }, bg: kRed); @@ -125,7 +125,7 @@ void main() async { "baseColorFactor", 1.0, 1.0, 0.0, 1.0); await model.setMaterialInstanceAt(materialInstance); await testHelper.capture(viewer, "gltf_set_material_instance"); - await viewer.removeAsset(model); + await viewer.destroyAsset(model); await viewer.destroyMaterialInstance(materialInstance); }); }); diff --git a/thermion_dart/test/helpers.dart b/thermion_dart/test/helpers.dart index 2d240fe9..ec17c399 100644 --- a/thermion_dart/test/helpers.dart +++ b/thermion_dart/test/helpers.dart @@ -19,6 +19,7 @@ import 'package:path/path.dart' as p; Color kWhite = ColorFloat32(4)..setRgba(1.0, 1.0, 1.0, 1.0); Color kRed = ColorFloat32(4)..setRgba(1.0, 0.0, 0.0, 1.0); +Color kGreen = ColorFloat32(4)..setRgba(0.0, 1.0, 0.0, 1.0); /// Test files are run in a variety of ways, find this package root in all. /// diff --git a/thermion_dart/test/input_handlers.mocks.dart b/thermion_dart/test/input_handlers.mocks.dart index a23a6295..ce0cd1f4 100644 --- a/thermion_dart/test/input_handlers.mocks.dart +++ b/thermion_dart/test/input_handlers.mocks.dart @@ -572,9 +572,9 @@ class MockThermionViewer extends _i1.Mock implements _i5.ThermionViewer { ) as _i6.Future); @override - _i6.Future clearLights() => (super.noSuchMethod( + _i6.Future destroyLights() => (super.noSuchMethod( Invocation.method( - #clearLights, + #destroyLights, [], ), returnValue: _i6.Future.value(), @@ -940,18 +940,18 @@ class MockThermionViewer extends _i1.Mock implements _i5.ThermionViewer { ) as _i6.Future); @override - _i6.Future removeEntity(int? entity) => (super.noSuchMethod( + _i6.Future removeAsset(int? entity) => (super.noSuchMethod( Invocation.method( - #removeEntity, + #removeAsset, [entity], ), returnValue: _i6.Future.value(), ) as _i6.Future); @override - _i6.Future clearEntities() => (super.noSuchMethod( + _i6.Future destroyAssets() => (super.noSuchMethod( Invocation.method( - #clearEntities, + #destroyAssets, [], ), returnValue: _i6.Future.value(), diff --git a/thermion_dart/test/light_tests.dart b/thermion_dart/test/light_tests.dart index a21db24e..9b98fb30 100644 --- a/thermion_dart/test/light_tests.dart +++ b/thermion_dart/test/light_tests.dart @@ -30,5 +30,17 @@ void main() async { await testHelper.capture(viewer, "remove_ibl"); }); }); + + test('add/remove skybox', () async { + await testHelper.withViewer((viewer) async { + await viewer.loadGlb("file://${testHelper.testDir}/assets/cube.glb"); + + await viewer + .loadSkybox("file://${testHelper.testDir}/assets/default_env_skybox.ktx"); + await testHelper.capture(viewer, "load_skybox"); + await viewer.removeSkybox(); + await testHelper.capture(viewer, "remove_skybox"); + }); + }); }); } diff --git a/thermion_dart/test/material_tests.dart b/thermion_dart/test/material_tests.dart index abe1bc06..ececd7b5 100644 --- a/thermion_dart/test/material_tests.dart +++ b/thermion_dart/test/material_tests.dart @@ -123,7 +123,7 @@ void main() async { await viewer.applyTexture(texture as ThermionFFITexture, cube.entity); await testHelper.capture( viewer, "geometry_cube_with_custom_material_ubershader_texture"); - await viewer.removeAsset(cube); + await viewer.destroyAsset(cube); await viewer.destroyMaterialInstance(materialInstance); await viewer.destroyTexture(texture); await viewer.dispose(); @@ -149,7 +149,7 @@ void main() async { await viewer.applyTexture(texture, cube.entity); await testHelper.capture( viewer, "geometry_cube_with_custom_material_unlit_texture_only"); - await viewer.removeAsset(cube); + await viewer.destroyAsset(cube); cube = await viewer.createGeometry(GeometryHelper.cube(), materialInstances: [materialInstance]); @@ -159,7 +159,7 @@ void main() async { "baseColorFactor", 0.0, 1.0, 0.0, 1.0); await testHelper.capture( viewer, "geometry_cube_with_custom_material_unlit_color_only"); - await viewer.removeAsset(cube); + await viewer.destroyAsset(cube); cube = await viewer.createGeometry(GeometryHelper.cube(), materialInstances: [materialInstance]); @@ -172,7 +172,7 @@ void main() async { await testHelper.capture( viewer, "geometry_cube_with_custom_material_unlit_color_and_texture"); - await viewer.removeAsset(cube); + await viewer.destroyAsset(cube); await viewer.destroyTexture(texture); await viewer.destroyMaterialInstance(materialInstance); @@ -418,7 +418,7 @@ void main() async { // await testHelper.capture(viewer, "texture_applied_to_geometry"); - // await viewer.removeAsset(cube); + // await viewer.destroyAsset(cube); // await viewer.destroyTexture(texture); // await viewer.dispose(); // }); @@ -527,7 +527,7 @@ void main() async { // await viewer.setToneMapping(ToneMapper.LINEAR); // final unlit = await viewer.createUnlitMaterialInstance(); - // await viewer.removeAsset(cube); + // await viewer.destroyAsset(cube); // cube = await viewer.createGeometry(GeometryHelper.cube(), // materialInstance: unlit); // var reconstructedTexture = await viewer.createTexture(pixelBufferPng); diff --git a/thermion_dart/test/old/integration_test.dart b/thermion_dart/test/old/integration_test.dart new file mode 100644 index 00000000..c367ebeb --- /dev/null +++ b/thermion_dart/test/old/integration_test.dart @@ -0,0 +1,782 @@ +// import 'dart:async'; +// import 'dart:io'; +// import 'dart:math'; +// import 'package:thermion_dart/src/viewer/src/events.dart'; +// import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart'; +// import 'package:thermion_dart/thermion_dart.dart'; +// import 'package:test/test.dart'; + +// import 'package:vector_math/vector_math_64.dart'; + +// import 'helpers.dart'; + +// void main() async { +// final testHelper = TestHelper("integration"); + +// group('background', () { +// test('set background color to solid green', () async { +// var viewer = await testHelper.createViewer(); +// await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0); +// await testHelper.capture(viewer, "set_background_color_to_solid_green"); +// await viewer.dispose(); +// }); + +// test('set background color to full transparency', () async { +// var viewer = await testHelper.createViewer(); +// await viewer.setBackgroundColor(0.0, 1.0, 0.0, 0.0); +// await testHelper.capture( +// viewer, "set_background_color_to_transparent_green"); +// await viewer.dispose(); +// }); + +// test('set background image', () async { +// var viewer = await testHelper.createViewer(); +// await viewer.setBackgroundImage( +// "file:///${testHelper.testDir}/assets/cube_texture_512x512.png"); +// await viewer.setPostProcessing(true); +// await viewer.setToneMapping(ToneMapper.LINEAR); +// await testHelper.capture(viewer, "set_background_image"); +// await viewer.dispose(); +// }); +// }); + + + +// group("scene update events", () { +// test('add light fires SceneUpdateEvent', () async { +// var viewer = await testHelper.createViewer(); + +// final success = Completer(); +// var light = DirectLight( +// type: LightType.POINT, +// color: 6500, +// intensity: 1000000, +// position: Vector3(0, 0.6, 0.6), +// direction: Vector3(0, 0, 0), +// falloffRadius: 2.0); + +// late StreamSubscription listener; +// listener = viewer.sceneUpdated.listen((updateEvent) { +// var wasSuccess = updateEvent.eventType == EventType.EntityAdded && +// updateEvent.addedEntityType == EntityType.DirectLight && +// updateEvent.getDirectLight() == light; +// success.complete(wasSuccess); +// listener.cancel(); +// }); +// await viewer.addDirectLight(light); +// expect(await success.future, true); +// }); + +// test('remove light fires SceneUpdateEvent', () async { +// var viewer = await testHelper.createViewer(); + +// final success = Completer(); +// var light = await viewer.addDirectLight(DirectLight.point()); + +// late StreamSubscription listener; +// listener = viewer.sceneUpdated.listen((updateEvent) { +// var wasSuccess = updateEvent.eventType == EventType.EntityRemoved && +// updateEvent.entity == light; +// success.complete(wasSuccess); +// listener.cancel(); +// }); + +// await viewer.removeLight(light); + +// expect(await success.future, true); +// }); + +// test('add geometry fires SceneUpdateEvent', () async { +// var viewer = await testHelper.createViewer(); + +// final success = Completer(); +// var geometry = GeometryHelper.cube(); + +// late StreamSubscription listener; +// listener = viewer.sceneUpdated.listen((updateEvent) { +// var wasSuccess = updateEvent.eventType == EventType.EntityAdded && +// updateEvent.addedEntityType == EntityType.Geometry && +// updateEvent.getAsGeometry() == geometry; +// success.complete(wasSuccess); +// listener.cancel(); +// }); +// await viewer.createGeometry(geometry); +// expect(await success.future, true); +// }); + +// test('remove geometry fires SceneUpdateEvent', () async { +// var viewer = await testHelper.createViewer(); +// var geometry = await viewer.createGeometry(GeometryHelper.cube()); +// final success = Completer(); + +// late StreamSubscription listener; +// listener = viewer.sceneUpdated.listen((updateEvent) { +// var wasSuccess = updateEvent.eventType == EventType.EntityRemoved && +// updateEvent.entity == geometry; +// success.complete(wasSuccess); +// listener.cancel(); +// }); + +// await viewer.destroyAsset(geometry); + +// expect(await success.future, true); +// }); + +// test('loadGlb fires SceneUpdateEvent', () async { +// var viewer = await testHelper.createViewer(); + +// final success = Completer(); + +// late StreamSubscription listener; + +// final uri = "${testHelper.testDir}/cube.glb"; + +// listener = viewer.sceneUpdated.listen((updateEvent) { +// var wasSuccess = updateEvent.eventType == EventType.EntityAdded && +// updateEvent.addedEntityType == EntityType.Gltf && +// updateEvent.getAsGLTF().uri == uri; +// success.complete(wasSuccess); +// listener.cancel(); +// }); +// await viewer.loadGlb(uri, keepData: false); +// expect(await success.future, true); +// }); + +// test('remove glb fires SceneUpdateEvent', () async { +// var viewer = await testHelper.createViewer(); +// final uri = "${testHelper.testDir}/cube.glb"; +// var entity = await viewer.loadGlb(uri, keepData: false); + +// final success = Completer(); + +// late StreamSubscription listener; +// listener = viewer.sceneUpdated.listen((updateEvent) { +// var wasSuccess = updateEvent.eventType == EventType.EntityRemoved && +// updateEvent.entity == entity; +// success.complete(wasSuccess); +// listener.cancel(); +// }); +// await viewer.destroyAsset(entity); +// expect(await success.future, true); +// }); +// }); + + +// group("MaterialInstance", () { +// test('disable depth write', () async { +// var viewer = await testHelper.createViewer(); +// await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0); +// await viewer.setCameraPosition(0, 0, 6); +// await viewer.addDirectLight( +// DirectLight.sun(direction: Vector3(0, 0, -1)..normalize())); + +// final cube1 = await viewer.createGeometry(GeometryHelper.cube()); +// var materialInstance = await viewer.getMaterialInstanceAt(cube1, 0); + +// final cube2 = await viewer.createGeometry(GeometryHelper.cube()); +// await viewer.setMaterialPropertyFloat4( +// cube2, "baseColorFactor", 0, 0, 1, 0, 1); +// await viewer.setPosition(cube2, 1.0, 0.0, -1.0); + +// expect(materialInstance, isNotNull); + +// // with depth write enabled on both materials, cube2 renders behind the white cube +// await testHelper.capture(viewer, "material_instance_depth_write_enabled"); + +// // if we disable depth write on cube1, then cube2 will always appear in front +// // (relying on insertion order) +// materialInstance!.setDepthWriteEnabled(false); +// await testHelper.capture( +// viewer, "material_instance_depth_write_disabled"); + +// // set priority for the cube1 cube to 7 (render) last, cube1 renders in front +// await viewer.setPriority(cube1, 7); +// await testHelper.capture( +// viewer, "material_instance_depth_write_disabled_with_priority"); +// }); +// }); + +// // test('create instance from glb when keepData is true', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true); +// // await viewer.transformToUnitCube(model); +// // var instance = await viewer.createInstance(model); +// // await viewer.setPosition(instance, 0.5, 0.5, -0.5); +// // await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0); +// // await viewer.setCameraPosition(0, 1, 5); +// // await viewer +// // .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); +// // await viewer.setRendering(true); +// // await testHelper.capture(viewer, "glb_create_instance"); +// // await viewer.setRendering(false); +// // }); + +// // test('create instance from glb fails when keepData is false', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: false); +// // bool thrown = false; +// // try { +// // await viewer.createInstance(model); +// // } catch (err) { +// // thrown = true; +// // } +// // expect(thrown, true); +// // }); +// // }); + +// // group('Skinning & animations', () { +// // test('get bone names', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/assets/shapes.glb"); +// // var names = await viewer.getBoneNames(model); +// // expect(names.first, "Bone"); +// // }); + +// // test('reset bones', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/assets/shapes.glb"); +// // await viewer.resetBones(model); +// // }); +// // test('set from BVH', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/assets/shapes.glb"); +// // var animation = BVHParser.parse( +// // File("${testHelper.testDir}/assets/animation.bvh").readAsStringSync(), +// // boneRegex: RegExp(r"Bone$")); +// // await viewer.addBoneAnimation(model, animation); +// // }); + +// // test('fade in/out', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/assets/shapes.glb"); +// // var animation = BVHParser.parse( +// // File("${testHelper.testDir}/assets/animation.bvh").readAsStringSync(), +// // boneRegex: RegExp(r"Bone$")); +// // await viewer.addBoneAnimation(model, animation, +// // fadeInInSecs: 0.5, fadeOutInSecs: 0.5); +// // await Future.delayed(Duration(seconds: 1)); +// // }); + +// group("materials", () { +// test('set float4 material property for custom geometry', () async { +// var viewer = await testHelper.createViewer(); + +// await viewer.setCameraPosition(0, 0, 6); +// await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0); +// var light = await viewer.addLight( +// LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1); + +// final cube = await viewer.createGeometry(GeometryHelper.cube()); + +// await testHelper.capture(viewer, "set_material_float4_pre"); +// await viewer.setMaterialPropertyFloat4( +// cube, "baseColorFactor", 0, 0.0, 1.0, 0.0, 1.0); +// await testHelper.capture(viewer, "set_material_float4_post"); +// }); +// test('set float material property for custom geometry', () async { +// var viewer = await testHelper.createViewer(); + +// await viewer.setCameraPosition(0, 0, 6); +// await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0); +// var light = await viewer.addLight( +// LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1); + +// final cube = await viewer.createGeometry(GeometryHelper.cube()); + +// // this won't actually do anything because the default ubershader doesn't use specular/glossiness +// // but we can at least check that the call succeeds +// await testHelper.capture(viewer, "set_material_specular_pre"); +// await viewer.setMaterialPropertyFloat(cube, "specularFactor", 0, 0.0); +// await testHelper.capture(viewer, "set_material_specular_post"); +// }); + +// test('set float material property (roughness) for custom geometry', +// () async { +// var viewer = await testHelper.createViewer(); + +// await viewer.setCameraPosition(0, 0, 6); +// await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0); +// var light = await viewer.addLight( +// LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1); + +// final cube = await viewer.createGeometry(GeometryHelper.cube()); + +// // this won't actually do anything because the default ubershader doesn't use specular/glossiness +// // but we can at least check that the call succeeds +// await testHelper.capture(viewer, "set_material_roughness_pre"); + +// await viewer.setMaterialPropertyFloat(cube, "metallicFactor", 0, 0.0); +// await viewer.setMaterialPropertyFloat(cube, "roughnessFactor", 0, 0.0); +// await testHelper.capture(viewer, "set_material_roughness_post"); +// }); +// }); + +// group("transforms & parenting", () { +// test('set multiple transforms simultaneously with setTransforms', () async { +// var viewer = +// await testHelper.createViewer(bg: kRed, cameraPosition: Vector3(0, 0, 5)); +// final cube1 = await viewer.createGeometry(GeometryHelper.cube()); +// final cube2 = await viewer.createGeometry(GeometryHelper.cube()); + +// await viewer.queueTransformUpdates([ +// cube1, +// cube2 +// ], [ +// Matrix4.translation(Vector3(-1, 0, 0)), +// Matrix4.translation(Vector3(1, 0, 0)) +// ]); + +// await viewer.render(testHelper.swapChain); + +// await testHelper.capture(viewer, "set_multiple_transforms"); +// }); + +// test('getParent and getAncestor both return null when entity has no parent', +// () async { +// var viewer = await testHelper.createViewer(); + +// final cube = await viewer.createGeometry(GeometryHelper.cube()); + +// expect(await viewer.getParent(cube), isNull); +// expect(await viewer.getAncestor(cube), isNull); +// }); + +// test( +// 'getParent returns the parent entity after one has been set via setParent', +// () async { +// var viewer = await testHelper.createViewer(); + +// final cube1 = await viewer.createGeometry(GeometryHelper.cube()); + +// final cube2 = await viewer.createGeometry(GeometryHelper.cube()); + +// await viewer.setParent(cube1, cube2); + +// final parent = await viewer.getParent(cube1); + +// expect(parent, cube2); +// }); + +// test('getAncestor returns the ultimate parent entity', () async { +// var viewer = await testHelper.createViewer(); + +// final grandparent = await viewer.createGeometry(GeometryHelper.cube()); +// final parent = await viewer.createGeometry(GeometryHelper.cube()); +// final child = await viewer.createGeometry(GeometryHelper.cube()); + +// await viewer.setParent(child, parent); +// await viewer.setParent(parent, grandparent); + +// expect(await viewer.getAncestor(child), grandparent); +// }); + +// test('set position based on screenspace coord', () async { +// var viewer = await testHelper.createViewer(); +// print(await viewer.getCameraFov(true)); +// await viewer.createIbl(1.0, 1.0, 1.0, 1000); +// await viewer.setCameraPosition(0, 0, 6); +// await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0); +// // Create the cube geometry +// final cube = await viewer.createGeometry(GeometryHelper.cube()); +// // await viewer.setPosition(cube, -0.05, 0.04, 5.9); +// // await viewer.setPosition(cube, -2.54, 2.54, 0); +// await viewer.queuePositionUpdateFromViewportCoords(cube, 0, 0); + +// // we need an explicit render call here to process the transform queue +// await viewer.render(testHelper.swapChain); + +// await testHelper.capture(viewer, "set_position_from_viewport_coords"); +// }); +// }); + +// group("layers & overlays", () { +// test('enable grid overlay', () async { +// var viewer = await testHelper.createViewer(); +// await viewer.setBackgroundColor(0, 0, 0, 1); +// await viewer +// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8)); +// await viewer.setCameraPosition(0, 2, 0); +// await testHelper.capture(viewer, "grid_overlay_default"); +// await viewer.setLayerVisibility(7, true); +// await testHelper.capture(viewer, "grid_overlay_enabled"); +// await viewer.setLayerVisibility(7, false); +// await testHelper.capture(viewer, "grid_overlay_disabled"); +// }); + +// test('load glb from buffer with layer', () async { +// var viewer = await testHelper.createViewer(); + +// await viewer.setBackgroundColor(1, 0, 1, 1); +// await viewer.setCameraPosition(0, 2, 5); +// await viewer +// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); + +// var buffer = File("${testHelper.testDir}/cube.glb").readAsBytesSync(); +// var model = await viewer.loadGlbFromBuffer(buffer, layer: 1); +// await testHelper.capture( +// viewer, "load_glb_from_buffer_with_layer_disabled"); +// await viewer.setLayerVisibility(1, true); +// await testHelper.capture( +// viewer, "load_glb_from_buffer_with_layer_enabled"); +// }); + +// test('change layer visibility at runtime', () async { +// var viewer = await testHelper.createViewer(); + +// await viewer.setBackgroundColor(1, 0, 1, 1); +// await viewer.setCameraPosition(0, 2, 5); +// await viewer +// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); + +// var cube = await viewer.createGeometry(GeometryHelper.cube()); +// await testHelper.capture( +// viewer, "change_layer_visibility_at_runtime_default"); + +// // all entities set to layer 0 by default, so this should now be invisible +// await viewer.setLayerVisibility(0, false); +// await testHelper.capture( +// viewer, "change_layer_visibility_at_runtime_layer0_invisible"); + +// // now change the visibility layer to 5, should be invisible +// await viewer.setVisibilityLayer(cube, 5); +// await testHelper.capture( +// viewer, "change_layer_visibility_at_runtime_layer5_invisible"); + +// // now toggle layer 5 visibility, cube should now be visible +// await viewer.setLayerVisibility(5, true); +// await testHelper.capture( +// viewer, "change_layer_visibility_at_runtime_layer5_visible"); +// }); +// }); + +// // test('point light', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb"); +// // await viewer.transformToUnitCube(model); +// // var light = await viewer.addLight( +// // LightType.POINT, 6500, 1000000, 0, 2, 0, 0, -1, 0, +// // falloffRadius: 10.0); +// // await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0); +// // await viewer.setCameraPosition(0, 1, 5); +// // await viewer +// // .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); +// // await viewer.setRendering(true); +// // await testHelper.capture(viewer, "point_light"); +// // await viewer.setRendering(false); +// // }); + +// // test('set point light position', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb"); +// // await viewer.transformToUnitCube(model); +// // var light = await viewer.addLight( +// // LightType.POINT, 6500, 1000000, 0, 2, 0, 0, -1, 0, +// // falloffRadius: 10.0); +// // await viewer.setLightPosition(light, 0.5, 2, 0); +// // await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0); +// // await viewer.setCameraPosition(0, 1, 5); +// // await viewer +// // .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); +// // await viewer.setRendering(true); +// // await testHelper.capture(viewer, "move_point_light"); +// // await viewer.setRendering(false); +// // }); + +// // test('directional light', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb"); +// // await viewer.transformToUnitCube(model); +// // var light = await viewer.addLight( +// // LightType.SUN, 6500, 1000000, 0, 0, 0, 0, -1, 0); +// // await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0); +// // await viewer.setCameraPosition(0, 1, 5); +// // await viewer +// // .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); +// // await viewer.setRendering(true); +// // await testHelper.capture(viewer, "directional_light"); +// // await viewer.setRendering(false); +// // }); + +// // test('set directional light direction', () async { +// // var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb"); +// // await viewer.transformToUnitCube(model); +// // var light = await viewer.addLight( +// // LightType.SUN, 6500, 1000000, 0, 0, 0, 0, -1, 0); +// // await viewer.setLightDirection(light, Vector3(-1, -1, -1)); +// // await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0); +// // await viewer.setCameraPosition(0, 1, 5); +// // await viewer +// // .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); +// // await viewer.setRendering(true); +// // await testHelper.capture(viewer, "set_directional_light_direction"); +// // await viewer.setRendering(false); +// // }); + +// group("stencil", () { +// test('set stencil highlight for glb', () async { +// final viewer = await testHelper.createViewer(); +// var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true); +// await viewer.setPostProcessing(true); + +// var light = await viewer.addLight( +// LightType.SUN, 6500, 1000000, 0, 0, 0, 0, -1, 0); +// await viewer.setLightDirection(light, Vector3(0, 1, -1)); + +// await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0); +// await viewer.setCameraPosition(0, -1, 5); +// await viewer +// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), pi / 8)); +// await viewer.setStencilHighlight(model); +// await testHelper.capture(viewer, "stencil_highlight_glb"); +// }); + +// test('set stencil highlight for geometry', () async { +// var viewer = await testHelper.createViewer(); +// await viewer.setPostProcessing(true); +// await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0); +// await viewer.setCameraPosition(0, 2, 5); +// await viewer +// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); + +// var cube = await viewer.createGeometry(GeometryHelper.cube()); +// await viewer.setStencilHighlight(cube); + +// await testHelper.capture(viewer, "stencil_highlight_geometry"); + +// await viewer.removeStencilHighlight(cube); + +// await testHelper.capture(viewer, "stencil_highlight_geometry_remove"); +// }); + +// test('set stencil highlight for gltf asset', () async { +// var viewer = await testHelper.createViewer(); +// await viewer.setPostProcessing(true); +// await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0); +// await viewer.setCameraPosition(0, 1, 5); +// await viewer +// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); + +// var cube1 = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true); +// await viewer.transformToUnitCube(cube1); + +// await viewer.setStencilHighlight(cube1); + +// await testHelper.capture(viewer, "stencil_highlight_gltf"); + +// await viewer.removeStencilHighlight(cube1); + +// await testHelper.capture(viewer, "stencil_highlight_gltf_removed"); +// }); + +// test('set stencil highlight for multiple geometry ', () async { +// var viewer = await testHelper.createViewer(); +// await viewer.setPostProcessing(true); +// await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0); +// await viewer.setCameraPosition(0, 1, 5); +// await viewer +// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); + +// var cube1 = await viewer.createGeometry(GeometryHelper.cube()); +// var cube2 = await viewer.createGeometry(GeometryHelper.cube()); +// await viewer.setPosition(cube2, 0.5, 0.5, 0); +// await viewer.setStencilHighlight(cube1); +// await viewer.setStencilHighlight(cube2, r: 0.0, g: 0.0, b: 1.0); + +// await testHelper.capture(viewer, "stencil_highlight_multiple_geometry"); + +// await viewer.removeStencilHighlight(cube1); +// await viewer.removeStencilHighlight(cube2); + +// await testHelper.capture( +// viewer, "stencil_highlight_multiple_geometry_removed"); +// }); + +// test('set stencil highlight for multiple gltf assets ', () async { +// var viewer = await testHelper.createViewer(); +// await viewer.setPostProcessing(true); +// await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0); +// await viewer.setCameraPosition(0, 1, 5); +// await viewer +// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5)); + +// var cube1 = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true); +// await viewer.transformToUnitCube(cube1); +// var cube2 = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true); +// await viewer.transformToUnitCube(cube2); +// await viewer.setPosition(cube2, 0.5, 0.5, 0); +// await viewer.setStencilHighlight(cube1); +// await viewer.setStencilHighlight(cube2, r: 0.0, g: 0.0, b: 1.0); + +// await testHelper.capture(viewer, "stencil_highlight_multiple_geometry"); + +// await viewer.removeStencilHighlight(cube1); +// await viewer.removeStencilHighlight(cube2); + +// await testHelper.capture( +// viewer, "stencil_highlight_multiple_geometry_removed"); +// }); +// }); + +// group("texture", () { +// test("create/apply/dispose texture", () async { +// var viewer = await testHelper.createViewer(); + +// var textureData = +// File("${testHelper.testDir}/assets/cube_texture_512x512.png").readAsBytesSync(); + +// var texture = await viewer.createTexture(textureData); +// await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0); +// await viewer.addDirectLight( +// DirectLight.sun(direction: Vector3(0, -10, -1)..normalize())); +// await viewer.addDirectLight(DirectLight.spot( +// intensity: 1000000, +// position: Vector3(0, 0, 1.5), +// direction: Vector3(0, 0, -1)..normalize(), +// falloffRadius: 10, +// spotLightConeInner: 1, +// spotLightConeOuter: 1)); +// await viewer.setCameraPosition(0, 2, 6); +// await viewer +// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8)); +// var materialInstance = +// await viewer.createUbershaderMaterialInstance(unlit: true); +// var cube = await viewer.createGeometry(GeometryHelper.cube(), +// materialInstance: materialInstance); + +// await viewer.setPostProcessing(true); +// await viewer.setToneMapping(ToneMapper.LINEAR); + +// await viewer.applyTexture(texture, cube, +// materialIndex: 0, parameterName: "baseColorMap"); + +// await testHelper.capture(viewer, "texture_applied_to_geometry"); + +// await viewer.destroyAsset(cube); +// await viewer.destroyTexture(texture); +// }); +// }); + +// // group("unproject", () { +// // test("unproject", () async { +// // final dimensions = (width: 1280, height: 768); + +// // var viewer = await testHelper.createViewer(viewportDimensions: dimensions); +// // await viewer.setPostProcessing(false); +// // // await viewer.setToneMapping(ToneMapper.LINEAR); +// // await viewer.setBackgroundColor(1.0, 1.0, 1.0, 1.0); +// // // await viewer.createIbl(1.0, 1.0, 1.0, 100000); +// // await viewer.addLight(LightType.SUN, 6500, 100000, -2, 0, 0, 1, -1, 0); +// // await viewer.addLight(LightType.SPOT, 6500, 500000, 0, 0, 2, 0, 0, -1, +// // falloffRadius: 10, spotLightConeInner: 1.0, spotLightConeOuter: 2.0); + +// // await viewer.setCameraPosition(-3, 4, 6); +// // await viewer.setCameraRotation( +// // Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) * +// // Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 6)); +// // var cube = +// // await viewer.createGeometry(GeometryHelper.cube(), keepData: true); +// // await viewer.setMaterialPropertyFloat4( +// // cube, "baseColorFactor", 0, 1.0, 1.0, 1.0, 1.0); +// // var textureData = +// // File("${testHelper.testDir}/assets/cube_texture_512x512.png").readAsBytesSync(); +// // var texture = await viewer.createTexture(textureData); +// // await viewer.applyTexture(texture, cube, +// // materialIndex: 0, parameterName: "baseColorMap"); + +// // var numFrames = 60; + +// // // first do the render +// // for (int i = 0; i < numFrames; i++) { +// // await viewer.setCameraPosition(-3 + (i / numFrames * 2), 4, 6); + +// // await viewer.setCameraRotation( +// // Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) * +// // Quaternion.axisAngle( +// // Vector3(1, 0, 0), -pi / 6 - (i / numFrames * pi / 6))); + +// // var rendered = await testHelper.capture(viewer, "unproject_render$i"); +// // var renderPng = +// // await pixelsToPng(rendered, dimensions.width, dimensions.height); + +// // File("${outDir.path}/unproject_render${i}.png") +// // .writeAsBytesSync(renderPng); +// // } + +// // // then go off and convert the video + +// // // now unproject the render back onto the geometry +// // final textureSize = (width: 1280, height: 768); +// // var pixels = []; +// // // note we skip the first frame +// // for (int i = 0; i < numFrames; i++) { +// // await viewer.setCameraPosition(-3 + (i / numFrames * 2), 4, 6); + +// // await viewer.setCameraRotation( +// // Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) * +// // Quaternion.axisAngle( +// // Vector3(1, 0, 0), -pi / 6 - (i / numFrames * pi / 6))); + +// // var input = pngToPixelBuffer(File( +// // "${outDir.path}/a8c317af-6081-4848-8a06-f6b69bc57664_${i + 1}.png") +// // .readAsBytesSync()); +// // var pixelBuffer = await (await viewer as ThermionViewerFFI).unproject( +// // cube, +// // input, +// // dimensions.width, +// // dimensions.height, +// // textureSize.width, +// // textureSize.height); + +// // // var png = await pixelsToPng(Uint8List.fromList(pixelBuffer), +// // // dimensions.width, dimensions.height); + +// // await savePixelBufferToBmp( +// // pixelBuffer, +// // textureSize.width, +// // textureSize.height, +// // p.join(outDir.path, "unprojected_texture${i}.bmp")); + +// // pixels.add(pixelBuffer); + +// // if (i > 10) { +// // break; +// // } +// // } + +// // // } + +// // final aggregatePixelBuffer = medianImages(pixels); +// // await savePixelBufferToBmp(aggregatePixelBuffer, textureSize.width, +// // textureSize.height, "unproject_texture.bmp"); +// // var pixelBufferPng = await pixelsToPng( +// // Uint8List.fromList(aggregatePixelBuffer), +// // dimensions.width, +// // dimensions.height); +// // File("${outDir.path}/unproject_texture.png") +// // .writeAsBytesSync(pixelBufferPng); + +// // await viewer.setPostProcessing(true); +// // await viewer.setToneMapping(ToneMapper.LINEAR); + +// // final unlit = await viewer.createUnlitMaterialInstance(); +// // await viewer.destroyAsset(cube); +// // cube = await viewer.createGeometry(GeometryHelper.cube(), +// // materialInstance: unlit); +// // var reconstructedTexture = await viewer.createTexture(pixelBufferPng); +// // await viewer.applyTexture(reconstructedTexture, cube); + +// // await viewer.setCameraRotation( +// // Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) * +// // Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 6)); +// // await testHelper.capture(viewer, "unproject_reconstruct"); + +// // // now re-render +// // for (int i = 0; i < numFrames; i++) { +// // await viewer.setCameraPosition(-3 + (i / numFrames * 2), 4, 6); + +// // await viewer.setCameraRotation( +// // Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) * +// // Quaternion.axisAngle( +// // Vector3(1, 0, 0), -pi / 6 - (i / numFrames * pi / 6))); + +// // var rendered = await testHelper.capture(viewer, "unproject_rerender$i"); +// // var renderPng = +// // await pixelsToPng(rendered, dimensions.width, dimensions.height); + +// // File("${outDir.path}/unproject_rerender${i}.png") +// // .writeAsBytesSync(renderPng); +// // } +// // }, timeout: Timeout(Duration(minutes: 2))); +// // }); +// } diff --git a/thermion_dart/test/overlay_tests.dart b/thermion_dart/test/overlay_tests.dart index 76c92b15..ee407fec 100644 --- a/thermion_dart/test/overlay_tests.dart +++ b/thermion_dart/test/overlay_tests.dart @@ -145,7 +145,7 @@ void main() async { await testHelper.capture( viewer, "geometry_bounding_box_not_visible"); await cube.setBoundingBoxVisibility(true); - await viewer.removeAsset(cube); + await viewer.destroyAsset(cube); await testHelper.capture( viewer, "geometry_bounding_box_removed"); }, @@ -229,7 +229,7 @@ void main() async { // await testHelper.capture(viewer, "texture_applied_to_geometry"); - // await viewer.removeAsset(cube); + // await viewer.destroyAsset(cube); // await viewer.destroyTexture(texture); // await viewer.dispose(); // }); @@ -338,7 +338,7 @@ void main() async { // await viewer.setToneMapping(ToneMapper.LINEAR); // final unlit = await viewer.createUnlitMaterialInstance(); - // await viewer.removeAsset(cube); + // await viewer.destroyAsset(cube); // cube = await viewer.createGeometry(GeometryHelper.cube(), // materialInstance: unlit); // var reconstructedTexture = await viewer.createTexture(pixelBufferPng);