diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_render_target.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_render_target.dart index d1b5ec7b..28d69723 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_render_target.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_render_target.dart @@ -16,4 +16,10 @@ class FFIRenderTarget extends RenderTarget { final ptr = RenderTarget_getColorTexture(renderTarget); return FFITexture(engine, ptr); } + + @override + Future getDepthTexture() async { + final ptr = RenderTarget_getDepthTexture(renderTarget); + return FFITexture(engine, ptr); + } } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_texture.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_texture.dart index 5dbba1c5..d205f82f 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_texture.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_texture.dart @@ -9,18 +9,18 @@ class FFITexture extends Texture { FFITexture(this._engine, this.pointer); - Future setLinearImage(covariant FFILinearImage image, PixelDataFormat format, - PixelDataType type) async { + Future setLinearImage(covariant FFILinearImage image, + PixelDataFormat format, PixelDataType type) async { final result = await withBoolCallback((cb) { Texture_loadImageRenderThread( - _engine, - pointer, - image.pointer, - TPixelDataFormat.values[format.index], - TPixelDataType.values[type.index], - cb); + _engine, + pointer, + image.pointer, + format.index, + type.index, + cb); }); - + if (!result) { throw Exception("Failed to set linear image"); } @@ -40,9 +40,8 @@ class FFITexture extends Texture { } @override - Future getDepth([int level = 0]) { - // TODO: implement getDepth - throw UnimplementedError(); + Future getDepth([int level = 0]) async { + return Texture_getDepth(pointer, level); } @override @@ -52,9 +51,8 @@ class FFITexture extends Texture { } @override - Future getHeight([int level = 0]) { - // TODO: implement getHeight - throw UnimplementedError(); + Future getHeight([int level = 0]) async { + return Texture_getHeight(pointer, level); } @override @@ -70,9 +68,8 @@ class FFITexture extends Texture { } @override - Future getWidth([int level = 0]) { - // TODO: implement getWidth - throw UnimplementedError(); + Future getWidth([int level = 0]) async { + return Texture_getWidth(pointer, level); } @override @@ -86,19 +83,19 @@ class FFITexture extends Texture { int channels, PixelDataFormat format, PixelDataType type) async { final success = await withBoolCallback((cb) { Texture_setImageRenderThread( - _engine, - pointer, - level, - buffer.address, - buffer.lengthInBytes, - width, - height, - channels, - format.index, - type.index, - cb); + _engine, + pointer, + level, + buffer.address, + buffer.lengthInBytes, + width, + height, + channels, + format.index, + type.index, + cb); }); - + if (!success) { throw Exception("Failed to set image"); } @@ -118,32 +115,39 @@ class FFITexture extends Texture { PixelDataFormat format, PixelDataType type) async { final success = await withBoolCallback((cb) { - Texture_setImageWithDepthRenderThread( - _engine, - pointer, - level, - buffer.address, - buffer.lengthInBytes, - 0, - 0, - zOffset, - width, - height, - channels, - depth, - format.index, - type.index, - cb); + Texture_setImageWithDepthRenderThread( + _engine, + pointer, + level, + buffer.address, + buffer.lengthInBytes, + 0, + 0, + zOffset, + width, + height, + channels, + depth, + format.index, + type.index, + cb); }); - + if (!success) { throw Exception("Failed to set image"); } } @override - Future setSubImage(int level, int xOffset, int yOffset, int width, int height, - Uint8List buffer, PixelDataFormat format, PixelDataType type) { + Future setSubImage( + int level, + int xOffset, + int yOffset, + int width, + int height, + Uint8List buffer, + PixelDataFormat format, + PixelDataType type) { // TODO: implement setSubImage throw UnimplementedError(); } @@ -154,22 +158,25 @@ class FFILinearImage extends LinearImage { FFILinearImage(this.pointer); - static Future createEmpty(int width, int height, int channels) async { + static Future createEmpty( + int width, int height, int channels) async { final imagePtr = await withPointerCallback((cb) { Image_createEmptyRenderThread(width, height, channels, cb); }); - + return FFILinearImage(imagePtr); } - - static Future decode(Uint8List data, [String name = "image"]) async { + + static Future decode(Uint8List data, + [String name = "image"]) async { final namePtr = name.toNativeUtf8(); - + try { final imagePtr = await withPointerCallback((cb) { - Image_decodeRenderThread(data.address, data.lengthInBytes, namePtr.cast(), cb); + Image_decodeRenderThread( + data.address, data.lengthInBytes, namePtr.cast(), cb); }); - + return FFILinearImage(imagePtr); } finally { calloc.free(namePtr); @@ -208,11 +215,11 @@ class FFILinearImage extends LinearImage { final height = await getHeight(); final width = await getWidth(); final channels = await getChannels(); - + final ptr = await withPointerCallback((cb) { Image_getBytesRenderThread(pointer, cb); }); - + return ptr.asTypedList(height * width * channels); } } @@ -228,7 +235,7 @@ class FFITextureSampler extends TextureSampler { final samplerPtr = await withPointerCallback((cb) { TextureSampler_createRenderThread(cb); }); - + return FFITextureSampler(samplerPtr); } @@ -247,7 +254,7 @@ class FFITextureSampler extends TextureSampler { // TSamplerWrapMode.values[wrapR.index], // cb); // }); - + // return FFITextureSampler(samplerPtr); // } @@ -260,15 +267,15 @@ class FFITextureSampler extends TextureSampler { // TTextureSamplerCompareFunc.values[compareFunc.index], // cb); // }); - + // return FFITextureSampler(samplerPtr); // } // Future setMinFilter(SamplerMinFilter filter) async { // await withVoidCallback((cb) { // TextureSampler_setMinFilterRenderThread( - // pointer, - // TSamplerMinFilter.values[filter.index], + // pointer, + // TSamplerMinFilter.values[filter.index], // cb); // }); // } @@ -276,8 +283,8 @@ class FFITextureSampler extends TextureSampler { // Future setMagFilter(SamplerMagFilter filter) async { // await withVoidCallback((cb) { // TextureSampler_setMagFilterRenderThread( - // pointer, - // TSamplerMagFilter.values[filter.index], + // pointer, + // TSamplerMagFilter.values[filter.index], // cb); // }); // } @@ -285,8 +292,8 @@ class FFITextureSampler extends TextureSampler { // Future setWrapModeS(SamplerWrapMode mode) async { // await withVoidCallback((cb) { // TextureSampler_setWrapModeSRenderThread( - // pointer, - // TSamplerWrapMode.values[mode.index], + // pointer, + // TSamplerWrapMode.values[mode.index], // cb); // }); // } @@ -294,8 +301,8 @@ class FFITextureSampler extends TextureSampler { // Future setWrapModeT(SamplerWrapMode mode) async { // await withVoidCallback((cb) { // TextureSampler_setWrapModeTRenderThread( - // pointer, - // TSamplerWrapMode.values[mode.index], + // pointer, + // TSamplerWrapMode.values[mode.index], // cb); // }); // } @@ -303,8 +310,8 @@ class FFITextureSampler extends TextureSampler { // Future setWrapModeR(SamplerWrapMode mode) async { // await withVoidCallback((cb) { // TextureSampler_setWrapModeRRenderThread( - // pointer, - // TSamplerWrapMode.values[mode.index], + // pointer, + // TSamplerWrapMode.values[mode.index], // cb); // }); // } @@ -325,11 +332,11 @@ class FFITextureSampler extends TextureSampler { // cb); // }); // } - + @override Future dispose() async { await withVoidCallback((cb) { TextureSampler_destroyRenderThread(pointer, cb); }); } -} \ No newline at end of file +} 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 dcac8fdc..55d142e8 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 @@ -1,5 +1,6 @@ import 'dart:ffi'; import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart'; import 'package:thermion_dart/src/viewer/src/shared_types/shared_types.dart'; import 'callbacks.dart'; @@ -24,8 +25,8 @@ class FFIView extends View { } @override - Future updateViewport(int width, int height) async { - View_updateViewport(view, width, height); + Future setViewport(int width, int height) async { + View_setViewport(view, width, height); } Future getRenderTarget() async { 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 19315ca5..c178c87c 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 @@ -7,6 +7,18 @@ library; import 'dart:ffi' as ffi; +@ffi.Native() +external int TSWAP_CHAIN_CONFIG_TRANSPARENT; + +@ffi.Native() +external int TSWAP_CHAIN_CONFIG_READABLE; + +@ffi.Native() +external int TSWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER; + +@ffi.Native() +external int TSWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER; + @ffi.Native Function(ffi.Pointer)>( isLeaf: true) external ffi.Pointer Material_createInstance( @@ -387,6 +399,11 @@ external ffi.Pointer Viewer_create( ffi.Pointer uberArchivePath, ); +@ffi.Native Function(ffi.Pointer)>(isLeaf: true) +external ffi.Pointer Viewer_getRenderer( + ffi.Pointer tViewer, +); + @ffi.Native)>(isLeaf: true) external void Viewer_destroy( ffi.Pointer viewer, @@ -399,11 +416,12 @@ external ffi.Pointer Viewer_getSceneManager( ); @ffi.Native< - ffi.Pointer Function( - ffi.Pointer, ffi.IntPtr, ffi.Uint32, ffi.Uint32)>(isLeaf: true) + ffi.Pointer Function(ffi.Pointer, ffi.IntPtr, + ffi.IntPtr, ffi.Uint32, ffi.Uint32)>(isLeaf: true) external ffi.Pointer Viewer_createRenderTarget( ffi.Pointer viewer, - int texture, + int colorTextureId, + int depthTextureId, int width, int height, ); @@ -451,12 +469,14 @@ external void Viewer_render( ffi.Pointer, ffi.Pointer, ffi.Pointer, + ffi.Bool, ffi.Pointer>)>(isLeaf: true) external void Viewer_capture( ffi.Pointer viewer, ffi.Pointer view, ffi.Pointer swapChain, ffi.Pointer pixelBuffer, + bool useFence, ffi.Pointer> callback, ); @@ -467,6 +487,7 @@ external void Viewer_capture( ffi.Pointer, ffi.Pointer, ffi.Pointer, + ffi.Bool, ffi.Pointer>)>(isLeaf: true) external void Viewer_captureRenderTarget( ffi.Pointer viewer, @@ -474,6 +495,7 @@ external void Viewer_captureRenderTarget( ffi.Pointer swapChain, ffi.Pointer renderTarget, ffi.Pointer pixelBuffer, + bool useFence, ffi.Pointer> callback, ); @@ -707,7 +729,7 @@ external TViewport View_getViewport( @ffi.Native, ffi.Uint32, ffi.Uint32)>( isLeaf: true) -external void View_updateViewport( +external void View_setViewport( ffi.Pointer view, int width, int height, @@ -859,6 +881,13 @@ external bool View_isDitheringEnabled( ffi.Pointer tView, ); +@ffi.Native, ffi.Pointer)>( + isLeaf: true) +external void View_setScene( + ffi.Pointer tView, + ffi.Pointer tScene, +); + @ffi.Native< ffi.Void Function(ffi.Pointer, ffi.Uint32, ffi.Uint32, ffi.Uint32, PickCallback)>(isLeaf: true) @@ -884,8 +913,8 @@ external ffi.Pointer NameComponentManager_getName( ffi.Pointer, ffi.Pointer, ffi.UnsignedInt, - ffi.UnsignedInt)>(symbol: "Texture_loadImage", isLeaf: true) -external bool _Texture_loadImage( + ffi.UnsignedInt)>(isLeaf: true) +external bool Texture_loadImage( ffi.Pointer tEngine, ffi.Pointer tTexture, ffi.Pointer tImage, @@ -893,21 +922,6 @@ external bool _Texture_loadImage( int pixelDataType, ); -bool Texture_loadImage( - ffi.Pointer tEngine, - ffi.Pointer tTexture, - ffi.Pointer tImage, - TPixelDataFormat bufferFormat, - TPixelDataType pixelDataType, -) => - _Texture_loadImage( - tEngine, - tTexture, - tImage, - bufferFormat.value, - pixelDataType.value, - ); - @ffi.Native< ffi.Bool Function( ffi.Pointer, @@ -966,6 +980,27 @@ external bool Texture_setImageWithDepth( int pixelDataType, ); +@ffi.Native, ffi.Uint32)>( + isLeaf: true) +external int Texture_getWidth( + ffi.Pointer tTexture, + int level, +); + +@ffi.Native, ffi.Uint32)>( + isLeaf: true) +external int Texture_getHeight( + ffi.Pointer tTexture, + int level, +); + +@ffi.Native, ffi.Uint32)>( + isLeaf: true) +external int Texture_getDepth( + ffi.Pointer tTexture, + int level, +); + @ffi.Native< ffi.Pointer Function( ffi.Uint32, ffi.Uint32, ffi.Uint32)>(isLeaf: true) @@ -1016,6 +1051,12 @@ external ffi.Pointer RenderTarget_getColorTexture( ffi.Pointer tRenderTarget, ); +@ffi.Native Function(ffi.Pointer)>( + isLeaf: true) +external ffi.Pointer RenderTarget_getDepthTexture( + ffi.Pointer tRenderTarget, +); + @ffi.Native Function()>(isLeaf: true) external ffi.Pointer TextureSampler_create(); @@ -1215,6 +1256,19 @@ external ffi.Pointer MaterialProvider_createMaterialInstance( ffi.Pointer key, ); +@ffi.Native, EntityId)>(isLeaf: true) +external void Scene_addEntity( + ffi.Pointer tScene, + int entityId, +); + +@ffi.Native, ffi.Pointer)>( + isLeaf: true) +external void Scene_setSkybox( + ffi.Pointer tScene, + ffi.Pointer skybox, +); + @ffi.Native< ffi.Void Function( ffi.Pointer, ffi.Float, ffi.Float, ffi.Float)>(isLeaf: true) @@ -1231,13 +1285,6 @@ external void set_camera_model_matrix( double4x4 matrix, ); -@ffi.Native Function(ffi.Pointer, EntityId)>( - isLeaf: true) -external ffi.Pointer get_camera( - ffi.Pointer viewer, - int entity, -); - @ffi.Native)>(isLeaf: true) external double4x4 get_camera_model_matrix( ffi.Pointer camera, @@ -1316,6 +1363,15 @@ external double4x4 Camera_getModelMatrix( ffi.Pointer camera, ); +@ffi.Native, double3, double3, double3)>( + isLeaf: true) +external void Camera_lookAt( + ffi.Pointer camera, + double3 eye, + double3 focus, + double3 up, +); + @ffi.Native)>(isLeaf: true) external double get_camera_near( ffi.Pointer camera, @@ -1466,6 +1522,65 @@ external int TransformManager_getAncestor( int childEntityId, ); +@ffi.Native< + ffi.Void Function(ffi.Pointer, ffi.Double, ffi.Double, + ffi.Double, ffi.Double, ffi.Uint8, ffi.Bool, ffi.Bool)>(isLeaf: true) +external void Renderer_setClearOptions( + ffi.Pointer tRenderer, + double clearR, + double clearG, + double clearB, + double clearA, + int clearStencil, + bool clear, + bool discard, +); + +@ffi.Native< + ffi.Bool Function(ffi.Pointer, ffi.Pointer, + ffi.Uint64)>(isLeaf: true) +external bool Renderer_beginFrame( + ffi.Pointer tRenderer, + ffi.Pointer tSwapChain, + int frameTimeInNanos, +); + +@ffi.Native)>(isLeaf: true) +external void Renderer_endFrame( + ffi.Pointer tRenderer, +); + +@ffi.Native, ffi.Pointer)>( + isLeaf: true) +external void Renderer_render( + ffi.Pointer tRenderer, + ffi.Pointer tView, +); + +@ffi.Native, ffi.Pointer)>( + isLeaf: true) +external void Renderer_renderStandaloneView( + ffi.Pointer tRenderer, + ffi.Pointer tView, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Int, + ffi.Int, + ffi.Pointer)>(isLeaf: true) +external void Renderer_readPixels( + ffi.Pointer tRenderer, + ffi.Pointer tView, + ffi.Pointer tRenderTarget, + int tPixelBufferFormat, + int tPixelDataType, + ffi.Pointer out, +); + @ffi.Native(isLeaf: true) external void RenderLoop_create(); @@ -1500,6 +1615,19 @@ external void Viewer_createOnRenderThread( callback, ); +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer< + ffi + .NativeFunction tView)>>)>( + isLeaf: true) +external void Viewer_createViewRenderThread( + ffi.Pointer viewer, + ffi.Pointer tView)>> + onComplete, +); + @ffi.Native)>(isLeaf: true) external void Viewer_destroyOnRenderThread( ffi.Pointer viewer, @@ -1561,12 +1689,14 @@ external void Viewer_renderRenderThread( ffi.Pointer, ffi.Pointer, ffi.Pointer, + ffi.Bool, ffi.Pointer>)>(isLeaf: true) external void Viewer_captureRenderThread( ffi.Pointer viewer, ffi.Pointer view, ffi.Pointer swapChain, ffi.Pointer out, + bool useFence, ffi.Pointer> onComplete, ); @@ -1577,6 +1707,7 @@ external void Viewer_captureRenderThread( ffi.Pointer, ffi.Pointer, ffi.Pointer, + ffi.Bool, ffi.Pointer>)>(isLeaf: true) external void Viewer_captureRenderTargetRenderThread( ffi.Pointer viewer, @@ -1584,6 +1715,7 @@ external void Viewer_captureRenderTargetRenderThread( ffi.Pointer swapChain, ffi.Pointer renderTarget, ffi.Pointer out, + bool useFence, ffi.Pointer> onComplete, ); @@ -1617,6 +1749,7 @@ external void Viewer_removeIblRenderThread( ffi.Void Function( ffi.Pointer, ffi.IntPtr, + ffi.IntPtr, ffi.Uint32, ffi.Uint32, ffi.Pointer< @@ -1624,7 +1757,8 @@ external void Viewer_removeIblRenderThread( ffi.Void Function(ffi.Pointer)>>)>(isLeaf: true) external void Viewer_createRenderTargetRenderThread( ffi.Pointer viewer, - int texture, + int colorTexture, + int depthTexture, int width, int height, ffi.Pointer)>> @@ -1657,6 +1791,91 @@ external void Viewer_removeSkyboxRenderThread( ffi.Pointer> onComplete, ); +@ffi.Native< + ffi.Void Function( + ffi.Int, + ffi.Pointer< + ffi.NativeFunction)>>)>( + isLeaf: true) +external void Engine_createRenderThread( + int backend, + ffi.Pointer)>> + onComplete, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer< + ffi + .NativeFunction)>>)>( + isLeaf: true) +external void Engine_createRendererRenderThread( + ffi.Pointer tEngine, + ffi.Pointer)>> + onComplete, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Uint64, + ffi.Pointer< + ffi + .NativeFunction)>>)>( + isLeaf: true) +external void Engine_createSwapChainRenderThread( + ffi.Pointer tEngine, + ffi.Pointer window, + int flags, + ffi.Pointer)>> + onComplete, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Uint32, + ffi.Uint32, + ffi.Uint64, + ffi.Pointer< + ffi + .NativeFunction)>>)>( + isLeaf: true) +external void Engine_createHeadlessSwapChainRenderThread( + ffi.Pointer tEngine, + int width, + int height, + int flags, + ffi.Pointer)>> + onComplete, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction)>>)>( + isLeaf: true) +external void Engine_createCameraRenderThread( + ffi.Pointer tEngine, + ffi.Pointer)>> + onComplete, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction)>>)>( + isLeaf: true) +external void Engine_createViewRenderThread( + ffi.Pointer tEngine, + ffi.Pointer)>> + onComplete, +); + @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -1738,6 +1957,134 @@ external void Engine_destroyTextureRenderThread( ffi.Pointer> onComplete, ); +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction)>>)>( + isLeaf: true) +external void Engine_createFenceRenderThread( + ffi.Pointer tEngine, + ffi.Pointer)>> + onComplete, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void Engine_destroyFenceRenderThread( + ffi.Pointer tEngine, + ffi.Pointer tFence, + ffi.Pointer> onComplete, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void Engine_flushAndWaitRenderThead( + ffi.Pointer tEngine, + ffi.Pointer> onComplete, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Size, + ffi.Pointer< + ffi.NativeFunction)>>, + ffi.Pointer>)>(isLeaf: true) +external void Engine_buildSkyboxRenderThread( + ffi.Pointer tEngine, + ffi.Pointer skyboxData, + int length, + ffi.Pointer)>> + onComplete, + ffi.Pointer> onTextureUploadComplete, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Double, + ffi.Double, + ffi.Double, + ffi.Double, + ffi.Uint8, + ffi.Bool, + ffi.Bool, + ffi.Pointer>)>(isLeaf: true) +external void Renderer_setClearOptionsRenderThread( + ffi.Pointer tRenderer, + double clearR, + double clearG, + double clearB, + double clearA, + int clearStencil, + bool clear, + bool discard, + ffi.Pointer> onComplete, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Uint64, + ffi.Pointer>)>( + isLeaf: true) +external void Renderer_beginFrameRenderThread( + ffi.Pointer tRenderer, + ffi.Pointer tSwapChain, + int frameTimeInNanos, + ffi.Pointer> onComplete, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void Renderer_endFrameRenderThread( + ffi.Pointer tRenderer, + ffi.Pointer> onComplete, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void Renderer_renderRenderThread( + ffi.Pointer tRenderer, + ffi.Pointer tView, + ffi.Pointer> onComplete, +); + +@ffi.Native< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void Renderer_renderStandaloneViewRenderThread( + ffi.Pointer tRenderer, + ffi.Pointer tView, + ffi.Pointer> onComplete, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.UnsignedInt, + ffi.UnsignedInt, + ffi.Pointer, + ffi.Pointer>)>(isLeaf: true) +external void Renderer_readPixelsRenderThread( + ffi.Pointer tRenderer, + ffi.Pointer tView, + ffi.Pointer tRenderTarget, + int tPixelBufferFormat, + int tPixelDataType, + ffi.Pointer out, + ffi.Pointer> onComplete, +); + @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -2127,6 +2474,41 @@ external void SceneAsset_createInstanceRenderThread( callback, ); +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Uint32, + ffi.Pointer, + ffi.Uint32, + ffi.Pointer, + ffi.Uint32, + ffi.Pointer, + ffi.Uint32, + ffi.UnsignedInt, + ffi.Pointer>, + ffi.Int, + ffi.Pointer< + ffi + .NativeFunction)>>)>( + isLeaf: true) +external void SceneAsset_createGeometryRenderThread( + ffi.Pointer tEngine, + ffi.Pointer vertices, + int numVertices, + ffi.Pointer normals, + int numNormals, + ffi.Pointer uvs, + int numUvs, + ffi.Pointer indices, + int numIndices, + int tPrimitiveType, + ffi.Pointer> materialInstances, + int materialInstanceCount, + ffi.Pointer)>> + callback, +); + @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -2270,8 +2652,8 @@ external void Image_getChannelsRenderThread( ffi.UnsignedInt, ffi.UnsignedInt, ffi.Pointer>)>( - symbol: "Texture_loadImageRenderThread", isLeaf: true) -external void _Texture_loadImageRenderThread( + isLeaf: true) +external void Texture_loadImageRenderThread( ffi.Pointer tEngine, ffi.Pointer tTexture, ffi.Pointer tImage, @@ -2280,23 +2662,6 @@ external void _Texture_loadImageRenderThread( ffi.Pointer> onComplete, ); -void Texture_loadImageRenderThread( - ffi.Pointer tEngine, - ffi.Pointer tTexture, - ffi.Pointer tImage, - TPixelDataFormat bufferFormat, - TPixelDataType pixelDataType, - ffi.Pointer> onComplete, -) => - _Texture_loadImageRenderThread( - tEngine, - tTexture, - tImage, - bufferFormat.value, - pixelDataType.value, - onComplete, - ); - @ffi.Native< ffi.Void Function( ffi.Pointer, @@ -3065,6 +3430,53 @@ external bool RenderableManager_getFogEnabled( int entityId, ); +@ffi.Native Function(ffi.UnsignedInt)>( + symbol: "Engine_create", isLeaf: true) +external ffi.Pointer _Engine_create( + int backend, +); + +ffi.Pointer Engine_create( + TBackend backend, +) => + _Engine_create( + backend.value, + ); + +@ffi.Native Function(ffi.Pointer)>(isLeaf: true) +external ffi.Pointer Engine_createRenderer( + ffi.Pointer tEngine, +); + +@ffi.Native< + ffi.Pointer Function( + ffi.Pointer, ffi.Pointer, ffi.Uint64)>(isLeaf: true) +external ffi.Pointer Engine_createSwapChain( + ffi.Pointer tEngine, + ffi.Pointer window, + int flags, +); + +@ffi.Native< + ffi.Pointer Function( + ffi.Pointer, ffi.Uint32, ffi.Uint32, ffi.Uint64)>(isLeaf: true) +external ffi.Pointer Engine_createHeadlessSwapChain( + ffi.Pointer tEngine, + int width, + int height, + int flags, +); + +@ffi.Native Function(ffi.Pointer)>(isLeaf: true) +external ffi.Pointer Engine_createCamera( + ffi.Pointer tEngine, +); + +@ffi.Native Function(ffi.Pointer)>(isLeaf: true) +external ffi.Pointer Engine_createView( + ffi.Pointer tEngine, +); + @ffi.Native Function(ffi.Pointer, EntityId)>( isLeaf: true) external ffi.Pointer Engine_getCameraComponent( @@ -3141,6 +3553,23 @@ external void Engine_destroyTexture( ffi.Pointer tTexture, ); +@ffi.Native Function(ffi.Pointer)>(isLeaf: true) +external ffi.Pointer Engine_createFence( + ffi.Pointer tEngine, +); + +@ffi.Native, ffi.Pointer)>( + isLeaf: true) +external void Engine_destroyFence( + ffi.Pointer tEngine, + ffi.Pointer tFence, +); + +@ffi.Native)>(isLeaf: true) +external void Engine_flushAndWait( + ffi.Pointer tEngine, +); + @ffi.Native< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Size)>(isLeaf: true) @@ -3157,6 +3586,53 @@ external void Engine_destroyMaterial( ffi.Pointer tMaterial, ); +@ffi.Native Function(ffi.Pointer)>(isLeaf: true) +external ffi.Pointer Engine_createScene( + ffi.Pointer tEngine, +); + +@ffi.Native< + ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, + ffi.Size, + ffi.Pointer>)>(isLeaf: true) +external ffi.Pointer Engine_buildSkybox( + ffi.Pointer tEngine, + ffi.Pointer ktxData, + int length, + ffi.Pointer> onTextureUploadComplete, +); + +@ffi.Native< + ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, + ffi.Uint32, + ffi.Pointer, + ffi.Uint32, + ffi.Pointer, + ffi.Uint32, + ffi.Pointer, + ffi.Uint32, + ffi.UnsignedInt, + ffi.Pointer>, + ffi.Int)>(isLeaf: true) +external ffi.Pointer SceneAsset_createGeometry( + ffi.Pointer tEngine, + ffi.Pointer vertices, + int numVertices, + ffi.Pointer normals, + int numNormals, + ffi.Pointer uvs, + int numUvs, + ffi.Pointer indices, + int numIndices, + int tPrimitiveType, + ffi.Pointer> materialInstances, + int materialInstanceCount, +); + @ffi.Native, ffi.Pointer)>( isLeaf: true) external void SceneAsset_addToScene( @@ -3471,6 +3947,10 @@ final class TSceneManager extends ffi.Opaque {} final class TLightManager extends ffi.Opaque {} +final class TRenderer extends ffi.Opaque {} + +final class TFence extends ffi.Opaque {} + final class TRenderTarget extends ffi.Opaque {} final class TSwapChain extends ffi.Opaque {} @@ -3481,6 +3961,8 @@ final class TGizmo extends ffi.Opaque {} final class TScene extends ffi.Opaque {} +final class TSkybox extends ffi.Opaque {} + final class TTransformManager extends ffi.Opaque {} final class TAnimationManager extends ffi.Opaque {} @@ -3635,6 +4117,17 @@ final class UnnamedStruct2 extends ffi.Struct { external int specularGlossinessUV; } +final class double3 extends ffi.Struct { + @ffi.Double() + external double x; + + @ffi.Double() + external double y; + + @ffi.Double() + external double z; +} + final class double4 extends ffi.Struct { @ffi.Double() external double x; @@ -3711,6 +4204,23 @@ enum TGizmoType { }; } +abstract class TPrimitiveType { + /// !< points + static const PRIMITIVETYPE_POINTS = 0; + + /// !< lines + static const PRIMITIVETYPE_LINES = 1; + + /// !< line strip + static const PRIMITIVETYPE_LINE_STRIP = 3; + + /// !< triangles + static const PRIMITIVETYPE_TRIANGLES = 4; + + /// !< triangle strip + static const PRIMITIVETYPE_TRIANGLE_STRIP = 5; +} + enum TSamplerCompareFunc { /// !< Less or equal LE(0), @@ -4156,114 +4666,76 @@ enum TTextureFormat { } /// ! Pixel Data Format -enum TPixelDataFormat { +abstract class TPixelDataFormat { /// !< One Red channel, float - PIXELDATAFORMAT_R(0), + static const PIXELDATAFORMAT_R = 0; /// !< One Red channel, integer - PIXELDATAFORMAT_R_INTEGER(1), + static const PIXELDATAFORMAT_R_INTEGER = 1; /// !< Two Red and Green channels, float - PIXELDATAFORMAT_RG(2), + static const PIXELDATAFORMAT_RG = 2; /// !< Two Red and Green channels, integer - PIXELDATAFORMAT_RG_INTEGER(3), + static const PIXELDATAFORMAT_RG_INTEGER = 3; /// !< Three Red, Green and Blue channels, float - PIXELDATAFORMAT_RGB(4), + static const PIXELDATAFORMAT_RGB = 4; /// !< Three Red, Green and Blue channels, integer - PIXELDATAFORMAT_RGB_INTEGER(5), + static const PIXELDATAFORMAT_RGB_INTEGER = 5; /// !< Four Red, Green, Blue and Alpha channels, float - PIXELDATAFORMAT_RGBA(6), + static const PIXELDATAFORMAT_RGBA = 6; /// !< Four Red, Green, Blue and Alpha channels, integer - PIXELDATAFORMAT_RGBA_INTEGER(7), - PIXELDATAFORMAT_UNUSED(8), + static const PIXELDATAFORMAT_RGBA_INTEGER = 7; + static const PIXELDATAFORMAT_UNUSED = 8; /// !< Depth, 16-bit or 24-bits usually - PIXELDATAFORMAT_DEPTH_COMPONENT(9), + static const PIXELDATAFORMAT_DEPTH_COMPONENT = 9; /// !< Two Depth (24-bits) + Stencil (8-bits) channels - PIXELDATAFORMAT_DEPTH_STENCIL(10), - PIXELDATAFORMAT_ALPHA(11); - - final int value; - const TPixelDataFormat(this.value); - - static TPixelDataFormat fromValue(int value) => switch (value) { - 0 => PIXELDATAFORMAT_R, - 1 => PIXELDATAFORMAT_R_INTEGER, - 2 => PIXELDATAFORMAT_RG, - 3 => PIXELDATAFORMAT_RG_INTEGER, - 4 => PIXELDATAFORMAT_RGB, - 5 => PIXELDATAFORMAT_RGB_INTEGER, - 6 => PIXELDATAFORMAT_RGBA, - 7 => PIXELDATAFORMAT_RGBA_INTEGER, - 8 => PIXELDATAFORMAT_UNUSED, - 9 => PIXELDATAFORMAT_DEPTH_COMPONENT, - 10 => PIXELDATAFORMAT_DEPTH_STENCIL, - 11 => PIXELDATAFORMAT_ALPHA, - _ => throw ArgumentError("Unknown value for TPixelDataFormat: $value"), - }; + static const PIXELDATAFORMAT_DEPTH_STENCIL = 10; + static const PIXELDATAFORMAT_ALPHA = 11; } -enum TPixelDataType { +abstract class TPixelDataType { /// !< unsigned byte - PIXELDATATYPE_UBYTE(0), + static const PIXELDATATYPE_UBYTE = 0; /// !< signed byte - PIXELDATATYPE_BYTE(1), + static const PIXELDATATYPE_BYTE = 1; /// !< unsigned short (16-bit) - PIXELDATATYPE_USHORT(2), + static const PIXELDATATYPE_USHORT = 2; /// !< signed short (16-bit) - PIXELDATATYPE_SHORT(3), + static const PIXELDATATYPE_SHORT = 3; /// !< unsigned int (32-bit) - PIXELDATATYPE_UINT(4), + static const PIXELDATATYPE_UINT = 4; /// !< signed int (32-bit) - PIXELDATATYPE_INT(5), + static const PIXELDATATYPE_INT = 5; /// !< half-float (16-bit float) - PIXELDATATYPE_HALF(6), + static const PIXELDATATYPE_HALF = 6; /// !< float (32-bits float) - PIXELDATATYPE_FLOAT(7), + static const PIXELDATATYPE_FLOAT = 7; /// !< compressed pixels, @see CompressedPixelDataType - PIXELDATATYPE_COMPRESSED(8), + static const PIXELDATATYPE_COMPRESSED = 8; /// !< three low precision floating-point numbers - PIXELDATATYPE_UINT_10F_11F_11F_REV(9), + static const PIXELDATATYPE_UINT_10F_11F_11F_REV = 9; /// !< unsigned int (16-bit), encodes 3 RGB channels - PIXELDATATYPE_USHORT_565(10), + static const PIXELDATATYPE_USHORT_565 = 10; /// !< unsigned normalized 10 bits RGB, 2 bits alpha - PIXELDATATYPE_UINT_2_10_10_10_REV(11); - - final int value; - const TPixelDataType(this.value); - - static TPixelDataType fromValue(int value) => switch (value) { - 0 => PIXELDATATYPE_UBYTE, - 1 => PIXELDATATYPE_BYTE, - 2 => PIXELDATATYPE_USHORT, - 3 => PIXELDATATYPE_SHORT, - 4 => PIXELDATATYPE_UINT, - 5 => PIXELDATATYPE_INT, - 6 => PIXELDATATYPE_HALF, - 7 => PIXELDATATYPE_FLOAT, - 8 => PIXELDATATYPE_COMPRESSED, - 9 => PIXELDATATYPE_UINT_10F_11F_11F_REV, - 10 => PIXELDATATYPE_USHORT_565, - 11 => PIXELDATATYPE_UINT_2_10_10_10_REV, - _ => throw ArgumentError("Unknown value for TPixelDataType: $value"), - }; + static const PIXELDATATYPE_UINT_2_10_10_10_REV = 11; } enum TSamplerWrapMode { @@ -4398,6 +4870,35 @@ typedef FilamentRenderCallbackFunction = ffi.Void Function( typedef DartFilamentRenderCallbackFunction = void Function( ffi.Pointer owner); +enum TBackend { + /// !< Automatically selects an appropriate driver for the platform. + BACKEND_DEFAULT(0), + + /// !< Selects the OpenGL/ES driver (default on Android) + BACKEND_OPENGL(1), + + /// !< Selects the Vulkan driver if the platform supports it (default on Linux/Windows) + BACKEND_VULKAN(2), + + /// !< Selects the Metal driver if the platform supports it (default on MacOS/iOS). + BACKEND_METAL(3), + + /// !< Selects the no-op driver for testing purposes. + BACKEND_NOOP(4); + + final int value; + const TBackend(this.value); + + static TBackend fromValue(int value) => switch (value) { + 0 => BACKEND_DEFAULT, + 1 => BACKEND_OPENGL, + 2 => BACKEND_VULKAN, + 3 => BACKEND_METAL, + 4 => BACKEND_NOOP, + _ => throw ArgumentError("Unknown value for TBackend: $value"), + }; +} + final class ResourceBuffer extends ffi.Struct { external ffi.Pointer data; 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 7b7c3379..f1b78c6b 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 @@ -7,6 +7,7 @@ import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_gizmo.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart'; import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart'; import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart' as v64; @@ -18,6 +19,33 @@ import 'callbacks.dart'; import 'ffi_camera.dart'; import 'ffi_view.dart'; +class FFIBindings { + final Pointer sceneManager; + final Pointer engine; + final Pointer unlitMaterialProvider; + final Pointer ubershaderMaterialProvider; + final Pointer transformManager; + final Pointer lightManager; + final Pointer renderableManager; + final Pointer viewer; + final Pointer animationManager; + final Pointer nameComponentManager; + final Pointer renderer; + + FFIBindings( + {required this.renderer, + required this.sceneManager, + required this.engine, + required this.unlitMaterialProvider, + required this.ubershaderMaterialProvider, + required this.transformManager, + required this.lightManager, + required this.renderableManager, + required this.viewer, + required this.animationManager, + required this.nameComponentManager}); +} + // ignore: constant_identifier_names const ThermionEntity FILAMENT_ASSET_ERROR = 0; @@ -37,6 +65,7 @@ class ThermionViewerFFI extends ThermionViewer { Pointer? _animationManager; Pointer? _nameComponentManager; + late FFIBindings bindings; final String? uberArchivePath; final _initialized = Completer(); @@ -78,10 +107,11 @@ class ThermionViewerFFI extends ThermionViewer { /// /// Future createRenderTarget( - int width, int height, int textureHandle) async { + int width, int height, { int? colorTextureHandle, + int? depthTextureHandle}) async { final renderTarget = await withPointerCallback((cb) { - Viewer_createRenderTargetRenderThread( - _viewer!, textureHandle, width, height, cb); + Viewer_createRenderTargetRenderThread(_viewer!, colorTextureHandle ?? 0, + depthTextureHandle ?? 0, width, height, cb); }); return FFIRenderTarget(renderTarget, _viewer!, _engine!); @@ -107,7 +137,9 @@ class ThermionViewerFFI extends ThermionViewer { /// /// Future createView() async { - var view = Viewer_createView(_viewer!); + var view = await withPointerCallback((cb) { + Viewer_createViewRenderThread(_viewer!, cb); + }); if (view == nullptr) { throw Exception("Failed to create view"); } @@ -117,9 +149,9 @@ class ThermionViewerFFI extends ThermionViewer { /// /// /// - Future updateViewportAndCameraProjection(double width, double height) async { + Future setViewportAndCameraProjection(double width, double height) async { var mainView = FFIView(Viewer_getViewAt(_viewer!, 0), _viewer!, _engine!); - mainView.updateViewport(width.toInt(), height.toInt()); + mainView.setViewport(width.toInt(), height.toInt()); final cameraCount = await getCameraCount(); @@ -212,7 +244,18 @@ class ThermionViewerFFI extends ThermionViewer { _nameComponentManager = SceneManager_getNameComponentManager(_sceneManager!); _renderableManager = Engine_getRenderableManager(_engine!); - + bindings = FFIBindings( + sceneManager: _sceneManager!, + engine: _engine!, + unlitMaterialProvider: _unlitMaterialProvider!, + ubershaderMaterialProvider: _ubershaderMaterialProvider!, + transformManager: _transformManager!, + lightManager: _lightManager!, + renderableManager: _renderableManager!, + viewer: _viewer!, + animationManager: _animationManager!, + nameComponentManager: _nameComponentManager!, + renderer: Viewer_getRenderer(_viewer!)); this._initialized.complete(true); } @@ -249,27 +292,75 @@ class ThermionViewerFFI extends ThermionViewer { /// /// @override - Future capture( - {FFIView? view, - FFISwapChain? swapChain, - FFIRenderTarget? renderTarget}) async { - view ??= (await getViewAt(0)) as FFIView; - final vp = await view.getViewport(); - final length = vp.width * vp.height * 4; - final out = Uint8List(length); + Future> capture( + List<({View view, SwapChain? swapChain, RenderTarget? renderTarget})> + targets) async { + var renderer = Viewer_getRenderer(_viewer!); - swapChain ??= FFISwapChain(Viewer_getSwapChainAt(_viewer!, 0), _viewer!); + final fence = await withPointerCallback((cb) { + Engine_createFenceRenderThread(_engine!, cb); + }); + + var pixelBuffers = []; + + for (final entry in targets) { + final view = entry.view as FFIView; + var swapChain = entry.swapChain as FFISwapChain?; + final renderTarget = entry.renderTarget as FFIRenderTarget?; + final vp = await view.getViewport(); + final length = vp.width * vp.height * 4; + + await withBoolCallback((cb) { + Renderer_beginFrameRenderThread(renderer, + swapChain?.swapChain ?? Viewer_getSwapChainAt(_viewer!, 0), 0, cb); + }); + + await withVoidCallback((cb) { + Renderer_renderRenderThread(renderer, view.view, cb); + }); + final out = Uint8List(length); + await withVoidCallback((cb) { + Renderer_readPixelsRenderThread( + renderer, + view.view, + renderTarget!.renderTarget, + TPixelDataFormat.PIXELDATAFORMAT_RGBA, + TPixelDataType.PIXELDATATYPE_UBYTE, + out.address, + cb); + }); + + pixelBuffers.add(out); + } await withVoidCallback((cb) { - if (renderTarget != null) { - Viewer_captureRenderTargetRenderThread(_viewer!, view!.view, - swapChain!.swapChain, renderTarget.renderTarget, out.address, cb); - } else { - Viewer_captureRenderThread( - _viewer!, view!.view, swapChain!.swapChain, out.address, cb); - } + Renderer_endFrameRenderThread(renderer, cb); }); - return out; + + await withVoidCallback((cb) { + Engine_flushAndWaitRenderThead(_engine!, cb); + }); + + await withVoidCallback((cb) { + Engine_destroyFenceRenderThread(_engine!, fence, cb); + }); + + // await withVoidCallback((cb) { + // if (renderTarget != null) { + // Viewer_captureRenderTargetRenderThread( + // _viewer!, + // view!.view, + // swapChain!.swapChain, + // renderTarget.renderTarget, + // out.address, + // useFence, + // cb); + // } else { + // Viewer_captureRenderThread(_viewer!, view!.view, swapChain!.swapChain, + // out.address, useFence, cb); + // } + // }); + return pixelBuffers; } double _msPerFrame = 1000.0 / 60.0; @@ -1830,7 +1921,8 @@ class ThermionViewerFFI extends ThermionViewer { /// /// Future createTexture(int width, int height, - {int depth = 1, int levels = 1, + {int depth = 1, + int levels = 1, TextureSamplerType textureSamplerType = TextureSamplerType.SAMPLER_2D, TextureFormat textureFormat = TextureFormat.RGBA16F}) async { final texturePtr = await withPointerCallback((cb) { @@ -1862,6 +1954,7 @@ class ThermionViewerFFI extends ThermionViewer { double anisotropy = 0.0, TextureCompareMode compareMode = TextureCompareMode.NONE, TextureCompareFunc compareFunc = TextureCompareFunc.LESS_EQUAL}) async { + return FFITextureSampler(TextureSampler_create()); final samplerPtr = TextureSampler_create(); TextureSampler_setMinFilter( samplerPtr, TSamplerMinFilter.values[minFilter.index]); @@ -1876,12 +1969,12 @@ class ThermionViewerFFI extends ThermionViewer { if (anisotropy > 0) { TextureSampler_setAnisotropy(samplerPtr, anisotropy); } - if (compareMode != TextureCompareMode.NONE) { - TextureSampler_setCompareMode( - samplerPtr, - TSamplerCompareMode.values[compareMode.index], - TSamplerCompareFunc.values[compareFunc.index]); - } + + TextureSampler_setCompareMode( + samplerPtr, + TSamplerCompareMode.values[compareMode.index], + TSamplerCompareFunc.values[compareFunc.index]); + return FFITextureSampler(samplerPtr); } @@ -2216,11 +2309,14 @@ class ThermionViewerFFI extends ThermionViewer { Future isReceiveShadowsEnabled(ThermionEntity entity) async { return RenderableManager_isShadowReceiver(_renderableManager!, entity); } -} -class FFISwapChain extends SwapChain { - final Pointer swapChain; - final Pointer viewer; - - FFISwapChain(this.swapChain, this.viewer); + /// + /// + /// + Future setClearOptions( + Vector4 clearColor, int clearStencil, bool clear, bool discard) async { + final renderer = Viewer_getRenderer(_viewer!); + Renderer_setClearOptions(renderer, clearColor.r, clearColor.g, clearColor.b, + clearColor.a, clearStencil, clear, discard); + } }