diff --git a/ios/Classes/SwiftPolyvoxFilamentPlugin.swift b/ios/Classes/SwiftPolyvoxFilamentPlugin.swift index 92aa6c0d..37f4f7e6 100644 --- a/ios/Classes/SwiftPolyvoxFilamentPlugin.swift +++ b/ios/Classes/SwiftPolyvoxFilamentPlugin.swift @@ -128,6 +128,11 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture let instance:SwiftPolyvoxFilamentPlugin = Unmanaged.fromOpaque(resourcesPtr!).takeUnretainedValue() instance.resources.removeObject(forKey:rbuf.id) } + + var markTextureFrameAvailable : @convention(c) (UnsafeMutableRawPointer?) -> () = { rbuf, resourcesPtr in + let instance:SwiftPolyvoxFilamentPlugin = Unmanaged.fromOpaque(resourcesPtr!).takeUnretainedValue() + instance.registry.textureFrameAvailable(instance.flutterTextureId) + } @objc func doRender() { if(viewer != nil && rendering) { @@ -241,6 +246,9 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture update_viewport_and_camera_projection(viewer, UInt32(args[0] as! Int64), UInt32(args[1] as! Int64), 1.0) set_frame_interval(viewer, Float(frameInterval)) result(unsafeBitCast(viewer, to:Int64.self)) + case "textureFrameAvailable": + self.registry.textureFrameAvailable(flutterTextureId) + result(nil) case "getAssetManager": let assetManager = get_asset_manager(viewer) result(unsafeBitCast(assetManager, to:Int64.self)) diff --git a/ios/include/PolyvoxFilamentFFIApi.h b/ios/include/PolyvoxFilamentFFIApi.h index 02551403..bd6c2516 100644 --- a/ios/include/PolyvoxFilamentFFIApi.h +++ b/ios/include/PolyvoxFilamentFFIApi.h @@ -10,18 +10,18 @@ typedef int32_t EntityId; -const void* create_filament_viewer_ffi(void* const context, const ResourceLoaderWrapper* const loader); +void* const create_filament_viewer_ffi(void* const context, const ResourceLoaderWrapper* const loader, void (*renderCallback)(void* const renderCallbackOwner), void* const renderCallbackOwner); +void create_swap_chain_ffi(void* const viewer, void* const surface, uint32_t width, uint32_t height); +void create_render_target_ffi(void* const viewer, uint32_t nativeTextureId, uint32_t width, uint32_t height); void destroy_filament_viewer_ffi(void* const viewer); void render_ffi(void* const viewer); void set_rendering_ffi(void* const viewer, bool rendering); void set_frame_interval_ffi(float frameInterval); void update_viewport_and_camera_projection_ffi(void* const viewer, const uint32_t width, const uint32_t height, const float scaleFactor); -void create_render_target_ffi(void* const viewer, uint32_t textureId, uint32_t width, uint32_t height); void set_background_color_ffi(void* const viewer, const float r, const float g, const float b, const float a); void clear_background_image_ffi(void* const viewer); void set_background_image_ffi(void* const viewer, const char *path, bool fillHeight); void set_background_image_position_ffi(void* const viewer, float x, float y, bool clamp); -void set_background_color_ffi(void* const viewer, const float r, const float g, const float b, const float a); void set_tone_mapping_ffi(void* const viewer, int toneMapping); void set_bloom_ffi(void* const viewer, float strength); void load_skybox_ffi(void* const viewer, const char *skyboxPath); @@ -33,8 +33,8 @@ void remove_light_ffi(void* const viewer, EntityId entityId); void clear_lights_ffi(void* const viewer); EntityId load_glb_ffi(void* const assetManager, const char *assetPath, bool unlit); EntityId load_gltf_ffi(void* const assetManager, const char *assetPath, const char *relativePath); -void remove_asset_ffi(const void* const viewer, EntityId asset); -void clear_assets_ffi(const void* const viewer); +void remove_asset_ffi(void* const const viewer, EntityId asset); +void clear_assets_ffi(void* const const viewer); bool set_camera_ffi(void* const viewer, EntityId asset, const char *nodeName); void apply_weights_ffi( void* assetManager, diff --git a/ios/src/PolyvoxFilamentApi.cpp b/ios/src/PolyvoxFilamentApi.cpp index 42226671..4ecc0757 100644 --- a/ios/src/PolyvoxFilamentApi.cpp +++ b/ios/src/PolyvoxFilamentApi.cpp @@ -311,7 +311,7 @@ extern "C" { void* assetManager, EntityId asset) { auto names = ((AssetManager*)assetManager)->getAnimationNames(asset); - return names->size(); + return (int)names->size(); } FLUTTER_PLUGIN_EXPORT void get_animation_name( @@ -326,12 +326,8 @@ extern "C" { } FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count(void* assetManager, EntityId asset, const char* meshName) { - //std::packaged_task lambda([=]() mutable { unique_ptr> names = ((AssetManager*)assetManager)->getMorphTargetNames(asset, meshName); - return names->size(); - - - //return fut.get(); + return (int)names->size(); } FLUTTER_PLUGIN_EXPORT void get_morph_target_name(void* assetManager, EntityId asset, const char* meshName, char* const outPtr, int index ) { diff --git a/ios/src/PolyvoxFilamentFFIApi.cpp b/ios/src/PolyvoxFilamentFFIApi.cpp index 1cd8ec4d..8ed0021c 100644 --- a/ios/src/PolyvoxFilamentFFIApi.cpp +++ b/ios/src/PolyvoxFilamentFFIApi.cpp @@ -28,6 +28,10 @@ public: _tasks.pop_front(); std::this_thread::sleep_for( std::chrono::milliseconds(_frameIntervalInMilliseconds)); + if(_rendering) { + doRender(); + } + } task(); @@ -39,10 +43,27 @@ public: _t->join(); } + void* const createViewer(void* const context, const ResourceLoaderWrapper* const loader, void (*renderCallback)(void*), void* const owner) { + _renderCallback = renderCallback; + _renderCallbackOwner = owner; + std::packaged_task lambda([&]() mutable { + return new FilamentViewer(context, loader); + }); + auto fut = add_task(lambda); + fut.wait(); + _viewer = fut.get(); + return (void* const)_viewer; + } + void setRendering(bool rendering) { _rendering = rendering; } + void doRender() { + render(_viewer, 0); + _renderCallback(_renderCallbackOwner); + } + template auto add_task(std::packaged_task& pt) -> std::future { std::unique_lock lock(_access); @@ -57,6 +78,8 @@ private: int _frameIntervalInMilliseconds = 1000 / 60; std::mutex _access; FilamentViewer* _viewer = nullptr; + void (*_renderCallback)(void* const) = nullptr; + void* _renderCallbackOwner = nullptr; std::thread* _t = nullptr; std::condition_variable _cond; std::deque> _tasks; @@ -71,19 +94,32 @@ extern "C" { static RenderLoop* _rl; - FLUTTER_PLUGIN_EXPORT const void* create_filament_viewer_ffi(const void* context, const ResourceLoaderWrapper* const loader) { + FLUTTER_PLUGIN_EXPORT void* const create_filament_viewer_ffi(void* const context, const ResourceLoaderWrapper* const loader, void (*renderCallback)(void* const renderCallbackOwner), void* const renderCallbackOwner) { if(!_rl) { _rl = new RenderLoop(); } - std::packaged_task lambda([&]() mutable { - return (const void*) new FilamentViewer(context, loader); + return _rl->createViewer(context, loader, renderCallback, renderCallbackOwner); + } + + + FLUTTER_PLUGIN_EXPORT void create_swap_chain_ffi(void* const viewer, void* const surface, uint32_t width, uint32_t height) { + std::packaged_task lambda([&]() mutable { + create_swap_chain(viewer, surface, width, height); }); auto fut = _rl->add_task(lambda); fut.wait(); - return fut.get(); } - FLUTTER_PLUGIN_EXPORT void update_viewport_and_camera_projection_ffi(void* const viewer, const uint32_t width, const uint32_t height, const float scaleFactor); + FLUTTER_PLUGIN_EXPORT void create_render_target_ffi(void* const viewer, uint32_t nativeTextureId, uint32_t width, uint32_t height) { + std::packaged_task lambda([&]() mutable { + create_render_target(viewer, nativeTextureId, width, height); + }); + auto fut = _rl->add_task(lambda); + fut.wait(); + } + + + FLUTTER_PLUGIN_EXPORT void update_viewport_and_camera_projection_ffi(void* const viewer, const uint32_t width, const uint32_t height, const float scaleFactor) { std::packaged_task lambda([&]() mutable { update_viewport_and_camera_projection(viewer, width, height, scaleFactor); }); @@ -92,7 +128,7 @@ extern "C" { } - FLUTTER_PLUGIN_EXPORT bool set_rendering(bool rendering) { + FLUTTER_PLUGIN_EXPORT bool set_rendering_ffi(bool rendering) { if(!_rl) { return false; } @@ -102,13 +138,13 @@ extern "C" { FLUTTER_PLUGIN_EXPORT void render_ffi(void* const viewer) { std::packaged_task lambda([&]() mutable { - render(viewer, 0); + _rl->doRender(); }); auto fut = _rl->add_task(lambda); fut.wait(); } - FLUTTER_PLUGIN_EXPORT void set_background_color_ffi(const void* const viewer, const float r, const float g, const float b, const float a) { + FLUTTER_PLUGIN_EXPORT void set_background_color_ffi(void* const viewer, const float r, const float g, const float b, const float a) { std::packaged_task lambda([&]() mutable { set_background_color(viewer, r, g,b, a); }); diff --git a/lib/filament_controller_ffi.dart b/lib/filament_controller_ffi.dart index 0be942a7..eab70760 100644 --- a/lib/filament_controller_ffi.dart +++ b/lib/filament_controller_ffi.dart @@ -103,15 +103,34 @@ class FilamentControllerFFI extends FilamentController { } size = ui.Size(width * _pixelRatio, height * _pixelRatio); - _textureId = + var textures = await _channel.invokeMethod("createTexture", [size.width, size.height]); + var flutterTextureId = textures[0]; + _textureId = flutterTextureId; + var pixelBuffer = textures[1] as int; + var nativeTexture = textures[2] as int; + + var renderCallbackResult = await _channel.invokeMethod("getRenderCallback"); + var renderCallback = + Pointer)>>.fromAddress( + renderCallbackResult[0]); + var renderCallbackOwner = + Pointer.fromAddress(renderCallbackResult[1]); var sharedContext = await _channel.invokeMethod("getSharedContext"); var loader = await _channel.invokeMethod("getResourceLoaderWrapper"); _viewer = _lib.create_filament_viewer_ffi( Pointer.fromAddress(sharedContext ?? 0), - Pointer.fromAddress(loader)); + Pointer.fromAddress(loader), + renderCallback, + renderCallbackOwner); + + _lib.create_swap_chain( + _viewer!, Pointer.fromAddress(pixelBuffer), width, height); + + _lib.create_render_target(_viewer!, nativeTexture, width, height); + _lib.update_viewport_and_camera_projection_ffi( _viewer!, width, height, 1.0); diff --git a/lib/generated_bindings.dart b/lib/generated_bindings.dart index b6cd8d92..8e525dfb 100644 --- a/lib/generated_bindings.dart +++ b/lib/generated_bindings.dart @@ -1278,22 +1278,82 @@ class NativeLibrary { ffi.Pointer create_filament_viewer_ffi( ffi.Pointer context, ffi.Pointer loader, + ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer renderCallbackOwner)>> + renderCallback, + ffi.Pointer renderCallbackOwner, ) { return _create_filament_viewer_ffi( context, loader, + renderCallback, + renderCallbackOwner, ); } late final _create_filament_viewer_ffiPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>( - 'create_filament_viewer_ffi'); + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer renderCallbackOwner)>>, + ffi.Pointer)>>('create_filament_viewer_ffi'); late final _create_filament_viewer_ffi = _create_filament_viewer_ffiPtr.asFunction< ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); + ffi.Pointer, + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer renderCallbackOwner)>>, + ffi.Pointer)>(); + + void create_swap_chain_ffi( + ffi.Pointer viewer, + ffi.Pointer surface, + int width, + int height, + ) { + return _create_swap_chain_ffi( + viewer, + surface, + width, + height, + ); + } + + late final _create_swap_chain_ffiPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Uint32, ffi.Uint32)>>('create_swap_chain_ffi'); + late final _create_swap_chain_ffi = _create_swap_chain_ffiPtr.asFunction< + void Function(ffi.Pointer, ffi.Pointer, int, int)>(); + + void create_render_target_ffi( + ffi.Pointer viewer, + int nativeTextureId, + int width, + int height, + ) { + return _create_render_target_ffi( + viewer, + nativeTextureId, + width, + height, + ); + } + + late final _create_render_target_ffiPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Uint32, ffi.Uint32, + ffi.Uint32)>>('create_render_target_ffi'); + late final _create_render_target_ffi = _create_render_target_ffiPtr + .asFunction, int, int, int)>(); void destroy_filament_viewer_ffi( ffi.Pointer viewer, @@ -1376,27 +1436,6 @@ class NativeLibrary { _update_viewport_and_camera_projection_ffiPtr .asFunction, int, int, double)>(); - void create_render_target_ffi( - ffi.Pointer viewer, - int textureId, - int width, - int height, - ) { - return _create_render_target_ffi( - viewer, - textureId, - width, - height, - ); - } - - late final _create_render_target_ffiPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Uint32, ffi.Uint32, - ffi.Uint32)>>('create_render_target_ffi'); - late final _create_render_target_ffi = _create_render_target_ffiPtr - .asFunction, int, int, int)>(); - void set_background_color_ffi( ffi.Pointer viewer, double r, diff --git a/macos/Classes/SwiftPolyvoxFilamentPlugin.swift b/macos/Classes/SwiftPolyvoxFilamentPlugin.swift index 4781f202..3972abbe 100644 --- a/macos/Classes/SwiftPolyvoxFilamentPlugin.swift +++ b/macos/Classes/SwiftPolyvoxFilamentPlugin.swift @@ -13,7 +13,7 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture var pixelBufferAttrs = [ kCVPixelBufferPixelFormatTypeKey: NSNumber(value: kCVPixelFormatType_32ABGR ), - kCVPixelBufferOpenGLCompatibilityKey: kCFBooleanTrue, + kCVPixelBufferOpenGLCompatibilityKey: kCFBooleanTrue!, kCVPixelBufferIOSurfacePropertiesKey: [:] ] as CFDictionary @@ -67,6 +67,11 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture let instance:SwiftPolyvoxFilamentPlugin = Unmanaged.fromOpaque(resourcesPtr!).takeUnretainedValue() instance.resources.removeValue(forKey:rbuf.id) } + + var markTextureFrameAvailable : @convention(c) (UnsafeMutableRawPointer?) -> () = { instancePtr in + let instance:SwiftPolyvoxFilamentPlugin = Unmanaged.fromOpaque(instancePtr!).takeUnretainedValue() + instance.registry.textureFrameAvailable(instance.flutterTextureId!) + } var displayLinkRenderCallback : @convention(c) (CVDisplayLink, UnsafePointer, UnsafePointer, CVOptionFlags, UnsafeMutablePointer, UnsafeMutableRawPointer?) -> CVReturn = { displayLink, ts1, ts2, options, optionsPtr, resourcesPtr in let instance:SwiftPolyvoxFilamentPlugin = Unmanaged.fromOpaque(resourcesPtr!).takeUnretainedValue() @@ -150,6 +155,10 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture case "getResourceLoaderWrapper": let resourceLoaderWrapper = make_resource_loader(loadResource, freeResource, Unmanaged.passUnretained(self).toOpaque()) result(unsafeBitCast(resourceLoaderWrapper, to:Int64.self)) + case "getRenderCallback": + let renderCallback = markTextureFrameAvailable + result([ + unsafeBitCast(renderCallback, to:Int64.self), unsafeBitCast(Unmanaged.passUnretained(self), to:UInt64.self)]) case "createTexture": let args = call.arguments as! Array createPixelBuffer(width:Int(args[0]), height:Int(args[1])) @@ -160,6 +169,10 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture metalDevice!, nil, &cvMetalTextureCache); + if(cvret != 0) { + result(FlutterError()) + return + } cvret = CVMetalTextureCacheCreateTextureFromImage( kCFAllocatorDefault, cvMetalTextureCache!, @@ -169,8 +182,10 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture 0, &cvMetalTexture); metalTexture = CVMetalTextureGetTexture(cvMetalTexture!); - createDisplayLink() - result(self.flutterTextureId) + // createDisplayLink() + let pixelBufferAddress = Int(bitPattern:CVPixelBufferGetBaseAddress(pixelBuffer!)); + let metalTextureAddress = Int(bitPattern:Unmanaged.passUnretained(metalTexture!).toOpaque()) + result([self.flutterTextureId as! Any, pixelBufferAddress, metalTextureAddress]) case "destroyTexture": if(viewer != nil) { result(FlutterError(code: "INVALID_ARGUMENTS", message: "Destroy the viewer before destroying the texture", details: nil)) @@ -207,484 +222,6 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture rendering = true print("Resized to \(args[0])x\(args[1])") result(self.flutterTextureId); - case "createFilamentViewer": - if(viewer != nil) { - destroy_swap_chain(viewer) - destroy_filament_viewer(viewer) - viewer = nil - } - let callback = make_resource_loader(loadResource, freeResource, Unmanaged.passUnretained(self).toOpaque()) - let args = call.arguments as! [Any] - let width = UInt32(args[0] as! Int64) - let height = UInt32(args[1] as! Int64) - - viewer = create_filament_viewer(nil, callback) - create_swap_chain(viewer, CVPixelBufferGetBaseAddress(pixelBuffer!), width, height) - - let metalTextureId = Int(bitPattern:Unmanaged.passUnretained(metalTexture!).toOpaque()) - - create_render_target(viewer, UInt32(metalTextureId), width,height); - - update_viewport_and_camera_projection(viewer, width, height, 1.0) - set_frame_interval(viewer, Float(frameInterval)) - print("Viewer created") - result(unsafeBitCast(viewer, to:Int64.self)) - case "getAssetManager": - let assetManager = get_asset_manager(viewer) - result(unsafeBitCast(assetManager, to:Int64.self)) - case "clearBackgroundImage": - clear_background_image(viewer) - result(true) - case "setBackgroundImage": - let args = call.arguments as! [Any] - set_background_image(viewer, args[0] as! String, args[1] as! Bool) - result(true) - case "setBackgroundImagePosition": - let args = call.arguments as! [Any] - set_background_image_position(viewer, Float(args[0] as! Double), Float(args[1] as! Double), args[2] as! Bool) - result(true) - case "setBackgroundColor": - guard let args = call.arguments as? [Double], args.count == 4 else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected RGBA values for setBackgroundColor", details: nil)) - return - } - set_background_color(viewer, Float(args[0]), Float(args[1]), Float(args[2]), Float(args[3])) - result(true) - case "setToneMapping": - guard let args = call.arguments as? Int else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected ToneMapping argument for setToneMapping", details: nil)) - return - } - set_tone_mapping(viewer, Int32(args)); - result(true) - case "setBloom": - guard let args = call.arguments as? Double else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected double argument for setBloom", details: nil)) - return - } - set_bloom(viewer, Float(args)); - result(true) - case "loadSkybox": - load_skybox(viewer, call.arguments as! String) - result(true) - case "loadIbl": - let args = call.arguments as! [Any] - load_ibl(viewer, args[0] as! String, args[1] as! Float) - result(true) - case "removeSkybox": - remove_skybox(viewer) - result(true) - case "removeIbl": - remove_ibl(viewer) - result(true) - case "addLight": - guard let args = call.arguments as? [Any], args.count == 10, - let type = args[0] as? Int32, - let colour = args[1] as? Double, - let intensity = args[2] as? Double, - let posX = args[3] as? Double, - let posY = args[4] as? Double, - let posZ = args[5] as? Double, - let dirX = args[6] as? Double, - let dirY = args[7] as? Double, - let dirZ = args[8] as? Double, - let shadows = args[9] as? Bool else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected viewer and light parameters for addLight", details: nil)) - return - } - let entityId = add_light(viewer, UInt8(type), Float(colour), Float(intensity),Float(posX), Float(posY), Float(posZ), Float(dirX), Float(dirY), Float(dirZ), shadows) - result(entityId) - - case "removeLight": - remove_light(viewer, Int32(call.arguments as! Int64)) - result(true) - case "clearLights": - clear_lights(viewer) - result(true) - case "loadGlb": - guard let args = call.arguments as? [Any], args.count == 3, - let assetManager = args[0] as? Int64, - let assetPath = args[1] as? String, - let unlit = args[2] as? Bool else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected assetManager, assetPath, and unlit for load_glb", details: nil)) - return - } - let entityId = load_glb(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), assetPath, unlit) - result(entityId) - case "loadGltf": - guard let args = call.arguments as? [Any], args.count == 3, - let assetManager = args[0] as? Int64, - let assetPath = args[1] as? String, - let relativePath = args[2] as? String else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected assetManager, assetPath, and relativePath for load_gltf", details: nil)) - return - } - let entityId = load_gltf(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), assetPath, relativePath) - result(entityId) - case "transformToUnitCube": - let args = call.arguments as! [Any] - transform_to_unit_cube(unsafeBitCast(args[0] as! Int64, to:UnsafeMutableRawPointer.self), args[1] as! EntityId) - result(true) - case "render": - print("Manual render") - doRender() - result(true) - case "setRendering": - rendering = call.arguments as! Bool - result(true) - case "setFrameInterval": - frameInterval = call.arguments as! Double - if(displayLink != nil) { - // displayLink!.preferredFramesPerSecond = Int(1 / frameInterval) - } - if(viewer != nil) { - set_frame_interval(viewer, Float(frameInterval)) - } - print("Set preferred frame interval to \(frameInterval)") - result(true) - case "updateViewportAndCameraProjection": - guard let args = call.arguments as? [Any], args.count == 3, - let width = args[0] as? Int, - let height = args[1] as? Int, - let scaleFactor = args[2] as? Float else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected viewer, width, height, and scaleFactor for update_viewport_and_camera_projection", details: nil)) - return - } - update_viewport_and_camera_projection(viewer, UInt32(width), UInt32(height), scaleFactor) - result(true) - case "scrollBegin": - scroll_begin(viewer) - result(true) - case "scrollUpdate": - guard let args = call.arguments as? [Any], args.count == 3, - let x = args[0] as? Double, - let y = args[1] as? Double, - let z = args[2] as? Double else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected viewer, x, y, and z for scroll_update", details: nil)) - return - } - scroll_update(viewer, Float(x), Float(y), Float(z)) - result(true) - - case "scrollEnd": - scroll_end(viewer) - result(true) - case "grabBegin": - guard let args = call.arguments as? [Any], args.count == 3, - let x = args[0] as? Double, - let y = args[1] as? Double, - let pan = args[2] as? Bool else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected viewer, x, y, and pan for grab_begin", details: nil)) - return - } - grab_begin(viewer, Float(x), Float(y), pan) - result(true) - - case "grabUpdate": - guard let args = call.arguments as? [Any], args.count == 2, - let x = args[0] as? Float, - let y = args[1] as? Float else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected viewer, x, and y for grab_update", details: nil)) - return - } - grab_update(viewer, x, y) - result(true) - - case "grabEnd": - grab_end(viewer) - result(true) - case "applyWeights": - // guard let args = call.arguments as? [Any], args.count == 5, - // let assetManager = args[0] as? Int64, - // let asset = args[1] as? EntityId, - // let entityName = args[2] as? String, - // let weights = args[3] as? [Float], - // let count = args[4] as? Int else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for apply_weights", details: nil)) - // return - // } - // apply_weights(assetManager, asset, entityName, UnsafeMutablePointer(&weights), Int32(count)) - // result(true) - case "setMorphTargetWeights": - guard let args = call.arguments as? [Any], args.count == 5, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let entityName = args[2] as? String, - let morphData = args[3] as? [Double], - let numMorphWeights = args[4] as? Int32 else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for setMorphTargetWeights", details: nil)) - return - } - - set_morph_target_weights(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, entityName, morphData.map { Float($0) }, Int32(numMorphWeights)) - - result(true) - - case "setMorphAnimation": - guard let args = call.arguments as? [Any], args.count == 8, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let entityName = args[2] as? String, - let morphData = args[3] as? [Double], - let morphIndices = args[4] as? [Int32], - let numMorphTargets = args[5] as? Int32, - let numFrames = args[6] as? Int32, - let frameLengthInMs = args[7] as? Double else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Incorrect arguments provided for setMorphAnimation", details: nil)) - return - } - let frameData = morphData.map { Float($0) } - let am = unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self) - - let success = set_morph_animation( - am, - asset, - entityName, - frameData, - morphIndices, - Int32(numMorphTargets), - Int32(numFrames), - Float(frameLengthInMs)) - result(success) - case "setBoneAnimation": - // guard let args = call.arguments as? [Any], args.count == 9, - // let assetManager = args[0] as? Int64, - // let asset = args[1] as? EntityId, - // let frameData = args[2] as? [Float], - // let numFrames = args[3] as? Int, - // let numBones = args[4] as? Int, - // let boneNames = args[5] as? [String], - // let meshName = args[6] as? [String], - // let numMeshTargets = args[7] as? Int, - // let frameLengthInMs = args[8] as? Float else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for set_bone_animation", details: nil)) - // return - // } - - // // Convert boneNames and meshName to C-style strings array. - // var cBoneNames: [UnsafePointer?] = boneNames.map { $0.cString(using: .utf8) } - // var cMeshName: [UnsafePointer?] = meshName.map { $0.cString(using: .utf8) } - // - // set_bone_animation(assetManager, asset, UnsafeMutablePointer(&frameData), numFrames, numBones, &cBoneNames, &cMeshName, numMeshTargets, frameLengthInMs) - - // // Clean up after conversion - // for cStr in cBoneNames { free(UnsafeMutablePointer(mutating: cStr)) } - // for cStr in cMeshName { free(UnsafeMutablePointer(mutating: cStr)) } - - result(true) - - case "playAnimation": - guard let args = call.arguments as? [Any], args.count == 7, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let index = args[2] as? Int, - let loop = args[3] as? Bool, - let reverse = args[4] as? Bool, - let replaceActive = args[5] as? Bool, - let crossfade = args[6] as? Double else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for play_animation", details: nil)) - return - } - play_animation(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, Int32(index), loop, reverse, replaceActive, Float(crossfade)) - result(true) - case "getAnimationDuration": - guard let args = call.arguments as? [Any], args.count == 3, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let animationIndex = args[2] as? Int else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for getAnimationDuration", details: nil)) - return - } - - let dur = get_animation_duration(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, Int32(animationIndex)) - result(dur) - - case "setAnimationFrame": - guard let args = call.arguments as? [Any], args.count == 4, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let animationIndex = args[2] as? Int, - let animationFrame = args[3] as? Int else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for set_animation_frame", details: nil)) - return - } - - set_animation_frame(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, Int32(animationIndex), Int32(animationFrame)) - result(true) - - case "stopAnimation": - guard let args = call.arguments as? [Any], args.count == 3, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let index = args[2] as? Int else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for stop_animation", details: nil)) - return - } - stop_animation(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, Int32(index)) - result(true) - case "getAnimationCount": - guard let args = call.arguments as? [Any], args.count == 2, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for get_animation_count", details: nil)) - return - } - - let count = get_animation_count(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset) - result(count) - case "getAnimationNames": - guard let args = call.arguments as? [Any], args.count == 2, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for get_animation_name", details: nil)) - return - } - var names:[String] = []; - let count = get_animation_count(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset) - var buffer = [CChar](repeating: 0, count: 256) // Assuming max name length of 256 for simplicity - for i in 0...count - 1 { - get_animation_name(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, &buffer, Int32(i)) - let name = String(cString: buffer) - names.append(name) - } - result(names) - case "getAnimationName": - guard let args = call.arguments as? [Any], args.count == 3, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let index = args[2] as? Int else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for get_animation_name", details: nil)) - return - } - - var buffer = [CChar](repeating: 0, count: 256) // Assuming max name length of 256 for simplicity - get_animation_name(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, &buffer, Int32(index)) - let name = String(cString: buffer) - result(name) - - case "getMorphTargetName": - guard let args = call.arguments as? [Any], args.count == 4, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let meshName = args[2] as? String, - let index = args[3] as? Int else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for get_morph_target_name", details: nil)) - return - } - - var buffer = [CChar](repeating: 0, count: 256) // Assuming max name length of 256 for simplicity - get_morph_target_name(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName, &buffer, Int32(index)) - let targetName = String(cString: buffer) - result(targetName) - case "getMorphTargetNames": - guard let args = call.arguments as? [Any], args.count == 3, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let meshName = args[2] as? String else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for get_morph_target_name", details: nil)) - return - } - let count = get_morph_target_name_count(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName) - var names:[String] = [] - if count > 0 { - for i in 0...count - 1 { - var buffer = [CChar](repeating: 0, count: 256) // Assuming max name length of 256 for simplicity - get_morph_target_name(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName, &buffer, Int32(i)) - names.append(String(cString:buffer)) - } - } - result(names) - case "getMorphTargetNameCount": - guard let args = call.arguments as? [Any], args.count == 3, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let meshName = args[2] as? String else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for get_morph_target_name_count", details: nil)) - return - } - - let count = get_morph_target_name_count(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName) - result(count) - - case "removeAsset": - remove_asset(viewer, call.arguments as! EntityId) - result(true) - case "clearAssets": - clear_assets(viewer) - result(true) - case "setCamera": - guard let args = call.arguments as? [Any], args.count == 2, - let asset = args[0] as? EntityId, - let nodeName = args[1] as? String? else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected asset and nodeName for set_camera", details: nil)) - return - } - let success = set_camera(viewer, asset, nodeName) - result(success) - case "moveCameraToAsset": - move_camera_to_asset(viewer, call.arguments as! EntityId) - result(true) - case "setViewFrustumCulling": - set_view_frustum_culling(viewer, call.arguments as! Bool) - result(true) - case "setCameraPosition": - let args = call.arguments as! [Any] - set_camera_position(viewer, Float(args[0] as! Double), Float(args[1] as! Double), Float(args[2] as! Double)) - result(true) - - case "setCameraRotation": - let args = call.arguments as! [Any] - set_camera_rotation(viewer, Float(args[0] as! Double), Float(args[1] as! Double), Float(args[2] as! Double), Float(args[3] as! Double)) - result(true) - case "setCameraModelMatrix": - guard let matrix = call.arguments as? [Float], matrix.count == 16 else { // Assuming a 4x4 matrix - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for set_camera_model_matrix", details: nil)) - return - } - set_camera_model_matrix(viewer, matrix) - result(true) - case "setCameraFocalLength": - set_camera_focal_length(viewer, call.arguments as! Float) - result(true) - case "setCameraFocusDistance": - set_camera_focus_distance(viewer, call.arguments as! Float) - result(true) - case "setMaterialColor": - guard let args = call.arguments as? [Any], args.count == 5, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let meshName = args[2] as? String, - let materialIndex = args[3] as? Int32, - let color = args[4] as? [Double] else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for setMaterialColor", details: nil)) - return - } - set_material_color(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName, materialIndex, Float(color[0]), Float(color[1]), Float(color[2]), Float(color[3])) - result(true) - - case "hideMesh": - guard let args = call.arguments as? [Any], args.count == 3, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let meshName = args[2] as? String else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for hide_mesh", details: nil)) - return - } - - let status = hide_mesh(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName) - result(status) - - case "revealMesh": - guard let args = call.arguments as? [Any], args.count == 3, - let assetManager = args[0] as? Int64, - let asset = args[1] as? EntityId, - let meshName = args[2] as? String else { - result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for reveal_mesh", details: nil)) - return - } - - let status = reveal_mesh(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName) - result(status) default: result(FlutterMethodNotImplemented) } diff --git a/macos/include/PolyvoxFilamentFFIApi.h b/macos/include/PolyvoxFilamentFFIApi.h index 02551403..bd6c2516 100644 --- a/macos/include/PolyvoxFilamentFFIApi.h +++ b/macos/include/PolyvoxFilamentFFIApi.h @@ -10,18 +10,18 @@ typedef int32_t EntityId; -const void* create_filament_viewer_ffi(void* const context, const ResourceLoaderWrapper* const loader); +void* const create_filament_viewer_ffi(void* const context, const ResourceLoaderWrapper* const loader, void (*renderCallback)(void* const renderCallbackOwner), void* const renderCallbackOwner); +void create_swap_chain_ffi(void* const viewer, void* const surface, uint32_t width, uint32_t height); +void create_render_target_ffi(void* const viewer, uint32_t nativeTextureId, uint32_t width, uint32_t height); void destroy_filament_viewer_ffi(void* const viewer); void render_ffi(void* const viewer); void set_rendering_ffi(void* const viewer, bool rendering); void set_frame_interval_ffi(float frameInterval); void update_viewport_and_camera_projection_ffi(void* const viewer, const uint32_t width, const uint32_t height, const float scaleFactor); -void create_render_target_ffi(void* const viewer, uint32_t textureId, uint32_t width, uint32_t height); void set_background_color_ffi(void* const viewer, const float r, const float g, const float b, const float a); void clear_background_image_ffi(void* const viewer); void set_background_image_ffi(void* const viewer, const char *path, bool fillHeight); void set_background_image_position_ffi(void* const viewer, float x, float y, bool clamp); -void set_background_color_ffi(void* const viewer, const float r, const float g, const float b, const float a); void set_tone_mapping_ffi(void* const viewer, int toneMapping); void set_bloom_ffi(void* const viewer, float strength); void load_skybox_ffi(void* const viewer, const char *skyboxPath); @@ -33,8 +33,8 @@ void remove_light_ffi(void* const viewer, EntityId entityId); void clear_lights_ffi(void* const viewer); EntityId load_glb_ffi(void* const assetManager, const char *assetPath, bool unlit); EntityId load_gltf_ffi(void* const assetManager, const char *assetPath, const char *relativePath); -void remove_asset_ffi(const void* const viewer, EntityId asset); -void clear_assets_ffi(const void* const viewer); +void remove_asset_ffi(void* const const viewer, EntityId asset); +void clear_assets_ffi(void* const const viewer); bool set_camera_ffi(void* const viewer, EntityId asset, const char *nodeName); void apply_weights_ffi( void* assetManager, diff --git a/macos/src/PolyvoxFilamentApi.cpp b/macos/src/PolyvoxFilamentApi.cpp index 42226671..4ecc0757 100644 --- a/macos/src/PolyvoxFilamentApi.cpp +++ b/macos/src/PolyvoxFilamentApi.cpp @@ -311,7 +311,7 @@ extern "C" { void* assetManager, EntityId asset) { auto names = ((AssetManager*)assetManager)->getAnimationNames(asset); - return names->size(); + return (int)names->size(); } FLUTTER_PLUGIN_EXPORT void get_animation_name( @@ -326,12 +326,8 @@ extern "C" { } FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count(void* assetManager, EntityId asset, const char* meshName) { - //std::packaged_task lambda([=]() mutable { unique_ptr> names = ((AssetManager*)assetManager)->getMorphTargetNames(asset, meshName); - return names->size(); - - - //return fut.get(); + return (int)names->size(); } FLUTTER_PLUGIN_EXPORT void get_morph_target_name(void* assetManager, EntityId asset, const char* meshName, char* const outPtr, int index ) { diff --git a/macos/src/PolyvoxFilamentFFIApi.cpp b/macos/src/PolyvoxFilamentFFIApi.cpp index fcfa6fc2..8ed0021c 100644 --- a/macos/src/PolyvoxFilamentFFIApi.cpp +++ b/macos/src/PolyvoxFilamentFFIApi.cpp @@ -28,6 +28,10 @@ public: _tasks.pop_front(); std::this_thread::sleep_for( std::chrono::milliseconds(_frameIntervalInMilliseconds)); + if(_rendering) { + doRender(); + } + } task(); @@ -39,10 +43,27 @@ public: _t->join(); } + void* const createViewer(void* const context, const ResourceLoaderWrapper* const loader, void (*renderCallback)(void*), void* const owner) { + _renderCallback = renderCallback; + _renderCallbackOwner = owner; + std::packaged_task lambda([&]() mutable { + return new FilamentViewer(context, loader); + }); + auto fut = add_task(lambda); + fut.wait(); + _viewer = fut.get(); + return (void* const)_viewer; + } + void setRendering(bool rendering) { _rendering = rendering; } + void doRender() { + render(_viewer, 0); + _renderCallback(_renderCallbackOwner); + } + template auto add_task(std::packaged_task& pt) -> std::future { std::unique_lock lock(_access); @@ -57,6 +78,8 @@ private: int _frameIntervalInMilliseconds = 1000 / 60; std::mutex _access; FilamentViewer* _viewer = nullptr; + void (*_renderCallback)(void* const) = nullptr; + void* _renderCallbackOwner = nullptr; std::thread* _t = nullptr; std::condition_variable _cond; std::deque> _tasks; @@ -71,20 +94,41 @@ extern "C" { static RenderLoop* _rl; - FLUTTER_PLUGIN_EXPORT const void* create_filament_viewer_ffi(const void* context, const ResourceLoaderWrapper* const loader) { + FLUTTER_PLUGIN_EXPORT void* const create_filament_viewer_ffi(void* const context, const ResourceLoaderWrapper* const loader, void (*renderCallback)(void* const renderCallbackOwner), void* const renderCallbackOwner) { if(!_rl) { _rl = new RenderLoop(); } - std::packaged_task lambda([&]() mutable { - return (const void*) new FilamentViewer(context, loader); + return _rl->createViewer(context, loader, renderCallback, renderCallbackOwner); + } + + + FLUTTER_PLUGIN_EXPORT void create_swap_chain_ffi(void* const viewer, void* const surface, uint32_t width, uint32_t height) { + std::packaged_task lambda([&]() mutable { + create_swap_chain(viewer, surface, width, height); + }); + auto fut = _rl->add_task(lambda); + fut.wait(); + } + + FLUTTER_PLUGIN_EXPORT void create_render_target_ffi(void* const viewer, uint32_t nativeTextureId, uint32_t width, uint32_t height) { + std::packaged_task lambda([&]() mutable { + create_render_target(viewer, nativeTextureId, width, height); + }); + auto fut = _rl->add_task(lambda); + fut.wait(); + } + + + FLUTTER_PLUGIN_EXPORT void update_viewport_and_camera_projection_ffi(void* const viewer, const uint32_t width, const uint32_t height, const float scaleFactor) { + std::packaged_task lambda([&]() mutable { + update_viewport_and_camera_projection(viewer, width, height, scaleFactor); }); auto fut = _rl->add_task(lambda); fut.wait(); - return fut.get(); } - FLUTTER_PLUGIN_EXPORT bool set_rendering(bool rendering) { + FLUTTER_PLUGIN_EXPORT bool set_rendering_ffi(bool rendering) { if(!_rl) { return false; } @@ -94,13 +138,13 @@ extern "C" { FLUTTER_PLUGIN_EXPORT void render_ffi(void* const viewer) { std::packaged_task lambda([&]() mutable { - render(viewer, 0); + _rl->doRender(); }); auto fut = _rl->add_task(lambda); fut.wait(); } - FLUTTER_PLUGIN_EXPORT void set_background_color_ffi(const void* const viewer, const float r, const float g, const float b, const float a) { + FLUTTER_PLUGIN_EXPORT void set_background_color_ffi(void* const viewer, const float r, const float g, const float b, const float a) { std::packaged_task lambda([&]() mutable { set_background_color(viewer, r, g,b, a); });