diff --git a/example/assets/cube.glb b/example/assets/cube.glb index e8407372..9575871e 100644 Binary files a/example/assets/cube.glb and b/example/assets/cube.glb differ 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: