From 255c0edd49db4185bade40b6294b3bbee37b1789 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Fri, 21 Mar 2025 14:56:20 +0800 Subject: [PATCH] refactoring --- thermion_dart/lib/src/filament/src/asset.dart | 20 + .../lib/src/filament/src/filament_app.dart | 2 +- .../viewer/src/ffi/src/background_image.dart | 29 +- .../lib/src/viewer/src/ffi/src/callbacks.dart | 2 +- .../lib/src/viewer/src/ffi/src/ffi_asset.dart | 24 +- .../viewer/src/ffi/src/ffi_filament_app.dart | 105 ++- .../src/viewer/src/ffi/src/ffi_material.dart | 2 +- .../lib/src/viewer/src/ffi/src/ffi_view.dart | 17 +- .../viewer/src/ffi/src/thermion_dart.g.dart | 62 +- .../src/ffi/src/thermion_viewer_ffi.dart | 75 +- .../src/viewer/src/thermion_viewer_base.dart | 18 +- .../src/viewer/src/thermion_viewer_stub.dart | 40 +- thermion_dart/lib/thermion_dart.dart | 1 + .../native/include/c_api/TAnimationManager.h | 2 + thermion_dart/native/include/c_api/TView.h | 6 + .../c_api/ThermionDartRenderThreadApi.h | 11 +- .../{RenderLoop.hpp => RenderThread.hpp} | 12 +- thermion_dart/native/src/RenderTicker.cpp | 19 +- .../native/src/c_api/TAnimationManager.cpp | 5 + thermion_dart/native/src/c_api/TEngine.cpp | 27 + .../src/c_api/TNameComponentManager.cpp | 8 +- thermion_dart/native/src/c_api/TView.cpp | 31 +- .../src/c_api/ThermionDartRenderThreadApi.cpp | 181 ++-- .../{RenderLoop.cpp => RenderThread.cpp} | 17 +- thermion_dart/test/geometry_tests.dart | 555 ++++++------ thermion_dart/test/helpers.dart | 41 +- .../lib/src/thermion_flutter_plugin.dart | 1 + .../src/camera/camera_orientation_widget.dart | 166 ++-- .../src/camera/camera_selector_widget.dart | 144 ++-- .../src/debug/child_renderable_widget.dart | 204 ++--- .../src/debug/skeleton_menu_item_widget.dart | 806 +++++++++--------- .../widgets/src/thermion_texture_widget.dart | 3 +- .../Classes/ThermionFlutterTexture.swift | 4 + .../macos/Classes/ThermionTexture.swift | 1 + ...rmion_flutter_method_channel_platform.dart | 57 +- .../thermion_flutter_platform_interface.dart | 20 +- .../lib/thermion_flutter_web.dart | 4 +- .../lib/thermion_flutter_web_options.dart | 6 +- 38 files changed, 1521 insertions(+), 1207 deletions(-) rename thermion_dart/native/include/rendering/{RenderLoop.hpp => RenderThread.hpp} (86%) rename thermion_dart/native/src/rendering/{RenderLoop.cpp => RenderThread.cpp} (83%) create mode 120000 thermion_flutter/thermion_flutter/macos/Classes/ThermionTexture.swift diff --git a/thermion_dart/lib/src/filament/src/asset.dart b/thermion_dart/lib/src/filament/src/asset.dart index 694f5df3..1e7fd70a 100644 --- a/thermion_dart/lib/src/filament/src/asset.dart +++ b/thermion_dart/lib/src/filament/src/asset.dart @@ -32,6 +32,11 @@ abstract class ThermionAsset { /// Future> getChildEntities(); + /// + /// + /// + Future> getChildEntityNames(); + /// /// /// @@ -91,6 +96,21 @@ abstract class ThermionAsset { /// Future setReceiveShadows(bool castShadows); + /// + /// + /// + Future isCastShadowsEnabled({ThermionEntity? entity}); + + /// + /// + /// + Future isReceiveShadowsEnabled({ThermionEntity? entity}); + + /// + /// + /// + Future transformToUnitCube(); + /// /// All renderable entities are assigned a layer mask. /// diff --git a/thermion_dart/lib/src/filament/src/filament_app.dart b/thermion_dart/lib/src/filament/src/filament_app.dart index 7e027a5d..7e9c43db 100644 --- a/thermion_dart/lib/src/filament/src/filament_app.dart +++ b/thermion_dart/lib/src/filament/src/filament_app.dart @@ -241,7 +241,7 @@ abstract class FilamentApp { /// /// /// - Future loadGlbFromBuffer(Uint8List data, T animationManager, + Future loadGltfFromBuffer(Uint8List data, T animationManager, {int numInstances = 1, bool keepData = false, int priority = 4, diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/background_image.dart b/thermion_dart/lib/src/viewer/src/ffi/src/background_image.dart index fcd24076..6cc5455c 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/background_image.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/background_image.dart @@ -31,8 +31,8 @@ class BackgroundImage extends ThermionAsset { Future destroy() async { Scene_removeEntity(scene.scene, entity); - await texture!.dispose(); - await sampler!.dispose(); + await texture?.dispose(); + await sampler?.dispose(); await mi.destroy(); } @@ -63,6 +63,10 @@ class BackgroundImage extends ThermionAsset { await mi.setParameterFloat4("backgroundColor", r, g, b, a); } + Future hideImage() async { + await mi.setParameterInt("showImage", 0); + } + /// /// /// @@ -317,4 +321,25 @@ class BackgroundImage extends ThermionAsset { // TODO: implement updateBoneMatrices throw UnimplementedError(); } + + @override + Future> getChildEntityNames() async { + return []; + } + + @override + Future isCastShadowsEnabled({ThermionEntity? entity}) async { + return false; + } + + @override + Future isReceiveShadowsEnabled({ThermionEntity? entity}) async { + return false; + } + + @override + Future transformToUnitCube() { + // TODO: implement transformToUnitCube + throw UnimplementedError(); + } } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/callbacks.dart b/thermion_dart/lib/src/viewer/src/ffi/src/callbacks.dart index ea169f42..24d9212d 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/callbacks.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/callbacks.dart @@ -21,7 +21,7 @@ Future withVoidCallback2(Function() func) async { completer.complete(); }; final nativeCallable = NativeCallable.listener(callback); - RenderLoop_addTask(nativeCallable.nativeFunction); + RenderThread_addTask(nativeCallable.nativeFunction); await completer.future; nativeCallable.close(); } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_asset.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_asset.dart index 5598c2de..da729a41 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_asset.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_asset.dart @@ -63,6 +63,24 @@ class FFIAsset extends ThermionAsset { return children; } + /// + /// + /// + @override + Future> getChildEntityNames() async { + final childEntities = await getChildEntities(); + var names = []; + for (final entity in childEntities) { + var name = NameComponentManager_getName(app.nameComponentManager, entity); + if (name == nullptr) { + names.add(null); + } else { + names.add(name.cast().toDartString()); + } + } + return names; + } + /// /// /// @@ -392,14 +410,16 @@ class FFIAsset extends ThermionAsset { /// /// /// - Future isCastShadowsEnabled(ThermionEntity entity) async { + Future isCastShadowsEnabled({ThermionEntity? entity}) async { + entity ??= this.entity; return RenderableManager_isShadowCaster(app.renderableManager, entity); } /// /// /// - Future isReceiveShadowsEnabled(ThermionEntity entity) async { + Future isReceiveShadowsEnabled({ThermionEntity? entity}) async { + entity ??= this.entity; return RenderableManager_isShadowReceiver(app.renderableManager, entity); } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart index b9c6db89..ab597853 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart @@ -70,8 +70,8 @@ class FFIFilamentApp extends FilamentApp { await FilamentApp.instance!.destroy(); } - RenderLoop_destroy(); - RenderLoop_create(); + RenderThread_destroy(); + RenderThread_create(); final engine = await withPointerCallback((cb) => Engine_createRenderThread( @@ -95,6 +95,8 @@ class FFIFilamentApp extends FilamentApp { final renderTicker = RenderTicker_create(renderer); + RenderThread_setRenderTicker(renderTicker); + final nameComponentManager = NameComponentManager_create(); FilamentApp.instance = FFIFilamentApp( @@ -110,30 +112,34 @@ class FFIFilamentApp extends FilamentApp { config.resourceLoader); } - final _views = >{}; - final _viewMappings = {}; + final _swapChains = >{}; + final viewsPtr = calloc>(255); /// /// /// 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); - } + await view.setRenderable(renderable); + await _updateRenderableSwapChains(); + } - final views = calloc>(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; + Future _updateRenderableSwapChains() async { + for (final swapChain in _swapChains.keys) { + final views = _swapChains[swapChain]; + if (views == null) { + continue; + } + + int numRenderable = 0; + for (final view in views) { + if (view.renderable) { + viewsPtr[numRenderable] = view.view; + numRenderable++; + } } RenderTicker_setRenderable( - renderTicker, swapChain.swapChain, views, numViews); + renderTicker, swapChain.swapChain, viewsPtr, numRenderable); } - calloc.free(views); } @override @@ -143,6 +149,7 @@ class FFIFilamentApp extends FilamentApp { if (hasStencilBuffer) { flags |= TSWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER; } + print("swapchain flags $flags"); final swapChain = await withPointerCallback((cb) => Engine_createHeadlessSwapChainRenderThread( this.engine, width, height, flags, cb)); @@ -173,6 +180,7 @@ class FFIFilamentApp extends FilamentApp { Engine_destroySwapChainRenderThread( engine, (swapChain as FFISwapChain).swapChain, callback); }); + _swapChains.remove(swapChain); } /// @@ -180,17 +188,21 @@ class FFIFilamentApp extends FilamentApp { /// @override Future destroy() async { - for (final swapChain in _views.keys) { - for (final view in _views[swapChain]!) { + for (final swapChain in _swapChains.keys) { + if (_swapChains[swapChain] == null) { + continue; + } + for (final view in _swapChains[swapChain]!) { await setRenderable(view, false); } } - for (final swapChain in _views.keys) { + for (final swapChain in _swapChains.keys.toList()) { await destroySwapChain(swapChain); } - RenderLoop_destroy(); + RenderThread_destroy(); RenderTicker_destroy(renderTicker); Engine_destroy(engine); + calloc.free(viewsPtr); } /// @@ -440,8 +452,24 @@ class FFIFilamentApp extends FilamentApp { /// @override Future render() async { - await withVoidCallback( - (cb) => RenderTicker_renderRenderThread(renderTicker, 0, cb)); + // await withVoidCallback( + // (cb) => RenderTicker_renderRenderThread(renderTicker, 0, cb)); + final swapchain = _swapChains.keys.first; + final view = _swapChains[swapchain]!.first; + await withBoolCallback((cb) { + Renderer_beginFrameRenderThread(renderer, swapchain.swapChain, 0, cb); + }); + await withVoidCallback((cb) { + Renderer_renderRenderThread( + renderer, + view.view, + cb, + ); + }); + + await withVoidCallback((cb) { + Renderer_endFrameRenderThread(renderer, cb); + }); } /// @@ -450,11 +478,11 @@ class FFIFilamentApp extends FilamentApp { @override Future register( covariant FFISwapChain swapChain, covariant FFIView view) async { - _viewMappings[view] = swapChain; - if (!_views.containsKey(swapChain)) { - _views[swapChain] = []; + if (!_swapChains.containsKey(swapChain)) { + _swapChains[swapChain] = []; } - _views[swapChain]!.add(view); + _swapChains[swapChain]!.add(view); + await _updateRenderableSwapChains(); } final _hooks = []; @@ -493,7 +521,7 @@ class FFIFilamentApp extends FilamentApp { completer.complete(true); }); - RenderLoop_requestAnimationFrame(callback.nativeFunction.cast()); + RenderThread_requestAnimationFrame(callback.nativeFunction.cast()); try { await completer.future.timeout(Duration(seconds: 1)); @@ -572,15 +600,20 @@ class FFIFilamentApp extends FilamentApp { Future capture(covariant FFIView view, {bool captureRenderTarget = false}) async { final viewport = await view.getViewport(); - final swapChain = _viewMappings[view]; + final swapChain = _swapChains.keys + .firstWhere((x) => _swapChains[x]?.contains(view) == true); final out = Uint8List(viewport.width * viewport.height * 4); await withVoidCallback((cb) { Engine_flushAndWaitRenderThead(engine, cb); }); + var fence = await withPointerCallback((cb) { + Engine_createFenceRenderThread(engine, cb); + }); + await withBoolCallback((cb) { - Renderer_beginFrameRenderThread(renderer, swapChain!.swapChain, 0, cb); + Renderer_beginFrameRenderThread(renderer, swapChain.swapChain, 0, cb); }); await withVoidCallback((cb) { Renderer_renderRenderThread( @@ -607,9 +640,14 @@ class FFIFilamentApp extends FilamentApp { await withVoidCallback((cb) { Renderer_endFrameRenderThread(renderer, cb); }); + await withVoidCallback((cb) { - Engine_flushAndWaitRenderThead(engine, cb); + Engine_destroyFenceRenderThread(engine, fence, cb); }); + + // await withVoidCallback((cb) { + // Engine_flushAndWaitRenderThead(engine, cb); + // }); return out; } @@ -623,7 +661,7 @@ class FFIFilamentApp extends FilamentApp { /// /// /// - Future loadGlbFromBuffer( + Future loadGltfFromBuffer( Uint8List data, Pointer animationManager, {int numInstances = 1, bool keepData = false, @@ -631,7 +669,7 @@ class FFIFilamentApp extends FilamentApp { int layer = 0, String? relativeResourcePath, bool loadResourcesAsync = false}) async { - if (relativeResourcePath != null && !relativeResourcePath!.endsWith("/")) { + if (relativeResourcePath != null && !relativeResourcePath.endsWith("/")) { relativeResourcePath = "$relativeResourcePath/"; } var gltfResourceLoader = await withPointerCallback( @@ -648,7 +686,6 @@ class FFIFilamentApp extends FilamentApp { var resourceUris = SceneAsset_getResourceUris(asset); var resourceUriCount = SceneAsset_getResourceUriCount(asset); - final resources = []; for (int i = 0; i < resourceUriCount; i++) { diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_material.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_material.dart index 10a02aee..039ef8ed 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_material.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_material.dart @@ -202,7 +202,7 @@ class FFIMaterialInstance extends MaterialInstance { completer.complete(); }; final nativeCallable = NativeCallable.listener(func); - RenderLoop_addTask(nativeCallable.nativeFunction); + RenderThread_addTask(nativeCallable.nativeFunction); await completer.future; } } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_view.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_view.dart index 7b78446c..c8b9e283 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_view.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_view.dart @@ -11,6 +11,9 @@ class FFIView extends View { final Pointer view; final FFIFilamentApp app; + bool _renderable = false; + bool get renderable => _renderable; + FFIRenderTarget? renderTarget; FFIView(this.view, this.app) { @@ -20,8 +23,19 @@ class FFIView extends View { } } + Future setRenderable(bool renderable) async { + this._renderable = renderable; + } + @override Future setViewport(int width, int height) async { + // var width_logbase2 = log(width) / ln2; + // var height_logbase2 = log(height) / ln2; + // var newWidth = pow(2.0, width_logbase2.ceil()); + // var newHeight = pow(2.0, height_logbase2.ceil()); + // print("old: ${width}x${height} new: ${height}x${newHeight}"); + // width = newWidth.toInt(); + // height = newHeight.toInt(); View_setViewport(view, width, height); } @@ -80,8 +94,7 @@ class FFIView extends View { @override Future setToneMapper(ToneMapper mapper) async { - await withVoidCallback((cb) => - View_setToneMappingRenderThread( + await withVoidCallback((cb) => View_setToneMappingRenderThread( view, app.engine, TToneMapping.values[mapper.index], cb)); } 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 aec23598..cc0aa67a 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 @@ -473,6 +473,22 @@ external TViewport View_getViewport( ffi.Pointer view, ); +@ffi.Native, ffi.UnsignedInt)>( + symbol: "View_setBlendMode", isLeaf: true) +external void _View_setBlendMode( + ffi.Pointer view, + int blendMode, +); + +void View_setBlendMode( + ffi.Pointer view, + TBlendMode blendMode, +) => + _View_setBlendMode( + view, + blendMode.value, + ); + @ffi.Native, ffi.Uint32, ffi.Uint32)>( isLeaf: true) external void View_setViewport( @@ -1494,18 +1510,30 @@ external void RenderTicker_setRenderable( ); @ffi.Native(isLeaf: true) -external void RenderLoop_create(); +external void RenderThread_create(); @ffi.Native(isLeaf: true) -external void RenderLoop_destroy(); +external void RenderThread_destroy(); @ffi.Native< ffi.Void Function( ffi.Pointer>)>(isLeaf: true) -external void RenderLoop_requestAnimationFrame( +external void RenderThread_requestAnimationFrame( ffi.Pointer> onComplete, ); +@ffi.Native)>(isLeaf: true) +external void RenderThread_setRenderTicker( + ffi.Pointer tRenderTicker, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer>)>(isLeaf: true) +external void RenderThread_addTask( + ffi.Pointer> task, +); + @ffi.Native< ffi.Void Function(ffi.Pointer, ffi.Uint64, ffi.Pointer>)>(isLeaf: true) @@ -1515,13 +1543,6 @@ external void RenderTicker_renderRenderThread( ffi.Pointer> onComplete, ); -@ffi.Native< - ffi.Void Function( - ffi.Pointer>)>(isLeaf: true) -external void RenderLoop_addTask( - ffi.Pointer> task, -); - @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -3212,6 +3233,13 @@ external ffi.Pointer AnimationManager_create( ffi.Pointer tScene, ); +@ffi.Native, ffi.Uint64)>( + isLeaf: true) +external void AnimationManager_update( + ffi.Pointer tAnimationManager, + int frameTimeInNanos, +); + @ffi.Native, EntityId)>( isLeaf: true) external void AnimationManager_addAnimationComponent( @@ -3951,6 +3979,20 @@ enum TQualityLevel { }; } +enum TBlendMode { + OPAQUE(0), + TRANSLUCENT(1); + + final int value; + const TBlendMode(this.value); + + static TBlendMode fromValue(int value) => switch (value) { + 0 => OPAQUE, + 1 => TRANSLUCENT, + _ => throw ArgumentError("Unknown value for TBlendMode: $value"), + }; +} + typedef PickCallback = ffi.Pointer>; typedef PickCallbackFunction = ffi.Void Function( ffi.Uint32 requestId, 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 ba8cd099..c46f5101 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 @@ -33,8 +33,6 @@ class ThermionViewerFFI extends ThermionViewer { late final FFIFilamentApp app; - final FFIRenderTarget? renderTarget; - late final FFIView view; late final FFIScene scene; late final Pointer animationManager; @@ -43,7 +41,7 @@ class ThermionViewerFFI extends ThermionViewer { /// /// /// - ThermionViewerFFI({required this.loadAssetFromUri, this.renderTarget}) { + ThermionViewerFFI({required this.loadAssetFromUri}) { if (FilamentApp.instance == null) { throw Exception("FilamentApp has not been created"); } @@ -56,7 +54,7 @@ class ThermionViewerFFI extends ThermionViewer { /// /// /// - Future setViewport(double width, double height) async { + Future setViewport(int width, int height) async { await view.setViewport(width.toInt(), height.toInt()); for (final camera in _cameras) { @@ -69,12 +67,12 @@ class ThermionViewerFFI extends ThermionViewer { far = kFar; } - var aspect = width / height; + var aspect = width.toDouble() / height.toDouble(); var focalLength = await camera.getFocalLength(); if (focalLength.abs() < 0.1) { focalLength = kFocalLength; } - camera.setLensProjection( + await camera.setLensProjection( near: near, far: far, aspect: aspect, focalLength: focalLength); } } @@ -85,6 +83,14 @@ class ThermionViewerFFI extends ThermionViewer { await withPointerCallback( (cb) => Engine_createViewRenderThread(app.engine, cb)), app); + await view.setFrustumCullingEnabled(true); + View_setBlendMode(view.view, TBlendMode.TRANSLUCENT); + View_setShadowsEnabled(view.view, false); + View_setStencilBufferEnabled(view.view, false); + View_setAntiAliasing(view.view, false, false, false); + View_setDitheringEnabled(view.view, false); + View_setRenderQuality(view.view, TQualityLevel.MEDIUM); + await FilamentApp.instance!.setClearColor(1.0, 0.0, 0.0, 1.0); scene = FFIScene(Engine_createScene(app.engine)); await view.setScene(scene); final camera = FFICamera( @@ -92,12 +98,10 @@ class ThermionViewerFFI extends ThermionViewer { (cb) => Engine_createCameraRenderThread(app.engine, cb)), app); _cameras.add(camera); + await camera.setLensProjection(); await view.setCamera(camera); - if (renderTarget != null) { - await view.setRenderTarget(renderTarget); - } animationManager = await withPointerCallback((cb) => AnimationManager_createRenderThread(app.engine, scene.scene, cb)); @@ -180,9 +184,13 @@ class ThermionViewerFFI extends ThermionViewer { /// /// @override - Future clearBackgroundImage() async { - await _backgroundImage?.destroy(); - _backgroundImage = null; + Future clearBackgroundImage({bool destroy = false}) async { + if (destroy) { + await _backgroundImage?.destroy(); + _backgroundImage = null; + } else { + _backgroundImage?.hideImage(); + } } /// @@ -335,7 +343,7 @@ class ThermionViewerFFI extends ThermionViewer { /// @override Future destroyLights() async { - for (final light in _lights) { + for (final light in _lights.toList()) { await removeLight(light); } } @@ -347,37 +355,45 @@ class ThermionViewerFFI extends ThermionViewer { /// /// @override - Future loadGlb(String path, - {int numInstances = 1, bool keepData = false, String? relativeResourcePath}) async { + Future loadGltf(String path, + {bool addToScene = true, + int numInstances = 1, + bool keepData = false, + String? relativeResourcePath}) async { final data = await loadAssetFromUri(path); - return loadGlbFromBuffer(data, - numInstances: numInstances, keepData: keepData, relativeResourcePath: relativeResourcePath); + return loadGltfFromBuffer(data, + addToScene: addToScene, + numInstances: numInstances, + keepData: keepData, + relativeResourcePath: relativeResourcePath); } /// /// /// @override - Future loadGlbFromBuffer(Uint8List data, - {int numInstances = 1, + Future loadGltfFromBuffer(Uint8List data, + {bool addToScene = true, + int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0, bool loadResourcesAsync = false, String? relativeResourcePath}) async { - var asset = await FilamentApp.instance!.loadGlbFromBuffer(data, animationManager, + var asset = await FilamentApp.instance!.loadGltfFromBuffer( + data, animationManager, numInstances: numInstances, keepData: keepData, priority: priority, layer: layer, loadResourcesAsync: loadResourcesAsync, - relativeResourcePath:relativeResourcePath - ) as FFIAsset; - - _assets.add(asset); + relativeResourcePath: relativeResourcePath) as FFIAsset; - await scene.add(asset); + _assets.add(asset); + if (addToScene) { + await scene.add(asset); + } return asset; } @@ -424,6 +440,8 @@ class ThermionViewerFFI extends ThermionViewer { @override Future setPostProcessing(bool enabled) async { View_setPostProcessing(view.view, enabled); + await withVoidCallback( + (cb) => Engine_flushAndWaitRenderThead(app.engine, cb)); } /// @@ -655,7 +673,8 @@ class ThermionViewerFFI extends ThermionViewer { @override Future createGeometry(Geometry geometry, {List? materialInstances, - bool keepData = false}) async { + bool keepData = false, + bool addToScene = true}) async { var assetPtr = await withPointerCallback((callback) { var ptrList = Int64List(materialInstances?.length ?? 0); if (materialInstances != null && materialInstances.isNotEmpty) { @@ -688,7 +707,9 @@ class ThermionViewerFFI extends ThermionViewer { } var asset = FFIAsset(assetPtr, app, animationManager); - + if (addToScene) { + await scene.add(asset); + } return asset; } 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 b2bb1442..38c6cd3c 100644 --- a/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart +++ b/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart @@ -71,7 +71,7 @@ abstract class ThermionViewer { /// /// Removes the background image. /// - Future clearBackgroundImage(); + Future clearBackgroundImage({bool destroy = false}); /// /// Sets the color for the background plane (positioned at the maximum depth, i.e. behind all other objects including the skybox). @@ -128,10 +128,11 @@ abstract class ThermionViewer { /// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData]. /// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception. /// - Future loadGlb(String path, - {int numInstances = 1, + Future loadGltf(String path, + { bool addToScene=true, + int numInstances = 1, bool keepData = false, - String relativeResourcePath}); + String? relativeResourcePath}); /// /// Load the .glb asset from the specified buffer, adding all entities to the scene. @@ -142,7 +143,7 @@ abstract class ThermionViewer { /// be loaded asynchronously (so expect some material/texture pop-in); /// /// - Future loadGlbFromBuffer(Uint8List data, + Future loadGltfFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int priority = 4, @@ -177,6 +178,11 @@ abstract class ThermionViewer { /// Future setViewFrustumCulling(bool enabled); + /// + /// Sets the viewport sizes and updates all cameras to use the new aspect ratio. + /// + Future setViewport(int width, int height); + /// /// Set the world space position for [lightEntity] to the given coordinates. /// @@ -230,7 +236,7 @@ abstract class ThermionViewer { /// /// Future createGeometry(Geometry geometry, - {List? materialInstances, bool keepData = false}); + {List? materialInstances, bool keepData = false, bool addToScene=true}); /// /// The gizmo for translating/rotating objects. Only one gizmo can be active for a given view. 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 750ff1a5..2401f13b 100644 --- a/thermion_dart/lib/src/viewer/src/thermion_viewer_stub.dart +++ b/thermion_dart/lib/src/viewer/src/thermion_viewer_stub.dart @@ -9,6 +9,12 @@ class ThermionViewerStub extends ThermionViewer { throw UnimplementedError(); } + @override + Future addToScene(covariant ThermionAsset asset) { + // TODO: implement addToScene + throw UnimplementedError(); + } + @override Future clearBackgroundImage() { // TODO: implement clearBackgroundImage @@ -21,12 +27,6 @@ class ThermionViewerStub extends ThermionViewer { throw UnimplementedError(); } - @override - Future createGeometry(Geometry geometry, {List? materialInstances, bool keepData = false}) { - // TODO: implement createGeometry - throw UnimplementedError(); - } - @override Future createGizmo(covariant View view, GizmoType type) { // TODO: implement createGizmo @@ -92,23 +92,17 @@ class ThermionViewerStub extends ThermionViewer { Future get initialized => throw UnimplementedError(); @override - Future loadGlb(String path, {int numInstances = 1, bool keepData = false}) { - // TODO: implement loadGlb - throw UnimplementedError(); - } - - @override - Future loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0, bool loadResourcesAsync = false}) { - // TODO: implement loadGlbFromBuffer - throw UnimplementedError(); - } - - @override - Future loadGltf(String path, String relativeResourcePath, {bool keepData = false}) { + Future loadGltf(String path, {int numInstances = 1, bool keepData = false, String? relativeResourcePath}) { // TODO: implement loadGltf throw UnimplementedError(); } + @override + Future loadGltfFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0, bool loadResourcesAsync = false, String? relativeResourcePath}) { + // TODO: implement loadGltfFromBuffer + throw UnimplementedError(); + } + @override Future loadIbl(String lightingPath, {double intensity = 30000}) { // TODO: implement loadIbl @@ -136,6 +130,12 @@ class ThermionViewerStub extends ThermionViewer { throw UnimplementedError(); } + @override + Future removeFromScene(covariant ThermionAsset asset) { + // TODO: implement removeFromScene + throw UnimplementedError(); + } + @override Future removeGridOverlay() { // TODO: implement removeGridOverlay @@ -287,5 +287,5 @@ class ThermionViewerStub extends ThermionViewer { @override // TODO: implement view View get view => throw UnimplementedError(); - + } diff --git a/thermion_dart/lib/thermion_dart.dart b/thermion_dart/lib/thermion_dart.dart index 22a6afc4..ec4a80ed 100644 --- a/thermion_dart/lib/thermion_dart.dart +++ b/thermion_dart/lib/thermion_dart.dart @@ -4,3 +4,4 @@ export 'package:vector_math/vector_math_64.dart' hide Colors; export 'src/viewer/viewer.dart'; export 'src/input/input.dart'; export 'src/utils/utils.dart'; +export 'src/filament/filament.dart'; diff --git a/thermion_dart/native/include/c_api/TAnimationManager.h b/thermion_dart/native/include/c_api/TAnimationManager.h index ae8527c9..789dc7f3 100644 --- a/thermion_dart/native/include/c_api/TAnimationManager.h +++ b/thermion_dart/native/include/c_api/TAnimationManager.h @@ -9,6 +9,8 @@ extern "C" #endif EMSCRIPTEN_KEEPALIVE TAnimationManager *AnimationManager_create(TEngine *tEngine, TScene *tScene); + + EMSCRIPTEN_KEEPALIVE void AnimationManager_update(TAnimationManager *tAnimationManager, uint64_t frameTimeInNanos); EMSCRIPTEN_KEEPALIVE void AnimationManager_addAnimationComponent(TAnimationManager *tAnimationManager, EntityId entityId); diff --git a/thermion_dart/native/include/c_api/TView.h b/thermion_dart/native/include/c_api/TView.h index 4ffb8e39..63384ba4 100644 --- a/thermion_dart/native/include/c_api/TView.h +++ b/thermion_dart/native/include/c_api/TView.h @@ -32,8 +32,14 @@ enum TQualityLevel { ULTRA }; +enum TBlendMode { + OPAQUE, + TRANSLUCENT +}; + // View EMSCRIPTEN_KEEPALIVE TViewport View_getViewport(TView *view); +EMSCRIPTEN_KEEPALIVE void View_setBlendMode(TView *view, TBlendMode blendMode); EMSCRIPTEN_KEEPALIVE void View_setViewport(TView *view, uint32_t width, uint32_t height); EMSCRIPTEN_KEEPALIVE void View_setRenderTarget(TView *view, TRenderTarget *renderTarget); EMSCRIPTEN_KEEPALIVE void View_setFrustumCullingEnabled(TView *view, bool enabled); diff --git a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h index a9e8bf51..eb4740ff 100644 --- a/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h +++ b/thermion_dart/native/include/c_api/ThermionDartRenderThreadApi.h @@ -14,12 +14,13 @@ namespace thermion typedef int32_t EntityId; typedef void (*FilamentRenderCallback)(void *const owner); - EMSCRIPTEN_KEEPALIVE void RenderLoop_create(); - EMSCRIPTEN_KEEPALIVE void RenderLoop_destroy(); - EMSCRIPTEN_KEEPALIVE void RenderLoop_requestAnimationFrame(void (*onComplete)()); + EMSCRIPTEN_KEEPALIVE void RenderThread_create(); + EMSCRIPTEN_KEEPALIVE void RenderThread_destroy(); + EMSCRIPTEN_KEEPALIVE void RenderThread_requestAnimationFrame(void (*onComplete)()); + EMSCRIPTEN_KEEPALIVE void RenderThread_setRenderTicker(TRenderTicker *tRenderTicker); + EMSCRIPTEN_KEEPALIVE void RenderThread_addTask(void (*task)()); + EMSCRIPTEN_KEEPALIVE void RenderTicker_renderRenderThread(TRenderTicker *tRenderTicker, uint64_t frameTimeInNanos, void (*onComplete)()); - EMSCRIPTEN_KEEPALIVE void RenderLoop_addTask(void (*task)()); - EMSCRIPTEN_KEEPALIVE void AnimationManager_createRenderThread(TEngine *tEngine, TScene *tScene, void (*onComplete)(TAnimationManager *)); EMSCRIPTEN_KEEPALIVE void Engine_createRenderThread( diff --git a/thermion_dart/native/include/rendering/RenderLoop.hpp b/thermion_dart/native/include/rendering/RenderThread.hpp similarity index 86% rename from thermion_dart/native/include/rendering/RenderLoop.hpp rename to thermion_dart/native/include/rendering/RenderThread.hpp index 0dfc956a..e6140fa9 100644 --- a/thermion_dart/native/include/rendering/RenderLoop.hpp +++ b/thermion_dart/native/include/rendering/RenderThread.hpp @@ -17,17 +17,17 @@ namespace thermion { * This class handles frame rendering requests, viewer creation, and maintains * a task queue for rendering operations. */ -class RenderLoop { +class RenderThread { public: /** - * @brief Constructs a new RenderLoop and starts the render thread. + * @brief Constructs a new RenderThread and starts the render thread. */ - explicit RenderLoop(); + explicit RenderThread(); /** - * @brief Destroys the RenderLoop and stops the render thread. + * @brief Destroys the RenderThread and stops the render thread. */ - ~RenderLoop(); + ~RenderThread(); /** * @brief Requests a frame to be rendered. @@ -74,7 +74,7 @@ private: // Template implementation template -auto RenderLoop::add_task(std::packaged_task& pt) -> std::future { +auto RenderThread::add_task(std::packaged_task& pt) -> std::future { std::unique_lock lock(_taskMutex); auto ret = pt.get_future(); _tasks.push_back([pt = std::make_shared>( diff --git a/thermion_dart/native/src/RenderTicker.cpp b/thermion_dart/native/src/RenderTicker.cpp index 438db81a..99630cc7 100644 --- a/thermion_dart/native/src/RenderTicker.cpp +++ b/thermion_dart/native/src/RenderTicker.cpp @@ -69,12 +69,21 @@ namespace thermion for (auto animationManager : mAnimationManagers) { animationManager->update(frameTimeInNanos); - } + TRACE("Updated AnimationManager"); + } + + #ifdef ENABLE_TRACING + int numRendered = 0; + TRACE("%d swapchains", mRenderable.size()); + #endif + for (const auto& [swapChain, views] : mRenderable) { if (!views.empty()) { + TRACE("Rendering %d views", views.size()); + bool beginFrame = mRenderer->beginFrame(swapChain, frameTimeInNanos); if (beginFrame) { @@ -84,7 +93,15 @@ namespace thermion } } mRenderer->endFrame(); + #ifdef ENABLE_TRACING + numRendered++; + } else { + TRACE("No views for swapchain"); } + TRACE("%d swapchains rendered", numRendered); + #else + } + #endif } #ifdef __EMSCRIPTEN__ _engine->execute(); diff --git a/thermion_dart/native/src/c_api/TAnimationManager.cpp b/thermion_dart/native/src/c_api/TAnimationManager.cpp index 44490266..73a5a3db 100644 --- a/thermion_dart/native/src/c_api/TAnimationManager.cpp +++ b/thermion_dart/native/src/c_api/TAnimationManager.cpp @@ -17,6 +17,11 @@ extern "C" return reinterpret_cast(animationManager); } + EMSCRIPTEN_KEEPALIVE void AnimationManager_update(TAnimationManager *tAnimationManager, uint64_t frameTimeInNanos) { + auto animationManager = reinterpret_cast(tAnimationManager); + animationManager->update(frameTimeInNanos); + } + EMSCRIPTEN_KEEPALIVE void AnimationManager_addAnimationComponent(TAnimationManager *tAnimationManager, EntityId entityId) { auto animationManager = reinterpret_cast(tAnimationManager); diff --git a/thermion_dart/native/src/c_api/TEngine.cpp b/thermion_dart/native/src/c_api/TEngine.cpp index b53f2129..94b6662c 100644 --- a/thermion_dart/native/src/c_api/TEngine.cpp +++ b/thermion_dart/native/src/c_api/TEngine.cpp @@ -80,14 +80,38 @@ namespace thermion EMSCRIPTEN_KEEPALIVE TSwapChain *Engine_createSwapChain(TEngine *tEngine, void *window, uint64_t flags) { auto *engine = reinterpret_cast(tEngine); + #ifdef ENABLE_TRACING + if((flags & filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT) == filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT) { + TRACE("SWAP_CHAIN_CONFIG_TRANSPARENT"); + + } + if((flags & filament::backend::SWAP_CHAIN_CONFIG_READABLE) == filament::backend::SWAP_CHAIN_CONFIG_READABLE) { + TRACE("SWAP_CHAIN_CONFIG_READABLE"); + } + if((flags & filament::backend::SWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER) == filament::backend::SWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER) { + TRACE("SWAP_CHAIN_CONFIG_READABLE"); + } + #endif auto *swapChain = engine->createSwapChain(window, flags); return reinterpret_cast(swapChain); } EMSCRIPTEN_KEEPALIVE TSwapChain *Engine_createHeadlessSwapChain(TEngine *tEngine, uint32_t width, uint32_t height, uint64_t flags) { + TRACE("Creating headless swapchain %dx%d, flags %flags", width, height, flags); auto *engine = reinterpret_cast(tEngine); auto *swapChain = engine->createSwapChain(width, height, flags); + #ifdef ENABLE_TRACING + if((flags & filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT) == filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT) { + TRACE("SWAP_CHAIN_CONFIG_TRANSPARENT"); + } + if((flags & filament::backend::SWAP_CHAIN_CONFIG_READABLE) == filament::backend::SWAP_CHAIN_CONFIG_READABLE) { + TRACE("SWAP_CHAIN_CONFIG_READABLE"); + } + if((flags & filament::backend::SWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER) == filament::backend::SWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER) { + TRACE("SWAP_CHAIN_CONFIG_READABLE"); + } + #endif return reinterpret_cast(swapChain); } @@ -101,6 +125,9 @@ namespace thermion { auto *engine = reinterpret_cast(tEngine); auto *view = engine->createView(); + view->setShadowingEnabled(false); + view->setAmbientOcclusionOptions({.enabled = false}); + view->setDynamicResolutionOptions({.enabled = false}); return reinterpret_cast(view); } diff --git a/thermion_dart/native/src/c_api/TNameComponentManager.cpp b/thermion_dart/native/src/c_api/TNameComponentManager.cpp index 401e902a..3b58ca88 100644 --- a/thermion_dart/native/src/c_api/TNameComponentManager.cpp +++ b/thermion_dart/native/src/c_api/TNameComponentManager.cpp @@ -14,10 +14,14 @@ extern "C" return reinterpret_cast(ncm); } - EMSCRIPTEN_KEEPALIVE const char *NameComponentManager_getName(TNameComponentManager *tNameComponentManager, EntityId entity) + EMSCRIPTEN_KEEPALIVE const char *NameComponentManager_getName(TNameComponentManager *tNameComponentManager, EntityId entityId) { auto ncm = reinterpret_cast(tNameComponentManager); - auto instance = ncm->getInstance(utils::Entity::import(entity)); + auto entity = utils::Entity::import(entityId); + if(!ncm->hasComponent(entity)) { + return nullptr; + } + auto instance = ncm->getInstance(entity); return ncm->getName(instance); } diff --git a/thermion_dart/native/src/c_api/TView.cpp b/thermion_dart/native/src/c_api/TView.cpp index c3b1f9d0..99fc8d9e 100644 --- a/thermion_dart/native/src/c_api/TView.cpp +++ b/thermion_dart/native/src/c_api/TView.cpp @@ -16,6 +16,11 @@ using namespace filament; #endif + EMSCRIPTEN_KEEPALIVE void View_setBlendMode(TView *tView, TBlendMode tBlendMode) { + auto view = reinterpret_cast(tView); + view->setBlendMode(static_cast(tBlendMode)); + } + EMSCRIPTEN_KEEPALIVE TViewport View_getViewport(TView *tView) { auto view = reinterpret_cast(tView); @@ -58,6 +63,8 @@ using namespace filament; { auto view = reinterpret_cast(tView); view->setPostProcessingEnabled(enabled); + TRACE("Set postprocessing enabled : %d", enabled); + } EMSCRIPTEN_KEEPALIVE void View_setShadowsEnabled(TView *tView, bool enabled) @@ -88,6 +95,7 @@ using namespace filament; decltype(view->getBloomOptions()) opts; opts.enabled = enabled; opts.strength = strength; + TRACE("Setting bloom options {.enabled = %d, strength = %f}", enabled, strength); view->setBloomOptions(opts); #endif } @@ -101,19 +109,19 @@ using namespace filament; switch (tToneMapping) { case TToneMapping::ACES: - Log("Setting tone mapping to ACES"); + TRACE("Setting tone mapping to ACES"); tm = new ACESToneMapper(); break; case TToneMapping::LINEAR: - Log("Setting tone mapping to Linear"); + TRACE("Setting tone mapping to Linear"); tm = new LinearToneMapper(); break; case TToneMapping::FILMIC: - Log("Setting tone mapping to Filmic"); + TRACE("Setting tone mapping to Filmic"); tm = new FilmicToneMapper(); break; default: - Log("ERROR: Unsupported tone mapping"); + TRACE("ERROR: Unsupported tone mapping"); return; } auto newColorGrading = ColorGrading::Builder().toneMapper(tm).build(*engine); @@ -200,6 +208,21 @@ using namespace filament; auto view = reinterpret_cast(tView); RenderQuality rq; rq.hdrColorBuffer = (filament::QualityLevel)qualityLevel; + switch(rq.hdrColorBuffer) { + case filament::QualityLevel::LOW: + TRACE("Render Quality: LOW"); + break; + case filament::QualityLevel::MEDIUM: + TRACE("Render Quality: MEDIUM"); + break; + case filament::QualityLevel::HIGH: + TRACE("Render Quality: HIGH"); + break; + case filament::QualityLevel::ULTRA: + TRACE("Render Quality: ULTRA"); + break; + } + view->setRenderQuality(rq); } diff --git a/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp b/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp index 4a9ce676..2823fc50 100644 --- a/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp +++ b/thermion_dart/native/src/c_api/ThermionDartRenderThreadApi.cpp @@ -19,7 +19,7 @@ #include "c_api/TView.h" #include "c_api/ThermionDartRenderThreadApi.h" -#include "rendering/RenderLoop.hpp" +#include "rendering/RenderThread.hpp" #include "Log.hpp" using namespace thermion; @@ -29,36 +29,41 @@ using namespace std::chrono_literals; extern "C" { - static std::unique_ptr _rl; + static std::unique_ptr _renderThread; - EMSCRIPTEN_KEEPALIVE void RenderLoop_create() { - TRACE("RenderLoop_create"); - if (_rl) + EMSCRIPTEN_KEEPALIVE void RenderThread_create() { + TRACE("RenderThread_create"); + if (_renderThread) { - Log("WARNING - you are attempting to create a RenderLoop when the previous one has not been disposed."); + Log("WARNING - you are attempting to create a RenderThread when the previous one has not been disposed."); } - _rl = std::make_unique(); + _renderThread = std::make_unique(); } - EMSCRIPTEN_KEEPALIVE void RenderLoop_destroy() { - TRACE("RenderLoop_destroy"); - if (_rl) + EMSCRIPTEN_KEEPALIVE void RenderThread_destroy() { + TRACE("RenderThread_destroy"); + if (_renderThread) { - _rl = nullptr; + _renderThread = nullptr; } } - EMSCRIPTEN_KEEPALIVE void RenderLoop_addTask(void (*task)()) { + EMSCRIPTEN_KEEPALIVE void RenderThread_addTask(void (*task)()) { std::packaged_task lambda( [=]() mutable { task(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } - EMSCRIPTEN_KEEPALIVE void RenderLoop_requestAnimationFrame(void (*onComplete)()) { - _rl->requestFrame(onComplete); + EMSCRIPTEN_KEEPALIVE void RenderThread_setRenderTicker(TRenderTicker *tRenderTicker) { + auto *renderTicker = reinterpret_cast(tRenderTicker); + _renderThread->setRenderTicker(renderTicker); + } + + EMSCRIPTEN_KEEPALIVE void RenderThread_requestAnimationFrame(void (*onComplete)()) { + _renderThread->requestFrame(onComplete); } @@ -69,7 +74,7 @@ extern "C" RenderTicker_render(tRenderTicker, frameTimeInNanos); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_createRenderThread( @@ -85,7 +90,7 @@ extern "C" auto engine = Engine_create(backend, platform, sharedContext, stereoscopicEyeCount, disableHandleUseAfterFreeCheck); onComplete(engine); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_createRendererRenderThread(TEngine *tEngine, void (*onComplete)(TRenderer *)) { @@ -95,7 +100,7 @@ extern "C" auto renderer = Engine_createRenderer(tEngine); onComplete(renderer); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_createSwapChainRenderThread(TEngine *tEngine, void *window, uint64_t flags, void (*onComplete)(TSwapChain *)) { @@ -105,7 +110,7 @@ extern "C" auto swapChain = Engine_createSwapChain(tEngine, window, flags); onComplete(swapChain); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_createHeadlessSwapChainRenderThread(TEngine *tEngine, uint32_t width, uint32_t height, uint64_t flags, void (*onComplete)(TSwapChain *)) { @@ -115,7 +120,7 @@ extern "C" auto swapChain = Engine_createHeadlessSwapChain(tEngine, width, height, flags); onComplete(swapChain); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_destroySwapChainRenderThread(TEngine *tEngine, TSwapChain *tSwapChain, void (*onComplete)()) { @@ -125,7 +130,7 @@ extern "C" Engine_destroySwapChain(tEngine, tSwapChain); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_createCameraRenderThread(TEngine* tEngine, void (*onComplete)(TCamera *)) { @@ -135,7 +140,7 @@ extern "C" auto camera = Engine_createCamera(tEngine); onComplete(camera); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_createViewRenderThread(TEngine *tEngine, void (*onComplete)(TView *)) { @@ -145,7 +150,7 @@ extern "C" auto * view = Engine_createView(tEngine); onComplete(view); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_destroyTextureRenderThread(TEngine *engine, TTexture *tTexture, void (*onComplete)()) @@ -156,7 +161,7 @@ extern "C" Engine_destroyTexture(engine, tTexture); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_destroySkyboxRenderThread(TEngine *tEngine, TSkybox *tSkybox, void (*onComplete)()) { @@ -166,7 +171,7 @@ extern "C" Engine_destroySkybox(tEngine, tSkybox); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_destroyIndirectLightRenderThread(TEngine *tEngine, TIndirectLight *tIndirectLight, void (*onComplete)()) { @@ -176,7 +181,7 @@ extern "C" Engine_destroyIndirectLight(tEngine, tIndirectLight); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t *materialData, size_t length, void (*onComplete)(TMaterial *)) @@ -187,7 +192,7 @@ extern "C" auto material = Engine_buildMaterial(tEngine, materialData, length); onComplete(material); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } @@ -199,7 +204,17 @@ extern "C" Engine_destroyMaterial(tEngine, tMaterial); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); + } + + EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialInstanceRenderThread(TEngine *tEngine, TMaterialInstance *tMaterialInstance, void (*onComplete)()) { + std::packaged_task lambda( + [=]() mutable + { + Engine_destroyMaterialInstance(tEngine, tMaterialInstance); + onComplete(); + }); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_createFenceRenderThread(TEngine *tEngine, void (*onComplete)(TFence*)) { @@ -209,7 +224,7 @@ extern "C" auto *fence = Engine_createFence(tEngine); onComplete(fence); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_destroyFenceRenderThread(TEngine *tEngine, TFence *tFence, void (*onComplete)()) { @@ -219,7 +234,7 @@ extern "C" Engine_destroyFence(tEngine, tFence); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_flushAndWaitRenderThead(TEngine *tEngine, void (*onComplete)()) { @@ -229,7 +244,7 @@ extern "C" Engine_flushAndWait(tEngine); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_buildSkyboxRenderThread(TEngine *tEngine, uint8_t *skyboxData, size_t length, void (*onComplete)(TSkybox *), void (*onTextureUploadComplete)()) { @@ -239,7 +254,7 @@ extern "C" auto *skybox = Engine_buildSkybox(tEngine, skyboxData, length, onTextureUploadComplete); onComplete(skybox); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Engine_buildIndirectLightRenderThread(TEngine *tEngine, uint8_t *iblData, size_t length, float intensity, void (*onComplete)(TIndirectLight *), void (*onTextureUploadComplete)()) { @@ -249,7 +264,7 @@ extern "C" auto *indirectLight = Engine_buildIndirectLight(tEngine, iblData, length, intensity, onTextureUploadComplete); onComplete(indirectLight); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Renderer_beginFrameRenderThread(TRenderer *tRenderer, TSwapChain *tSwapChain, uint64_t frameTimeInNanos, void (*onComplete)(bool)) { @@ -259,7 +274,7 @@ extern "C" auto result = Renderer_beginFrame(tRenderer, tSwapChain, frameTimeInNanos); onComplete(result); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Renderer_endFrameRenderThread(TRenderer *tRenderer, void (*onComplete)()) { std::packaged_task lambda( @@ -268,7 +283,7 @@ extern "C" Renderer_endFrame(tRenderer); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Renderer_renderRenderThread(TRenderer *tRenderer, TView *tView, void (*onComplete)()) { @@ -278,7 +293,7 @@ extern "C" Renderer_render(tRenderer, tView); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Renderer_renderStandaloneViewRenderThread(TRenderer *tRenderer, TView *tView, void (*onComplete)()) { @@ -288,7 +303,7 @@ extern "C" Renderer_renderStandaloneView(tRenderer, tView); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Renderer_setClearOptionsRenderThread( @@ -306,7 +321,7 @@ extern "C" Renderer_setClearOptions(tRenderer, clearR, clearG, clearB, clearA, clearStencil, clear, discard); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Renderer_readPixelsRenderThread( @@ -323,7 +338,7 @@ extern "C" Renderer_readPixels(tRenderer, tView, tRenderTarget, tPixelBufferFormat, tPixelDataType, out); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Material_createImageMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *)) { @@ -333,7 +348,7 @@ extern "C" auto *instance = Material_createImageMaterial(tEngine); onComplete(instance); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance *)) @@ -344,7 +359,7 @@ extern "C" auto *instance = Material_createInstance(tMaterial); onComplete(instance); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void SceneAsset_destroyRenderThread(TSceneAsset *tSceneAsset, void (*onComplete)()) { @@ -354,7 +369,7 @@ extern "C" SceneAsset_destroy(tSceneAsset); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void SceneAsset_loadGlbRenderThread( @@ -372,7 +387,7 @@ extern "C" auto sceneAsset = SceneAsset_loadGlb(tEngine, tAssetLoader, tNameComponentManager, data, length, numInstances); callback(sceneAsset); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void SceneAsset_createGeometryRenderThread( @@ -396,7 +411,7 @@ extern "C" auto sceneAsset = SceneAsset_createGeometry(tEngine, vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, tPrimitiveType, materialInstances, materialInstanceCount); callback(sceneAsset); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void SceneAsset_createInstanceRenderThread( @@ -410,7 +425,7 @@ extern "C" auto instanceAsset = SceneAsset_createInstance(asset, tMaterialInstances, materialInstanceCount); callback(instanceAsset); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void MaterialProvider_createMaterialInstanceRenderThread(TMaterialProvider *tMaterialProvider, TMaterialKey *tKey, void (*callback)(TMaterialInstance *)) @@ -421,7 +436,7 @@ extern "C" auto materialInstance = MaterialProvider_createMaterialInstance(tMaterialProvider, tKey); callback(materialInstance); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, TToneMapping toneMapping, void (*callback)()) @@ -432,7 +447,7 @@ extern "C" View_setToneMapping(tView, tEngine, toneMapping); callback(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, bool enabled, double strength, void (*callback)()) @@ -443,7 +458,7 @@ extern "C" View_setBloom(tView, enabled, strength); callback(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void View_setCameraRenderThread(TView *tView, TCamera *tCamera, void (*callback)()) @@ -454,7 +469,7 @@ extern "C" View_setCamera(tView, tCamera); callback(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void AnimationManager_createRenderThread(TEngine *tEngine, TScene *tScene, void (*onComplete)(TAnimationManager *)) { @@ -464,7 +479,7 @@ extern "C" auto *animationManager = AnimationManager_create(tEngine, tScene); onComplete(animationManager); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void AnimationManager_updateBoneMatricesRenderThread( @@ -478,7 +493,7 @@ extern "C" bool result = AnimationManager_updateBoneMatrices(tAnimationManager, sceneAsset); callback(result); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void AnimationManager_setMorphTargetWeightsRenderThread( @@ -494,7 +509,7 @@ extern "C" bool result = AnimationManager_setMorphTargetWeights(tAnimationManager, entityId, morphData, numWeights); callback(result); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } // Add these implementations to your ThermionDartRenderThreadApi.cpp file @@ -508,7 +523,7 @@ extern "C" auto image = Image_createEmpty(width, height, channel); onComplete(image); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Image_decodeRenderThread(uint8_t *data, size_t length, const char *name, void (*onComplete)(TLinearImage *)) @@ -519,7 +534,7 @@ extern "C" auto image = Image_decode(data, length, name); onComplete(image); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Image_getBytesRenderThread(TLinearImage *tLinearImage, void (*onComplete)(float *)) @@ -530,7 +545,7 @@ extern "C" auto bytes = Image_getBytes(tLinearImage); onComplete(bytes); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Image_destroyRenderThread(TLinearImage *tLinearImage, void (*onComplete)()) @@ -541,7 +556,7 @@ extern "C" Image_destroy(tLinearImage); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Image_getWidthRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t)) @@ -552,7 +567,7 @@ extern "C" auto width = Image_getWidth(tLinearImage); onComplete(width); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Image_getHeightRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t)) @@ -563,7 +578,7 @@ extern "C" auto height = Image_getHeight(tLinearImage); onComplete(height); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Image_getChannelsRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t)) @@ -574,7 +589,7 @@ extern "C" auto channels = Image_getChannels(tLinearImage); onComplete(channels); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Texture_buildRenderThread( @@ -593,7 +608,7 @@ extern "C" auto *texture = Texture_build(tEngine, width, height, depth, levels, tUsage, import, sampler, format); onComplete(texture); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } // Texture methods @@ -607,7 +622,7 @@ extern "C" bool result = Texture_loadImage(tEngine, tTexture, tImage, bufferFormat, pixelDataType); onComplete(result); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Texture_setImageRenderThread( @@ -630,7 +645,7 @@ extern "C" bufferFormat, pixelDataType); onComplete(result); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Texture_setImageWithDepthRenderThread( @@ -671,7 +686,7 @@ extern "C" ); onComplete(result); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void RenderTarget_getColorTextureRenderThread(TRenderTarget *tRenderTarget, void (*onComplete)(TTexture *)) @@ -682,7 +697,7 @@ extern "C" auto texture = RenderTarget_getColorTexture(tRenderTarget); onComplete(texture); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void RenderTarget_createRenderThread( @@ -702,7 +717,7 @@ extern "C" auto texture = RenderTarget_create(tEngine, width, height, tColor, tDepth); onComplete(texture); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } @@ -716,7 +731,7 @@ extern "C" auto sampler = TextureSampler_create(); onComplete(sampler); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_createWithFilteringRenderThread( @@ -733,7 +748,7 @@ extern "C" auto sampler = TextureSampler_createWithFiltering(minFilter, magFilter, wrapS, wrapT, wrapR); onComplete(sampler); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_createWithComparisonRenderThread( @@ -747,7 +762,7 @@ extern "C" auto sampler = TextureSampler_createWithComparison(compareMode, compareFunc); onComplete(sampler); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_setMinFilterRenderThread( @@ -761,7 +776,7 @@ extern "C" TextureSampler_setMinFilter(sampler, filter); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_setMagFilterRenderThread( @@ -775,7 +790,7 @@ extern "C" TextureSampler_setMagFilter(sampler, filter); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeSRenderThread( @@ -789,7 +804,7 @@ extern "C" TextureSampler_setWrapModeS(sampler, mode); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeTRenderThread( @@ -803,7 +818,7 @@ extern "C" TextureSampler_setWrapModeT(sampler, mode); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeRRenderThread( @@ -817,7 +832,7 @@ extern "C" TextureSampler_setWrapModeR(sampler, mode); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_setAnisotropyRenderThread( @@ -831,7 +846,7 @@ extern "C" TextureSampler_setAnisotropy(sampler, anisotropy); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_setCompareModeRenderThread( @@ -846,7 +861,7 @@ extern "C" TextureSampler_setCompareMode(sampler, mode, func); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void TextureSampler_destroyRenderThread( @@ -859,7 +874,7 @@ extern "C" TextureSampler_destroy(sampler); onComplete(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void GltfAssetLoader_createRenderThread(TEngine *tEngine, TMaterialProvider *tMaterialProvider, void (*callback)(TGltfAssetLoader *)) { @@ -869,7 +884,7 @@ extern "C" auto loader = GltfAssetLoader_create(tEngine, tMaterialProvider); callback(loader); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_createRenderThread(TEngine *tEngine, const char* relativeResourcePath, void (*callback)(TGltfResourceLoader *)) { @@ -879,7 +894,7 @@ extern "C" auto loader = GltfResourceLoader_create(tEngine, relativeResourcePath); callback(loader); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_destroyRenderThread(TEngine *tEngine, TGltfResourceLoader *tResourceLoader, void (*callback)()) { @@ -889,7 +904,7 @@ extern "C" GltfResourceLoader_destroy(tEngine, tResourceLoader); callback(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_loadResourcesRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool)) { @@ -899,7 +914,7 @@ extern "C" auto result = GltfResourceLoader_loadResources(tGltfResourceLoader, tFilamentAsset); callback(result); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_addResourceDataRenderThread( @@ -914,7 +929,7 @@ extern "C" GltfResourceLoader_addResourceData(tGltfResourceLoader, uri, data, length); callback(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void GltfAssetLoader_loadRenderThread( @@ -931,7 +946,7 @@ extern "C" auto loader = GltfAssetLoader_load(tEngine, tAssetLoader, data, length, numInstances); callback(loader); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } EMSCRIPTEN_KEEPALIVE void Scene_addFilamentAssetRenderThread(TScene* tScene, TFilamentAsset *tAsset, void (*callback)()) { @@ -941,6 +956,6 @@ extern "C" Scene_addFilamentAsset(tScene, tAsset); callback(); }); - auto fut = _rl->add_task(lambda); + auto fut = _renderThread->add_task(lambda); } } diff --git a/thermion_dart/native/src/rendering/RenderLoop.cpp b/thermion_dart/native/src/rendering/RenderThread.cpp similarity index 83% rename from thermion_dart/native/src/rendering/RenderLoop.cpp rename to thermion_dart/native/src/rendering/RenderThread.cpp index a0e309b9..30244ddd 100644 --- a/thermion_dart/native/src/rendering/RenderLoop.cpp +++ b/thermion_dart/native/src/rendering/RenderThread.cpp @@ -1,4 +1,4 @@ -#include "rendering/RenderLoop.hpp" +#include "rendering/RenderThread.hpp" #include #include @@ -8,7 +8,7 @@ namespace thermion { -RenderLoop::RenderLoop() +RenderThread::RenderThread() { srand(time(NULL)); t = new std::thread([this]() { @@ -18,26 +18,27 @@ RenderLoop::RenderLoop() }); } -RenderLoop::~RenderLoop() +RenderThread::~RenderThread() { - TRACE("Destroying RenderLoop"); + TRACE("Destroying RenderThread"); _stop = true; _cv.notify_one(); - TRACE("Joining RenderLoop thread.."); + TRACE("Joining RenderThread thread.."); t->join(); delete t; - TRACE("RenderLoop destructor complete"); + TRACE("RenderThread destructor complete"); } -void RenderLoop::requestFrame(void (*callback)()) +void RenderThread::requestFrame(void (*callback)()) { + TRACE("Request frame"); std::unique_lock lock(_mutex); this->_requestFrameRenderCallback = callback; _cv.notify_one(); } -void RenderLoop::iter() +void RenderThread::iter() { { std::unique_lock lock(_mutex); diff --git a/thermion_dart/test/geometry_tests.dart b/thermion_dart/test/geometry_tests.dart index 4dbf44b6..880f7444 100644 --- a/thermion_dart/test/geometry_tests.dart +++ b/thermion_dart/test/geometry_tests.dart @@ -10,283 +10,288 @@ void main() async { final testHelper = TestHelper("geometry"); await testHelper.setup(); group("custom geometry", () { - test('create cube (uvs only)', () async { - var viewer = await testHelper.createViewer(); - await viewer - .createGeometry(GeometryHelper.cube(normals: false, uvs: true)); - await testHelper.capture(viewer, "geometry_cube_with_uvs"); - }); - test('create cube with normals & uvs', () async { - var viewer = await testHelper.createViewer(); - await viewer - .createGeometry(GeometryHelper.cube(normals: true, uvs: true)); - await testHelper.capture(viewer, "geometry_cube_with_normals_uvs"); - }); - - test('create cube (no normals/uvs)', () async { + test('add geometry', () async { await testHelper.withViewer((viewer) async { - var viewMatrix = - makeViewMatrix(Vector3(0, 2, 5), Vector3.zero(), Vector3(0, 1, 0)); - viewMatrix.invert(); - await viewer.setCameraModelMatrix4(viewMatrix); - final cube = await viewer - .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); - await testHelper.capture(viewer, "geometry_cube_no_normals_uvs"); - await viewer.destroyAsset(cube); - await testHelper.capture(viewer, "geometry_remove_cube"); - }); - }); - - test('create cube with unlit ubershader material (no normals/uvs)', - () async { - await testHelper.withViewer((viewer) async { - final materialInstance = - await viewer.createUbershaderMaterialInstance(unlit: true); - await materialInstance.setParameterFloat4( - "baseColorFactor", 1.0, 0.0, 0.0, 1.0); - final cube = await viewer.createGeometry( - GeometryHelper.cube(normals: false, uvs: false), - materialInstances: [materialInstance]); - await testHelper.capture(viewer, "geometry_cube_ubershader"); - }); - }); - - test('create cube with lit ubershader material (normals/ no uvs)', - () async { - await testHelper.withViewer((viewer) async { - final materialInstance = await viewer.createUbershaderMaterialInstance( - unlit: false, alphaMode: AlphaMode.BLEND, hasVertexColors: false); - await materialInstance.setParameterFloat4( - "baseColorFactor", 1.0, 0.0, 0.0, 1.0); - final cube = await viewer.createGeometry( - GeometryHelper.cube(normals: true, uvs: false), - materialInstances: [materialInstance]); - - await viewer.addDirectLight(DirectLight.sun( - intensity: 100000, - castShadows: false, - direction: Vector3(0, -0.5, -1))); - // await viewer.addDirectLight(DirectLight.spot( - // intensity: 1000000, - // position: Vector3(0,3,3), - // direction: Vector3(0,-1.5,-1), - // falloffRadius: 10)); - await materialInstance.setParameterFloat4( - "baseColorFactor", 1.0, 0.0, 0.0, 1.0); - await testHelper.capture(viewer, "geometry_cube_lit_ubershader"); - }); - }); - - test('create instance', () async { - await testHelper.withViewer((viewer) async { - final cube = await viewer - .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); - await viewer.setTransform( - cube.entity, Matrix4.translation(Vector3.all(-1))); - final instance = await cube.createInstance(); - await instance.addToScene(); - await viewer.setTransform( - instance.entity, Matrix4.translation(Vector3.all(1))); - - await testHelper.capture(viewer, "geometry_instanced"); - await viewer.destroyAsset(instance); - await testHelper.capture(viewer, "geometry_instance_removed"); - }); - }); - - test('create instance (shared material)', () async { - await testHelper.withViewer((viewer) async { - final materialInstance = await viewer.createUnlitMaterialInstance(); - await materialInstance.setParameterFloat4( - "baseColorFactor", 1.0, 0.0, 0.0, 1.0); - final cube = await viewer.createGeometry( - GeometryHelper.cube(normals: true, uvs: false), - materialInstances: [materialInstance]); - - final instance = await cube.createInstance(); - await instance.addToScene(); - await viewer.setTransform( - instance.entity, Matrix4.translation(Vector3.all(1))); - - await testHelper.capture( - viewer, "geometry_instanced_with_shared_material"); - }); - }); - - // test('create instance (no material on second instance)', () async { - // await testHelper.withViewer((viewer) async { - // final materialInstance = await viewer.createUnlitMaterialInstance(); - // await materialInstance.setParameterFloat4( - // "baseColorFactor", 1.0, 0.0, 0.0, 1.0); - // final cube = await viewer.createGeometry( - // GeometryHelper.cube(normals: true, uvs: false), - // materialInstances: [materialInstance]); - - // final instance = await viewer - // .createInstance(cube); - // await viewer.setTransform( - // instance.entity, Matrix4.translation(Vector3.all(1))); - - // await testHelper.capture( - // viewer, "geometry_instanced_with_no_material_instance"); - // }); - // }); - - // test('create instance (separate materials)', () async { - // await testHelper.withViewer((viewer) async { - // final materialInstance = await viewer.createUnlitMaterialInstance(); - // await materialInstance.setParameterFloat4( - // "baseColorFactor", 1.0, 0.0, 0.0, 1.0); - // final cube = await viewer.createGeometry( - // GeometryHelper.cube(normals: true, uvs: false), - // materialInstances: [materialInstance]); - - // final materialInstance2 = await viewer.createUnlitMaterialInstance(); - // await materialInstance2.setParameterFloat4( - // "baseColorFactor", 0.0, 1.0, 0.0, 1.0); - // final instance = await viewer - // .createInstance(cube, materialInstances: [materialInstance2]); - // await viewer.setTransform( - // instance.entity, Matrix4.translation(Vector3.all(1))); - - // await testHelper.capture( - // viewer, "geometry_instanced_with_separate_material_instances"); - // }); - // }); - - test('create cube with custom ubershader material (color)', () async { - await testHelper.withViewer((viewer) async { - await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1); - await viewer.setCameraPosition(0, 2, 6); - await viewer - .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8)); - await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0); - - var materialInstance = - await viewer.createUbershaderMaterialInstance(unlit: true); - final cube = await viewer.createGeometry( - GeometryHelper.cube(uvs: false, normals: true), - materialInstances: [materialInstance]); - await materialInstance.setParameterFloat4( - "baseColorFactor", 0.0, 1.0, 0.0, 0.0); - await testHelper.capture( - viewer, "geometry_cube_with_custom_material_ubershader"); - await viewer.destroyAsset(cube); - }); - }); - - test('create cube with custom ubershader material instance (texture)', - () async { - var viewer = await testHelper.createViewer(); - await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1); - await viewer.setCameraPosition(0, 2, 6); - await viewer - .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8)); - await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0); - - var materialInstance = await viewer.createUbershaderMaterialInstance(); - final cube = await viewer.createGeometry( - GeometryHelper.cube(uvs: true, normals: true), - materialInstances: [materialInstance]); - final image = await viewer.decodeImage( - File("${testHelper.testDir}/assets/cube_texture_512x512.png") - .readAsBytesSync()); - var texture = await viewer.createTexture( - await image.getWidth(), await image.getHeight()); - await texture.setLinearImage( - image, PixelDataFormat.RGBA, PixelDataType.FLOAT); - await testHelper.capture( - viewer, "geometry_cube_with_custom_material_ubershader_texture"); - await viewer.destroyAsset(cube); - await texture.dispose(); - await image.destroy(); - }); - - test('unlit material with color only', () async { - await testHelper.withViewer((viewer) async { - var materialInstance = await viewer.createUnlitMaterialInstance(); - var cube = await viewer.createGeometry(GeometryHelper.cube(), - materialInstances: [materialInstance]); - - await materialInstance.setParameterFloat4( - "baseColorFactor", 0.0, 1.0, 0.0, 1.0); - - await testHelper.capture(viewer, "unlit_material_base_color"); - }); - }); - - test('unlit material with texture', () async { - await testHelper.withViewer((viewer) async { - var materialInstance = await viewer.createUnlitMaterialInstance(); - var cube = await viewer.createGeometry(GeometryHelper.cube(), - materialInstances: [materialInstance]); - - await materialInstance.setParameterInt("baseColorIndex", 0); - - final image = await viewer.decodeImage( - File("${testHelper.testDir}/assets/cube_texture_512x512.png") - .readAsBytesSync()); - var texture = await viewer.createTexture( - await image.getWidth(), await image.getHeight()); - await texture.setLinearImage( - image, PixelDataFormat.RGBA, PixelDataType.FLOAT); - await testHelper.capture(viewer, "unlit_material_texture_only"); - await viewer.destroyAsset(cube); - }); - }); - - test('shared material instance with texture and base color', () async { - await testHelper.withViewer((viewer) async { - var materialInstance = await viewer.createUnlitMaterialInstance(); - var cube1 = await viewer.createGeometry(GeometryHelper.cube(), - materialInstances: [materialInstance]); - var cube2 = await viewer.createGeometry(GeometryHelper.cube(), - materialInstances: [materialInstance]); - await viewer.setTransform( - cube2.entity, Matrix4.translation(Vector3(1, 1, 1))); - - await materialInstance.setParameterInt("baseColorIndex", 0); - final image = await viewer.decodeImage( - File("${testHelper.testDir}/assets/cube_texture_512x512.png") - .readAsBytesSync()); - var texture = await viewer.createTexture( - await image.getWidth(), await image.getHeight()); - await texture.setLinearImage( - image, PixelDataFormat.RGBA, PixelDataType.FLOAT); - - await testHelper.capture(viewer, "unlit_material_shared"); - await texture.dispose(); - await image.destroy(); - }); - }); - - test('create sphere (no normals)', () async { - await testHelper.withViewer((viewer) async { - await viewer - .createGeometry(GeometryHelper.sphere(normals: false, uvs: false)); - await testHelper.capture(viewer, "geometry_sphere_no_normals"); - }, bg: kBlue, cameraPosition: Vector3(0, 0, 6)); - }); - - 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"); + final asset = await viewer.createGeometry(GeometryHelper.cube()); + await viewer.addToScene(asset); + await testHelper.capture(viewer.view, "add_geometry"); + await viewer.removeFromScene(asset); + await testHelper.capture(viewer.view, "remove_geometry"); + await viewer.destroyAsset(asset); }, bg: kRed); }); - - test('create camera geometry', () async { - await testHelper.withViewer((viewer) async { - final camera = await viewer.createGeometry( - GeometryHelper.wireframeCamera(normals: false, uvs: false)); - await viewer.setTransform(camera.entity, Matrix4.rotationY(pi / 4)); - await testHelper.capture(viewer, "camera_geometry"); - }); - }); }); + // test('create cube with normals & uvs', () async { + // var viewer = await testHelper.createViewer(); + // await viewer + // .createGeometry(GeometryHelper.cube(normals: true, uvs: true)); + // await testHelper.capture(viewer, "geometry_cube_with_normals_uvs"); + // }); + + // test('create cube (no normals/uvs)', () async { + // await testHelper.withViewer((viewer) async { + // var viewMatrix = + // makeViewMatrix(Vector3(0, 2, 5), Vector3.zero(), Vector3(0, 1, 0)); + // viewMatrix.invert(); + // await viewer.setCameraModelMatrix4(viewMatrix); + // final cube = await viewer + // .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); + // await testHelper.capture(viewer, "geometry_cube_no_normals_uvs"); + // await viewer.destroyAsset(cube); + // await testHelper.capture(viewer, "geometry_remove_cube"); + // }); + // }); + + // test('create cube with unlit ubershader material (no normals/uvs)', + // () async { + // await testHelper.withViewer((viewer) async { + // final materialInstance = + // await viewer.createUbershaderMaterialInstance(unlit: true); + // await materialInstance.setParameterFloat4( + // "baseColorFactor", 1.0, 0.0, 0.0, 1.0); + // final cube = await viewer.createGeometry( + // GeometryHelper.cube(normals: false, uvs: false), + // materialInstances: [materialInstance]); + // await testHelper.capture(viewer, "geometry_cube_ubershader"); + // }); + // }); + + // test('create cube with lit ubershader material (normals/ no uvs)', + // () async { + // await testHelper.withViewer((viewer) async { + // final materialInstance = await viewer.createUbershaderMaterialInstance( + // unlit: false, alphaMode: AlphaMode.BLEND, hasVertexColors: false); + // await materialInstance.setParameterFloat4( + // "baseColorFactor", 1.0, 0.0, 0.0, 1.0); + // final cube = await viewer.createGeometry( + // GeometryHelper.cube(normals: true, uvs: false), + // materialInstances: [materialInstance]); + + // await viewer.addDirectLight(DirectLight.sun( + // intensity: 100000, + // castShadows: false, + // direction: Vector3(0, -0.5, -1))); + // // await viewer.addDirectLight(DirectLight.spot( + // // intensity: 1000000, + // // position: Vector3(0,3,3), + // // direction: Vector3(0,-1.5,-1), + // // falloffRadius: 10)); + // await materialInstance.setParameterFloat4( + // "baseColorFactor", 1.0, 0.0, 0.0, 1.0); + // await testHelper.capture(viewer, "geometry_cube_lit_ubershader"); + // }); + // }); + + // test('create instance', () async { + // await testHelper.withViewer((viewer) async { + // final cube = await viewer + // .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); + // await viewer.setTransform( + // cube.entity, Matrix4.translation(Vector3.all(-1))); + // final instance = await cube.createInstance(); + // await instance.addToScene(); + // await viewer.setTransform( + // instance.entity, Matrix4.translation(Vector3.all(1))); + + // await testHelper.capture(viewer, "geometry_instanced"); + // await viewer.destroyAsset(instance); + // await testHelper.capture(viewer, "geometry_instance_removed"); + // }); + // }); + + // test('create instance (shared material)', () async { + // await testHelper.withViewer((viewer) async { + // final materialInstance = await viewer.createUnlitMaterialInstance(); + // await materialInstance.setParameterFloat4( + // "baseColorFactor", 1.0, 0.0, 0.0, 1.0); + // final cube = await viewer.createGeometry( + // GeometryHelper.cube(normals: true, uvs: false), + // materialInstances: [materialInstance]); + + // final instance = await cube.createInstance(); + // await instance.addToScene(); + // await viewer.setTransform( + // instance.entity, Matrix4.translation(Vector3.all(1))); + + // await testHelper.capture( + // viewer, "geometry_instanced_with_shared_material"); + // }); + // }); + + // // test('create instance (no material on second instance)', () async { + // // await testHelper.withViewer((viewer) async { + // // final materialInstance = await viewer.createUnlitMaterialInstance(); + // // await materialInstance.setParameterFloat4( + // // "baseColorFactor", 1.0, 0.0, 0.0, 1.0); + // // final cube = await viewer.createGeometry( + // // GeometryHelper.cube(normals: true, uvs: false), + // // materialInstances: [materialInstance]); + + // // final instance = await viewer + // // .createInstance(cube); + // // await viewer.setTransform( + // // instance.entity, Matrix4.translation(Vector3.all(1))); + + // // await testHelper.capture( + // // viewer, "geometry_instanced_with_no_material_instance"); + // // }); + // // }); + + // // test('create instance (separate materials)', () async { + // // await testHelper.withViewer((viewer) async { + // // final materialInstance = await viewer.createUnlitMaterialInstance(); + // // await materialInstance.setParameterFloat4( + // // "baseColorFactor", 1.0, 0.0, 0.0, 1.0); + // // final cube = await viewer.createGeometry( + // // GeometryHelper.cube(normals: true, uvs: false), + // // materialInstances: [materialInstance]); + + // // final materialInstance2 = await viewer.createUnlitMaterialInstance(); + // // await materialInstance2.setParameterFloat4( + // // "baseColorFactor", 0.0, 1.0, 0.0, 1.0); + // // final instance = await viewer + // // .createInstance(cube, materialInstances: [materialInstance2]); + // // await viewer.setTransform( + // // instance.entity, Matrix4.translation(Vector3.all(1))); + + // // await testHelper.capture( + // // viewer, "geometry_instanced_with_separate_material_instances"); + // // }); + // // }); + + // test('create cube with custom ubershader material (color)', () async { + // await testHelper.withViewer((viewer) async { + // await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1); + // await viewer.setCameraPosition(0, 2, 6); + // await viewer + // .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8)); + // await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0); + + // var materialInstance = + // await viewer.createUbershaderMaterialInstance(unlit: true); + // final cube = await viewer.createGeometry( + // GeometryHelper.cube(uvs: false, normals: true), + // materialInstances: [materialInstance]); + // await materialInstance.setParameterFloat4( + // "baseColorFactor", 0.0, 1.0, 0.0, 0.0); + // await testHelper.capture( + // viewer, "geometry_cube_with_custom_material_ubershader"); + // await viewer.destroyAsset(cube); + // }); + // }); + + // test('create cube with custom ubershader material instance (texture)', + // () async { + // var viewer = await testHelper.createViewer(); + // await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1); + // await viewer.setCameraPosition(0, 2, 6); + // await viewer + // .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8)); + // await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0); + + // var materialInstance = await viewer.createUbershaderMaterialInstance(); + // final cube = await viewer.createGeometry( + // GeometryHelper.cube(uvs: true, normals: true), + // materialInstances: [materialInstance]); + // final image = await viewer.decodeImage( + // File("${testHelper.testDir}/assets/cube_texture_512x512.png") + // .readAsBytesSync()); + // var texture = await viewer.createTexture( + // await image.getWidth(), await image.getHeight()); + // await texture.setLinearImage( + // image, PixelDataFormat.RGBA, PixelDataType.FLOAT); + // await testHelper.capture( + // viewer, "geometry_cube_with_custom_material_ubershader_texture"); + // await viewer.destroyAsset(cube); + // await texture.dispose(); + // await image.destroy(); + // }); + + // test('unlit material with color only', () async { + // await testHelper.withViewer((viewer) async { + // var materialInstance = await viewer.createUnlitMaterialInstance(); + // var cube = await viewer.createGeometry(GeometryHelper.cube(), + // materialInstances: [materialInstance]); + + // await materialInstance.setParameterFloat4( + // "baseColorFactor", 0.0, 1.0, 0.0, 1.0); + + // await testHelper.capture(viewer, "unlit_material_base_color"); + // }); + // }); + + // test('unlit material with texture', () async { + // await testHelper.withViewer((viewer) async { + // var materialInstance = await viewer.createUnlitMaterialInstance(); + // var cube = await viewer.createGeometry(GeometryHelper.cube(), + // materialInstances: [materialInstance]); + + // await materialInstance.setParameterInt("baseColorIndex", 0); + + // final image = await viewer.decodeImage( + // File("${testHelper.testDir}/assets/cube_texture_512x512.png") + // .readAsBytesSync()); + // var texture = await viewer.createTexture( + // await image.getWidth(), await image.getHeight()); + // await texture.setLinearImage( + // image, PixelDataFormat.RGBA, PixelDataType.FLOAT); + // await testHelper.capture(viewer, "unlit_material_texture_only"); + // await viewer.destroyAsset(cube); + // }); + // }); + + // test('shared material instance with texture and base color', () async { + // await testHelper.withViewer((viewer) async { + // var materialInstance = await viewer.createUnlitMaterialInstance(); + // var cube1 = await viewer.createGeometry(GeometryHelper.cube(), + // materialInstances: [materialInstance]); + // var cube2 = await viewer.createGeometry(GeometryHelper.cube(), + // materialInstances: [materialInstance]); + // await viewer.setTransform( + // cube2.entity, Matrix4.translation(Vector3(1, 1, 1))); + + // await materialInstance.setParameterInt("baseColorIndex", 0); + // final image = await viewer.decodeImage( + // File("${testHelper.testDir}/assets/cube_texture_512x512.png") + // .readAsBytesSync()); + // var texture = await viewer.createTexture( + // await image.getWidth(), await image.getHeight()); + // await texture.setLinearImage( + // image, PixelDataFormat.RGBA, PixelDataType.FLOAT); + + // await testHelper.capture(viewer, "unlit_material_shared"); + // await texture.dispose(); + // await image.destroy(); + // }); + // }); + + // test('create sphere (no normals)', () async { + // await testHelper.withViewer((viewer) async { + // await viewer + // .createGeometry(GeometryHelper.sphere(normals: false, uvs: false)); + // await testHelper.capture(viewer, "geometry_sphere_no_normals"); + // }, bg: kBlue, cameraPosition: Vector3(0, 0, 6)); + // }); + + // 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( + // GeometryHelper.wireframeCamera(normals: false, uvs: false)); + // await viewer.setTransform(camera.entity, Matrix4.rotationY(pi / 4)); + // await testHelper.capture(viewer, "camera_geometry"); + // }); + // }); + // }); } diff --git a/thermion_dart/test/helpers.dart b/thermion_dart/test/helpers.dart index 1e43e1ec..5b3dc14e 100644 --- a/thermion_dart/test/helpers.dart +++ b/thermion_dart/test/helpers.dart @@ -165,22 +165,25 @@ class TestHelper { resourceLoader.ref.freeResource = freeResource.nativeFunction; await FFIFilamentApp.create(); - await FilamentApp.instance!.setClearColor(0, 0, 0, 1); + await FilamentApp.instance!.setClearColor(0, 1, 0, 1); } /// /// /// - Future withViewer(Future Function(ThermionViewer viewer) fn, - {img.Color? bg, - Vector3? cameraPosition, - ({int width, int height}) viewportDimensions = (width: 500, height: 500), - bool postProcessing = false, - bool createRenderTarget = false}) async { + Future withViewer( + Future Function(ThermionViewer viewer) fn, { + img.Color? bg, + Vector3? cameraPosition, + ({int width, int height}) viewportDimensions = (width: 512, height: 512), + bool postProcessing = false, + bool addSkybox = false, + bool createRenderTarget = false, + }) async { cameraPosition ??= Vector3(0, 2, 6); - var swapChain = await FilamentApp.instance!.createHeadlessSwapChain( - viewportDimensions.width, viewportDimensions.height) as FFISwapChain; + var swapChain = await FilamentApp.instance! + .createHeadlessSwapChain(viewportDimensions.width, viewportDimensions.height) as FFISwapChain; FFIRenderTarget? renderTarget; if (createRenderTarget) { @@ -198,7 +201,8 @@ class TestHelper { }, textureFormat: TextureFormat.RGB32F, importedTextureHandle: metalColorTexture.metalTextureAddress); - + var width = await color.getWidth(); + var height = await color.getHeight(); var depth = await FilamentApp.instance! .createTexture(viewportDimensions.width, viewportDimensions.height, flags: { @@ -216,16 +220,23 @@ class TestHelper { var viewer = ThermionViewerFFI( loadAssetFromUri: (path) async => - File(path.replaceAll("file://", "")).readAsBytesSync(), - renderTarget: renderTarget); + File(path.replaceAll("file://", "")).readAsBytesSync()); await viewer.initialized; await FilamentApp.instance!.register(swapChain, viewer.view); - + if (renderTarget != null) { + await viewer.view.setRenderTarget(renderTarget); + } await viewer.view - .setViewport(viewportDimensions.width, viewportDimensions.height); + .setViewport( + viewportDimensions.width, + viewportDimensions.height + ); - await viewer.view.setBloom(false, 0); + if (addSkybox) { + await viewer + .loadSkybox("file://${testDir}/assets/default_env_skybox.ktx"); + } if (bg != null) { await viewer.setBackgroundColor( diff --git a/thermion_flutter/thermion_flutter/lib/src/thermion_flutter_plugin.dart b/thermion_flutter/thermion_flutter/lib/src/thermion_flutter_plugin.dart index 8f9919ad..a3391e98 100644 --- a/thermion_flutter/thermion_flutter/lib/src/thermion_flutter_plugin.dart +++ b/thermion_flutter/thermion_flutter/lib/src/thermion_flutter_plugin.dart @@ -20,4 +20,5 @@ class ThermionFlutterPlugin { return viewer; } + } diff --git a/thermion_flutter/thermion_flutter/lib/src/widgets/src/camera/camera_orientation_widget.dart b/thermion_flutter/thermion_flutter/lib/src/widgets/src/camera/camera_orientation_widget.dart index 710acece..1fb51dd7 100644 --- a/thermion_flutter/thermion_flutter/lib/src/widgets/src/camera/camera_orientation_widget.dart +++ b/thermion_flutter/thermion_flutter/lib/src/widgets/src/camera/camera_orientation_widget.dart @@ -1,98 +1,98 @@ -import 'dart:math'; +// import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:thermion_flutter/thermion_flutter.dart'; -import 'package:vector_math/vector_math_64.dart' as v64; +// import 'package:flutter/material.dart'; +// import 'package:thermion_flutter/thermion_flutter.dart'; +// import 'package:vector_math/vector_math_64.dart' as v64; -class CameraOrientationWidget extends StatefulWidget { - final ThermionViewer viewer; +// class CameraOrientationWidget extends StatefulWidget { +// final ThermionViewer viewer; - const CameraOrientationWidget({Key? key, required this.viewer}) - : super(key: key); +// const CameraOrientationWidget({Key? key, required this.viewer}) +// : super(key: key); - @override - _CameraOrientationWidgetState createState() => - _CameraOrientationWidgetState(); -} +// @override +// _CameraOrientationWidgetState createState() => +// _CameraOrientationWidgetState(); +// } -class _CameraOrientationWidgetState extends State - with SingleTickerProviderStateMixin { - late AnimationController _controller; - v64.Vector3? _position; - v64.Matrix3? _rotation; +// class _CameraOrientationWidgetState extends State +// with SingleTickerProviderStateMixin { +// late AnimationController _controller; +// v64.Vector3? _position; +// v64.Matrix3? _rotation; - @override - void initState() { - super.initState(); - _controller = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 16), // ~60 FPS - )..repeat(); +// @override +// void initState() { +// super.initState(); +// _controller = AnimationController( +// vsync: this, +// duration: const Duration(milliseconds: 16), // ~60 FPS +// )..repeat(); - _controller.addListener(_updateCameraInfo); - } +// _controller.addListener(_updateCameraInfo); +// } - void _updateCameraInfo() async { - final camera = await widget.viewer.getActiveCamera(); - final position = await widget.viewer.getCameraPosition(); - final rotation = await widget.viewer.getCameraRotation(); - setState(() { - _position = position; - _rotation = rotation; - }); - } +// void _updateCameraInfo() async { +// final camera = await widget.viewer.getActiveCamera(); +// final position = await widget.viewer.getCameraPosition(); +// final rotation = await widget.viewer.getCameraRotation(); +// setState(() { +// _position = position; +// _rotation = rotation; +// }); +// } - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } +// @override +// void dispose() { +// _controller.dispose(); +// super.dispose(); +// } - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.7), - borderRadius: BorderRadius.circular(8.0), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Position: ${_formatVector(_position)}', - style: const TextStyle(color: Colors.white), - ), - const SizedBox(height: 4), - Text( - 'Rotation: ${_formatMatrix(_rotation)}', - style: const TextStyle(color: Colors.white), - ), - ], - ), - ); - } +// @override +// Widget build(BuildContext context) { +// return Container( +// padding: const EdgeInsets.all(8.0), +// decoration: BoxDecoration( +// color: Colors.black.withOpacity(0.7), +// borderRadius: BorderRadius.circular(8.0), +// ), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisSize: MainAxisSize.min, +// children: [ +// Text( +// 'Position: ${_formatVector(_position)}', +// style: const TextStyle(color: Colors.white), +// ), +// const SizedBox(height: 4), +// Text( +// 'Rotation: ${_formatMatrix(_rotation)}', +// style: const TextStyle(color: Colors.white), +// ), +// ], +// ), +// ); +// } - String _formatVector(v64.Vector3? vector) { - if (vector == null) return 'N/A'; - return '(${vector.x.toStringAsFixed(2)}, ${vector.y.toStringAsFixed(2)}, ${vector.z.toStringAsFixed(2)})'; - } +// String _formatVector(v64.Vector3? vector) { +// if (vector == null) return 'N/A'; +// return '(${vector.x.toStringAsFixed(2)}, ${vector.y.toStringAsFixed(2)}, ${vector.z.toStringAsFixed(2)})'; +// } - String _formatMatrix(v64.Matrix3? matrix) { - if (matrix == null) return 'N/A'; - return 'Yaw: ${_getYaw(matrix).toStringAsFixed(2)}°, Pitch: ${_getPitch(matrix).toStringAsFixed(2)}°, Roll: ${_getRoll(matrix).toStringAsFixed(2)}°'; - } +// String _formatMatrix(v64.Matrix3? matrix) { +// if (matrix == null) return 'N/A'; +// return 'Yaw: ${_getYaw(matrix).toStringAsFixed(2)}°, Pitch: ${_getPitch(matrix).toStringAsFixed(2)}°, Roll: ${_getRoll(matrix).toStringAsFixed(2)}°'; +// } - double _getYaw(v64.Matrix3 matrix) { - return -atan2(matrix[2], matrix[0]) * 180 / pi; - } +// double _getYaw(v64.Matrix3 matrix) { +// return -atan2(matrix[2], matrix[0]) * 180 / pi; +// } - double _getPitch(v64.Matrix3 matrix) { - return -asin(matrix[5]) * 180 / pi; - } +// double _getPitch(v64.Matrix3 matrix) { +// return -asin(matrix[5]) * 180 / pi; +// } - double _getRoll(v64.Matrix3 matrix) { - return atan2(matrix[3], matrix[4]) * 180 / pi; - } -} +// double _getRoll(v64.Matrix3 matrix) { +// return atan2(matrix[3], matrix[4]) * 180 / pi; +// } +// } diff --git a/thermion_flutter/thermion_flutter/lib/src/widgets/src/camera/camera_selector_widget.dart b/thermion_flutter/thermion_flutter/lib/src/widgets/src/camera/camera_selector_widget.dart index 756c3045..7135eec0 100644 --- a/thermion_flutter/thermion_flutter/lib/src/widgets/src/camera/camera_selector_widget.dart +++ b/thermion_flutter/thermion_flutter/lib/src/widgets/src/camera/camera_selector_widget.dart @@ -1,79 +1,79 @@ -import 'package:flutter/material.dart'; -import 'package:thermion_dart/thermion_dart.dart'; +// import 'package:flutter/material.dart'; +// import 'package:thermion_dart/thermion_dart.dart'; -class CameraSelectorWidget extends StatefulWidget { - final ThermionViewer viewer; +// class CameraSelectorWidget extends StatefulWidget { +// final ThermionViewer viewer; - const CameraSelectorWidget({Key? key, required this.viewer}) : super(key: key); +// const CameraSelectorWidget({Key? key, required this.viewer}) : super(key: key); - @override - _CameraSelectorWidgetState createState() => _CameraSelectorWidgetState(); -} +// @override +// _CameraSelectorWidgetState createState() => _CameraSelectorWidgetState(); +// } -class _CameraSelectorWidgetState extends State { - int _activeIndex = 0; +// class _CameraSelectorWidgetState extends State { +// int _activeIndex = 0; - @override - Widget build(BuildContext context) { - int cameraCount = widget.viewer.getCameraCount(); +// @override +// Widget build(BuildContext context) { +// int cameraCount = widget.viewer.getCameraCount(); - return Container( - height:32, - margin: const EdgeInsets.all(8), - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - _buildCameraButton("Main", 0), - if (cameraCount > 1) const VerticalDivider(width: 16, thickness: 1), - ...List.generate(cameraCount - 1, (index) { - return _buildCameraButton("${index + 1}", index + 1); - }), - ], - ), - ); - } +// return Container( +// height:32, +// margin: const EdgeInsets.all(8), +// padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(8), +// boxShadow: [ +// BoxShadow( +// color: Colors.black.withOpacity(0.1), +// blurRadius: 4, +// offset: const Offset(0, 2), +// ), +// ], +// ), +// child: Row( +// crossAxisAlignment: CrossAxisAlignment.center, +// mainAxisSize: MainAxisSize.min, +// children: [ +// _buildCameraButton("Main", 0), +// if (cameraCount > 1) const VerticalDivider(width: 16, thickness: 1), +// ...List.generate(cameraCount - 1, (index) { +// return _buildCameraButton("${index + 1}", index + 1); +// }), +// ], +// ), +// ); +// } - Widget _buildCameraButton(String label, int index) { - bool isActive = _activeIndex == index; - return Flexible(child:TextButton( - onPressed: () async { - if (index == 0) { - await widget.viewer.setMainCamera(); - } else { - Camera camera = widget.viewer.getCameraAt(index); - await widget.viewer.setActiveCamera(camera); - } - setState(() { - _activeIndex = index; - }); - }, - style: TextButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - backgroundColor: isActive ? Colors.blue.withOpacity(0.1) : null, - ), - child: Text( - label, - style: TextStyle( - fontSize: 10, - fontWeight: isActive ? FontWeight.bold : FontWeight.normal, - color: isActive ? Colors.blue : Colors.black87, - ), - ), - )); - } -} \ No newline at end of file +// Widget _buildCameraButton(String label, int index) { +// bool isActive = _activeIndex == index; +// return Flexible(child:TextButton( +// onPressed: () async { +// if (index == 0) { +// await widget.viewer.setMainCamera(); +// } else { +// Camera camera = widget.viewer.getCameraAt(index); +// await widget.viewer.setActiveCamera(camera); +// } +// setState(() { +// _activeIndex = index; +// }); +// }, +// style: TextButton.styleFrom( +// padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), +// minimumSize: Size.zero, +// tapTargetSize: MaterialTapTargetSize.shrinkWrap, +// backgroundColor: isActive ? Colors.blue.withOpacity(0.1) : null, +// ), +// child: Text( +// label, +// style: TextStyle( +// fontSize: 10, +// fontWeight: isActive ? FontWeight.bold : FontWeight.normal, +// color: isActive ? Colors.blue : Colors.black87, +// ), +// ), +// )); +// } +// } \ No newline at end of file diff --git a/thermion_flutter/thermion_flutter/lib/src/widgets/src/debug/child_renderable_widget.dart b/thermion_flutter/thermion_flutter/lib/src/widgets/src/debug/child_renderable_widget.dart index d4048f64..9d679052 100644 --- a/thermion_flutter/thermion_flutter/lib/src/widgets/src/debug/child_renderable_widget.dart +++ b/thermion_flutter/thermion_flutter/lib/src/widgets/src/debug/child_renderable_widget.dart @@ -1,110 +1,110 @@ -import 'package:animation_tools_dart/animation_tools_dart.dart'; -import 'package:thermion_dart/thermion_dart.dart'; +// import 'package:animation_tools_dart/animation_tools_dart.dart'; +// import 'package:thermion_dart/thermion_dart.dart'; -import 'package:flutter/material.dart'; -import 'dart:math'; +// import 'package:flutter/material.dart'; +// import 'dart:math'; -class ChildRenderableWidget extends StatelessWidget { - final ThermionViewer controller; - final ThermionEntity entity; +// class ChildRenderableWidget extends StatelessWidget { +// final ThermionViewer controller; +// final ThermionEntity entity; - const ChildRenderableWidget( - {super.key, required this.controller, required this.entity}); +// const ChildRenderableWidget( +// {super.key, required this.controller, required this.entity}); - Widget _childRenderable(ThermionEntity childEntity) { - var name = controller.getNameForEntity(childEntity) ?? ""; - var names = controller.getMorphTargetNames(entity, childEntity); +// Widget _childRenderable(ThermionEntity childEntity) { +// var name = controller.getNameForEntity(childEntity) ?? ""; +// var names = controller.getMorphTargetNames(entity, childEntity); - return FutureBuilder( - future: names, - builder: (_, morphTargetsSnapshot) { - if (!morphTargetsSnapshot.hasData) { - return Container(); - } - var morphTargets = morphTargetsSnapshot.data!; +// return FutureBuilder( +// future: names, +// builder: (_, morphTargetsSnapshot) { +// if (!morphTargetsSnapshot.hasData) { +// return Container(); +// } +// var morphTargets = morphTargetsSnapshot.data!; - final menuChildren = []; - if (morphTargets.isEmpty) { - menuChildren.add(Text("None")); - } else { - for (int i = 0; i < 2; i++) { - var newWeights = List.filled(morphTargets.length, i.toDouble()); - menuChildren.add(MenuItemButton( - child: Text("Set to $i"), - onPressed: () async { - try { - await controller! - .setMorphTargetWeights(childEntity, newWeights); - } catch (err, st) { - print("Error setting morph target weights"); - print(err); - print(st); - } - })); - } - menuChildren.add(MenuItemButton( - child: Text("Animate all morph target from 0 to 1"), - onPressed: () async { - var morphData = MorphAnimationData( - List>.generate( - 120, - (i) => List.filled( - morphTargets.length, i / 120)), - morphTargets); - await controller!.setMorphAnimationData(entity, morphData, - targetMeshNames: [name]); - })); - menuChildren.addAll(morphTargets.map((t) => Text(t))); - } - return SubmenuButton(child: Text(name), menuChildren: menuChildren); - }); - } +// final menuChildren = []; +// if (morphTargets.isEmpty) { +// menuChildren.add(Text("None")); +// } else { +// for (int i = 0; i < 2; i++) { +// var newWeights = List.filled(morphTargets.length, i.toDouble()); +// menuChildren.add(MenuItemButton( +// child: Text("Set to $i"), +// onPressed: () async { +// try { +// await controller! +// .setMorphTargetWeights(childEntity, newWeights); +// } catch (err, st) { +// print("Error setting morph target weights"); +// print(err); +// print(st); +// } +// })); +// } +// menuChildren.add(MenuItemButton( +// child: Text("Animate all morph target from 0 to 1"), +// onPressed: () async { +// var morphData = MorphAnimationData( +// List>.generate( +// 120, +// (i) => List.filled( +// morphTargets.length, i / 120)), +// morphTargets); +// await controller!.setMorphAnimationData(entity, morphData, +// targetMeshNames: [name]); +// })); +// menuChildren.addAll(morphTargets.map((t) => Text(t))); +// } +// return SubmenuButton(child: Text(name), menuChildren: menuChildren); +// }); +// } - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: controller!.getChildEntities(entity, true), - builder: (ctx, snapshot) { - if (!snapshot.hasData) { - return Container(); - } +// @override +// Widget build(BuildContext context) { +// return FutureBuilder( +// future: controller!.getChildEntities(entity, true), +// builder: (ctx, snapshot) { +// if (!snapshot.hasData) { +// return Container(); +// } - var children = snapshot.data!; - return SubmenuButton( - child: Text("Renderable entities"), - menuChildren: [ - MenuItemButton( - child: Text("Set children transforms to identity"), - onPressed: () async { - var childEntities = - await controller.getChildEntities(entity, true); - for (final child in childEntities) { - await controller.setTransform( - child, Matrix4.identity()); - } - }), - MenuItemButton( - child: Text("Set children transforms to 90/X"), - onPressed: () async { - var childEntities = - await controller.getChildEntities(entity, true); - for (final child in childEntities) { - await controller.setTransform( - child, Matrix4.rotationX(pi / 2)); - } - }), - MenuItemButton( - child: Text("Set children transforms to 90/Y"), - onPressed: () async { - var childEntities = - await controller.getChildEntities(entity, true); - for (final child in childEntities) { - await controller.setTransform( - child, Matrix4.rotationY(pi / 2)); - } - }), - ] + - children.map(_childRenderable).toList()); - }); - } -} +// var children = snapshot.data!; +// return SubmenuButton( +// child: Text("Renderable entities"), +// menuChildren: [ +// MenuItemButton( +// child: Text("Set children transforms to identity"), +// onPressed: () async { +// var childEntities = +// await controller.getChildEntities(entity, true); +// for (final child in childEntities) { +// await controller.setTransform( +// child, Matrix4.identity()); +// } +// }), +// MenuItemButton( +// child: Text("Set children transforms to 90/X"), +// onPressed: () async { +// var childEntities = +// await controller.getChildEntities(entity, true); +// for (final child in childEntities) { +// await controller.setTransform( +// child, Matrix4.rotationX(pi / 2)); +// } +// }), +// MenuItemButton( +// child: Text("Set children transforms to 90/Y"), +// onPressed: () async { +// var childEntities = +// await controller.getChildEntities(entity, true); +// for (final child in childEntities) { +// await controller.setTransform( +// child, Matrix4.rotationY(pi / 2)); +// } +// }), +// ] + +// children.map(_childRenderable).toList()); +// }); +// } +// } diff --git a/thermion_flutter/thermion_flutter/lib/src/widgets/src/debug/skeleton_menu_item_widget.dart b/thermion_flutter/thermion_flutter/lib/src/widgets/src/debug/skeleton_menu_item_widget.dart index b9819368..cd7afb6d 100644 --- a/thermion_flutter/thermion_flutter/lib/src/widgets/src/debug/skeleton_menu_item_widget.dart +++ b/thermion_flutter/thermion_flutter/lib/src/widgets/src/debug/skeleton_menu_item_widget.dart @@ -1,421 +1,421 @@ -import 'dart:math'; +// import 'dart:math'; -import 'package:thermion_dart/thermion_dart.dart'; -import 'package:animation_tools_dart/animation_tools_dart.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:vector_math/vector_math_64.dart'; +// import 'package:thermion_dart/thermion_dart.dart'; +// import 'package:animation_tools_dart/animation_tools_dart.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter/widgets.dart'; +// import 'package:vector_math/vector_math_64.dart'; -class SkeletonMenuItemWidget extends StatelessWidget { - final ThermionViewer controller; - final ThermionEntity entity; +// class SkeletonMenuItemWidget extends StatelessWidget { +// final ThermionViewer controller; +// final ThermionEntity entity; - const SkeletonMenuItemWidget( - {super.key, required this.controller, required this.entity}); +// const SkeletonMenuItemWidget( +// {super.key, required this.controller, required this.entity}); - void _addBoneAnimation(String bone) async { - await controller.addAnimationComponent(entity); - var numFrames = 120; - var animationData = List>.generate( - numFrames, - (frameNum) => [ - ( - rotation: Quaternion.axisAngle( - Vector3(1, 0, 0), (frameNum / 90) * 2 * pi), - translation: Vector3.zero() - ) - ]); - var animation = - BoneAnimationData([bone], animationData, space: Space.ParentWorldRotation); - await controller.addAnimationComponent(entity); - await controller.addBoneAnimation(entity, animation); - } +// void _addBoneAnimation(String bone) async { +// await controller.addAnimationComponent(entity); +// var numFrames = 120; +// var animationData = List>.generate( +// numFrames, +// (frameNum) => [ +// ( +// rotation: Quaternion.axisAngle( +// Vector3(1, 0, 0), (frameNum / 90) * 2 * pi), +// translation: Vector3.zero() +// ) +// ]); +// var animation = +// BoneAnimationData([bone], animationData, space: Space.ParentWorldRotation); +// await controller.addAnimationComponent(entity); +// await controller.addBoneAnimation(entity, animation); +// } - @override - Widget build(BuildContext context) { - var boneNames = controller.getBoneNames(entity); +// @override +// Widget build(BuildContext context) { +// var boneNames = controller.getBoneNames(entity); - return FutureBuilder( - future: boneNames, - builder: (_, boneNamesSnapshot) { - if (!boneNamesSnapshot.hasData) { - return Container(); - } - var boneNames = boneNamesSnapshot.data!; - if (boneNames.isEmpty) { - return Text("No bones"); - } +// return FutureBuilder( +// future: boneNames, +// builder: (_, boneNamesSnapshot) { +// if (!boneNamesSnapshot.hasData) { +// return Container(); +// } +// var boneNames = boneNamesSnapshot.data!; +// if (boneNames.isEmpty) { +// return Text("No bones"); +// } - return SubmenuButton( - menuChildren: [ - MenuItemButton( - onPressed: () async { - await controller.resetBones(entity); - }, - child: Text("Reset")), - MenuItemButton( - onPressed: () async { - await controller.resetBones(entity); +// return SubmenuButton( +// menuChildren: [ +// MenuItemButton( +// onPressed: () async { +// await controller.resetBones(entity); +// }, +// child: Text("Reset")), +// MenuItemButton( +// onPressed: () async { +// await controller.resetBones(entity); - var bone = await controller.getBone(entity, 1); - var frames = >[]; - for (int i = 0; i < 60; i++) { - var frame = []; - frame.add(( - rotation: - Quaternion.axisAngle( - Vector3(1, 0, 0), i/60 * pi/4) * - (Quaternion.axisAngle( - Vector3(0, 0, 1), i/60*-pi/4) - * - Quaternion.axisAngle( - Vector3(0, 1, 0), i/60 * pi/4) ), - translation: Vector3.zero() - )); - frames.add(frame); - } +// var bone = await controller.getBone(entity, 1); +// var frames = >[]; +// for (int i = 0; i < 60; i++) { +// var frame = []; +// frame.add(( +// rotation: +// Quaternion.axisAngle( +// Vector3(1, 0, 0), i/60 * pi/4) * +// (Quaternion.axisAngle( +// Vector3(0, 0, 1), i/60*-pi/4) +// * +// Quaternion.axisAngle( +// Vector3(0, 1, 0), i/60 * pi/4) ), +// translation: Vector3.zero() +// )); +// frames.add(frame); +// } - var animation = BoneAnimationData(["Bone.002"], frames, - space: Space.ParentWorldRotation); - await controller.addAnimationComponent(entity); - await controller.addBoneAnimation(entity, animation); - }, - child: Text("Test animation (parent space)")), - MenuItemButton( - onPressed: () async { - await controller.resetBones(entity); +// var animation = BoneAnimationData(["Bone.002"], frames, +// space: Space.ParentWorldRotation); +// await controller.addAnimationComponent(entity); +// await controller.addBoneAnimation(entity, animation); +// }, +// child: Text("Test animation (parent space)")), +// MenuItemButton( +// onPressed: () async { +// await controller.resetBones(entity); - var bone = await controller.getBone(entity, 1); +// var bone = await controller.getBone(entity, 1); - var frames = >[]; - for (int i = 0; i < 60; i++) { - var frame = []; - frame.add(( - rotation: Quaternion.axisAngle( - Vector3(0, 0, 1), (i / 60) * pi / 2), - translation: Vector3.zero() - )); - frames.add(frame); - } - var animation = BoneAnimationData( - ["Bone.001"], frames, - space: Space.Bone); - await controller.addAnimationComponent(entity); - await controller.addBoneAnimation(entity, animation); - }, - child: Text("Test animation (bone space)")), - MenuItemButton( - onPressed: () async { - var frames = >[]; - for (int i = 0; i < 60; i++) { - var frame = []; - frame.add(( - rotation: Quaternion.axisAngle( - Vector3(0, 0, 1), (i / 60) * pi / 2), - translation: Vector3.zero() - )); - frames.add(frame); - } - var animation = BoneAnimationData( - ["Bone.001"], frames, - space: Space.ParentWorldRotation); - await controller.addAnimationComponent(entity); - await controller.addBoneAnimation(entity, animation); - }, - child: Text("Test animation 2")), - MenuItemButton( - onPressed: () async { - var frames = >[]; - for (int i = 0; i < 60; i++) { - var frame = []; - frame.add(( - rotation: Quaternion.axisAngle( - Vector3(0, 0, 1), (i / 60) * pi / 2), - translation: Vector3.zero() - )); - frames.add(frame); - } - var animation = BoneAnimationData( - ["Bone.002"], frames, - space: Space.ParentWorldRotation); - await controller.addAnimationComponent(entity); - await controller.addBoneAnimation(entity, animation); - }, - child: Text("Test animation 3")) - ] + - boneNames - .map((name) { - var boneIndex = boneNames.indexOf(name); - return SubmenuButton(child: Text(name), menuChildren: [ - MenuItemButton( - child: Text("Print bone transforms "), - onPressed: () async { - var boneEntity = - await controller.getBone(entity, boneIndex); - var localTransform = await controller - .getLocalTransform(boneEntity); - var worldTransform = await controller - .getWorldTransform(boneEntity); - var inverseWorldTransform = Matrix4.identity() - ..copyInverse(worldTransform); - print("Local $localTransform"); - print("World $worldTransform"); - print("World inverse $inverseWorldTransform"); - }), - MenuItemButton( - child: Text("Set bone transform to identity"), - onPressed: () async { - var boneEntity = - await controller.getBone(entity, boneIndex); - var localTransform = Matrix4.identity(); - await controller.setTransform( - boneEntity, localTransform); - await controller.updateBoneMatrices(entity); - }), - MenuItemButton( - child: Text( - "Set bone transform to 90/X (parent space)"), - onPressed: () async { - var boneEntity = - await controller.getBone(entity, boneIndex); - var localTransform = Matrix4.rotationX(pi / 2); - await controller.setTransform( - boneEntity, localTransform); - await controller.updateBoneMatrices(entity); - }), - MenuItemButton( - child: Text( - "Set bone transform to 90/X (pose space)"), - onPressed: () async { - var boneEntity = - await controller.getBone(entity, boneIndex); - var localTransform = await controller - .getLocalTransform(boneEntity); - localTransform = - localTransform * Matrix4.rotationX(pi / 2); - await controller.setTransform( - boneEntity, localTransform); - await controller.updateBoneMatrices(entity); - }), - MenuItemButton( - child: Text("Set bone transform to 90/X"), - onPressed: () async { - var boneEntity = - await controller.getBone(entity, boneIndex); - var localTransform = Matrix4.rotationX(pi / 2); - await controller.setTransform( - boneEntity, localTransform); - await controller.updateBoneMatrices(entity); - }), - MenuItemButton( - child: Text("Set bone transform to 0,-1,0"), - onPressed: () async { - var boneEntity = - await controller.getBone(entity, boneIndex); - var localTransform = - Matrix4.translation(Vector3(0, -1, 0)); - await controller.setTransform( - boneEntity, localTransform); - await controller.updateBoneMatrices(entity); - }), - MenuItemButton( - child: Text( - "Set bone matrices/transform to identity"), - onPressed: () async { - var boneEntity = await controller.getBone( - entity, boneNames.indexOf(name)); - await controller.setTransform( - boneEntity, Matrix4.identity()); - var childEntities = await controller - .getChildEntities(entity, true); - for (final child in childEntities) { - await controller.setBoneTransform( - child, - boneNames.indexOf(name), - Matrix4.identity()); - } - }), - SubmenuButton( - child: Text("Set bone matrices to"), - menuChildren: [ - MenuItemButton( - child: Text("Identity"), - onPressed: () async { - await controller - .removeAnimationComponent(entity); - for (var child in await controller - .getChildEntities(entity, true)) { - print( - "Setting transform for ${await controller.getNameForEntity(child)}"); - await controller.setBoneTransform( - child, - boneNames.indexOf(name), - Matrix4.identity()); - } - }), - SubmenuButton( - child: Text("Global"), - menuChildren: ["90/X", "90/Y"] - .map((rot) => MenuItemButton( - onPressed: () async { - var transform = rot == "90/X" - ? Matrix4.rotationX(pi / 2) - : Matrix4.rotationY(pi / 2); - await controller - .removeAnimationComponent( - entity); +// var frames = >[]; +// for (int i = 0; i < 60; i++) { +// var frame = []; +// frame.add(( +// rotation: Quaternion.axisAngle( +// Vector3(0, 0, 1), (i / 60) * pi / 2), +// translation: Vector3.zero() +// )); +// frames.add(frame); +// } +// var animation = BoneAnimationData( +// ["Bone.001"], frames, +// space: Space.Bone); +// await controller.addAnimationComponent(entity); +// await controller.addBoneAnimation(entity, animation); +// }, +// child: Text("Test animation (bone space)")), +// MenuItemButton( +// onPressed: () async { +// var frames = >[]; +// for (int i = 0; i < 60; i++) { +// var frame = []; +// frame.add(( +// rotation: Quaternion.axisAngle( +// Vector3(0, 0, 1), (i / 60) * pi / 2), +// translation: Vector3.zero() +// )); +// frames.add(frame); +// } +// var animation = BoneAnimationData( +// ["Bone.001"], frames, +// space: Space.ParentWorldRotation); +// await controller.addAnimationComponent(entity); +// await controller.addBoneAnimation(entity, animation); +// }, +// child: Text("Test animation 2")), +// MenuItemButton( +// onPressed: () async { +// var frames = >[]; +// for (int i = 0; i < 60; i++) { +// var frame = []; +// frame.add(( +// rotation: Quaternion.axisAngle( +// Vector3(0, 0, 1), (i / 60) * pi / 2), +// translation: Vector3.zero() +// )); +// frames.add(frame); +// } +// var animation = BoneAnimationData( +// ["Bone.002"], frames, +// space: Space.ParentWorldRotation); +// await controller.addAnimationComponent(entity); +// await controller.addBoneAnimation(entity, animation); +// }, +// child: Text("Test animation 3")) +// ] + +// boneNames +// .map((name) { +// var boneIndex = boneNames.indexOf(name); +// return SubmenuButton(child: Text(name), menuChildren: [ +// MenuItemButton( +// child: Text("Print bone transforms "), +// onPressed: () async { +// var boneEntity = +// await controller.getBone(entity, boneIndex); +// var localTransform = await controller +// .getLocalTransform(boneEntity); +// var worldTransform = await controller +// .getWorldTransform(boneEntity); +// var inverseWorldTransform = Matrix4.identity() +// ..copyInverse(worldTransform); +// print("Local $localTransform"); +// print("World $worldTransform"); +// print("World inverse $inverseWorldTransform"); +// }), +// MenuItemButton( +// child: Text("Set bone transform to identity"), +// onPressed: () async { +// var boneEntity = +// await controller.getBone(entity, boneIndex); +// var localTransform = Matrix4.identity(); +// await controller.setTransform( +// boneEntity, localTransform); +// await controller.updateBoneMatrices(entity); +// }), +// MenuItemButton( +// child: Text( +// "Set bone transform to 90/X (parent space)"), +// onPressed: () async { +// var boneEntity = +// await controller.getBone(entity, boneIndex); +// var localTransform = Matrix4.rotationX(pi / 2); +// await controller.setTransform( +// boneEntity, localTransform); +// await controller.updateBoneMatrices(entity); +// }), +// MenuItemButton( +// child: Text( +// "Set bone transform to 90/X (pose space)"), +// onPressed: () async { +// var boneEntity = +// await controller.getBone(entity, boneIndex); +// var localTransform = await controller +// .getLocalTransform(boneEntity); +// localTransform = +// localTransform * Matrix4.rotationX(pi / 2); +// await controller.setTransform( +// boneEntity, localTransform); +// await controller.updateBoneMatrices(entity); +// }), +// MenuItemButton( +// child: Text("Set bone transform to 90/X"), +// onPressed: () async { +// var boneEntity = +// await controller.getBone(entity, boneIndex); +// var localTransform = Matrix4.rotationX(pi / 2); +// await controller.setTransform( +// boneEntity, localTransform); +// await controller.updateBoneMatrices(entity); +// }), +// MenuItemButton( +// child: Text("Set bone transform to 0,-1,0"), +// onPressed: () async { +// var boneEntity = +// await controller.getBone(entity, boneIndex); +// var localTransform = +// Matrix4.translation(Vector3(0, -1, 0)); +// await controller.setTransform( +// boneEntity, localTransform); +// await controller.updateBoneMatrices(entity); +// }), +// MenuItemButton( +// child: Text( +// "Set bone matrices/transform to identity"), +// onPressed: () async { +// var boneEntity = await controller.getBone( +// entity, boneNames.indexOf(name)); +// await controller.setTransform( +// boneEntity, Matrix4.identity()); +// var childEntities = await controller +// .getChildEntities(entity, true); +// for (final child in childEntities) { +// await controller.setBoneTransform( +// child, +// boneNames.indexOf(name), +// Matrix4.identity()); +// } +// }), +// SubmenuButton( +// child: Text("Set bone matrices to"), +// menuChildren: [ +// MenuItemButton( +// child: Text("Identity"), +// onPressed: () async { +// await controller +// .removeAnimationComponent(entity); +// for (var child in await controller +// .getChildEntities(entity, true)) { +// print( +// "Setting transform for ${await controller.getNameForEntity(child)}"); +// await controller.setBoneTransform( +// child, +// boneNames.indexOf(name), +// Matrix4.identity()); +// } +// }), +// SubmenuButton( +// child: Text("Global"), +// menuChildren: ["90/X", "90/Y"] +// .map((rot) => MenuItemButton( +// onPressed: () async { +// var transform = rot == "90/X" +// ? Matrix4.rotationX(pi / 2) +// : Matrix4.rotationY(pi / 2); +// await controller +// .removeAnimationComponent( +// entity); - var index = - boneNames.indexOf(name); - var childEntities = - await controller - .getChildEntities( - entity, true); +// var index = +// boneNames.indexOf(name); +// var childEntities = +// await controller +// .getChildEntities( +// entity, true); - for (var child in childEntities) { - print( - "Setting transform for ${await controller.getNameForEntity(child)} / bone $name (index $index)"); - await controller - .setBoneTransform(child, - index, transform); - } - }, - child: Text(rot))) - .toList()), - SubmenuButton( - child: Text("Bone"), - menuChildren: ["90/X", "90/Y", "90/Z"] - .map((rot) => MenuItemButton( - onPressed: () async { - await controller - .removeAnimationComponent( - entity); - var index = - boneNames.indexOf(name); - var boneEntity = await controller - .getBone(entity, index); - var rotation = rot == "90/X" - ? Matrix4.rotationX(pi / 2) - : rot == "90/Y" - ? Matrix4.rotationY( - pi / 2) - : Matrix4.rotationZ( - pi / 2); +// for (var child in childEntities) { +// print( +// "Setting transform for ${await controller.getNameForEntity(child)} / bone $name (index $index)"); +// await controller +// .setBoneTransform(child, +// index, transform); +// } +// }, +// child: Text(rot))) +// .toList()), +// SubmenuButton( +// child: Text("Bone"), +// menuChildren: ["90/X", "90/Y", "90/Z"] +// .map((rot) => MenuItemButton( +// onPressed: () async { +// await controller +// .removeAnimationComponent( +// entity); +// var index = +// boneNames.indexOf(name); +// var boneEntity = await controller +// .getBone(entity, index); +// var rotation = rot == "90/X" +// ? Matrix4.rotationX(pi / 2) +// : rot == "90/Y" +// ? Matrix4.rotationY( +// pi / 2) +// : Matrix4.rotationZ( +// pi / 2); - var inverseBindMatrix = - await controller - .getInverseBindMatrix( - entity, index); - var bindMatrix = - Matrix4.identity(); - bindMatrix.copyInverse( - inverseBindMatrix); - var childEntities = - await controller - .getChildEntities( - entity, true); +// var inverseBindMatrix = +// await controller +// .getInverseBindMatrix( +// entity, index); +// var bindMatrix = +// Matrix4.identity(); +// bindMatrix.copyInverse( +// inverseBindMatrix); +// var childEntities = +// await controller +// .getChildEntities( +// entity, true); - for (var child in childEntities) { - var childGlobalTransform = - await controller - .getWorldTransform( - child); - var inverseGlobalTransform = - Matrix4.identity(); - inverseGlobalTransform - .copyInverse( - childGlobalTransform); - var globalBoneTransform = - childGlobalTransform * - bindMatrix; +// for (var child in childEntities) { +// var childGlobalTransform = +// await controller +// .getWorldTransform( +// child); +// var inverseGlobalTransform = +// Matrix4.identity(); +// inverseGlobalTransform +// .copyInverse( +// childGlobalTransform); +// var globalBoneTransform = +// childGlobalTransform * +// bindMatrix; - var transform = - (inverseGlobalTransform * - (globalBoneTransform * - rotation)) * - inverseBindMatrix; - await controller - .setBoneTransform(child, - index, transform); - } - }, - child: Text(rot))) - .toList()), - ]), - MenuItemButton( - onPressed: () => _addBoneAnimation(name), - child: Text( - "Test animation (90 degreees around pose Y)")), - ]); - }) - .cast() - .toList(), - child: Text("Skeleton")); - }); - } -} +// var transform = +// (inverseGlobalTransform * +// (globalBoneTransform * +// rotation)) * +// inverseBindMatrix; +// await controller +// .setBoneTransform(child, +// index, transform); +// } +// }, +// child: Text(rot))) +// .toList()), +// ]), +// MenuItemButton( +// onPressed: () => _addBoneAnimation(name), +// child: Text( +// "Test animation (90 degreees around pose Y)")), +// ]); +// }) +// .cast() +// .toList(), +// child: Text("Skeleton")); +// }); +// } +// } - // MenuItemButton( - // onPressed: () async { - // var frames = >[]; - // for (int i = 0; i < 60; i++) { - // var frame = []; - // frame.add(( - // rotation: Quaternion.axisAngle( - // Vector3(0, 0, 1), (i / 60) * pi / 2), - // translation: Vector3.zero() - // )); - // frame.add(( - // rotation: Quaternion.identity(), - // translation: Vector3.zero() - // )); - // frame.add(( - // rotation: Quaternion.identity(), - // translation: Vector3.zero() - // )); - // frames.add(frame); - // } - // for (int i = 0; i < 60; i++) { - // var frame = []; - // frame.add(( - // rotation: Quaternion.axisAngle( - // Vector3(0, 0, 1), pi / 2), - // translation: Vector3.zero() - // )); - // frame.add(( - // rotation: Quaternion.axisAngle( - // Vector3(1, 0, 0), i / 60 * (-pi / 2)), - // translation: Vector3.zero() - // )); - // frame.add(( - // rotation: Quaternion.identity(), - // translation: Vector3.zero() - // )); - // frames.add(frame); - // } - // for (int i = 0; i < 60; i++) { - // var frame = []; - // frame.add(( - // rotation: Quaternion.axisAngle( - // Vector3(0, 0, 1), pi / 2), - // translation: Vector3.zero() - // )); - // frame.add(( - // rotation: Quaternion.axisAngle( - // Vector3(1, 0, 0), (-pi / 2)), - // translation: Vector3.zero() - // )); - // frame.add(( - // rotation: Quaternion.axisAngle( - // Vector3(1, 0, 0), i / 60 * (pi / 2)), - // translation: Vector3.zero() - // )); - // frames.add(frame); - // } +// // MenuItemButton( +// // onPressed: () async { +// // var frames = >[]; +// // for (int i = 0; i < 60; i++) { +// // var frame = []; +// // frame.add(( +// // rotation: Quaternion.axisAngle( +// // Vector3(0, 0, 1), (i / 60) * pi / 2), +// // translation: Vector3.zero() +// // )); +// // frame.add(( +// // rotation: Quaternion.identity(), +// // translation: Vector3.zero() +// // )); +// // frame.add(( +// // rotation: Quaternion.identity(), +// // translation: Vector3.zero() +// // )); +// // frames.add(frame); +// // } +// // for (int i = 0; i < 60; i++) { +// // var frame = []; +// // frame.add(( +// // rotation: Quaternion.axisAngle( +// // Vector3(0, 0, 1), pi / 2), +// // translation: Vector3.zero() +// // )); +// // frame.add(( +// // rotation: Quaternion.axisAngle( +// // Vector3(1, 0, 0), i / 60 * (-pi / 2)), +// // translation: Vector3.zero() +// // )); +// // frame.add(( +// // rotation: Quaternion.identity(), +// // translation: Vector3.zero() +// // )); +// // frames.add(frame); +// // } +// // for (int i = 0; i < 60; i++) { +// // var frame = []; +// // frame.add(( +// // rotation: Quaternion.axisAngle( +// // Vector3(0, 0, 1), pi / 2), +// // translation: Vector3.zero() +// // )); +// // frame.add(( +// // rotation: Quaternion.axisAngle( +// // Vector3(1, 0, 0), (-pi / 2)), +// // translation: Vector3.zero() +// // )); +// // frame.add(( +// // rotation: Quaternion.axisAngle( +// // Vector3(1, 0, 0), i / 60 * (pi / 2)), +// // translation: Vector3.zero() +// // )); +// // frames.add(frame); +// // } - // var animation = BoneAnimationData( - // ["Bone", "Bone.001", "Bone.002"], frames); - // await controller.addAnimationComponent(entity); - // await controller.addBoneAnimation(entity, animation); - // }, - // child: Text("Test animation (pose space)")), \ No newline at end of file +// // var animation = BoneAnimationData( +// // ["Bone", "Bone.001", "Bone.002"], frames); +// // await controller.addAnimationComponent(entity); +// // await controller.addBoneAnimation(entity, animation); +// // }, +// // child: Text("Test animation (pose space)")), \ No newline at end of file diff --git a/thermion_flutter/thermion_flutter/lib/src/widgets/src/thermion_texture_widget.dart b/thermion_flutter/thermion_flutter/lib/src/widgets/src/thermion_texture_widget.dart index 821dbc55..f334b997 100644 --- a/thermion_flutter/thermion_flutter/lib/src/widgets/src/thermion_texture_widget.dart +++ b/thermion_flutter/thermion_flutter/lib/src/widgets/src/thermion_texture_widget.dart @@ -174,6 +174,7 @@ class _ThermionTextureWidgetState extends State { } WidgetsBinding.instance.scheduleFrameCallback((d) async { + if (!mounted) { return; } @@ -241,7 +242,7 @@ class _ThermionTextureWidgetState extends State { _logger.info( "Resized texture to dimensions ${_texture!.width}x${_texture!.height} (pixel ratio : $dpr)"); - await widget.viewer.view.setViewport(_texture!.width, _texture!.height); + await widget.viewer.setViewport(_texture!.width, _texture!.height); await widget.onResize?.call( Size(_texture!.width.toDouble(), _texture!.height.toDouble()), diff --git a/thermion_flutter/thermion_flutter/macos/Classes/ThermionFlutterTexture.swift b/thermion_flutter/thermion_flutter/macos/Classes/ThermionFlutterTexture.swift index 1ea78a3c..6583344c 100644 --- a/thermion_flutter/thermion_flutter/macos/Classes/ThermionFlutterTexture.swift +++ b/thermion_flutter/thermion_flutter/macos/Classes/ThermionFlutterTexture.swift @@ -11,6 +11,10 @@ public class ThermionFlutterTexture : NSObject, FlutterTexture { init(registry:FlutterTextureRegistry, width:Int64, height:Int64) { self.registry = registry self.texture = ThermionTextureSwift(width:width, height: height, isDepth: false) + // if you need to debug + // self.texture.fillColor() + // let imageURL = URL(fileURLWithPath: "/Users/nickfisher/Documents/thermion/thermion_dart/test/assets/cube_texture_512x512.png") + // let success = self.texture.fillWithPNGImage(imageURL: imageURL) super.init() self.flutterTextureId = registry.register(self) } diff --git a/thermion_flutter/thermion_flutter/macos/Classes/ThermionTexture.swift b/thermion_flutter/thermion_flutter/macos/Classes/ThermionTexture.swift new file mode 120000 index 00000000..061bbc70 --- /dev/null +++ b/thermion_flutter/thermion_flutter/macos/Classes/ThermionTexture.swift @@ -0,0 +1 @@ +../../../..//thermion_dart/native/macos/ThermionTexture.swift \ No newline at end of file diff --git a/thermion_flutter/thermion_flutter_method_channel/lib/src/thermion_flutter_method_channel_platform.dart b/thermion_flutter/thermion_flutter_method_channel/lib/src/thermion_flutter_method_channel_platform.dart index f0963216..8e94b61e 100644 --- a/thermion_flutter/thermion_flutter_method_channel/lib/src/thermion_flutter_method_channel_platform.dart +++ b/thermion_flutter/thermion_flutter_method_channel/lib/src/thermion_flutter_method_channel_platform.dart @@ -18,7 +18,7 @@ import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dar /// class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform { final channel = const MethodChannel("dev.thermion.flutter/event"); - + late final _logger = Logger(this.runtimeType.toString()); static SwapChain? _swapChain; @@ -37,9 +37,10 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform { return File(path.replaceAll("file://", "")).readAsBytesSync(); } if (path.startsWith("asset://")) { - throw UnimplementedError(); + path = path.replaceAll("asset://", ""); } - throw UnimplementedError(); + var asset = await rootBundle.load(path); + return asset.buffer.asUint8List(asset.offsetInBytes); } Future createViewer({ThermionFlutterOptions? options}) async { @@ -92,18 +93,19 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform { throw Exception("Unsupported platform"); } } + final config = FFIFilamentConfig( backend: backend, - resourceLoader: resourceLoader, + resourceLoader: loadAsset, driver: driverPtr, platform: nullptr, sharedContext: sharedContextPtr, uberArchivePath: options?.uberarchivePath); - await FFIFilamentApp.create(config); + await FFIFilamentApp.create(config: config); final viewer = ThermionViewerFFI( - loadAsset: loadAsset, + loadAssetFromUri: loadAsset, ); await viewer.initialized; @@ -117,9 +119,10 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform { // avoid this if (Platform.isMacOS || Platform.isIOS) { _swapChain = await FilamentApp.instance!.createHeadlessSwapChain(1, 1); + await FilamentApp.instance!.register(_swapChain!, viewer.view); } - return viewer!; + return viewer; } Future createTextureDescriptor( @@ -157,27 +160,36 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform { _swapChain = await FilamentApp.instance! .createHeadlessSwapChain(descriptor.width, descriptor.height); + await FilamentApp.instance!.register(_swapChain!, view); } else if (Platform.isAndroid) { if (_swapChain != null) { await FilamentApp.instance!.setRenderable(view, false); await FilamentApp.instance!.destroySwapChain(_swapChain!); } - _swapChain = await FilamentApp.instance!.createSwapChain(descriptor.windowHandle!); + _swapChain = + await FilamentApp.instance!.createSwapChain(descriptor.windowHandle!); + await FilamentApp.instance!.register(_swapChain!, view); + } else { - final color = await FilamentApp.instance!.createTexture( - descriptor.width, descriptor.height, - importedTextureHandle: descriptor.hardwareId, - flags: { - TextureUsage.TEXTURE_USAGE_BLIT_DST, - TextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT, - TextureUsage.TEXTURE_USAGE_SAMPLEABLE - }); - final depth = - await FilamentApp.instance!.createTexture(descriptor.width, descriptor.height, flags: { - TextureUsage.TEXTURE_USAGE_BLIT_DST, - TextureUsage.TEXTURE_USAGE_DEPTH_ATTACHMENT, - TextureUsage.TEXTURE_USAGE_SAMPLEABLE - }); + final color = await FilamentApp.instance! + .createTexture(descriptor.width, descriptor.height, + importedTextureHandle: descriptor.hardwareId, + flags: { + // TextureUsage.TEXTURE_USAGE_BLIT_DST, + TextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT, + TextureUsage.TEXTURE_USAGE_SAMPLEABLE + }, + textureFormat: TextureFormat.RGBA8, + textureSamplerType: TextureSamplerType.SAMPLER_2D); + final depth = await FilamentApp.instance! + .createTexture(descriptor.width, descriptor.height, + flags: { + // TextureUsage.TEXTURE_USAGE_BLIT_DST, + TextureUsage.TEXTURE_USAGE_DEPTH_ATTACHMENT, + TextureUsage.TEXTURE_USAGE_SAMPLEABLE, + }, + textureFormat: TextureFormat.DEPTH32F, + textureSamplerType: TextureSamplerType.SAMPLER_2D); var renderTarget = await FilamentApp.instance!.createRenderTarget( descriptor.width, descriptor.height, @@ -185,7 +197,6 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform { await view.setRenderTarget(renderTarget); } - await FilamentApp.instance!.register(_swapChain!, view); return descriptor; } diff --git a/thermion_flutter/thermion_flutter_platform_interface/lib/thermion_flutter_platform_interface.dart b/thermion_flutter/thermion_flutter_platform_interface/lib/thermion_flutter_platform_interface.dart index 32767ef7..05fc3a16 100644 --- a/thermion_flutter/thermion_flutter_platform_interface/lib/thermion_flutter_platform_interface.dart +++ b/thermion_flutter/thermion_flutter_platform_interface/lib/thermion_flutter_platform_interface.dart @@ -1,19 +1,17 @@ import 'dart:async'; -import 'package:thermion_dart/thermion_dart.dart' as t; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:thermion_dart/thermion_dart.dart'; +import 'package:thermion_dart/src/filament/filament.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'thermion_flutter_texture.dart'; class ThermionFlutterOptions { final String? uberarchivePath; + final Backend? backend; - ThermionFlutterOptions({this.uberarchivePath}); - const ThermionFlutterOptions.empty() : uberarchivePath = null; + const ThermionFlutterOptions({this.uberarchivePath = null, this.backend = null}); } - - abstract class ThermionFlutterPlatform extends PlatformInterface { ThermionFlutterPlatform() : super(token: _token); @@ -34,12 +32,13 @@ abstract class ThermionFlutterPlatform extends PlatformInterface { {covariant ThermionFlutterOptions? options}); /// - /// Creates a raw rendering surface. + /// Creates a raw rendering surface. /// /// This is internal; unless you are [thermion_*] package developer, don't /// call this yourself. May not be supported on all platforms. /// - Future createTextureDescriptor(int width, int height); + Future createTextureDescriptor( + int width, int height); /// /// Destroys a raw rendering surface. @@ -53,15 +52,14 @@ abstract class ThermionFlutterPlatform extends PlatformInterface { /// call this yourself. May not be supported on all platforms. /// Future createTextureAndBindToView( - t.View view, int width, int height); + View view, int width, int height); /// /// /// /// Future resizeTexture( - PlatformTextureDescriptor texture, t.View view, int width, int height); - + PlatformTextureDescriptor texture, View view, int width, int height); /// /// diff --git a/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web.dart b/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web.dart index 28931a93..e4ce6265 100644 --- a/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web.dart +++ b/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web.dart @@ -31,7 +31,7 @@ class ThermionFlutterWebPlugin extends ThermionFlutterPlatform { (offsetTop * pixelRatio).ceil().toString(); _viewer! - .updateViewportAndCameraProjection(width.ceil(), height.ceil(), 1.0); + .setViewportAndCameraProjection(width.ceil(), height.ceil(), 1.0); return PlatformTextureDescriptor(null, null, 0, 0, null); } @@ -53,7 +53,7 @@ class ThermionFlutterWebPlugin extends ThermionFlutterPlatform { (offsetLeft * pixelRatio).ceil().toString(); (canvas as HTMLElement).style.top = (offsetTop * pixelRatio).ceil().toString(); - _viewer!.updateViewportAndCameraProjection(width, height, 1.0); + _viewer!.setViewportAndCameraProjection(width, height, 1.0); return PlatformTextureDescriptor(null, null, 0, 0, null); } diff --git a/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web_options.dart b/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web_options.dart index ade9f7d0..9e794ac5 100644 --- a/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web_options.dart +++ b/thermion_flutter/thermion_flutter_web/lib/thermion_flutter_web_options.dart @@ -11,9 +11,5 @@ class ThermionFlutterWebOptions extends ThermionFlutterOptions { String? uberarchivePath}) : super(uberarchivePath: uberarchivePath); - const ThermionFlutterWebOptions.empty( - {this.importCanvasAsWidget = false, - this.createCanvas = true, - String? uberarchivePath}) - : super.empty(); + }