From 44aa3109bc58f251b7094e9c922cbbbc8e002db4 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Tue, 8 Aug 2023 10:44:10 +0800 Subject: [PATCH] add animation fading and revert to platform channel handler --- example/assets/cube.glb | Bin 678472 -> 731404 bytes example/lib/main.dart | 256 ++++--- ios/Classes/SwiftPolyvoxFilamentPlugin.swift | 670 +++++++++++++++---- ios/include/AssetManager.hpp | 7 +- ios/include/FilamentViewer.hpp | 7 +- ios/include/PolyvoxFilamentApi.h | 81 +-- ios/include/ResourceBuffer.hpp | 4 +- ios/include/SceneAsset.hpp | 26 +- ios/src/AssetManager.cpp | 111 +-- ios/src/FilamentViewer.cpp | 38 +- ios/src/PolyvoxFilamentApi.cpp | 316 ++------- lib/animations/animation_builder.dart | 4 +- lib/filament_controller.dart | 326 ++++----- lib/filament_gesture_detector.dart | 1 - lib/generated_bindings.dart | 44 +- pubspec.yaml | 2 +- 16 files changed, 1038 insertions(+), 855 deletions(-) diff --git a/example/assets/cube.glb b/example/assets/cube.glb index e8407372079beb013d9808b0926b94d5c86ab812..9575871eea1fbc83e88994ff130f92a5cd9204e3 100644 GIT binary patch delta 24638 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 delta 8620 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 ga4zr^;C$dBT*IHpF diff --git a/example/lib/main.dart b/example/lib/main.dart index 690b3905..9db84323 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -21,6 +21,23 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State with SingleTickerProviderStateMixin { + @override + Widget build(BuildContext context) { + return MaterialApp( + // showPerformanceOverlay: true, + color: Colors.white, + home: Scaffold(backgroundColor: Colors.white, body: ExampleWidget())); + } +} + +class ExampleWidget extends StatefulWidget { + @override + State createState() { + return _ExampleWidgetState(); + } +} + +class _ExampleWidgetState extends State { late FilamentController _filamentController; FilamentEntity? _cube; @@ -28,8 +45,7 @@ class _MyAppState extends State with SingleTickerProviderStateMixin { FilamentEntity? _light; final weights = List.filled(255, 0.0); - List _targetNames = []; - List _animationNames = []; + bool _loop = false; bool _vertical = false; bool _rendering = false; @@ -38,7 +54,7 @@ class _MyAppState extends State with SingleTickerProviderStateMixin { @override void initState() { super.initState(); - _filamentController = FilamentController(this); + _filamentController = FilamentController(); } void onClick(int index) async { @@ -61,6 +77,9 @@ class _MyAppState extends State with SingleTickerProviderStateMixin { _filamentController.setFrameRate(_framerate); }); break; + case -6: + _filamentController.setBackgroundColor(Color(0xFF73C9FA)); + break; case 0: _filamentController.setBackgroundImage('assets/background.ktx'); @@ -76,18 +95,17 @@ class _MyAppState extends State with SingleTickerProviderStateMixin { _filamentController.removeSkybox(); break; case 3: - _cube = _filamentController.loadGlb('assets/cube.glb'); - _animationNames = _filamentController.getAnimationNames(_cube!); + _cube = await _filamentController.loadGlb('assets/cube.glb'); break; - case 4: if (_cube != null) { _filamentController.removeAsset(_cube!); } - _cube = _filamentController.loadGltf('assets/cube.gltf', 'assets'); + _cube = + await _filamentController.loadGltf('assets/cube.gltf', 'assets'); break; case 5: - _flightHelmet ??= _filamentController.loadGltf( + _flightHelmet ??= await _filamentController.loadGltf( 'assets/FlightHelmet/FlightHelmet.gltf', 'assets/FlightHelmet'); break; case 6: @@ -102,16 +120,6 @@ class _MyAppState extends State with SingleTickerProviderStateMixin { _filamentController.setMorphTargetWeights( _cube!, "Cube.001", List.filled(8, 0)); break; - case 9: - for (int i = 0; i < _animationNames.length; i++) { - print("Playing animation ${_animationNames[i]}"); - _filamentController.playAnimation(_cube!, i, loop: _loop); - } - - break; - case 10: - _filamentController.stopAnimation(_cube!, 0); - break; case 11: setState(() { _loop = !_loop; @@ -142,12 +150,32 @@ class _MyAppState extends State with SingleTickerProviderStateMixin { .set(); break; case 16: - _targetNames = _filamentController.getMorphTargetNames(_cube!, "Cube"); - setState(() {}); + var names = + await _filamentController.getMorphTargetNames(_cube!, "Cube"); + await showDialog( + context: context, + builder: (ctx) { + return Container( + height: 100, + width: 100, + color: Colors.white, + child: Text(names.join(","))); + }); + break; case 17: - _animationNames = _filamentController.getAnimationNames(_cube!); - setState(() {}); + var animationNames = + await _filamentController.getAnimationNames(_cube!); + + await showDialog( + context: context, + builder: (ctx) { + return Container( + height: 100, + width: 100, + color: Colors.white, + child: Text(animationNames.join(","))); + }); break; case 18: @@ -192,14 +220,13 @@ class _MyAppState extends State with SingleTickerProviderStateMixin { _filamentController.setBackgroundImagePosition(25, 25); break; case 29: - _light = _filamentController.addLight( + _light = await _filamentController.addLight( 1, 6500, 15000000, 0, 1, 0, 0, -1, 0, true); - _light = _filamentController.addLight( - 2, 6500, 15000000, 0, 0, 1, 0, 0, -1, true); break; case 30: if (_light != null) { _filamentController.removeLight(_light!); + _light = null; } break; case 31: @@ -236,6 +263,22 @@ class _MyAppState extends State with SingleTickerProviderStateMixin { setState(() { _coneHidden = !_coneHidden; }); + break; + case 34: + _filamentController.playAnimation(_cube!, 0, + loop: false, crossfade: 0.5); + break; + case 35: + _filamentController.playAnimation(_cube!, 1, + loop: false, crossfade: 0.5); + break; + case 36: + _filamentController.playAnimation(_cube!, 2, + loop: false, crossfade: 0.5); + break; + case 37: + _filamentController.stopAnimation(_cube!, 0); + break; } } @@ -247,92 +290,89 @@ class _MyAppState extends State with SingleTickerProviderStateMixin { onClick(value); }, child: Container( - margin: EdgeInsets.symmetric(vertical: 10), child: child)); + color: Colors.transparent, + padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10), + child: child)); } @override Widget build(BuildContext context) { - return MaterialApp( - // showPerformanceOverlay: true, - color: Colors.white, - home: Scaffold( - backgroundColor: Colors.white, - body: Row(children: [ - SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - "Target names : ${_targetNames.join(",")}, Animation names : ${_animationNames.join(",")}"), - _item(value: -1, child: Text("initialize")), - _item(value: -2, child: Text("render")), - _item(value: -4, child: Text("Rendering: $_rendering ")), - _item(value: -5, child: Text("$_framerate fps")), - _item(value: 0, child: Text("load background image")), - _item( - value: 1, - child: Text('load skybox'), - ), - _item( - value: -3, - child: Text('load IBL'), - ), - _item( - value: 2, - child: Text('remove skybox'), - ), - _item(value: 3, child: Text('load cube GLB')), - _item( - value: 33, - child: Text(_coneHidden ? 'show cone' : 'hide cone')), - _item(value: 4, child: Text('load cube GLTF')), - _item(value: 21, child: Text('swap cube texture')), - _item(value: 22, child: Text('transform to unit cube')), - _item(value: 23, child: Text('set position to 1, 1, -1')), - _item(value: 32, child: Text('construct bone animation')), - _item(value: 24, child: Text('rotate by pi around Y axis')), - _item(value: 5, child: Text('load flight helmet')), - _item(value: 6, child: Text('remove cube')), - _item(value: 20, child: Text('clear all assets')), - _item(value: 7, child: Text('set all weights to 1')), - _item(value: 8, child: Text('set all weights to 0')), - _item(value: 9, child: Text('play all animations')), - _item(value: 10, child: Text('stop animations')), - _item( - value: 11, - child: Text( - _loop ? "don't loop animation" : "loop animation")), - _item(value: 14, child: Text('set camera')), - _item(value: 15, child: Text('animate weights')), - _item(value: 16, child: Text('get target names')), - _item(value: 17, child: Text('get animation names')), - _item(value: 18, child: Text('pan left')), - _item(value: 19, child: Text('pan right')), - _item( - value: 25, - child: Text( - _vertical ? 'set horizontal' : 'set vertical')), - _item(value: 26, child: Text('set camera pos to 0,0,3')), - _item(value: 27, child: Text('toggle framerate')), - _item(value: 28, child: Text('set bg image pos')), - _item(value: 29, child: Text('add light')), - _item(value: 30, child: Text('remove light')), - _item(value: 31, child: Text('clear all lights')), - _item(value: 32, child: Text('set camera model matrix')), - ])), - Container( - width: _vertical ? 200 : 400, - height: _vertical ? 400 : 200, - alignment: Alignment.center, - child: SizedBox( - child: FilamentGestureDetector( - showControlOverlay: true, - controller: _filamentController, - child: FilamentWidget( - controller: _filamentController, - )), - )), - ]))); + return Row(children: [ + SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _item(value: -1, child: Text("initialize")), + _item(value: -2, child: Text("render")), + _item(value: -4, child: Text("Rendering: $_rendering ")), + _item(value: -5, child: Text("$_framerate fps")), + _item(value: -6, child: Text("set background color")), + _item(value: 0, child: Text("load background image")), + _item( + value: 1, + child: Text('load skybox'), + ), + _item( + value: -3, + child: Text('load IBL'), + ), + _item( + value: 2, + child: Text('remove skybox'), + ), + _item(value: 3, child: Text('load cube GLB')), + _item( + value: 33, + child: Text(_coneHidden ? 'show cone' : 'hide cone')), + _item(value: 4, child: Text('load cube GLTF')), + _item(value: 21, child: Text('swap cube texture')), + _item(value: 22, child: Text('transform to unit cube')), + _item(value: 23, child: Text('set position to 1, 1, -1')), + _item(value: 32, child: Text('construct bone animation')), + _item(value: 24, child: Text('rotate by pi around Y axis')), + _item(value: 5, child: Text('load flight helmet')), + _item(value: 6, child: Text('remove cube')), + _item(value: 20, child: Text('clear all assets')), + _item(value: 7, child: Text('set all weights to 1')), + _item(value: 8, child: Text('set all weights to 0')), + _item(value: 9, child: Text('play all animations')), + _item(value: 34, child: Text('play animation 0')), + _item(value: 35, child: Text('play animation 1')), + _item(value: 36, child: Text('play animation 2')), + _item(value: 37, child: Text('stop animation 0')), + _item( + value: 11, + child: Text(_loop ? "don't loop animation" : "loop animation")), + _item(value: 14, child: Text('set camera')), + _item(value: 15, child: Text('animate weights')), + _item(value: 16, child: Text('get target names')), + _item(value: 17, child: Text('get animation names')), + _item(value: 18, child: Text('pan left')), + _item(value: 19, child: Text('pan right')), + _item( + value: 25, + child: Text(_vertical ? 'set horizontal' : 'set vertical')), + _item(value: 26, child: Text('set camera pos to 0,0,3')), + _item(value: 27, child: Text('toggle framerate')), + _item(value: 28, child: Text('set bg image pos')), + _item(value: 29, child: Text('add light')), + _item(value: 30, child: Text('remove light')), + _item(value: 31, child: Text('clear all lights')), + _item(value: 32, child: Text('set camera model matrix')), + ])), + Container( + width: _vertical ? 200 : 400, + height: _vertical ? 400 : 200, + alignment: Alignment.center, + child: SizedBox( + child: FilamentGestureDetector( + showControlOverlay: true, + controller: _filamentController, + child: FilamentWidget( + controller: _filamentController, + )), + )), + ]); } } diff --git a/ios/Classes/SwiftPolyvoxFilamentPlugin.swift b/ios/Classes/SwiftPolyvoxFilamentPlugin.swift index 23a2e6cc..16c05c8b 100644 --- a/ios/Classes/SwiftPolyvoxFilamentPlugin.swift +++ b/ios/Classes/SwiftPolyvoxFilamentPlugin.swift @@ -3,11 +3,11 @@ import UIKit import GLKit public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture { - + var registrar : FlutterPluginRegistrar var flutterTextureId: Int64? var registry: FlutterTextureRegistry - + var pixelBuffer: CVPixelBuffer?; var createdAt = Date() @@ -18,121 +18,126 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture kCVPixelBufferOpenGLESCompatibilityKey: kCFBooleanTrue, kCVPixelBufferIOSurfacePropertiesKey: [:] ] as CFDictionary - + var resources:NSMutableDictionary = [:] - + + var viewer:UnsafeRawPointer? = nil var displayLink:CADisplayLink? = nil + var rendering:Bool = false static var messenger : FlutterBinaryMessenger? = nil; - + var loadResource : @convention(c) (UnsafePointer?, UnsafeMutableRawPointer?) -> ResourceBuffer = { uri, resourcesPtr in - + let instance:SwiftPolyvoxFilamentPlugin = Unmanaged.fromOpaque(resourcesPtr!).takeUnretainedValue() - + let uriString = String(cString:uri!) - - var path:String? = nil - - // check for hot-reloaded asset - var found : URL? = nil - - if(uriString.hasPrefix("asset://")) { - let assetPath = String(uriString.dropFirst(8)) - print("Searching for hot reloaded asset under path : \(assetPath)") - let appFolder = Bundle.main.resourceURL - let dirPaths = NSSearchPathForDirectoriesInDomains(.applicationDirectory, - .userDomainMask, true) - let supportDirPaths = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, - .userDomainMask, true) - let devFsPath = URL(fileURLWithPath: supportDirPaths.first!, isDirectory:true).deletingLastPathComponent().deletingLastPathComponent().appendingPathComponent("tmp") - - let orderedURLs = try? FileManager.default.enumerator(at: devFsPath, includingPropertiesForKeys: [ .pathKey, .creationDateKey], options: .skipsHiddenFiles) - + var path:String? = nil - for case let fileURL as URL in orderedURLs! { - if !(fileURL.path.hasSuffix(assetPath)) { - continue - } - print("Found hot reloaded asset : \(fileURL)") - if found == nil { - found = fileURL - } else { - do { - let c1 = try found!.resourceValues(forKeys: [.creationDateKey]).creationDate - let c2 = try fileURL.resourceValues(forKeys: [.creationDateKey]).creationDate + // check for hot-reloaded asset + var found : URL? = nil + + if(uriString.hasPrefix("asset://")) { + let assetPath = String(uriString.dropFirst(8)) + print("Searching for hot reloaded asset under path : \(assetPath)") + let appFolder = Bundle.main.resourceURL + let dirPaths = NSSearchPathForDirectoriesInDomains(.applicationDirectory, + .userDomainMask, true) + let supportDirPaths = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, + .userDomainMask, true) + let devFsPath = URL(fileURLWithPath: supportDirPaths.first!, isDirectory:true).deletingLastPathComponent().deletingLastPathComponent().appendingPathComponent("tmp") - if c1! < c2! { - found = fileURL - print("\(fileURL) is newer, replacing") - } else { - print("Ignoring older asset") - } - } catch { - - } - } - } - } - - do { - if let cd = try found?.resourceValues(forKeys:[.creationDateKey]).creationDate { - if cd > instance.createdAt { - print("Using hot reloaded asset : \(found)") - path = found!.path - } - } - } catch { - - } - if path == nil { - if(uriString.hasPrefix("file://")) { - path = String(uriString.dropFirst(7)) - } else if(uriString.hasPrefix("asset://")) { - let key = instance.registrar.lookupKey(forAsset:String(uriString.dropFirst(8))) - path = Bundle.main.path(forResource: key, ofType:nil) - print("Found path \(path) for uri \(uriString)") - guard path != nil else { - print("File not present in bundle : \(uri)") - return ResourceBuffer() - } - } else { - let key = instance.registrar.lookupKey(forAsset:uriString) - path = Bundle.main.path(forResource: key, ofType:nil) - print("Found path \(path) for uri \(uriString)") - guard path != nil else { - print("File not present in bundle : \(uri)") - return ResourceBuffer() + + let orderedURLs = try? FileManager.default.enumerator(at: devFsPath, includingPropertiesForKeys: [ .pathKey, .creationDateKey], options: .skipsHiddenFiles) + + + for case let fileURL as URL in orderedURLs! { + if !(fileURL.path.hasSuffix(assetPath)) { + continue + } + print("Found hot reloaded asset : \(fileURL)") + if found == nil { + found = fileURL + } else { + do { + let c1 = try found!.resourceValues(forKeys: [.creationDateKey]).creationDate + let c2 = try fileURL.resourceValues(forKeys: [.creationDateKey]).creationDate + + if c1! < c2! { + found = fileURL + print("\(fileURL) is newer, replacing") + } else { + print("Ignoring older asset") + } + } catch { + + } + } } } - } - do { - print("Opening data from path \(path)") - let data = try Data(contentsOf: URL(fileURLWithPath:path!)) - let resId = instance.resources.count - let nsData = data as NSData - instance.resources[resId] = nsData - let rawPtr = nsData.bytes - return ResourceBuffer(data:rawPtr, size:UInt32(nsData.count), id:UInt32(resId)) - } catch { - print("Error opening file: \(error)") - } - return ResourceBuffer() + + do { + if let cd = try found?.resourceValues(forKeys:[.creationDateKey]).creationDate { + if cd > instance.createdAt { + print("Using hot reloaded asset : \(found)") + path = found!.path + } + } + } catch { + + } + if path == nil { + if(uriString.hasPrefix("file://")) { + path = String(uriString.dropFirst(7)) + } else if(uriString.hasPrefix("asset://")) { + let key = instance.registrar.lookupKey(forAsset:String(uriString.dropFirst(8))) + path = Bundle.main.path(forResource: key, ofType:nil) + print("Found path \(path) for uri \(uriString)") + guard path != nil else { + print("File not present in bundle : \(uri)") + return ResourceBuffer() + } + } else { + let key = instance.registrar.lookupKey(forAsset:uriString) + path = Bundle.main.path(forResource: key, ofType:nil) + print("Found path \(path) for uri \(uriString)") + guard path != nil else { + print("File not present in bundle : \(uri)") + return ResourceBuffer() + } + } + } + do { + print("Opening data from path \(path)") + let data = try Data(contentsOf: URL(fileURLWithPath:path!)) + let resId = instance.resources.count + let nsData = data as NSData + instance.resources[resId] = nsData + let rawPtr = nsData.bytes + return ResourceBuffer(data:rawPtr, size:UInt32(nsData.count), id:UInt32(resId)) + } catch { + print("Error opening file: \(error)") + } + return ResourceBuffer() } - + var freeResource : @convention(c) (ResourceBuffer,UnsafeMutableRawPointer?) -> () = { rbuf, resourcesPtr in - let instance:SwiftPolyvoxFilamentPlugin = Unmanaged.fromOpaque(resourcesPtr!).takeUnretainedValue() + let instance:SwiftPolyvoxFilamentPlugin = Unmanaged.fromOpaque(resourcesPtr!).takeUnretainedValue() instance.resources.removeObject(forKey:rbuf.id) } @objc func doRender() { - + if(viewer != nil && rendering) { + render(viewer, 0) + self.registry.textureFrameAvailable(flutterTextureId!) + } } - + func createDisplayLink() { - displayLink = CADisplayLink(target: self, - selector: #selector(doRender)) - displayLink!.add(to: .current, forMode: RunLoop.Mode.default) + displayLink = CADisplayLink(target: self, + selector: #selector(doRender)) + displayLink!.add(to: .current, forMode: RunLoop.Mode.default) } public func copyPixelBuffer() -> Unmanaged? { @@ -141,7 +146,7 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture } return Unmanaged.passRetained(pixelBuffer!); } - + public func onTextureUnregistered(_ texture:FlutterTexture) { print("Texture unregistered") } @@ -150,57 +155,454 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture let _messenger = registrar.messenger(); messenger = _messenger; let channel = FlutterMethodChannel(name: "app.polyvox.filament/event", binaryMessenger: _messenger) - let instance = SwiftPolyvoxFilamentPlugin(textureRegistry: registrar.textures(), registrar:registrar) + let instance = SwiftPolyvoxFilamentPlugin(textureRegistry: registrar.textures(), registrar:registrar) registrar.addMethodCallDelegate(instance, channel: channel) } - + init(textureRegistry: FlutterTextureRegistry, registrar:FlutterPluginRegistrar) { self.registry = textureRegistry; self.registrar = registrar } - + private func createPixelBuffer(width:Int, height:Int) { - if(CVPixelBufferCreate(kCFAllocatorDefault, Int(width), Int(height), - kCVPixelFormatType_32BGRA, pixelBufferAttrs, &pixelBuffer) != kCVReturnSuccess) { - print("Error allocating pixel buffer") - } - self.flutterTextureId = self.registry.register(self) + if(CVPixelBufferCreate(kCFAllocatorDefault, Int(width), Int(height), + kCVPixelFormatType_32BGRA, pixelBufferAttrs, &pixelBuffer) != kCVReturnSuccess) { + print("Error allocating pixel buffer") + } + self.flutterTextureId = self.registry.register(self) } - + private func resize(width:Int32, height:Int32) { - if(self.flutterTextureId != nil) { - self.registry.unregisterTexture(self.flutterTextureId!) - } - createPixelBuffer(width: Int(width), height:Int(height)) + if(self.flutterTextureId != nil) { + self.registry.unregisterTexture(self.flutterTextureId!) + } + createPixelBuffer(width: Int(width), height:Int(height)) } - + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let methodName = call.method; - print(methodName) - switch methodName { + let methodName = call.method; + switch methodName { case "createTexture": - let args = call.arguments as! Array - createPixelBuffer(width:Int(args[0]), height:Int(args[1])) -// we no longer need to call createDisplayLink() because we drive our render ticker from the Dart side, not the platform side - result(self.flutterTextureId) + let args = call.arguments as! Array + createPixelBuffer(width:Int(args[0]), height:Int(args[1])) + createDisplayLink() + result(self.flutterTextureId) case "getResourceLoader": - let callback = make_resource_loader(loadResource, freeResource, Unmanaged.passUnretained(self).toOpaque()) - result(unsafeBitCast(callback, to:Int64.self)) - case "getGlTextureId": - result(FlutterMethodNotImplemented) - case "getSurface": - var pixelBufferTextureId = Int64(Int(bitPattern:unsafeBitCast(pixelBuffer!, to: UnsafeMutableRawPointer.self))) - result(pixelBufferTextureId) - case "getContext": - result(0) //nullptr + let callback = make_resource_loader(loadResource, freeResource, Unmanaged.passUnretained(self).toOpaque()) + result(unsafeBitCast(callback, to:Int64.self)) case "resize": - result(self.flutterTextureId); - case "tick": - self.registry.textureFrameAvailable(flutterTextureId!) - result(true) + result(self.flutterTextureId); + case "createFilamentViewer": + let callback = make_resource_loader(loadResource, freeResource, Unmanaged.passUnretained(self).toOpaque()) + let args = call.arguments as! [Any] + let width = args[0] as! Int64 + let height = args[1] as! Int64 + viewer = create_filament_viewer(nil, callback) + var pixelBufferTextureId = unsafeBitCast(pixelBuffer!, to: UnsafeRawPointer.self) + create_swap_chain(viewer, pixelBufferTextureId, UInt32(width), UInt32(height)) + result(unsafeBitCast(viewer, to:Int64.self)) + case "deleteFilamentViewer": + delete_filament_viewer(viewer) + viewer = nil + result(true) + case "getAssetManager": + let assetManager = get_asset_manager(viewer) + result(unsafeBitCast(assetManager, to:Int64.self)) + case "createRenderTarget": + let args = call.arguments as! [Any] + create_render_target(viewer, args[0] as! UInt32, args[1] as! UInt32, args[2] as! UInt32) + result(true) + case "clearBackgroundImage": + clear_background_image(viewer) + result(true) + case "setBackgroundImage": + set_background_image(viewer, call.arguments as! String) + 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 "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": + render(viewer, 0) + result(true) + case "setRendering": + rendering = call.arguments as! Bool + result(true) + case "setFrameInterval": + set_frame_interval(viewer, Float(call.arguments as! Double)) + 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, Int32(width), Int32(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 == 4, + let assetManager = args[0] as? Int64, + let asset = args[1] as? EntityId, + let entityName = args[2] as? String, + let morphData = args[3] as? [Float], + let numWeights = args[4] as? Int else { + result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for set_morph_target_weights", details: nil)) + return + } + // set_morph_target_weights(assetManager, asset, entityName, UnsafeMutablePointer(&morphData), numWeights) + result(true) + + case "setMorphAnimation": + guard let args = call.arguments as? [Any], args.count == 7, + let assetManager = args[0] as? Int64, + let asset = args[1] as? EntityId, + let entityName = args[2] as? String, + let morphData = args[3] as? [Float], + let numMorphWeights = args[4] as? Int, + let numFrames = args[5] as? Int, + let frameLengthInMs = args[6] as? Float else { + result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for set_morph_animation", details: nil)) + return + } + // let success = set_morph_animation(assetManager, asset, entityName, UnsafeMutablePointer(&morphData), numMorphWeights, numFrames, frameLengthInMs) + result(-1) + 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 == 6, + 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 crossfade = args[5] as? Float 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, crossfade) + result(true) + 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] = []; + var 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] = [] + 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 == 3, + let asset = args[0] as? Int64, + let nodeName = args[1] as? String else { + result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected viewer, asset, and nodeName for set_camera", details: nil)) + return + } + let success = set_camera(viewer, Int32(asset), nodeName) + result(success) + + 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 "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) - } + result(FlutterMethodNotImplemented) + } } } diff --git a/ios/include/AssetManager.hpp b/ios/include/AssetManager.hpp index beab0a28..26908c2d 100644 --- a/ios/include/AssetManager.hpp +++ b/ios/include/AssetManager.hpp @@ -17,7 +17,7 @@ namespace polyvox { class AssetManager { public: - AssetManager(ResourceLoaderWrapper* loader, + AssetManager(const ResourceLoaderWrapper* const loader, NameComponentManager *ncm, Engine *engine, Scene *scene); @@ -40,7 +40,6 @@ namespace polyvox { size_t getLightEntityCount(EntityId e) const noexcept; void updateAnimations(); - bool setMorphAnimationBuffer( EntityId entityId, const char* entityName, @@ -59,7 +58,7 @@ namespace polyvox { const char** const meshName, int numMeshTargets, float frameLengthInMs); - void playAnimation(EntityId e, int index, bool loop, bool reverse); + void playAnimation(EntityId e, int index, bool loop, bool reverse, float crossfade = 0.3f); void stopAnimation(EntityId e, int index); void setMorphTargetWeights(const char* const entityName, float *weights, int count); void loadTexture(EntityId entity, const char* resourcePath, int renderableIndex); @@ -69,7 +68,7 @@ namespace polyvox { private: AssetLoader* _assetLoader = nullptr; - ResourceLoaderWrapper* _resourceLoaderWrapper; + const ResourceLoaderWrapper* const _resourceLoaderWrapper; NameComponentManager* _ncm = nullptr; Engine* _engine; Scene* _scene; diff --git a/ios/include/FilamentViewer.hpp b/ios/include/FilamentViewer.hpp index 467cda2a..6ae31988 100644 --- a/ios/include/FilamentViewer.hpp +++ b/ios/include/FilamentViewer.hpp @@ -44,8 +44,7 @@ typedef int32_t EntityId; namespace polyvox { class FilamentViewer { public: - // FilamentViewer(void* layer, LoadResource loadResource, FreeResource freeResource); - FilamentViewer(void* context, ResourceLoaderWrapper* resourceLoaderWrapper); + FilamentViewer(const void* context, const ResourceLoaderWrapper* const resourceLoaderWrapper); ~FilamentViewer(); void loadSkybox(const char* const skyboxUri); @@ -64,7 +63,7 @@ namespace polyvox { bool setCamera(EntityId asset, const char* nodeName); - void createSwapChain(void* surface, uint32_t width, uint32_t height); + void createSwapChain(const void* surface, uint32_t width, uint32_t height); void destroySwapChain(); void createRenderTarget(uint32_t glTextureId, uint32_t width,uint32_t height); @@ -108,7 +107,7 @@ namespace polyvox { math::mat4f _cameraPosition; math::mat4f _cameraRotation; - ResourceLoaderWrapper* _resourceLoaderWrapper; + const ResourceLoaderWrapper* const _resourceLoaderWrapper; Scene* _scene; View* _view; diff --git a/ios/include/PolyvoxFilamentApi.h b/ios/include/PolyvoxFilamentApi.h index 4ee60afe..3fb9c013 100644 --- a/ios/include/PolyvoxFilamentApi.h +++ b/ios/include/PolyvoxFilamentApi.h @@ -3,43 +3,38 @@ #include "ResourceBuffer.hpp" -#include - typedef int32_t EntityId; -void* create_filament_viewer(void *context, ResourceLoaderWrapper* loader); +const void* create_filament_viewer(const void* const context, const ResourceLoaderWrapper* const loader); ResourceLoaderWrapper* make_resource_loader(LoadResourceFromOwner loadFn, FreeResourceFromOwner freeFn, void* owner); -void delete_filament_viewer(void *viewer); -void* get_asset_manager(void* viewer); -void create_render_target(void *viewer, uint32_t textureId, uint32_t width, uint32_t height); -void clear_background_image(void *viewer); -void set_background_image(void *viewer, const char *path); -void set_background_image_position(void *viewer, float x, float y, bool clamp); -void set_background_color(void *viewer, const float r, const float g, const float b, const float a); -void load_skybox(void *viewer, const char *skyboxPath); -void load_ibl(void *viewer, const char *iblPath, float intensity); -void remove_skybox(void *viewer); -void remove_ibl(void *viewer); -EntityId add_light(void *viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows); -void remove_light(void *viewer, EntityId entityId); -void clear_lights(void *viewer); +void delete_filament_viewer(const void* const viewer); +void* get_asset_manager(const void* const viewer); +void create_render_target(const void* const viewer, uint32_t textureId, uint32_t width, uint32_t height); +void clear_background_image(const void* const viewer); +void set_background_image(const void* const viewer, const char *path); +void set_background_image_position(const void* const viewer, float x, float y, bool clamp); +void set_background_color(const void* const viewer, const float r, const float g, const float b, const float a); +void load_skybox(const void* const viewer, const char *skyboxPath); +void load_ibl(const void* const viewer, const char *iblPath, float intensity); +void remove_skybox(const void* const viewer); +void remove_ibl(const void* const viewer); +EntityId add_light(const void* const viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows); +void remove_light(const void* const viewer, EntityId entityId); +void clear_lights(const void* const viewer); EntityId load_glb(void *assetManager, const char *assetPath, bool unlit); EntityId load_gltf(void *assetManager, const char *assetPath, const char *relativePath); -bool set_camera(void *viewer, EntityId asset, const char *nodeName); -void render(void *viewer, uint64_t frameTimeInNanos); -void create_swap_chain(void *viewer, void *surface, uint32_t width, uint32_t height); -void destroy_swap_chain(void *viewer); -void set_frame_interval(void *viewer, float interval); -void* get_renderer(void *viewer); -void update_viewport_and_camera_projection(void *viewer, int width, int height, float scaleFactor); -void scroll_begin(void *viewer); -void scroll_update(void *viewer, float x, float y, float z); -void scroll_end(void *viewer); - -void grab_begin(void *viewer, float x, float y, bool pan); -void grab_update(void *viewer, float x, float y); -void grab_end(void *viewer); - +bool set_camera(const void* const viewer, EntityId asset, const char *nodeName); +void render(const void* const viewer, uint64_t frameTimeInNanos); +void create_swap_chain(const void* const viewer, const void* const surface, uint32_t width, uint32_t height); +void destroy_swap_chain(const void* const viewer); +void set_frame_interval(const void* const viewer, float interval); +void update_viewport_and_camera_projection(const void* const viewer, int width, int height, float scaleFactor); +void scroll_begin(const void* const viewer); +void scroll_update(const void* const viewer, float x, float y, float z); +void scroll_end(const void* const viewer); +void grab_begin(const void* const viewer, float x, float y, bool pan); +void grab_update(const void* const viewer, float x, float y); +void grab_end(const void* const viewer); void apply_weights( void* assetManager, EntityId asset, @@ -47,7 +42,6 @@ void apply_weights( float *const weights, int count ); - void set_morph_target_weights( void* assetManager, EntityId asset, @@ -55,7 +49,6 @@ void set_morph_target_weights( const float *const morphData, int numWeights ); - bool set_morph_animation( void* assetManager, EntityId asset, @@ -64,7 +57,6 @@ bool set_morph_animation( int numMorphWeights, int numFrames, float frameLengthInMs); - void set_bone_animation( void* assetManager, EntityId asset, @@ -76,29 +68,30 @@ void set_bone_animation( int numMeshTargets, float frameLengthInMs); -void play_animation(void* assetManager, EntityId asset, int index, bool loop, bool reverse); +void play_animation(void* assetManager, EntityId asset, int index, bool loop, bool reverse, float crossfade); void set_animation_frame(void* assetManager, EntityId asset, int animationIndex, int animationFrame); void stop_animation(void* assetManager, EntityId asset, int index); int get_animation_count(void* assetManager, EntityId asset); void get_animation_name(void* assetManager, EntityId asset, char *const outPtr, int index); void get_morph_target_name(void* assetManager, EntityId asset, const char *meshName, char *const outPtr, int index); int get_morph_target_name_count(void* assetManager, EntityId asset, const char *meshName); -void remove_asset(void *viewer, EntityId asset); -void clear_assets(void *viewer); +void remove_asset(const void* const viewer, EntityId asset); +void clear_assets(const void* const viewer); void load_texture(void* assetManager, EntityId asset, const char *assetPath, int renderableIndex); void set_texture(void* assetManager, EntityId asset); void transform_to_unit_cube(void* assetManager, EntityId asset); void set_position(void* assetManager, EntityId asset, float x, float y, float z); void set_rotation(void* assetManager, EntityId asset, float rads, float x, float y, float z); void set_scale(void* assetManager, EntityId asset, float scale); -void set_camera_exposure(void *viewer, float aperture, float shutterSpeed, float sensitivity); -void set_camera_position(void *viewer, float x, float y, float z); -void set_camera_rotation(void *viewer, float rads, float x, float y, float z); -void set_camera_model_matrix(void *viewer, const float *const matrix); -void set_camera_focal_length(void *viewer, float focalLength); -void set_camera_focus_distance(void *viewer, float focusDistance); +void set_camera_exposure(const void* const viewer, float aperture, float shutterSpeed, float sensitivity); +void set_camera_position(const void* const viewer, float x, float y, float z); +void set_camera_rotation(const void* const viewer, float rads, float x, float y, float z); +void set_camera_model_matrix(const void* const viewer, const float *const matrix); +void set_camera_focal_length(const void* const viewer, float focalLength); +void set_camera_focus_distance(const void* const viewer, float focusDistance); int hide_mesh(void* assetManager, EntityId asset, const char* meshName); int reveal_mesh(void* assetManager, EntityId asset, const char* meshName); void ios_dummy(); + #endif diff --git a/ios/include/ResourceBuffer.hpp b/ios/include/ResourceBuffer.hpp index 046caf5d..182e10ae 100644 --- a/ios/include/ResourceBuffer.hpp +++ b/ios/include/ResourceBuffer.hpp @@ -51,14 +51,14 @@ extern "C" { }; - ResourceBuffer load(const char* uri) { + ResourceBuffer load(const char* uri) const { if(mLoadResourceFromOwner) { return mLoadResourceFromOwner(uri, mOwner); } return mLoadResource(uri); } - void free(ResourceBuffer rb) { + void free(ResourceBuffer rb) const { if(mFreeResourceFromOwner) { mFreeResourceFromOwner(rb, mOwner); } else { diff --git a/ios/include/SceneAsset.hpp b/ios/include/SceneAsset.hpp index d7ee58e5..f5c1568b 100644 --- a/ios/include/SceneAsset.hpp +++ b/ios/include/SceneAsset.hpp @@ -35,8 +35,8 @@ namespace polyvox { time_point_t mStart = time_point_t::max(); bool mLoop = false; bool mReverse = false; - float mDuration = 0; - bool mAnimating = false; + float mDuration = 0; + bool mActive = false; }; // @@ -73,10 +73,16 @@ namespace polyvox { FilamentAsset* mAsset = nullptr; Animator* mAnimator = nullptr; - // fixed-sized vector containing the status of the morph, bone and GLTF animations. - // entries 0 and 1 are the morph/bone animations. - // subsequent entries are the GLTF animations. - vector mAnimations; + // fixed-sized array containing pointers to the active morph, bone and GLTF animations. + AnimationStatus mAnimations[3]; + // the index of the active glTF animation in the Filament Asset animations array + // if no glTF animation is active, this is -1 + int gltfAnimationIndex = -1; + // the index of the last active glTF animation, + // used to cross-fade + int fadeGltfAnimationIndex = -1; + float fadeDuration = 0.0f; + float fadeOutAnimationStart = 0.0f; MorphAnimationBuffer mMorphAnimationBuffer; BoneAnimationBuffer mBoneAnimationBuffer; @@ -96,12 +102,6 @@ namespace polyvox { FilamentAsset* asset ) : mAsset(asset) { mAnimator = mAsset->getInstance()->getAnimator(); - - mAnimations.resize(2 + mAnimator->getAnimationCount()); - - for(int i=0; i < mAnimations.size() - 2; i++) { - mAnimations[i].mDuration = mAnimator->getAnimationDuration(i); - } } }; -} \ No newline at end of file +} diff --git a/ios/src/AssetManager.cpp b/ios/src/AssetManager.cpp index 0bf02531..d706c0fc 100644 --- a/ios/src/AssetManager.cpp +++ b/ios/src/AssetManager.cpp @@ -37,7 +37,7 @@ using namespace utils; using namespace filament; using namespace filament::gltfio; -AssetManager::AssetManager(ResourceLoaderWrapper* resourceLoaderWrapper, +AssetManager::AssetManager(const ResourceLoaderWrapper* const resourceLoaderWrapper, NameComponentManager *ncm, Engine *engine, Scene *scene) @@ -249,37 +249,34 @@ void AssetManager::updateAnimations() { asset.mAnimating = false; // GLTF animations - for(int j = 0; j < asset.mAnimations.size() - 2; j++) { - AnimationStatus& anim = asset.mAnimations[j]; + AnimationStatus& anim = asset.mAnimations[2]; - if(!anim.mAnimating) { - // Log("Skipping anim at %d", j); - continue; - } - + if(anim.mActive) { auto elapsed = float(std::chrono::duration_cast(now - anim.mStart).count()) / 1000.0f; if(anim.mLoop || elapsed < anim.mDuration) { - asset.mAnimator->applyAnimation(j, elapsed); + asset.mAnimator->applyAnimation(asset.gltfAnimationIndex, elapsed); asset.mAnimating = true; - } else if(elapsed - anim.mDuration < 0.3) { - // cross-fade - // animator->applyCrossFade(j-2, anim.mDuration - 0.05, elapsed / 0.3); - // asset.mAnimating = true; - // anim.mStart = time_point_t::max(); + if(asset.fadeGltfAnimationIndex != -1 && elapsed < asset.fadeDuration) { + // cross-fade + auto fadeFromTime = asset.fadeOutAnimationStart + elapsed; + auto alpha = elapsed / asset.fadeDuration; + asset.mAnimator->applyCrossFade(asset.fadeGltfAnimationIndex, fadeFromTime, alpha); + } } else { // stop anim.mStart = time_point_t::max(); - anim.mAnimating = false; - Log("Finished"); + anim.mActive = false; + asset.gltfAnimationIndex = -1; + asset.fadeGltfAnimationIndex = -1; } asset.mAnimator->updateBoneMatrices(); } - // dynamically constructed morph animation - AnimationStatus& morphAnimation = asset.mAnimations[asset.mAnimations.size() - 2]; + // dynamic morph animation + AnimationStatus& morphAnimation = asset.mAnimations[0]; - if(morphAnimation.mAnimating) { + if(morphAnimation.mActive) { auto elapsed = float( std::chrono::duration_cast( @@ -290,13 +287,11 @@ void AssetManager::updateAnimations() { asset.mMorphAnimationBuffer.mFrameLengthInMs ); - // if more time has elapsed than the animation duration && not looping - // mark the animation as complete + // if more time has elapsed than the animation duration && we aren't looping, then mark the animation as complete if(elapsed >= morphAnimation.mDuration && !morphAnimation.mLoop) { morphAnimation.mStart = time_point_t::max(); - morphAnimation.mAnimating = false; + morphAnimation.mActive = false; } else { - asset.mAnimating = true; int frameNumber = static_cast(elapsed * 1000.0f / asset.mMorphAnimationBuffer.mFrameLengthInMs) % lengthInFrames; // offset from the end if reverse @@ -304,17 +299,18 @@ void AssetManager::updateAnimations() { frameNumber = lengthInFrames - frameNumber; } - // set the weights appropriately - rm.setMorphWeights( + // set the weights appropriately + rm.setMorphWeights( rm.getInstance(asset.mMorphAnimationBuffer.mMeshTarget), asset.mMorphAnimationBuffer.mFrameData.data() + (frameNumber * asset.mMorphAnimationBuffer.mNumMorphWeights), - asset.mMorphAnimationBuffer.mNumMorphWeights); + asset.mMorphAnimationBuffer.mNumMorphWeights + ); } } - // bone animation - AnimationStatus boneAnimation = asset.mAnimations[asset.mAnimations.size() - 1]; - if(boneAnimation.mAnimating) { + // dynamic bone animations + AnimationStatus boneAnimation = asset.mAnimations[1]; + if(boneAnimation.mActive) { auto elapsed = float( std::chrono::duration_cast( now - boneAnimation.mStart @@ -324,11 +320,10 @@ void AssetManager::updateAnimations() { asset.mBoneAnimationBuffer.mFrameLengthInMs ); - // if more time has elapsed than the animation duration && not looping - // mark the animation as complete + // if more time has elapsed than the animation duration and we are not looping, mark the animation as complete if(elapsed >= boneAnimation.mDuration && !boneAnimation.mLoop) { boneAnimation.mStart = time_point_t::max(); - boneAnimation.mAnimating = false; + boneAnimation.mActive = false; } else { asset.mAnimating = true; @@ -347,7 +342,6 @@ void AssetManager::updateAnimations() { asset.mAnimator->updateBoneMatrices(); } } - } void AssetManager::setBoneTransform(SceneAsset& asset, int frameNumber) { @@ -482,15 +476,11 @@ bool AssetManager::setMorphAnimationBuffer( asset.mMorphAnimationBuffer.mFrameLengthInMs = frameLengthInMs; asset.mMorphAnimationBuffer.mNumMorphWeights = numMorphWeights; - AnimationStatus& animation = asset.mAnimations[asset.mAnimations.size() - 2]; + AnimationStatus& animation = asset.mAnimations[0]; animation.mDuration = (frameLengthInMs * numFrames) / 1000.0f; animation.mStart = high_resolution_clock::now(); - animation.mAnimating = true; + animation.mActive = true; asset.mAnimating = true; - Log("set start to %d, dur is %f", - std::chrono::duration_cast(animation.mStart.time_since_epoch()).count(), - animation.mDuration - ); return true; } @@ -504,8 +494,6 @@ bool AssetManager::setBoneAnimationBuffer( int numMeshTargets, float frameLengthInMs) { - - const auto& pos = _entityIdLookup.find(entityId); if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); @@ -585,9 +573,9 @@ bool AssetManager::setBoneAnimationBuffer( animationBuffer.mMeshTargets.push_back(entity); } - auto& animation = asset.mAnimations[asset.mAnimations.size() - 1]; + auto& animation = asset.mAnimations[1]; animation.mStart = std::chrono::high_resolution_clock::now(); - animation.mAnimating = true; + animation.mActive = true; animation.mReverse = false; animation.mDuration = (frameLengthInMs * numFrames) / 1000.0f; asset.mAnimating = true; @@ -596,21 +584,31 @@ bool AssetManager::setBoneAnimationBuffer( } - -void AssetManager::playAnimation(EntityId e, int index, bool loop, bool reverse) { +void AssetManager::playAnimation(EntityId e, int index, bool loop, bool reverse, float crossfade) { const auto& pos = _entityIdLookup.find(e); if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return; } auto& asset = _assets[pos->second]; - Log("Playing animation at %d", index); - - asset.mAnimations[index].mStart = std::chrono::high_resolution_clock::now(); - asset.mAnimations[index].mLoop = loop; - asset.mAnimations[index].mReverse = reverse; - asset.mAnimations[index].mAnimating = true; - // Log("new start %d, dur is %f", std::chrono::duration_cast(asset.mAnimations[index+2].mStart.time_since_epoch()).count(), asset.mAnimations[index+2].mDuration); + + if(asset.gltfAnimationIndex != -1) { + asset.fadeGltfAnimationIndex = asset.gltfAnimationIndex; + asset.fadeDuration = crossfade; + auto now = high_resolution_clock::now(); + auto elapsed = float(std::chrono::duration_cast(now - asset.mAnimations[2].mStart).count()) / 1000.0f; + asset.fadeOutAnimationStart = elapsed; + } else { + asset.fadeGltfAnimationIndex = -1; + asset.fadeDuration = 0.0f; + } + + asset.gltfAnimationIndex = index; + asset.mAnimations[2].mStart = std::chrono::high_resolution_clock::now(); + asset.mAnimations[2].mLoop = loop; + asset.mAnimations[2].mReverse = reverse; + asset.mAnimations[2].mActive = true; + asset.mAnimations[2].mDuration = asset.mAnimator->getAnimationDuration(index); asset.mAnimating = true; } @@ -621,7 +619,12 @@ void AssetManager::stopAnimation(EntityId entityId, int index) { return; } auto& asset = _assets[pos->second]; - asset.mAnimations[index].mStart = time_point_t::max(); + if(asset.gltfAnimationIndex != index) { + // ignore? + } else { + asset.mAnimations[2].mStart = time_point_t::max(); + asset.mAnimations[2].mActive = false; + } } void AssetManager::loadTexture(EntityId entity, const char* resourcePath, int renderableIndex) { @@ -898,4 +901,4 @@ size_t AssetManager::getLightEntityCount(EntityId entity) const noexcept { // Log("%f %f %f %f", localTransform[0][1], localTransform[1][1], localTransform[2][1], localTransform[3][1] ) ; // Log("%f %f %f %f", localTransform[0][2], localTransform[1][2], localTransform[2][2], localTransform[3][2] ) ; // Log("%f %f %f %f", localTransform[0][3], localTransform[1][3], localTransform[2][3], localTransform[3][3] ) ; - // transformManager.getTransform(jointInstance); \ No newline at end of file + // transformManager.getTransform(jointInstance); diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index 370c499e..fb82d93e 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -107,7 +107,7 @@ static constexpr float4 sFullScreenTriangleVertices[3] = { static const uint16_t sFullScreenTriangleIndices[3] = {0, 1, 2}; -FilamentViewer::FilamentViewer(void* context, ResourceLoaderWrapper* resourceLoaderWrapper) +FilamentViewer::FilamentViewer(const void* context, const ResourceLoaderWrapper* const resourceLoaderWrapper) : _resourceLoaderWrapper(resourceLoaderWrapper) { #if TARGET_OS_IPHONE @@ -137,13 +137,14 @@ FilamentViewer::FilamentViewer(void* context, ResourceLoaderWrapper* resourceLoa _view = _engine->createView(); decltype(_view->getBloomOptions()) opts; - opts.enabled = false;//true; - // opts.strength = 0.6f; + opts.enabled = true; + opts.strength = 0.6f; _view->setBloomOptions(opts); _view->setScene(_scene); _view->setCamera(_mainCamera); +// ToneMapper *tm = new ACESToneMapper(); ToneMapper *tm = new LinearToneMapper(); colorGrading = ColorGrading::Builder().toneMapper(tm).build(*_engine); delete tm; @@ -168,8 +169,7 @@ FilamentViewer::FilamentViewer(void* context, ResourceLoaderWrapper* resourceLoa // options.minScale = filament::math::float2{ minScale }; // options.maxScale = filament::math::float2{ maxScale }; // options.sharpness = sharpness; - options.quality = View::QualityLevel::ULTRA; - + // options.quality = View::QualityLevel::ULTRA; _view->setDynamicResolutionOptions(options); View::MultiSampleAntiAliasingOptions multiSampleAntiAliasingOptions; @@ -206,7 +206,7 @@ FilamentViewer::FilamentViewer(void* context, ResourceLoaderWrapper* resourceLoa .package(IMAGE_PACKAGE, IMAGE_IMAGE_SIZE) .build(*_engine); _imageMaterial->setDefaultParameter("showImage",0); - _imageMaterial->setDefaultParameter("backgroundColor", RgbType::sRGB, float3(0.f)); + _imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(0.5f, 0.5f, 0.5f, 1.0f)); _imageMaterial->setDefaultParameter("image", _imageTexture, _imageSampler); _imageScale = mat4f { 1.0f , 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; @@ -251,7 +251,6 @@ void FilamentViewer::setFrameInterval(float frameInterval) { } int32_t FilamentViewer::addLight(LightManager::Type t, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows) { - Log("Adding light of type %d with colour %f intensity %f at (%f, %f, %f) with direction (%f, %f, %f) with shadows %d", t, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, shadows); auto light = EntityManager::get().create(); LightManager::Builder(t) .color(Color::cct(colour)) @@ -262,14 +261,22 @@ int32_t FilamentViewer::addLight(LightManager::Type t, float colour, float inten .build(*_engine, light); _scene->addEntity(light); _lights.push_back(light); - return Entity::smuggle(light); + auto entityId = Entity::smuggle(light); + Log("Added light under entity ID %d of type %d with colour %f intensity %f at (%f, %f, %f) with direction (%f, %f, %f) with shadows %d", entityId, t, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, shadows); + return entityId; } -void FilamentViewer::removeLight(int32_t id) { - Log("Removing light with entity ID %d", id); - auto e = utils::Entity::import(id); - _scene->removeEntities(&e, 1); - EntityManager::get().destroy(1, &e); +void FilamentViewer::removeLight(EntityId entityId) { + Log("Removing light with entity ID %d", entityId); + auto entity = utils::Entity::import(entityId); + if(entity.isNull()) { + Log("Error: light entity not found under ID %d", entityId); + } else { + + remove(_lights.begin(), _lights.end(), entity); + _scene->remove(entity); + EntityManager::get().destroy(1, &entity); + } } void FilamentViewer::clearLights() { @@ -388,7 +395,6 @@ void FilamentViewer::setBackgroundColor(const float r, const float g, const floa _imageMaterial->setDefaultParameter("showImage", 0); _imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(r, g, b, a)); const Viewport& vp = _view->getViewport(); - Log("Image width %d height %d vp width %d height %d", _imageWidth, _imageHeight, vp.width, vp.height); _imageMaterial->setDefaultParameter("transform", _imageScale); } @@ -522,9 +528,9 @@ FilamentViewer::~FilamentViewer() { Renderer *FilamentViewer::getRenderer() { return _renderer; } -void FilamentViewer::createSwapChain(void *surface, uint32_t width, uint32_t height) { +void FilamentViewer::createSwapChain(const void *surface, uint32_t width, uint32_t height) { #if TARGET_OS_IPHONE - _swapChain = _engine->createSwapChain(surface, filament::backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER); + _swapChain = _engine->createSwapChain((void*)surface, filament::backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER); #else if(surface) { _swapChain = _engine->createSwapChain(surface); diff --git a/ios/src/PolyvoxFilamentApi.cpp b/ios/src/PolyvoxFilamentApi.cpp index 1bdb63e8..fb91dab6 100644 --- a/ios/src/PolyvoxFilamentApi.cpp +++ b/ios/src/PolyvoxFilamentApi.cpp @@ -12,310 +12,158 @@ using namespace polyvox; #define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) - - -// static ThreadPool* _tp; - extern "C" { #include "PolyvoxFilamentApi.h" - FLUTTER_PLUGIN_EXPORT void* create_filament_viewer(void* context, ResourceLoaderWrapper* loader) { - // if(!_tp) { - // _tp = new ThreadPool(); - // } - // //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT const void* create_filament_viewer(const void* context, const ResourceLoaderWrapper* const loader) { return (void*) new FilamentViewer(context, loader); - // }); - // auto fut = _tp->add_task(lambda); - // fut.wait(); - // //return fut.get(); } FLUTTER_PLUGIN_EXPORT ResourceLoaderWrapper* make_resource_loader(LoadResourceFromOwner loadFn, FreeResourceFromOwner freeFn, void* const owner) { - return new ResourceLoaderWrapper(loadFn, freeFn, owner); -// ResourceLoaderWrapper* lod(loadFn, freeFn, owner); -// return &lod; + return new ResourceLoaderWrapper(loadFn, freeFn, owner); } - FLUTTER_PLUGIN_EXPORT void create_render_target(void* viewer, uint32_t textureId, uint32_t width, uint32_t height) { - // //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void create_render_target(const void* const viewer, uint32_t textureId, uint32_t width, uint32_t height) { ((FilamentViewer*)viewer)->createRenderTarget(textureId, width, height); - // }); - // auto fut = _tp->add_task(lambda); - // fut.wait(); } - FLUTTER_PLUGIN_EXPORT void delete_filament_viewer(void* viewer) { + FLUTTER_PLUGIN_EXPORT void delete_filament_viewer(const void* const viewer) { delete((FilamentViewer*)viewer); } - FLUTTER_PLUGIN_EXPORT void set_background_color(void* viewer, const float r, const float g, const float b, const float a) { - // //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void set_background_color(const void* const viewer, const float r, const float g, const float b, const float a) { ((FilamentViewer*)viewer)->setBackgroundColor(r, g, b, a); - // }); - // auto fut = _tp->add_task(lambda); - // fut.wait(); } - FLUTTER_PLUGIN_EXPORT void clear_background_image(void* viewer) { - // //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void clear_background_image(const void* const viewer) { ((FilamentViewer*)viewer)->clearBackgroundImage(); - // }); - // auto fut = _tp->add_task(lambda); - // fut.wait(); } - FLUTTER_PLUGIN_EXPORT void set_background_image(void* viewer, const char* path) { - // //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void set_background_image(const void* const viewer, const char* path) { ((FilamentViewer*)viewer)->setBackgroundImage(path); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void set_background_image_position(void* viewer, float x, float y, bool clamp) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void set_background_image_position(const void* const viewer, float x, float y, bool clamp) { ((FilamentViewer*)viewer)->setBackgroundImagePosition(x, y, clamp); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void load_skybox(void* viewer, const char* skyboxPath) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void load_skybox(const void* const viewer, const char* skyboxPath) { ((FilamentViewer*)viewer)->loadSkybox(skyboxPath); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void load_ibl(void* viewer, const char* iblPath, float intensity) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void load_ibl(const void* const viewer, const char* iblPath, float intensity) { ((FilamentViewer*)viewer)->loadIbl(iblPath, intensity); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void remove_skybox(void* viewer) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void remove_skybox(const void* const viewer) { ((FilamentViewer*)viewer)->removeSkybox(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void remove_ibl(void* viewer) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void remove_ibl(const void* const viewer) { ((FilamentViewer*)viewer)->removeIbl(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT EntityId add_light(void* viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT EntityId add_light(const void* const viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows) { return ((FilamentViewer*)viewer)->addLight((LightManager::Type)type, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, shadows); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); - //return fut.get(); } - FLUTTER_PLUGIN_EXPORT void remove_light(void* viewer, int32_t entityId) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void remove_light(const void* const viewer, int32_t entityId) { ((FilamentViewer*)viewer)->removeLight(entityId); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void clear_lights(void* viewer) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void clear_lights(const void* const viewer) { ((FilamentViewer*)viewer)->clearLights(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT EntityId load_glb(void* assetManager, const char* assetPath, bool unlit) { - //std::packaged_task lambda([=]() mutable { return ((AssetManager*)assetManager)->loadGlb(assetPath, unlit); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); - //return fut.get(); } FLUTTER_PLUGIN_EXPORT EntityId load_gltf(void* assetManager, const char* assetPath, const char* relativePath) { - //std::packaged_task lambda([=]() mutable { return ((AssetManager*)assetManager)->loadGltf(assetPath, relativePath); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); - //return fut.get(); } - FLUTTER_PLUGIN_EXPORT bool set_camera(void* viewer, EntityId asset, const char* nodeName) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT bool set_camera(const void* const viewer, EntityId asset, const char* nodeName) { return ((FilamentViewer*)viewer)->setCamera(asset, nodeName); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); - //return fut.get(); } - FLUTTER_PLUGIN_EXPORT void set_camera_exposure(void* viewer, float aperture, float shutterSpeed, float sensitivity) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void set_camera_focus_distance(const void* const viewer, float distance) { + ((FilamentViewer*)viewer)->setCameraFocusDistance(distance); + } + + FLUTTER_PLUGIN_EXPORT void set_camera_exposure(const void* const viewer, float aperture, float shutterSpeed, float sensitivity) { ((FilamentViewer*)viewer)->setCameraExposure(aperture, shutterSpeed, sensitivity); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void set_camera_position(void* viewer, float x, float y, float z) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void set_camera_position(const void* const viewer, float x, float y, float z) { ((FilamentViewer*)viewer)->setCameraPosition(x, y, z); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void set_camera_rotation(void* viewer, float rads, float x, float y, float z) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void set_camera_rotation(const void* const viewer, float rads, float x, float y, float z) { ((FilamentViewer*)viewer)->setCameraRotation(rads, x, y, z); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void set_camera_model_matrix(void* viewer, const float* const matrix) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void set_camera_model_matrix(const void* const viewer, const float* const matrix) { ((FilamentViewer*)viewer)->setCameraModelMatrix(matrix); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void set_camera_focal_length(void* viewer, float focalLength) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void set_camera_focal_length(const void* const viewer, float focalLength) { ((FilamentViewer*)viewer)->setCameraFocalLength(focalLength); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT void render( - void* viewer, + const void* const viewer, uint64_t frameTimeInNanos ) { - //std::packaged_task lambda([=]() mutable { ((FilamentViewer*)viewer)->render(frameTimeInNanos); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT void set_frame_interval( - void* viewer, + const void* const viewer, float frameInterval ) { - //std::packaged_task lambda([=]() mutable { ((FilamentViewer*)viewer)->setFrameInterval(frameInterval); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void destroy_swap_chain(void* viewer) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void destroy_swap_chain(const void* const viewer) { ((FilamentViewer*)viewer)->destroySwapChain(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void create_swap_chain(void* viewer, void* surface=nullptr, uint32_t width=0, uint32_t height=0) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void create_swap_chain(const void* const viewer, const void* const surface=nullptr, uint32_t width=0, uint32_t height=0) { ((FilamentViewer*)viewer)->createSwapChain(surface, width, height); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void* get_renderer(void* viewer) { - //std::packaged_task lambda([=]() mutable { - return ((FilamentViewer*)viewer)->getRenderer(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); - //return fut.get(); - } - - FLUTTER_PLUGIN_EXPORT void update_viewport_and_camera_projection(void* viewer, int width, int height, float scaleFactor) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void update_viewport_and_camera_projection(const void* const viewer, int width, int height, float scaleFactor) { return ((FilamentViewer*)viewer)->updateViewportAndCameraProjection(width, height, scaleFactor); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void scroll_update(void* viewer, float x, float y, float delta) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void scroll_update(const void* const viewer, float x, float y, float delta) { ((FilamentViewer*)viewer)->scrollUpdate(x, y, delta); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void scroll_begin(void* viewer) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void scroll_begin(const void* const viewer) { ((FilamentViewer*)viewer)->scrollBegin(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void scroll_end(void* viewer) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void scroll_end(const void* const viewer) { ((FilamentViewer*)viewer)->scrollEnd(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void grab_begin(void* viewer, float x, float y, bool pan) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void grab_begin(const void* const viewer, float x, float y, bool pan) { ((FilamentViewer*)viewer)->grabBegin(x, y, pan); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void grab_update(void* viewer, float x, float y) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void grab_update(const void* const viewer, float x, float y) { ((FilamentViewer*)viewer)->grabUpdate(x, y); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void grab_end(void* viewer) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void grab_end(const void* const viewer) { ((FilamentViewer*)viewer)->grabEnd(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void* get_asset_manager(void* viewer) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void* get_asset_manager(const void* const viewer) { return (void*)((FilamentViewer*)viewer)->getAssetManager(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); - //return fut.get(); } FLUTTER_PLUGIN_EXPORT void apply_weights( @@ -324,11 +172,7 @@ extern "C" { const char* const entityName, float* const weights, int count) { - // //std::packaged_task lambda([=]() mutable { // ((AssetManager*)assetManager)->setMorphTargetWeights(asset, entityName, weights, count); - // }); - // auto fut = _tp->add_task(lambda); - // fut.wait(); } FLUTTER_PLUGIN_EXPORT void set_morph_target_weights( @@ -339,16 +183,12 @@ extern "C" { const int numWeights ) { - //std::packaged_task lambda([=]() mutable { return ((AssetManager*)assetManager)->setMorphTargetWeights( asset, entityName, weights, numWeights ); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT bool set_morph_animation( @@ -360,7 +200,6 @@ extern "C" { int numFrames, float frameLengthInMs) { - //std::packaged_task lambda([=]() mutable { return ((AssetManager*)assetManager)->setMorphAnimationBuffer( asset, entityName, @@ -369,9 +208,6 @@ extern "C" { numFrames, frameLengthInMs ); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT void set_bone_animation( @@ -384,7 +220,6 @@ extern "C" { const char** const meshNames, int numMeshTargets, float frameLengthInMs) { - //std::packaged_task lambda([=]() mutable { ((AssetManager*)assetManager)->setBoneAnimationBuffer( asset, frameData, @@ -395,10 +230,7 @@ extern "C" { numMeshTargets, frameLengthInMs ); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); - } + } @@ -435,13 +267,9 @@ extern "C" { EntityId asset, int index, bool loop, - bool reverse) { - - //std::packaged_task lambda([=]() mutable { - ((AssetManager*)assetManager)->playAnimation(asset, index, loop, reverse); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); + bool reverse, + float crossfade) { + ((AssetManager*)assetManager)->playAnimation(asset, index, loop, reverse, crossfade); } FLUTTER_PLUGIN_EXPORT void set_animation_frame( @@ -449,11 +277,7 @@ extern "C" { EntityId asset, int animationIndex, int animationFrame) { - // //std::packaged_task lambda([=]() mutable { // ((AssetManager*)assetManager)->setAnimationFrame(asset, animationIndex, animationFrame); - // }); - // auto fut = _tp->add_task(lambda); - // fut.wait(); } FLUTTER_PLUGIN_EXPORT int get_animation_count( @@ -462,9 +286,8 @@ extern "C" { //std::packaged_task lambda([=]() mutable { auto names = ((AssetManager*)assetManager)->getAnimationNames(asset); return names->size(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); + + //return fut.get(); } @@ -474,49 +297,32 @@ extern "C" { char* const outPtr, int index ) { - //std::packaged_task lambda([=]() mutable { auto names = ((AssetManager*)assetManager)->getAnimationNames(asset); string name = names->at(index); strcpy(outPtr, name.c_str()); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } 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(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); + + //return fut.get(); } FLUTTER_PLUGIN_EXPORT void get_morph_target_name(void* assetManager, EntityId asset, const char* meshName, char* const outPtr, int index ) { - //std::packaged_task lambda([=]() mutable { unique_ptr> names = ((AssetManager*)assetManager)->getMorphTargetNames(asset, meshName); string name = names->at(index); strcpy(outPtr, name.c_str()); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void remove_asset(void* viewer, EntityId asset) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void remove_asset(const void* const viewer, EntityId asset) { ((FilamentViewer*)viewer)->removeAsset(asset); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } - FLUTTER_PLUGIN_EXPORT void clear_assets(void* viewer) { - //std::packaged_task lambda([=]() mutable { + FLUTTER_PLUGIN_EXPORT void clear_assets(const void* const viewer) { ((FilamentViewer*)viewer)->clearAssets(); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT void load_texture(void* assetManager, EntityId asset, const char* assetPath, int renderableIndex) { @@ -528,59 +334,31 @@ extern "C" { } FLUTTER_PLUGIN_EXPORT void transform_to_unit_cube(void* assetManager, EntityId asset) { - //std::packaged_task lambda([=]() mutable { ((AssetManager*)assetManager)->transformToUnitCube(asset); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT void set_position(void* assetManager, EntityId asset, float x, float y, float z) { - //std::packaged_task lambda([=]() mutable { ((AssetManager*)assetManager)->setPosition(asset, x, y, z); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT void set_rotation(void* assetManager, EntityId asset, float rads, float x, float y, float z) { - //std::packaged_task lambda([=]() mutable { ((AssetManager*)assetManager)->setRotation(asset, rads, x, y, z); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT void set_scale(void* assetManager, EntityId asset, float scale) { - //std::packaged_task lambda([=]() mutable { ((AssetManager*)assetManager)->setScale(asset, scale); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT void stop_animation(void* assetManager, EntityId asset, int index) { - //std::packaged_task lambda([=]() mutable { ((AssetManager*)assetManager)->stopAnimation(asset, index); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT int hide_mesh(void* assetManager, EntityId asset, const char* meshName) { - //std::packaged_task lambda([=]() mutable { return ((AssetManager*)assetManager)->hide(asset, meshName); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT int reveal_mesh(void* assetManager, EntityId asset, const char* meshName) { - //std::packaged_task lambda([=]() mutable { return ((AssetManager*)assetManager)->reveal(asset, meshName); - //}); -// auto fut = _tp->add_task(lambda); -// fut.wait(); } FLUTTER_PLUGIN_EXPORT void ios_dummy() { diff --git a/lib/animations/animation_builder.dart b/lib/animations/animation_builder.dart index 15bd1df2..969b9c82 100644 --- a/lib/animations/animation_builder.dart +++ b/lib/animations/animation_builder.dart @@ -28,7 +28,9 @@ class AnimationBuilder { required this.meshName, required int framerate}) { _frameLengthInMs = 1000 / framerate; - morphNames = controller.getMorphTargetNames(asset, meshName); + controller.getMorphTargetNames(asset, meshName).then((value) { + morphNames = value; + }); } void set() { diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 288a0840..5853b0fc 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -1,20 +1,15 @@ import 'dart:async'; import 'dart:ffi'; -import 'dart:io'; -import 'dart:isolate'; + import 'dart:ui' as ui; import 'package:ffi/ffi.dart'; -import 'package:flutter/animation.dart'; -import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:polyvox_filament/animations/bone_animation_data.dart'; import 'package:polyvox_filament/animations/morph_animation_data.dart'; -import 'package:polyvox_filament/generated_bindings.dart'; -typedef AssetManager = Pointer; -typedef FilamentViewer = Pointer; +typedef AssetManager = int; typedef FilamentEntity = int; const FilamentEntity FILAMENT_ASSET_ERROR = 0; @@ -34,23 +29,13 @@ class FilamentController { final _initialized = Completer(); Future get initialized => _initialized.future; - late NativeLibrary _nativeLibrary; - - late FilamentViewer _viewer; late AssetManager _assetManager; - bool _rendering = false; - - final TickerProvider _tickerProvider; - Ticker? _ticker; - /// - /// This now uses an FFI implementation. - /// Platform channels are only used to setup the context/texture (since this is platform-specific) and the render ticker. - /// All other methods directly invoke the FFI functions defined in PolyvoxFilamentApi.cpp, - /// which itself uses a threadpool so that calls are run on a separate thread. + /// This controller uses platform channels to bridge Dart with the C/C++ code for the Filament API. + /// Setting up the context/texture (since this is platform-specific) and the render ticker are platform-specific; all other methods are passed through by the platform channel to the methods specified in PolyvoxFilamentApi.h. /// - FilamentController(this._tickerProvider) { + FilamentController() { _channel.setMethodCallHandler((call) async { throw Exception("Unknown method channel invocation ${call.method}"); }); @@ -58,10 +43,6 @@ class FilamentController { _textureIdController.onListen = () { _textureIdController.add(_textureId); }; - - _nativeLibrary = NativeLibrary(Platform.isAndroid || Platform.isLinux - ? DynamicLibrary.open("libpolyvox_filament_plugin.so") - : DynamicLibrary.process()); } Future initialize() async { @@ -70,126 +51,106 @@ class FilamentController { } Future setRendering(bool render) async { - _rendering = render; + _channel.invokeMethod("setRendering", render); } void render() { - _nativeLibrary.render(_viewer, 0); + _channel.invokeMethod("render"); } - int _frameLengthInMicroseconds = 1000000 ~/ 60; - Future setFrameRate(int framerate) async { - _frameLengthInMicroseconds = 1000000 ~/ framerate; - _nativeLibrary.set_frame_interval(_viewer, 1 / framerate); + _channel.invokeMethod("setFrameInterval", 1000.0 / framerate); } void setPixelRatio(double ratio) { _pixelRatio = ratio; } - int _last = 0; - Future createViewer(int width, int height) async { size = ui.Size(width * _pixelRatio, height * _pixelRatio); _textureId = await _channel.invokeMethod("createTexture", [size.width, size.height]); _textureIdController.add(_textureId); - var glContext = - Pointer.fromAddress(await _channel.invokeMethod("getContext")); - final resourceLoader = Pointer.fromAddress( - await _channel.invokeMethod("getResourceLoader")); + await _channel + .invokeMethod("createFilamentViewer", [size.width, size.height]); - _viewer = _nativeLibrary.create_filament_viewer(glContext, resourceLoader); - if (Platform.isLinux) { - // don't pass a surface to the SwapChain as we are effectively creating a headless SwapChain that will render into a RenderTarget associated with a texture - _nativeLibrary.create_swap_chain( - _viewer, nullptr, size.width.toInt(), size.height.toInt()); + // if (Platform.isLinux) { + // // don't pass a surface to the SwapChain as we are effectively creating a headless SwapChain that will render into a RenderTarget associated with a texture + // _nativeLibrary.create_swap_chain( + // nullptr, size.width.toInt(), size.height.toInt()); - var glTextureId = await _channel.invokeMethod("getGlTextureId"); + // var glTextureId = await _channel.invokeMethod("getGlTextureId"); - _nativeLibrary.create_render_target( - _viewer, glTextureId, size.width.toInt(), size.height.toInt()); - } else { - var surface = - Pointer.fromAddress(await _channel.invokeMethod("getSurface")); - _nativeLibrary.create_swap_chain( - _viewer, surface, size.width.toInt(), size.height.toInt()); - } + // await _channel.invokeMethod("create_render_target( + // glTextureId, size.width.toInt(), size.height.toInt()); + // } else { - _nativeLibrary.update_viewport_and_camera_projection( - _viewer, size.width.toInt(), size.height.toInt(), 1.0); + // } + + await _channel.invokeMethod("updateViewportAndCameraProjection", + [size.width.toInt(), size.height.toInt(), 1.0]); _initialized.complete(true); - _assetManager = _nativeLibrary.get_asset_manager(_viewer); - - _ticker = _tickerProvider.createTicker((Duration elapsed) async { - if (elapsed.inMicroseconds - _last > _frameLengthInMicroseconds) { - render(); - _last = elapsed.inMicroseconds; - } - }); - _ticker!.start(); + _assetManager = await _channel.invokeMethod("getAssetManager"); } Future resize(int width, int height, {double contentScaleFactor = 1.0}) async { // await setRendering(false); // _textureIdController.add(null); - // _nativeLibrary.destroy_swap_chain(_viewer); + // await _channel.invokeMethod("destroy_swap_chain(_viewer); // size = ui.Size(width * _pixelRatio, height * _pixelRatio); // _textureId = await _channel.invokeMethod("resize", // [width * _pixelRatio, height * _pixelRatio, contentScaleFactor]); // _textureIdController.add(_textureId); - // _nativeLibrary.create_swap_chain(_viewer, nullptr, width, height); - // _nativeLibrary.create_render_target( - // _viewer, await _channel.invokeMethod("getGlTextureId"), width, height); - // _nativeLibrary.update_viewport_and_camera_projection( - // _viewer, width, height, contentScaleFactor); + // await _channel.invokeMethod("create_swap_chain( nullptr, width, height); + // await _channel.invokeMethod("create_render_target( + // await _channel.invokeMethod("getGlTextureId"), width, height); + // await _channel.invokeMethod("update_viewport_and_camera_projection( + // width, height, contentScaleFactor); // await setRendering(true); } void clearBackgroundImage() async { - _nativeLibrary.clear_background_image(_viewer); + await _channel.invokeMethod("clearBackgroundImage"); } void setBackgroundImage(String path) async { - _nativeLibrary.set_background_image( - _viewer, path.toNativeUtf8().cast()); + await _channel.invokeMethod("setBackgroundImage", path); } void setBackgroundColor(Color color) async { - _nativeLibrary.set_background_color( - _viewer, - color.red.toDouble() / 255.0, - color.green.toDouble() / 255.0, - color.blue.toDouble() / 255.0, - color.alpha.toDouble() / 255.0); + await _channel.invokeMethod("setBackgroundColor", [ + color.red.toDouble() / 255.0, + color.green.toDouble() / 255.0, + color.blue.toDouble() / 255.0, + color.alpha.toDouble() / 255.0 + ]); } void setBackgroundImagePosition(double x, double y, {bool clamp = false}) async { - _nativeLibrary.set_background_image_position(_viewer, x, y, clamp ? 1 : 0); + await _channel + .invokeMethod("setBackgroundImagePosition", [x, y, clamp ? 1 : 0]); } void loadSkybox(String skyboxPath) async { - _nativeLibrary.load_skybox(_viewer, skyboxPath.toNativeUtf8().cast()); + await _channel.invokeMethod("loadSkybox", skyboxPath); } void loadIbl(String lightingPath, {double intensity = 30000}) async { - _nativeLibrary.load_ibl( - _viewer, lightingPath.toNativeUtf8().cast(), intensity); + await _channel.invokeMethod("loadIbl", [lightingPath, intensity]); } void removeSkybox() async { - _nativeLibrary.remove_skybox(_viewer); + await _channel.invokeMethod("removeSkybox"); } void removeIbl() async { - _nativeLibrary.remove_ibl(_viewer); + await _channel.invokeMethod("removeIbl"); } // copied from LightManager.h @@ -200,8 +161,7 @@ class FilamentController { // FOCUSED_SPOT, //!< Physically correct spot light. // SPOT, //!< Spot light with coupling of outer cone and illumination disabled. // }; - - FilamentEntity addLight( + Future addLight( int type, double colour, double intensity, @@ -211,94 +171,97 @@ class FilamentController { double dirX, double dirY, double dirZ, - bool castShadows) { - return _nativeLibrary.add_light(_viewer, type, colour, intensity, posX, - posY, posZ, dirX, dirY, dirZ, castShadows ? 1 : 0); + bool castShadows) async { + var entity = await _channel.invokeMethod("addLight", [ + type, + colour, + intensity, + posX, + posY, + posZ, + dirX, + dirY, + dirZ, + castShadows ? 1 : 0 + ]); + return entity as FilamentEntity; } void removeLight(FilamentEntity light) async { - _nativeLibrary.remove_light(_viewer, light); + await _channel.invokeMethod("removeLight", light); } void clearLights() async { - _nativeLibrary.clear_lights(_viewer); + await _channel.invokeMethod("clearLights"); } - FilamentEntity loadGlb(String path, {bool unlit = false}) { - var asset = _nativeLibrary.load_glb( - _assetManager, path.toNativeUtf8().cast(), unlit ? 1 : 0); + Future loadGlb(String path, {bool unlit = false}) async { + var asset = await _channel + .invokeMethod("loadGlb", [_assetManager, path, unlit ? 1 : 0]); if (asset == FILAMENT_ASSET_ERROR) { throw Exception("An error occurred loading the asset at $path"); } return asset; } - FilamentEntity loadGltf(String path, String relativeResourcePath) { - return _nativeLibrary.load_gltf( - _assetManager, - path.toNativeUtf8().cast(), - relativeResourcePath.toNativeUtf8().cast()); + Future loadGltf( + String path, String relativeResourcePath) async { + var entity = await _channel + .invokeMethod("loadGltf", [_assetManager, path, relativeResourcePath]); + return entity as FilamentEntity; } void panStart(double x, double y) async { - _nativeLibrary.grab_begin(_viewer, x * _pixelRatio, y * _pixelRatio, 1); + await _channel + .invokeMethod("grabBegin", [x * _pixelRatio, y * _pixelRatio, 1]); } void panUpdate(double x, double y) async { - _nativeLibrary.grab_update(_viewer, x * _pixelRatio, y * _pixelRatio); + await _channel + .invokeMethod("grabUpdate", [x * _pixelRatio, y * _pixelRatio]); } void panEnd() async { - _nativeLibrary.grab_end(_viewer); + await _channel.invokeMethod("grabEnd"); } void rotateStart(double x, double y) async { - _nativeLibrary.grab_begin(_viewer, x * _pixelRatio, y * _pixelRatio, 0); + await _channel + .invokeMethod("grabBegin", [x * _pixelRatio, y * _pixelRatio, 0]); } void rotateUpdate(double x, double y) async { - _nativeLibrary.grab_update(_viewer, x * _pixelRatio, y * _pixelRatio); + await _channel + .invokeMethod("grabUpdate", [x * _pixelRatio, y * _pixelRatio]); } void rotateEnd() async { - _nativeLibrary.grab_end(_viewer); + await _channel.invokeMethod("grabEnd"); } void setMorphTargetWeights( - FilamentEntity asset, String meshName, List weights) { + FilamentEntity asset, String meshName, List weights) async { var weightPtr = calloc(weights.length); for (int i = 0; i < weights.length; i++) { weightPtr[i] = weights[i]; } - _nativeLibrary.set_morph_target_weights(_assetManager, asset, - meshName.toNativeUtf8().cast(), weightPtr, weights.length); + await _channel.invokeMethod("setMorphTargetWeights", + [_assetManager, asset, meshName, weightPtr, weights.length]); calloc.free(weightPtr); } - List getMorphTargetNames(FilamentEntity asset, String meshName) { - var meshNamePtr = meshName.toNativeUtf8().cast(); - var count = _nativeLibrary.get_morph_target_name_count( - _assetManager, asset, meshNamePtr); - var names = []; - for (int i = 0; i < count; i++) { - var outPtr = calloc(255); - _nativeLibrary.get_morph_target_name( - _assetManager, asset, meshNamePtr, outPtr, i); - names.add(outPtr.cast().toDartString()); - } - return names; + Future> getMorphTargetNames( + FilamentEntity asset, String meshName) async { + var names = await _channel + .invokeMethod("getMorphTargetNames", [_assetManager, asset, meshName]); + return names.cast(); } - List getAnimationNames(FilamentEntity asset) { - var count = _nativeLibrary.get_animation_count(_assetManager, asset); - var names = []; - for (int i = 0; i < count; i++) { - var outPtr = calloc(255); - _nativeLibrary.get_animation_name(_assetManager, asset, outPtr, i); - names.add(outPtr.cast().toDartString()); - } - return names; + Future> getAnimationNames(FilamentEntity asset) async { + var names = await _channel + .invokeMethod("getAnimationNames", [_assetManager, asset]); + return names.cast(); } /// @@ -312,14 +275,15 @@ class FilamentController { for (int i = 0; i < animation.data.length; i++) { data.elementAt(i).value = animation.data[i]; } - _nativeLibrary.set_morph_animation( - _assetManager, - asset, - animation.meshName.toNativeUtf8().cast(), - data, - animation.numMorphWeights, - animation.numFrames, - animation.frameLengthInMs); + await _channel.invokeMethod("setMorphAnimation", [ + _assetManager, + asset, + animation.meshName, + data, + animation.numMorphWeights, + animation.numFrames, + animation.frameLengthInMs + ]); calloc.free(data); } @@ -349,84 +313,89 @@ class FilamentController { offset += 1; } - _nativeLibrary.set_bone_animation( - _assetManager, - asset, - data, - numFrames, - 1, - boneNames, - meshNames, - animation.meshNames.length, - animation.frameLengthInMs); + await _channel.invokeMethod("setBoneAnimation", [ + _assetManager, + asset, + data, + numFrames, + 1, + boneNames, + meshNames, + animation.meshNames.length, + animation.frameLengthInMs + ]); calloc.free(data); } void removeAsset(FilamentEntity asset) async { - _nativeLibrary.remove_asset(_viewer, asset); + await _channel.invokeMethod("removeAsset", asset); } void clearAssets() async { - _nativeLibrary.clear_assets(_viewer); + await _channel.invokeMethod("clearAssets"); } void zoomBegin() async { - _nativeLibrary.scroll_begin(_viewer); + await _channel.invokeMethod("scrollBegin"); } void zoomUpdate(double z) async { - _nativeLibrary.scroll_update(_viewer, 0.0, 0.0, z); + await _channel.invokeMethod("scrollUpdate", [0.0, 0.0, z]); } void zoomEnd() async { - _nativeLibrary.scroll_end(_viewer); + await _channel.invokeMethod("scrollEnd"); } void playAnimation(FilamentEntity asset, int index, - {bool loop = false, bool reverse = false}) async { - _nativeLibrary.play_animation( - _assetManager, asset, index, loop ? 1 : 0, reverse ? 1 : 0); + {bool loop = false, bool reverse = false, double crossfade = 0.0}) async { + await _channel.invokeMethod("playAnimation", [ + _assetManager, + asset, + index, + loop ? 1 : 0, + reverse ? 1 : 0, + crossfade + ]); } void setAnimationFrame( FilamentEntity asset, int index, int animationFrame) async { - _nativeLibrary.set_animation_frame( - _assetManager, asset, index, animationFrame); + await _channel.invokeMethod( + "setAnimationFrame", [_assetManager, asset, index, animationFrame]); } void stopAnimation(FilamentEntity asset, int animationIndex) async { - _nativeLibrary.stop_animation(_assetManager, asset, animationIndex); + await _channel + .invokeMethod("stopAnimation", [_assetManager, asset, animationIndex]); } void setCamera(FilamentEntity asset, String? name) async { - if (_nativeLibrary.set_camera( - _viewer, asset, name?.toNativeUtf8()?.cast() ?? nullptr) != - 1) { + if (await _channel.invokeMethod("setCamera", [asset, name]) != 1) { throw Exception("Failed to set camera"); } - ; } void setCameraFocalLength(double focalLength) async { - _nativeLibrary.set_camera_focal_length(_viewer, focalLength); + await _channel.invokeMethod("setCameraFocalLength", focalLength); } void setCameraFocusDistance(double focusDistance) async { - _nativeLibrary.set_camera_focus_distance(_viewer, focusDistance); + await _channel.invokeMethod("setCameraFocusDistance", focusDistance); } void setCameraPosition(double x, double y, double z) async { - _nativeLibrary.set_camera_position(_viewer, x, y, z); + await _channel.invokeMethod("setCameraPosition", [x, y, z]); } void setCameraExposure( double aperture, double shutterSpeed, double sensitivity) async { - _nativeLibrary.set_camera_exposure( - _viewer, aperture, shutterSpeed, sensitivity); + await _channel.invokeMethod( + "setCameraExposure", [aperture, shutterSpeed, sensitivity]); } void setCameraRotation(double rads, double x, double y, double z) async { - _nativeLibrary.set_camera_rotation(_viewer, rads, x, y, z); + await _channel.invokeMethod("setCameraRotation", [rads, x, y, z]); } void setCameraModelMatrix(List matrix) async { @@ -435,42 +404,43 @@ class FilamentController { for (int i = 0; i < 16; i++) { ptr.elementAt(i).value = matrix[i]; } - _nativeLibrary.set_camera_model_matrix(_viewer, ptr); + await _channel.invokeMethod("setCameraModelMatrix", [ptr]); } void setTexture(FilamentEntity asset, String assetPath, {int renderableIndex = 0}) async { - _nativeLibrary.set_texture(_assetManager, asset); + await _channel.invokeMethod("setTexture", [_assetManager, asset]); } void transformToUnitCube(FilamentEntity asset) async { - _nativeLibrary.transform_to_unit_cube(_assetManager, asset); + await _channel.invokeMethod("transformToUnitCube", [_assetManager, asset]); } void setPosition(FilamentEntity asset, double x, double y, double z) async { - _nativeLibrary.set_position(_assetManager, asset, x, y, z); + await _channel.invokeMethod("setPosition", [_assetManager, asset, x, y, z]); } void setScale(FilamentEntity asset, double scale) async { - _nativeLibrary.set_scale(_assetManager, asset, scale); + await _channel.invokeMethod("setScale", [_assetManager, asset, scale]); } void setRotation( FilamentEntity asset, double rads, double x, double y, double z) async { - _nativeLibrary.set_rotation(_assetManager, asset, rads, x, y, z); + await _channel + .invokeMethod("setRotation", [_assetManager, asset, rads, x, y, z]); } - void hide(FilamentEntity asset, String meshName) { - if (_nativeLibrary.hide_mesh( - _assetManager, asset, meshName.toNativeUtf8().cast()) != + void hide(FilamentEntity asset, String meshName) async { + if (await _channel + .invokeMethod("hideMesh", [_assetManager, asset, meshName]) != 1) { throw Exception("Failed to hide mesh $meshName"); } } - void reveal(FilamentEntity asset, String meshName) { - if (_nativeLibrary.reveal_mesh( - _assetManager, asset, meshName.toNativeUtf8().cast()) != + void reveal(FilamentEntity asset, String meshName) async { + if (await _channel + .invokeMethod("revealMesh", [_assetManager, asset, meshName]) != 1) { throw Exception("Failed to reveal mesh $meshName"); } diff --git a/lib/filament_gesture_detector.dart b/lib/filament_gesture_detector.dart index 13fd8f93..9cb182b7 100644 --- a/lib/filament_gesture_detector.dart +++ b/lib/filament_gesture_detector.dart @@ -107,7 +107,6 @@ class _FilamentGestureDetectorState extends State { onPointerDown: !widget.enableControls ? null : (d) async { - print("a"); // if (d.buttons == kTertiaryButton || _rotating) { // widget.controller // .rotateStart(d.localPosition.dx, d.localPosition.dy); diff --git a/lib/generated_bindings.dart b/lib/generated_bindings.dart index 2648b08d..db1e4458 100644 --- a/lib/generated_bindings.dart +++ b/lib/generated_bindings.dart @@ -735,6 +735,7 @@ class NativeLibrary { int index, int loop, int reverse, + double crossfade, ) { return _play_animation( assetManager, @@ -742,15 +743,16 @@ class NativeLibrary { index, loop, reverse, + crossfade, ); } late final _play_animationPtr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, EntityId, ffi.Int, ffi.Int, - ffi.Int)>>('play_animation'); - late final _play_animation = _play_animationPtr - .asFunction, int, int, int, int)>(); + ffi.Int, ffi.Float)>>('play_animation'); + late final _play_animation = _play_animationPtr.asFunction< + void Function(ffi.Pointer, int, int, int, int, double)>(); void set_animation_frame( ffi.Pointer assetManager, @@ -1193,7 +1195,7 @@ class NativeLibrary { late final _ios_dummy = _ios_dummyPtr.asFunction(); } -class __mbstate_t extends ffi.Union { +final class __mbstate_t extends ffi.Union { @ffi.Array.multi([128]) external ffi.Array __mbstate8; @@ -1201,7 +1203,7 @@ class __mbstate_t extends ffi.Union { external int _mbstateL; } -class __darwin_pthread_handler_rec extends ffi.Struct { +final class __darwin_pthread_handler_rec extends ffi.Struct { external ffi .Pointer)>> __routine; @@ -1211,7 +1213,7 @@ class __darwin_pthread_handler_rec extends ffi.Struct { external ffi.Pointer<__darwin_pthread_handler_rec> __next; } -class _opaque_pthread_attr_t extends ffi.Struct { +final class _opaque_pthread_attr_t extends ffi.Struct { @ffi.Long() external int __sig; @@ -1219,7 +1221,7 @@ class _opaque_pthread_attr_t extends ffi.Struct { external ffi.Array __opaque; } -class _opaque_pthread_cond_t extends ffi.Struct { +final class _opaque_pthread_cond_t extends ffi.Struct { @ffi.Long() external int __sig; @@ -1227,7 +1229,7 @@ class _opaque_pthread_cond_t extends ffi.Struct { external ffi.Array __opaque; } -class _opaque_pthread_condattr_t extends ffi.Struct { +final class _opaque_pthread_condattr_t extends ffi.Struct { @ffi.Long() external int __sig; @@ -1235,7 +1237,7 @@ class _opaque_pthread_condattr_t extends ffi.Struct { external ffi.Array __opaque; } -class _opaque_pthread_mutex_t extends ffi.Struct { +final class _opaque_pthread_mutex_t extends ffi.Struct { @ffi.Long() external int __sig; @@ -1243,7 +1245,7 @@ class _opaque_pthread_mutex_t extends ffi.Struct { external ffi.Array __opaque; } -class _opaque_pthread_mutexattr_t extends ffi.Struct { +final class _opaque_pthread_mutexattr_t extends ffi.Struct { @ffi.Long() external int __sig; @@ -1251,7 +1253,7 @@ class _opaque_pthread_mutexattr_t extends ffi.Struct { external ffi.Array __opaque; } -class _opaque_pthread_once_t extends ffi.Struct { +final class _opaque_pthread_once_t extends ffi.Struct { @ffi.Long() external int __sig; @@ -1259,7 +1261,7 @@ class _opaque_pthread_once_t extends ffi.Struct { external ffi.Array __opaque; } -class _opaque_pthread_rwlock_t extends ffi.Struct { +final class _opaque_pthread_rwlock_t extends ffi.Struct { @ffi.Long() external int __sig; @@ -1267,7 +1269,7 @@ class _opaque_pthread_rwlock_t extends ffi.Struct { external ffi.Array __opaque; } -class _opaque_pthread_rwlockattr_t extends ffi.Struct { +final class _opaque_pthread_rwlockattr_t extends ffi.Struct { @ffi.Long() external int __sig; @@ -1275,7 +1277,7 @@ class _opaque_pthread_rwlockattr_t extends ffi.Struct { external ffi.Array __opaque; } -class _opaque_pthread_t extends ffi.Struct { +final class _opaque_pthread_t extends ffi.Struct { @ffi.Long() external int __sig; @@ -1285,7 +1287,7 @@ class _opaque_pthread_t extends ffi.Struct { external ffi.Array __opaque; } -class ResourceBuffer extends ffi.Struct { +final class ResourceBuffer extends ffi.Struct { external ffi.Pointer data; @ffi.Uint32() @@ -1295,7 +1297,7 @@ class ResourceBuffer extends ffi.Struct { external int id; } -class ResourceLoaderWrapper extends ffi.Struct { +final class ResourceLoaderWrapper extends ffi.Struct { external LoadResource mLoadResource; external FreeResource mFreeResource; @@ -1484,13 +1486,3 @@ const int WINT_MAX = 2147483647; const int SIG_ATOMIC_MIN = -2147483648; const int SIG_ATOMIC_MAX = 2147483647; - -const int __DARWIN_WCHAR_MAX = 2147483647; - -const int __DARWIN_WCHAR_MIN = -2147483648; - -const int __DARWIN_WEOF = -1; - -const int _FORTIFY_SOURCE = 2; - -const int NULL = 0; diff --git a/pubspec.yaml b/pubspec.yaml index ba0188b7..0b66ad02 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.0.1 homepage: environment: - sdk: ">=2.17.1 <3.0.0" + sdk: ">=3.0.0 <3.11.0" flutter: ">=1.20.0" dependencies: