From f50b5328dbd3b43a4cb96e57dcab40d4010fd31f Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Thu, 15 Dec 2022 16:56:57 +0800 Subject: [PATCH] add manual bone transform animation --- .../app/polyvox/filament/FilamentInterop.kt | 6 +- .../polyvox/filament/PolyvoxFilamentPlugin.kt | 12 +- example/lib/main.dart | 617 ++++++++---------- ios/Classes/SwiftPolyvoxFilamentPlugin.swift | 12 +- ios/include/PolyvoxFilamentApi.h | 29 +- ios/include/SceneAsset.hpp | 47 +- ios/include/SceneResources.hpp | 77 ++- ios/src/FilamentViewer.cpp | 12 +- ios/src/PolyvoxFilamentApi.cpp | 60 +- ios/src/SceneAsset.cpp | 170 +++-- ios/src/SceneAssetLoader.cpp | 12 +- ios/src/Untitled-1.cpp | 479 ++++++++++++++ lib/animations/Untitled-1.cpp | 21 + lib/animations/animation_builder.dart | 149 +++++ lib/animations/animations.dart | 69 ++ lib/filament_controller.dart | 63 +- lib/filament_widget.dart | 2 +- linux/polyvox_filament_plugin.cc | 85 ++- 18 files changed, 1422 insertions(+), 500 deletions(-) create mode 100644 ios/src/Untitled-1.cpp create mode 100644 lib/animations/Untitled-1.cpp create mode 100644 lib/animations/animation_builder.dart create mode 100644 lib/animations/animations.dart diff --git a/android/src/main/kotlin/app/polyvox/filament/FilamentInterop.kt b/android/src/main/kotlin/app/polyvox/filament/FilamentInterop.kt index db71d447..533710b1 100644 --- a/android/src/main/kotlin/app/polyvox/filament/FilamentInterop.kt +++ b/android/src/main/kotlin/app/polyvox/filament/FilamentInterop.kt @@ -60,11 +60,11 @@ interface FilamentInterop : Library { fun apply_weights(asset:Pointer, weights:FloatArray, size:Int); - fun animate_weights(asset:Pointer, frames:FloatArray, numWeights:Int, numFrames:Int, frameRate:Float); + fun set_animation(asset:Pointer, frames:FloatArray, numWeights:Int, numFrames:Int, frameRate:Float); - fun get_target_name_count(asset:Pointer, meshName:String) : Int; + fun get_morph_target_name_count(asset:Pointer, meshName:String) : Int; - fun get_target_name(asset:Pointer, meshName:String, outPtr:Pointer, index:Int); + fun get_morph_target_name(asset:Pointer, meshName:String, outPtr:Pointer, index:Int); fun get_animation_count(asset:Pointer) : Int; fun get_animation_name(asset:Pointer, outPtr:Pointer, index:Int); diff --git a/android/src/main/kotlin/app/polyvox/filament/PolyvoxFilamentPlugin.kt b/android/src/main/kotlin/app/polyvox/filament/PolyvoxFilamentPlugin.kt index db43710c..cfa3426a 100644 --- a/android/src/main/kotlin/app/polyvox/filament/PolyvoxFilamentPlugin.kt +++ b/android/src/main/kotlin/app/polyvox/filament/PolyvoxFilamentPlugin.kt @@ -423,15 +423,15 @@ class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { result.success("OK"); } } - "getTargetNames" -> { + "getMorphTargetNames" -> { executor.execute { val args = call.arguments as ArrayList<*> val assetPtr = Pointer(args[0] as Long) val meshName = args[1] as String val names = mutableListOf() val outPtr = Memory(256) - for(i in 0.._lib.get_target_name_count(assetPtr, meshName) - 1) { - _lib.get_target_name(assetPtr, meshName, outPtr, i) + for(i in 0.._lib.get_morph_target_name_count(assetPtr, meshName) - 1) { + _lib.get_morph_target_name(assetPtr, meshName, outPtr, i) val name = outPtr.getString(0) names.add(name) } @@ -451,7 +451,7 @@ class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { result.success(names) } } - "applyWeights" -> { + "setMorphTargetWeights" -> { executor.execute { val args = call.arguments as ArrayList<*> val assetPtr = Pointer(args[0] as Long) @@ -461,7 +461,7 @@ class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { result.success("OK"); } } - "animateWeights" -> { + "setAnimation" -> { executor.execute { val args = call.arguments as ArrayList val assetPtr = Pointer(args[0] as Long) @@ -470,7 +470,7 @@ class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { val numFrames = args[3] as Int val frameLenInMs = args[4] as Double - _lib.animate_weights(assetPtr, frames.toFloatArray(), numWeights, numFrames, frameLenInMs.toFloat()) + _lib.set_animation(assetPtr, frames.toFloatArray(), numWeights, numFrames, frameLenInMs.toFloat()) result.success("OK"); } } diff --git a/example/lib/main.dart b/example/lib/main.dart index 3ef5e1a0..f68167f8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -4,6 +4,8 @@ import 'package:flutter/material.dart'; import 'package:polyvox_filament/filament_controller.dart'; import 'package:polyvox_filament/filament_gesture_detector.dart'; import 'package:polyvox_filament/filament_widget.dart'; +import 'package:polyvox_filament/animations/animation_builder.dart'; +import 'package:polyvox_filament/animations/animations.dart'; void main() { runApp(const MyApp()); @@ -36,6 +38,195 @@ class _MyAppState extends State { super.initState(); } + void onClick(int index) async { + switch (index) { + case -1: + await _filamentController.initialize(); + break; + case -2: + await _filamentController.render(); + break; + case -4: + setState(() { + _rendering = !_rendering; + _filamentController.setRendering(_rendering); + }); + break; + case -5: + setState(() { + _framerate = _framerate == 60 ? 30 : 60; + _filamentController.setFrameRate(_framerate); + }); + break; + + case 0: + await _filamentController.setBackgroundImage('assets/background.ktx'); + break; + case 1: + await _filamentController + .loadSkybox('assets/default_env/default_env_skybox.ktx'); + break; + case -3: + await _filamentController + .loadIbl('assets/default_env/default_env_ibl.ktx'); + break; + case 2: + await _filamentController.removeSkybox(); + break; + case 3: + _cube = await _filamentController.loadGlb('assets/cube.glb'); + + _animationNames = await _filamentController.getAnimationNames(_cube!); + break; + + case 4: + if (_cube != null) { + await _filamentController.removeAsset(_cube!); + } + _cube = + await _filamentController.loadGltf('assets/cube.gltf', 'assets'); + print(await _filamentController.getAnimationNames(_cube!)); + break; + case 5: + if (_flightHelmet == null) { + _flightHelmet = await _filamentController.loadGltf( + 'assets/FlightHelmet/FlightHelmet.gltf', 'assets/FlightHelmet'); + } + break; + case 6: + await _filamentController.removeAsset(_cube!); + break; + + case 7: + await _filamentController.setMorphTargetWeights( + _cube!, List.filled(8, 1.0)); + break; + case 8: + await _filamentController.setMorphTargetWeights( + _cube!, List.filled(8, 0)); + break; + case 9: + _filamentController.playAnimations( + _cube!, List.generate(_animationNames.length, (i) => i), + loop: _loop); + break; + case 10: + _filamentController.stopAnimation(_cube!, 0); + break; + case 11: + setState(() { + _loop = !_loop; + }); + break; + case 14: + _filamentController.setCamera(_cube!, "Camera_Orientation"); + break; + case 15: + final animation = AnimationBuilder() + .setFramerate(30) + .setDuration(4) + .setNumMorphWeights(8) + .interpolateMorphWeights(0, 4, 0, 1) + .interpolateBoneTransform( + "Bone.001", + "Cube.001", + 2, + 4, + Vec3(), + Vec3(), + // Vec3(x: 1, y: 1, z: 1), + Quaternion(x: 0, y: 0, z: 0, w: 1), + Quaternion(x: 1, y: 1, z: 1, w: 1)) + // Quaternion(x: 1, y: 1, z: 1, w: 1)) + .build(); + + _filamentController.setAnimation(_cube!, animation); + break; + case 16: + _targetNames = + await _filamentController.getMorphTargetNames(_cube!, "Cube"); + setState(() {}); + break; + case 17: + _animationNames = await _filamentController.getAnimationNames(_cube!); + setState(() {}); + + break; + case 18: + await _filamentController.panStart(1, 1); + await _filamentController.panUpdate(1, 2); + await _filamentController.panEnd(); + break; + case 19: + await _filamentController.panStart(1, 1); + await _filamentController.panUpdate(0, 0); + await _filamentController.panEnd(); + break; + case 20: + await _filamentController.clearAssets(); + break; + case 21: + await _filamentController.setTexture(_cube!, "assets/background.png"); + break; + case 22: + await _filamentController.transformToUnitCube(_cube!); + break; + case 23: + await _filamentController.setPosition(_cube!, 1.0, 1.0, -1.0); + break; + case 24: + await _filamentController.setRotation(_cube!, pi / 2, 0.0, 1.0, 0.0); + break; + case 25: + setState(() { + _vertical = !_vertical; + }); + break; + case 26: + await _filamentController.setCameraPosition(0, 0, 3); + await _filamentController.setCameraRotation(0, 0, 1, 0); + break; + case 27: + _framerate = _framerate == 60 ? 30 : 60; + await _filamentController.setFrameRate(_framerate); + break; + case 28: + await _filamentController.setBackgroundImagePosition(25, 25); + break; + case 29: + _light = await _filamentController.addLight( + 1, 6500, 15000000, 0, 1, 0, 0, -1, 0, true); + _light = await _filamentController.addLight( + 2, 6500, 15000000, 0, 0, 1, 0, 0, -1, true); + break; + case 30: + if (_light != null) { + await _filamentController.removeLight(_light!); + } + break; + case 31: + await _filamentController.clearLights(); + break; + case 32: + await _filamentController.setBoneTransform( + _cube!, + "Bone.001", + "Cube.001", + BoneTransform([Vec3(x: 0, y: 0.0, z: 0.0)], + [Quaternion(x: 1, y: 1, z: 1, w: 1)])); + break; + } + } + + Widget _item({int value = 0, Widget? child = null}) { + return GestureDetector( + onTap: () { + onClick(value); + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 10), child: child)); + } + @override Widget build(BuildContext context) { return MaterialApp( @@ -43,356 +234,80 @@ class _MyAppState extends State { color: Colors.white, home: Scaffold( backgroundColor: Colors.white, - body: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: _vertical ? 200 : 400, - height: _vertical ? 400 : 200, - alignment: Alignment.center, - child: SizedBox( - child: FilamentGestureDetector( - showControls: true, - controller: _filamentController, - child: FilamentWidget( - controller: _filamentController, - )), - )), - Text( - "Target names : ${_targetNames.join(",")}, Animation names : ${_animationNames.join(",")}"), - Align( - alignment: Alignment.bottomLeft, - child: Container( - color: Colors.white, - margin: const EdgeInsets.all(15), - child: PopupMenuButton( - padding: EdgeInsets.all(50), - iconSize: 36, - child: const Icon(Icons.menu), - onSelected: (int item) async { - switch (item) { - case -1: - await _filamentController.initialize(); - break; - case -2: - await _filamentController.render(); - break; - case 0: - await _filamentController - .setBackgroundImage( - 'assets/background.ktx'); - break; - case 1: - await _filamentController.loadSkybox( - 'assets/default_env/default_env_skybox.ktx'); - break; - case -3: - await _filamentController.loadIbl( - 'assets/default_env/default_env_ibl.ktx'); - break; - case 2: - await _filamentController.removeSkybox(); - break; - case 3: - _cube = await _filamentController - .loadGlb('assets/cube.glb'); - - _animationNames = await _filamentController - .getAnimationNames(_cube!); - break; - - case 4: - if (_cube != null) { - await _filamentController - .removeAsset(_cube!); - } - _cube = await _filamentController.loadGltf( - 'assets/cube.gltf', 'assets'); - print(await _filamentController - .getAnimationNames(_cube!)); - break; - case 5: - if (_flightHelmet == null) { - _flightHelmet = - await _filamentController.loadGltf( - 'assets/FlightHelmet/FlightHelmet.gltf', - 'assets/FlightHelmet'); - } - break; - case 6: - await _filamentController - .removeAsset(_cube!); - break; - - case 7: - await _filamentController.applyWeights( - _cube!, List.filled(8, 1.0)); - break; - case 8: - await _filamentController.applyWeights( - _cube!, List.filled(8, 0)); - break; - case 9: - _filamentController.playAnimations( - _cube!, - List.generate( - _animationNames.length, (i) => i), - loop: _loop); - break; - case 10: - _filamentController.stopAnimation( - _cube!, 0); - break; - case 11: - setState(() { - _loop = !_loop; - }); - break; - case 14: - _filamentController.setCamera( - _cube!, "Camera_Orientation"); - break; - case 15: - final framerate = 30; - final totalSecs = 5; - final numWeights = 8; - final totalFrames = framerate * totalSecs; - final frames = List.generate( - totalFrames, - (frame) => List.filled( - numWeights, frame / totalFrames)); - - _filamentController.animate( - _cube!, - frames.reduce((a, b) => a + b), - numWeights, - totalFrames, - 1000 / framerate.toDouble()); - break; - case 16: - _targetNames = await _filamentController - .getTargetNames(_cube!, "Cube"); - setState(() {}); - break; - case 17: - _animationNames = await _filamentController - .getAnimationNames(_cube!); - setState(() {}); - - break; - case 18: - await _filamentController.panStart(1, 1); - await _filamentController.panUpdate(1, 2); - await _filamentController.panEnd(); - break; - case 19: - await _filamentController.panStart(1, 1); - await _filamentController.panUpdate(0, 0); - await _filamentController.panEnd(); - break; - case 20: - await _filamentController.clearAssets(); - break; - case 21: - await _filamentController.setTexture( - _cube!, "assets/background.png"); - break; - case 22: - await _filamentController - .transformToUnitCube(_cube!); - break; - case 23: - await _filamentController.setPosition( - _cube!, 1.0, 1.0, -1.0); - break; - case 24: - await _filamentController.setRotation( - _cube!, pi / 2, 0.0, 1.0, 0.0); - break; - case 25: - setState(() { - _vertical = !_vertical; - }); - break; - case 26: - await _filamentController.setCameraPosition( - 0, 0, 3); - await _filamentController.setCameraRotation( - 0, 0, 1, 0); - break; - case 27: - _framerate = _framerate == 60 ? 30 : 60; - await _filamentController - .setFrameRate(_framerate); - break; - case 28: - await _filamentController - .setBackgroundImagePosition(25, 25); - break; - case 29: - _light = await _filamentController.addLight( - 1, - 6500, - 15000000, - 0, - 1, - 0, - 0, - -1, - 0, - true); - _light = await _filamentController.addLight( - 2, - 6500, - 15000000, - 0, - 0, - 1, - 0, - 0, - -1, - true); - break; - case 30: - if (_light != null) { - await _filamentController - .removeLight(_light!); - } - break; - case 31: - await _filamentController.clearLights(); - break; - } - }, - itemBuilder: (BuildContext context) => - >[ - const PopupMenuItem( - value: -1, child: Text("initialize")), - const PopupMenuItem( - value: -2, child: Text("render")), - const PopupMenuItem( - value: 0, - child: Text("load background image")), - const PopupMenuItem( - value: 1, - child: Text('load skybox'), - ), - const PopupMenuItem( - value: -3, - child: Text('load IBL'), - ), - const PopupMenuItem( - value: 2, - child: Text('remove skybox'), - ), - const PopupMenuItem( - value: 3, child: Text('load cube GLB')), - const PopupMenuItem( - value: 4, - child: Text('load cube GLTF')), - const PopupMenuItem( - value: 21, - child: Text('swap cube texture')), - const PopupMenuItem( - value: 22, - child: Text('transform to unit cube')), - const PopupMenuItem( - value: 23, - child: - Text('set position to 1, 1, -1')), - const PopupMenuItem( - value: 24, - child: - Text('rotate by pi around Y axis')), - const PopupMenuItem( - value: 5, - child: Text('load flight helmet')), - const PopupMenuItem( - value: 6, child: Text('remove cube')), - const PopupMenuItem( - value: 20, - child: Text('clear all assets')), - const PopupMenuItem( - value: 7, - child: Text('set all weights to 1')), - const PopupMenuItem( - value: 8, - child: Text('set all weights to 0')), - const PopupMenuItem( - value: 9, - child: Text('play all animations')), - const PopupMenuItem( - value: 10, - child: Text('stop animations')), - PopupMenuItem( - value: 11, - child: Text(_loop - ? "don't loop animation" - : "loop animation")), - const PopupMenuItem( - value: 14, child: Text('set camera')), - const PopupMenuItem( - value: 15, - child: Text('animate weights')), - const PopupMenuItem( - value: 16, - child: Text('get target names')), - const PopupMenuItem( - value: 17, - child: Text('get animation names')), - const PopupMenuItem( - value: 18, child: Text('pan left')), - const PopupMenuItem( - value: 19, child: Text('pan right')), - PopupMenuItem( - value: 25, - child: Text(_vertical - ? 'set horizontal' - : 'set vertical')), - PopupMenuItem( - value: 26, - child: Text('set camera pos to 0,0,3')), - PopupMenuItem( - value: 27, - child: Text('toggle framerate')), - PopupMenuItem( - value: 28, - child: Text('set bg image pos')), - PopupMenuItem( - value: 29, child: Text('add light')), - PopupMenuItem( - value: 30, child: Text('remove light')), - PopupMenuItem( - value: 31, - child: Text('clear all lights')), - ]))), - Align( - alignment: Alignment.bottomRight, - child: Row(children: [ - GestureDetector( - onTap: () { - setState(() { - _rendering = !_rendering; - _filamentController.setRendering(_rendering); - }); - }, - child: Container( - color: Colors.white, - padding: const EdgeInsets.all(50), - child: Text("Rendering: $_rendering "))), - GestureDetector( - onTap: () { - setState(() { - _framerate = _framerate == 60 ? 30 : 60; - _filamentController.setFrameRate(_framerate); - }); - }, - child: Container( - color: Colors.white, - padding: const EdgeInsets.all(50), - child: Text("$_framerate fps"))) - ])) - ]))); + 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: 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('set bone transform to 1, 1, -1')), + _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')), + ])), + Container( + width: _vertical ? 200 : 400, + height: _vertical ? 400 : 200, + alignment: Alignment.center, + child: SizedBox( + child: FilamentGestureDetector( + showControls: true, + controller: _filamentController, + child: FilamentWidget( + controller: _filamentController, + )), + )), + ]))); } } diff --git a/ios/Classes/SwiftPolyvoxFilamentPlugin.swift b/ios/Classes/SwiftPolyvoxFilamentPlugin.swift index ffa1b85f..7f860549 100644 --- a/ios/Classes/SwiftPolyvoxFilamentPlugin.swift +++ b/ios/Classes/SwiftPolyvoxFilamentPlugin.swift @@ -168,7 +168,7 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture Float(args[8] as! Double), args[9] as! Bool) result(entity); - case "animateWeights": + case "setAnimation": let args = call.arguments as! Array let assetPtr = UnsafeMutableRawPointer.init(bitPattern: args[0] as! Int) let frameData = args[1] as! Array @@ -176,7 +176,7 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture let numFrames = args[3] as! Int let frameLenInMs = args[4] as! Double frameData.map { Float($0)}.withUnsafeBufferPointer { - animate_weights(assetPtr, UnsafeMutablePointer.init(mutating:$0.baseAddress), Int32(numWeights), Int32(numFrames), Float(frameLenInMs)) + set_animation(assetPtr, UnsafeMutablePointer.init(mutating:$0.baseAddress), Int32(numWeights), Int32(numFrames), Float(frameLenInMs)) } result("OK") case "initialize": @@ -232,15 +232,15 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture let animationIndex = args[1] as! Int32 stop_animation(assetPtr, animationIndex) // TODO result("OK"); - case "getTargetNames": + case "getMorphTargetNames": let args = call.arguments as! Array let assetPtr = UnsafeMutableRawPointer.init(bitPattern: args[0] as! Int) let meshName = args[1] as! String - let numNames = get_target_name_count(assetPtr, meshName) + let numNames = get_morph_target_name_count(assetPtr, meshName) var names = [String]() for i in 0...numNames - 1{ let outPtr = UnsafeMutablePointer.allocate(capacity:256) - get_target_name(assetPtr, meshName, outPtr, i) + get_morph_target_name(assetPtr, meshName, outPtr, i) names.append(String(cString:outPtr)) } result(names); @@ -254,7 +254,7 @@ public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin, FlutterTexture names.append(String(cString:outPtr)) } result(names); - case "applyWeights": + case "setMorphTargetWeights": let args = call.arguments as! Array let assetPtr = UnsafeMutableRawPointer.init(bitPattern: args[0] as! Int) let weights = args[1] as! Array diff --git a/ios/include/PolyvoxFilamentApi.h b/ios/include/PolyvoxFilamentApi.h index 334b4444..71e25a46 100644 --- a/ios/include/PolyvoxFilamentApi.h +++ b/ios/include/PolyvoxFilamentApi.h @@ -38,7 +38,30 @@ void grab_end(void* viewer); void apply_weights(void* asset, float* const weights, int count); -void animate_weights(void* asset, float* data, int numWeights, int numFrames, float frameRate); +void set_animation( + void* asset, + float* morphData, + int numMorphWeights, + float* boneData, + const char** boneNames, + const char** meshNames, + int numBones, + int numFrames, + float frameLengthInMs +); + +void set_bone_transform( + void* asset, + const char* boneName, + const char* entityName, + float transX, + float transY, + float transZ, + float quatX, + float quatY, + float quatZ, + float quatW +); void play_animation(void* asset, int index, bool loop, bool reverse); void stop_animation(void* asset, int index); @@ -47,9 +70,9 @@ int get_animation_count(void* asset); void get_animation_name(void* asset, char* const outPtr, int index); -void get_target_name(void* asset, const char* meshName, char* const outPtr, int index ); +void get_morph_target_name(void* asset, const char* meshName, char* const outPtr, int index ); -int get_target_name_count(void* asset, const char* meshName); +int get_morph_target_name_count(void* asset, const char* meshName); void remove_asset(void* viewer, void* asset); diff --git a/ios/include/SceneAsset.hpp b/ios/include/SceneAsset.hpp index 35e30ae9..c83bf2e7 100644 --- a/ios/include/SceneAsset.hpp +++ b/ios/include/SceneAsset.hpp @@ -31,7 +31,7 @@ namespace polyvox { SceneAsset(FilamentAsset* asset, Engine* engine, NameComponentManager* ncm, LoadResource loadResource, FreeResource freeResource); ~SceneAsset(); - unique_ptr> getTargetNames(const char* meshName); + unique_ptr> getMorphTargetNames(const char* meshName); unique_ptr> getAnimationNames(); /// @@ -57,18 +57,39 @@ namespace polyvox { /// /// Manually set the weights for all morph targets in the assets to the provided values. - /// See [animateWeights] if you want to automatically + /// See [setAnimation] if you want to do the same across a number of frames (and extended to bone transforms). /// - void applyWeights(float* weights, int count); + void setMorphTargetWeights(float* weights, int count); /// - /// Update the asset's morph target weights every "frame" (which is an arbitrary length of time, i.e. this is not the same as a frame at the framerate of the underlying rendering framework). - /// Accordingly: - /// length(data) = numWeights * numFrames - /// total_animation_duration_in_ms = number_of_frames * frameLengthInMs - /// [data] will be copied; you should ensure this is freed after invoking this function. + /// Animates the asset's morph targets/bone transforms according to the frame weights/transforms specified in [morphData]/[boneData]. + /// The duration of each "frame" is specified by [frameLengthInMs] (i.e. this is not the framerate of the renderer). + /// [morphData] is a contiguous chunk of floats whose length will be (numMorphWeights * numFrames). + /// [boneData] is a contiguous chunk of floats whose length will be (numBones * 7 * numFrames) (where 7 is 3 floats for translation, 4 for quat rotation). + /// [morphData] and [boneData] will both be copied, so remember to free these after calling this function. /// - void animateWeights(float* data, int numWeights, int numFrames, float frameLengthInMs); + void setAnimation( + float* morphData, + int numMorphWeights, + float* boneData, + const char** boneNames, + const char** meshNames, + int numBones, + int numFrames, + float frameLengthInMs + ); + + void setBoneTransform( + const char* boneName, + const char* meshName, + float transX, + float transY, + float transZ, + float quatX, + float quatY, + float quatZ, + float quatW + ); void transformToUnitCube(); @@ -77,6 +98,8 @@ namespace polyvox { void setPosition(float x, float y, float z); void setRotation(float rads, float x, float y, float z); + + const utils::Entity* getCameraEntities(); @@ -93,15 +116,15 @@ namespace polyvox { Engine* _engine = nullptr; NameComponentManager* _ncm; - void updateMorphAnimation(); + void updateRuntimeAnimation(); void updateEmbeddedAnimations(); Animator* _animator; // animation flags; - unique_ptr _morphAnimationBuffer; - vector _embeddedAnimationStatus; + unique_ptr _runtimeAnimationBuffer; + vector _embeddedAnimationStatus; LoadResource _loadResource; FreeResource _freeResource; diff --git a/ios/include/SceneResources.hpp b/ios/include/SceneResources.hpp index 012afc76..a86d8c67 100644 --- a/ios/include/SceneResources.hpp +++ b/ios/include/SceneResources.hpp @@ -4,11 +4,14 @@ #include #include #include +#include #include "ResourceBuffer.hpp" namespace polyvox { - using namespace std; + + using namespace std; + // // Typedef for a function that loads a resource into a ResourceBuffer from an asset URI. // @@ -22,11 +25,13 @@ namespace polyvox { typedef std::chrono::time_point time_point_t; // - // Holds the current state of a bone animation embeded in a GLTF asset. - // Currently, an instance will be constructed for every animation in an asset whenever a SceneAsset is created (and thus will persist for the lifetime of the SceneAsset). + // Holds the current state of a GLTF animation. + // Whenever a SceneAsset is created, an instance of GLTFAnimation will be created for every embedded animation. + // On each frame loop, we check if [play] is true, and if so, advance the animation to the correct frame based on [startedAt]. + // The [GLTFAnimation] will persist for the lifetime of the SceneAsset. // - struct EmbeddedAnimationStatus { - EmbeddedAnimationStatus(bool loop, bool reverse) : loop(loop), reverse(reverse) {} + struct GLTFAnimation { + GLTFAnimation(bool loop, bool reverse) : loop(loop), reverse(reverse) {} // // A flag that is checked each frame to determine whether or not the animation should play. @@ -59,34 +64,64 @@ namespace polyvox { // time_point_t startedAt; - }; // - // Holds the current state of a morph-target animation in a GLTF asset. + // An animation created by manually passing frame data for morph weights/bone transforms. // - struct MorphAnimationStatus { + struct RuntimeAnimation { - MorphAnimationStatus(float* data, - int numWeights, - int numFrames, - float frameLengthInMs) : numFrames(numFrames), frameLengthInMs(frameLengthInMs), numWeights(numWeights) { - size_t size = numWeights * numFrames * sizeof(float); - frameData = (float*)malloc(size); - memcpy(frameData, data, size); + RuntimeAnimation(float* morphData, + int numMorphWeights, + float* boneData, + const char** boneNames, + const char** meshNames, + int numBones, + int numFrames, + float frameLengthInMs) : + mNumFrames(numFrames), + mFrameLengthInMs(frameLengthInMs), + mNumMorphWeights(numMorphWeights), + mNumBones(numBones) { + + if(numMorphWeights > 0) { + size_t morphSize = numMorphWeights * mNumFrames * sizeof(float); + mMorphFrameData = (float*)malloc(morphSize); + memcpy(mMorphFrameData, morphData, morphSize); + } + + if(numBones > 0) { + size_t boneSize = numBones * numFrames * 7 * sizeof(float); + mBoneFrameData = (float*)malloc(boneSize); + memcpy(mBoneFrameData, boneData, boneSize); + } + + for(int i =0; i < numBones; i++) { + mBoneNames.push_back(string(boneNames[i])); + mMeshNames.push_back(string(meshNames[i])); + } } - ~MorphAnimationStatus() { - delete(frameData); + ~RuntimeAnimation() { + delete(mMorphFrameData); + delete(mBoneFrameData); } int frameIndex = -1; - int numFrames = -1; - float frameLengthInMs = 0; + int mNumFrames = -1; + float mFrameLengthInMs = 0; time_point_t startTime; - float* frameData = nullptr; - int numWeights = 0; + float* mMorphFrameData = nullptr; + int mNumMorphWeights = 0; + + float* mBoneFrameData = nullptr; + int mNumBones = 0; + + vector mBoneNames; + vector mMeshNames; + }; + } diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index 92349ae3..7b7e191f 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -170,16 +170,16 @@ FilamentViewer::FilamentViewer(void* context, LoadResource loadResource, // options.minScale = filament::math::float2{ minScale }; // options.maxScale = filament::math::float2{ maxScale }; // options.sharpness = sharpness; - options.quality = View::QualityLevel::MEDIUM; - ; + options.quality = View::QualityLevel::HIGH; + _view->setDynamicResolutionOptions(options); - View::MultiSampleAntiAliasingOptions multiSampleAntiAliasingOptions; - multiSampleAntiAliasingOptions.enabled = false; + //View::MultiSampleAntiAliasingOptions multiSampleAntiAliasingOptions; + //multiSampleAntiAliasingOptions.enabled = true; - _view->setMultiSampleAntiAliasingOptions(multiSampleAntiAliasingOptions); + //_view->setMultiSampleAntiAliasingOptions(multiSampleAntiAliasingOptions); - // _view->setAntiAliasing(AntiAliasing::NONE); + //_view->setAntiAliasing(AntiAliasing::NONE); _materialProvider = // new UnlitMaterialProvider(_engine); diff --git a/ios/src/PolyvoxFilamentApi.cpp b/ios/src/PolyvoxFilamentApi.cpp index 3ab92f48..88149988 100644 --- a/ios/src/PolyvoxFilamentApi.cpp +++ b/ios/src/PolyvoxFilamentApi.cpp @@ -141,13 +141,59 @@ extern "C" { } void apply_weights(void* asset, float* const weights, int count) { - ((SceneAsset*)asset)->applyWeights(weights, count); + ((SceneAsset*)asset)->setMorphTargetWeights(weights, count); } - void animate_weights(void* asset, float* data, int numWeights, int numFrames, float frameRate) { - ((SceneAsset*)asset)->animateWeights((float*)data, numWeights, numFrames, frameRate); + void set_animation( + void* asset, + float* morphData, + int numMorphWeights, + float* boneData, + const char** boneNames, + const char** meshNames, + int numBones, + int numFrames, + float frameLengthInMs) { + ((SceneAsset*)asset)->setAnimation( + morphData, + numMorphWeights, + boneData, + boneNames, + meshNames, + numBones, + numFrames, + frameLengthInMs + ); } + + void set_bone_transform( + void* asset, + const char* boneName, + const char* entityName, + float transX, + float transY, + float transZ, + float quatX, + float quatY, + float quatZ, + float quatW +) { + ((SceneAsset*)asset)->setBoneTransform( + boneName, + entityName, + transX, + transY, + transZ, + quatX, + quatY, + quatZ, + quatW + ); + + } + + void play_animation(void* asset, int index, bool loop, bool reverse) { ((SceneAsset*)asset)->playAnimation(index, loop, reverse); } @@ -163,13 +209,13 @@ extern "C" { strcpy(outPtr, name.c_str()); } - int get_target_name_count(void* asset, const char* meshName) { - unique_ptr> names = ((SceneAsset*)asset)->getTargetNames(meshName); + int get_morph_target_name_count(void* asset, const char* meshName) { + unique_ptr> names = ((SceneAsset*)asset)->getMorphTargetNames(meshName); return names->size(); } - void get_target_name(void* asset, const char* meshName, char* const outPtr, int index ) { - unique_ptr> names = ((SceneAsset*)asset)->getTargetNames(meshName); + void get_morph_target_name(void* asset, const char* meshName, char* const outPtr, int index ) { + unique_ptr> names = ((SceneAsset*)asset)->getMorphTargetNames(meshName); string name = names->at(index); strcpy(outPtr, name.c_str()); } diff --git a/ios/src/SceneAsset.cpp b/ios/src/SceneAsset.cpp index 72916a7a..9e377469 100644 --- a/ios/src/SceneAsset.cpp +++ b/ios/src/SceneAsset.cpp @@ -34,7 +34,7 @@ SceneAsset::SceneAsset(FilamentAsset *asset, Engine *engine, _animator = _asset->getInstance()->getAnimator(); for (int i = 0; i < _animator->getAnimationCount(); i++) { _embeddedAnimationStatus.push_back( - EmbeddedAnimationStatus(false,false)); + GLTFAnimation(false,false)); } Log("Created animation buffers for %d", _embeddedAnimationStatus.size()); } @@ -47,7 +47,7 @@ SceneAsset::~SceneAsset() { } } -void SceneAsset::applyWeights(float *weights, int count) { +void SceneAsset::setMorphTargetWeights(float *weights, int count) { RenderableManager &rm = _engine->getRenderableManager(); for (size_t i = 0, c = _asset->getEntityCount(); i != c; ++i) { auto inst = rm.getInstance(_asset->getEntities()[i]); @@ -55,54 +55,78 @@ void SceneAsset::applyWeights(float *weights, int count) { } } -void SceneAsset::animateWeights(float *data, int numWeights, int numFrames, - float frameLengthInMs) { - Log("Making morph animation buffer with %d weights across %d frames and " - "frame length %f ms ", - numWeights, numFrames, frameLengthInMs); - _morphAnimationBuffer = std::make_unique( - data, numWeights, numFrames, frameLengthInMs); +void SceneAsset::setAnimation( + float* morphData, + int numMorphWeights, + float* boneData, + const char** boneNames, + const char** meshNames, + int numBones, + int numFrames, + float frameLengthInMs) { + _runtimeAnimationBuffer = std::make_unique( + morphData, + numMorphWeights, + boneData, + boneNames, + meshNames, + numBones, + numFrames, + frameLengthInMs + ); } void SceneAsset::updateAnimations() { - updateMorphAnimation(); + updateRuntimeAnimation(); updateEmbeddedAnimations(); } -void SceneAsset::updateMorphAnimation() { - if (!_morphAnimationBuffer) { +void SceneAsset::updateRuntimeAnimation() { + + if (!_runtimeAnimationBuffer) { return; } - if (_morphAnimationBuffer->frameIndex == -1) { -// auto ms = duration_cast(system_clock::now().time_since_epoch()).count(); -// Log("Frame 1 at %lu", ms); - _morphAnimationBuffer->frameIndex++; - _morphAnimationBuffer->startTime = high_resolution_clock::now(); - applyWeights(_morphAnimationBuffer->frameData, - _morphAnimationBuffer->numWeights); - } else { - duration dur = - high_resolution_clock::now() - _morphAnimationBuffer->startTime; - int frameIndex = - static_cast(dur.count() / _morphAnimationBuffer->frameLengthInMs); + if (_runtimeAnimationBuffer->frameIndex == -1) { + _runtimeAnimationBuffer->startTime = high_resolution_clock::now(); + } - if (frameIndex > _morphAnimationBuffer->numFrames - 1) { - duration dur = - high_resolution_clock::now() - _morphAnimationBuffer->startTime; - Log("Morph animation completed in %f ms (%d frames at framerate %f), " - "final frame was %d", - dur.count(), _morphAnimationBuffer->numFrames, - 1000 / _morphAnimationBuffer->frameLengthInMs, - _morphAnimationBuffer->frameIndex); - _morphAnimationBuffer = nullptr; - } else if (frameIndex > _morphAnimationBuffer->frameIndex) { -// Log("Rendering frame %d (of a total %d)", frameIndex, -// _morphAnimationBuffer->numFrames); - _morphAnimationBuffer->frameIndex = frameIndex; - auto framePtrOffset = frameIndex * _morphAnimationBuffer->numWeights; - applyWeights(_morphAnimationBuffer->frameData + framePtrOffset, - _morphAnimationBuffer->numWeights); + duration dur = + high_resolution_clock::now() - _runtimeAnimationBuffer->startTime; + int frameIndex = + static_cast(dur.count() / _runtimeAnimationBuffer->mFrameLengthInMs); + + // if the animation has finished, return early + if (frameIndex >= _runtimeAnimationBuffer->mNumFrames) { + _runtimeAnimationBuffer = nullptr; + return; + } + + if (frameIndex > _runtimeAnimationBuffer->frameIndex) { + _runtimeAnimationBuffer->frameIndex = frameIndex; + if(_runtimeAnimationBuffer->mMorphFrameData) { + auto morphFramePtrOffset = frameIndex * _runtimeAnimationBuffer->mNumMorphWeights; + setMorphTargetWeights(_runtimeAnimationBuffer->mMorphFrameData + morphFramePtrOffset, + _runtimeAnimationBuffer->mNumMorphWeights); + } + + if(_runtimeAnimationBuffer->mBoneFrameData) { + + for(int i = 0; i < _runtimeAnimationBuffer->mNumBones; i++) { + auto boneFramePtrOffset = (frameIndex * _runtimeAnimationBuffer->mNumBones * 7) + (i*7); + const char* boneName = _runtimeAnimationBuffer->mBoneNames[i].c_str(); + const char* meshName = _runtimeAnimationBuffer->mMeshNames[i].c_str(); + float* frame = _runtimeAnimationBuffer->mBoneFrameData + boneFramePtrOffset; + + float transX = frame[0]; + float transY = frame[1]; + float transZ = frame[2]; + float quatX = frame[3]; + float quatY = frame[4]; + float quatZ = frame[5]; + float quatW = frame[6]; + setBoneTransform(boneName, meshName, transX, transY, transZ, quatX, quatY, quatZ, quatW); + } } } } @@ -201,10 +225,12 @@ void SceneAsset::setTexture() { void SceneAsset::updateEmbeddedAnimations() { auto now = high_resolution_clock::now(); int animationIndex = 0; + bool playing = false; for (auto &status : _embeddedAnimationStatus) { if (status.play == false) { continue; } + playing = true; float animationLength = _animator->getAnimationDuration(animationIndex); @@ -241,8 +267,8 @@ void SceneAsset::updateEmbeddedAnimations() { } animationIndex++; } - - _animator->updateBoneMatrices(); + if(playing) + _animator->updateBoneMatrices(); } unique_ptr> SceneAsset::getAnimationNames() { @@ -259,7 +285,7 @@ unique_ptr> SceneAsset::getAnimationNames() { return names; } -unique_ptr> SceneAsset::getTargetNames(const char *meshName) { +unique_ptr> SceneAsset::getMorphTargetNames(const char *meshName) { if (!_asset) { Log("No asset, ignoring call."); return nullptr; @@ -272,7 +298,7 @@ unique_ptr> SceneAsset::getTargetNames(const char *meshName) { Entity e = entities[i]; auto inst = _ncm->getInstance(e); const char *name = _ncm->getName(inst); -// Log("Got entity instance name %s", name); + if (strcmp(name, meshName) == 0) { size_t count = _asset->getMorphTargetCountAt(e); for (int j = 0; j < count; j++) { @@ -327,6 +353,62 @@ void SceneAsset::setRotation(float rads, float x, float y, float z) { updateTransform(); } +void SceneAsset::setBoneTransform( + const char* boneName, + const char* entityName, + float transX, + float transY, + float transZ, + float quatX, + float quatY, + float quatZ, + float quatW) { + + auto filamentInstance = _asset->getInstance(); + + if(filamentInstance->getSkinCount()) { + Log("WARNING - skin count > 1 not currently implemented. This will probably not work"); + } + + filamentInstance->getAnimator()->resetBoneMatrices(); + + int skinIndex = 0; + const utils::Entity* joints = filamentInstance->getJointsAt(skinIndex); + size_t numJoints = filamentInstance->getJointCountAt(skinIndex); + + int boneIndex = -1; + for(int i =0; i < numJoints; i++) { + const char* jointName = _ncm->getName(_ncm->getInstance(joints[i])); + if(strcmp(jointName, boneName) == 0) { + boneIndex = i; + Log("Found bone index %d for bone %s", boneIndex, boneName); + break; + } + } + if(boneIndex == -1) { + Log("Failed to find bone index %d for bone %s", boneName); + return; + } + + RenderableManager &rm = _engine->getRenderableManager(); + + RenderableManager::Bone transform = {.unitQuaternion={quatX,quatY,quatZ,quatW}, .translation={transX,transY,transZ}}; + + for(int j = 0; j < _asset->getEntityCount(); j++) { + Entity e = _asset->getEntities()[j]; + if(strcmp(entityName,_ncm->getName(_ncm->getInstance(e)))==0) { + + Log("Setting bone transform on entity %s", _ncm->getName(_ncm->getInstance(e))); + + auto inst = rm.getInstance(e); + if(!inst) { + Log("No renderable instance"); + } + rm.setBones(inst, &transform, 1, boneIndex); + } + } +} + const utils::Entity *SceneAsset::getCameraEntities() { return _asset->getCameraEntities(); diff --git a/ios/src/SceneAssetLoader.cpp b/ios/src/SceneAssetLoader.cpp index ad9dcaf0..c30f74b3 100644 --- a/ios/src/SceneAssetLoader.cpp +++ b/ios/src/SceneAssetLoader.cpp @@ -106,13 +106,15 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) { Log("Resources loaded."); const Entity *entities = asset->getEntities(); + RenderableManager &rm = _engine->getRenderableManager(); + + // why did I need to explicitly enable culling? for (int i = 0; i < asset->getEntityCount(); i++) { - Entity e = entities[i]; - auto inst = rm.getInstance(e); - // check this - rm.setCulling(inst, true); - } + auto entityInstance = rm.getInstance(entities[i]); + rm.setCulling(entityInstance, true); + } + FilamentInstance* inst = asset->getInstance(); inst->getAnimator()->updateBoneMatrices(); diff --git a/ios/src/Untitled-1.cpp b/ios/src/Untitled-1.cpp new file mode 100644 index 00000000..1d5ce991 --- /dev/null +++ b/ios/src/Untitled-1.cpp @@ -0,0 +1,479 @@ + + + // // /* GL objects */ + // // guint vao; + // // guint program; + // // guint position_index; + // // guint color_index; + + // // GError *error = NULL; + // // std::cout << "init shaders" << std::endl; + + // // if (!init_shaders (&program, + // // &position_index, + // // &color_index, + // // &error)) + // // { + + // // std::cout << "EROR" << std::endl; + // // return FALSE; + // // } + + // // std::cout << "init buffers" << std::endl; + + + // // /* initialize the vertex buffers */ + // // init_buffers (position_index, color_index, &vao); + // // std::cout << "use prog" << std::endl; + + // // GLuint texID = glGetUniformLocation(program, "myTextureSampler"); + + // // // The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer. + // // GLuint FramebufferName = 0; + // // glGenFramebuffers(1, &FramebufferName); + // // glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); + + // // The texture we're going to render to + // glGenTextures(1, &self->texture_id); + + // if(self->texture_id == 0) { + // std::cout << "tecxtur eeror" << std::endl; + // } + + + // // "Bind" the newly created texture : all future texture functions will modify this texture + // glBindTexture(GL_TEXTURE_2D, self->texture_id); + + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, self->width, self->height, 0, GL_RGBA, + // GL_UNSIGNED_BYTE, 0); + + + // // // Set "renderedTexture" as our colour attachement #0 + // // glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, self->texture_id, 0); + + // // // Set the list of draw buffers. + // // GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; + // // glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers + + // // // Always check that our framebuffer is ok + // // if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + // // std::cout << "FB error" << std::endl; + // // return FALSE; + // // } + + // // glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); + + // // glViewport(0,0,400,200); // Render on the whole framebuffer, complete from the lower left corner to the upper righ + + // // // Clear the screen + // // glClearColor (0.0, 1.0, 0.5, 1.0); + // // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // // /* load our program */ + // // glUseProgram (program); + + // // // Bind our texture in Texture Unit 0 + // // glActiveTexture(GL_TEXTURE0); + // // glBindTexture(GL_TEXTURE_2D, self->texture_id); + // // // Set our "renderedTexture" sampler to use Texture Unit 0 + // // glUniform1i(texID, 0); + + // // /* use the buffers in the VAO */ + // // glBindVertexArray (vao); + + // // /* draw the three vertices as a triangle */ + // // glDrawArrays (GL_TRIANGLES, 0, 3); + + // // /* we finished using the buffers and program */ + // // glBindVertexArray (0); + // // glUseProgram (0); + + + // // glFlush (); + + + // // glGenTextures (1, &self->texture_id); + // // glBindTexture (GL_TEXTURE_2D, self->texture_id); + // // // further configuration here. + + +// /* position and color information for each vertex */ +// struct vertex_info { +// float position[3]; +// float color[3]; +// }; + +// /* the vertex data is constant */ +// static const struct vertex_info vertex_data[] = { +// { { 0.0f, 0.500f, 0.0f }, { 1.f, 0.f, 0.f } }, +// { { 0.5f, -0.366f, 0.0f }, { 0.f, 1.f, 0.f } }, +// { { -0.5f, -0.366f, 0.0f }, { 0.f, 0.f, 1.f } }, +// }; + +// static void +// init_buffers (guint position_index, +// guint color_index, +// guint *vao_out) +// { +// guint vao, buffer; + +// /* we need to create a VAO to store the other buffers */ +// glGenVertexArrays (1, &vao); +// glBindVertexArray (vao); + +// /* this is the VBO that holds the vertex data */ +// glGenBuffers (1, &buffer); +// glBindBuffer (GL_ARRAY_BUFFER, buffer); +// glBufferData (GL_ARRAY_BUFFER, sizeof (vertex_data), vertex_data, GL_STATIC_DRAW); + +// /* enable and set the position attribute */ +// glEnableVertexAttribArray (position_index); +// glVertexAttribPointer (position_index, 3, GL_FLOAT, GL_FALSE, +// sizeof (struct vertex_info), +// (GLvoid *) (G_STRUCT_OFFSET (struct vertex_info, position))); + +// /* enable and set the color attribute */ +// glEnableVertexAttribArray (color_index); +// glVertexAttribPointer (color_index, 3, GL_FLOAT, GL_FALSE, +// sizeof (struct vertex_info), +// (GLvoid *) (G_STRUCT_OFFSET (struct vertex_info, color))); + +// /* reset the state; we will re-enable the VAO when needed */ +// glBindBuffer (GL_ARRAY_BUFFER, 0); +// glBindVertexArray (0); + +// /* the VBO is referenced by the VAO */ +// glDeleteBuffers (1, &buffer); + +// if (vao_out != NULL) +// *vao_out = vao; +// } + +// static guint +// create_shader (int shader_type, +// const char *source, +// GError **error, +// guint *shader_out) +// { +// guint shader = glCreateShader (shader_type); +// glShaderSource (shader, 1, &source, NULL); +// glCompileShader (shader); + +// int status; +// glGetShaderiv (shader, GL_COMPILE_STATUS, &status); +// if (status == GL_FALSE) +// { +// std::cout << "SHADER IV ERROR" << std::endl; +// } + +// if (shader_out != NULL) +// *shader_out = shader; + +// return shader != 0; +// } + + +// static gboolean +// init_shaders (guint *program_out, +// guint *position_location_out, +// guint *color_location_out, +// GError **error) +// { +// const char *vsource = R"POO(#version 330 core + +// layout(location=0) in vec3 position; +// layout(location=1) in vec2 vertexUV; + +// out vec2 UV; + +// void main() { +// gl_Position = vec4(position, 1.0); +// UV = vertexUV; +// })POO"; + +// const char *fsource = R"POO(#version 330 core + +// in vec2 UV; + +// // Ouput data +// layout(location = 0) out vec3 color; + +// uniform sampler2D myTextureSampler; + +// void main() { +// color = vec3(1.0,0.0,0.0); +// // color = texture( myTextureSampler, UV ).rgb; +// })POO"; + +// // const char *vsource2 = R"POO(#version 130 + +// // in vec3 position; +// // in vec3 color; + +// // uniform mat4 mvp; + +// // smooth out vec4 vertexColor; + +// // void main() { +// // gl_Position = vec4(position, 1.0); +// // vertexColor = vec4(color, 1.0); +// // })POO"; + +// // const char *fsource2 = R"POO(#version 130 + +// // in vec2 UV; +// // out vec3 color; + +// // uniform sampler2D renderedTexture; + +// // void main() { +// // color = texture(renderedTexture, UV.xyz); +// // })POO"; + +// guint program = 0; +// // guint program2 = 0; + +// guint vertex = 0, fragment = 0; +// // guint vertex2 = 0, fragment2 = 0; + +// guint position_location = 0; +// guint color_location = 0; + +// /* load the vertex shader */ +// create_shader (GL_VERTEX_SHADER, vsource, error, &vertex); +// // g_bytes_unref (source); +// if (vertex == 0) { +// std::cout << "VERTEX ERROR" << std::endl; +// } + + +// /* load the fragment shader */ +// // source = g_resources_lookup_data ("/io/bassi/glarea/glarea-fragment.glsl", 0, NULL); +// create_shader (GL_FRAGMENT_SHADER, fsource, error, &fragment); + +// if (fragment == 0) +// std::cout << "FRAF ERROR" << std::endl; + +// /* link the vertex and fragment shaders together */ +// program = glCreateProgram (); + +// if(program == 0) { +// std::cout << "PROG ZERO" << std::endl; +// } +// glAttachShader (program, vertex); +// glAttachShader (program, fragment); +// glLinkProgram (program); + +// int status = 0; +// glGetProgramiv (program, GL_LINK_STATUS, &status); +// if (status == GL_FALSE) +// { +// std::cout << "glGetProgramiv ERROR" << std::endl; +// goto out; +// } + +// position_location = glGetAttribLocation (program, "position"); + +// /* get the location of the "position" and "color" attributes */ +// color_location = glGetAttribLocation (program, "color"); + +// /* the individual shaders can be detached and destroyed */ +// glDetachShader (program, vertex); +// glDetachShader (program, fragment); + +// // program2 = glCreateProgram(); + +// // create_shader (GL_VERTEX_SHADER, vsource2, error, &vertex2); +// // // g_bytes_unref (source); +// // if (vertex2 == 0) { +// // std::cout << "VERTEX 2ERROR" << std::endl; +// // } +// // create_shader (GL_VERTEX_SHADER, fsource2, error, &fragment2); +// // // g_bytes_unref (source); +// // if (fragment2 == 0) { +// // std::cout << "fragment2 ERROR" << std::endl; +// // } + +// // glAttachShader (program2, vertex2); +// // glAttachShader (program2, fragment2); +// // glLinkProgram (program2); + +// // status = 0; +// // glGetProgramiv (program2, GL_LINK_STATUS, &status); +// // if (status == GL_FALSE) +// // { +// // std::cout << "glGetProgramiv2 ERROR" << std::endl; +// // goto out; +// // } + + + +// out: +// if (vertex != 0) +// glDeleteShader (vertex); +// if (fragment != 0) +// glDeleteShader (fragment); + +// if (program_out != NULL) +// *program_out = program; +// if (position_location_out != NULL) +// *position_location_out = position_location; +// if (color_location_out != NULL) +// *color_location_out = color_location; + +// return program != 0; +// } + + +std::vector raw_buffer; + uint32_t pixels_w = 400; //w; + uint32_t pixels_h = 200; //h; + raw_buffer.resize(pixels_w*pixels_h * 4); + filament::backend::PixelBufferDescriptor bd( + raw_buffer.data(), + raw_buffer.size(), + backend::PixelDataFormat::RGBA, + backend::PixelDataType::UBYTE, + [](void* buffer, size_t size, void* capture_state) { + uint8_t* foo = (uint8_t*)buffer; + int32_t sum = 0; + for(int i =0; i < size; i++) { + sum += foo[i]; + } + + Log("SUM : %d", sum); + + std::string path = "./out.raw"; + std::ofstream stream(path, std::ios::out | std::ios::binary); + if(!stream.good()) + { + std::cerr << "Failed to open: " << path << std::endl; + } + else { + std::cerr << "Raw buf size " << size << std::endl; + stream.write((char*)buffer, size); + stream.close(); + } + + }); + render(0); + //after rendering to the target we can now read it back + _renderer->readPixels(_rt,0,0,pixels_w,pixels_h,std::move(bd)); + + _engine->flushAndWait(); + + // static void +// gl_init (PolyvoxFilamentPlugin *self) +// { +// std::cout << "GL INIT!" << std::endl; +// /* we need to ensure that the GdkGLContext is set before calling GL API */ +// gtk_gl_area_make_current (GTK_GL_AREA (self->gl_drawing_area)); +// gtk_gl_area_attach_buffers(GTK_GL_AREA (self->gl_drawing_area)); + +// gtk_gl_area_set_has_alpha(GTK_GL_AREA (self->gl_drawing_area), TRUE); +// gtk_gl_area_set_has_depth_buffer(GTK_GL_AREA (self->gl_drawing_area), TRUE); +// gtk_gl_area_set_has_stencil_buffer(GTK_GL_AREA (self->gl_drawing_area), TRUE); + + +// if(!gtk_gl_area_get_has_depth_buffer(GTK_GL_AREA (self->gl_drawing_area))) { +// std::cout << "NO DEPTH" << std::endl; +// } + +// if(!gtk_gl_area_get_has_stencil_buffer(GTK_GL_AREA (self->gl_drawing_area))) { +// std::cout << "NO STENCIL" << std::endl; +// } + +// /* if the GtkGLArea is in an error state we don't do anything */ +// if (gtk_gl_area_get_error (GTK_GL_AREA (self->gl_drawing_area)) != NULL) { +// std::cout << "ERRIOR" << std::endl; +// return; +// } +// auto ctx = gtk_gl_area_get_context ( GTK_GL_AREA(self->gl_drawing_area) ); + +// // auto foo = gdk_gl_context_get_shared_context(ctx); + +// int default_id; + +// glGetIntegerv(GL_FRAMEBUFFER_BINDING, &default_id); + +// std::cout << "DEFAULT ID " << default_id << std::endl; + +// GLuint fbo = 0; +// glGenFramebuffers(1, &fbo); +// glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo); + + +// filament_viewer_new( +// (void*)ctx, +// loadResource, +// freeResource +// ); + +// // if(!viewer) { +// // std::cout << "ERROR" << std::endl; +// // } + +// // self->_viewer = viewer; + +// // create_swap_chain(self->_viewer); + +// // create_render_target(self->_viewer, ((FilamentTextureGL*)texture)->texture_id,400,200); + + +// } + +struct _PolyvoxFilamentPlugin { + GObject parent_instance; + FlTextureRegistrar* texture_registrar; + FlView* fl_view; + + FlTexture* texture; + void* _viewer; + GtkWidget* gl_drawing_area ; + + + /* GL objects */ + guint vao; + guint program; + guint position_index; + guint color_index; +}; + + +// GtkWidget *tview; +// GtkTextBuffer *buffer; + +// tview = gtk_text_view_new (); +// gtk_widget_show(GTK_WIDGET(tview)); + +// buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tview)); + +// gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1); + +// GtkCssProvider *provider; +// GtkStyleContext *context; +// provider = gtk_css_provider_new (); +// gtk_css_provider_load_from_data (provider, +// "textview {" +// " font: 15 serif;" +// " color: green;" +// "}", +// -1, +// NULL); +// context = gtk_widget_get_style_context (tview); +// gtk_style_context_add_provider (context, +// GTK_STYLE_PROVIDER (provider), +// GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + // gtk_box_pack_start(box, GTK_WIDGET(tview), true, true,0); + // gtk_widget_grab_focus(GTK_WIDGET(tview)); + + GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 1)); + gtk_widget_show(GTK_WIDGET(box)); + gtk_widget_show(GTK_WIDGET(view)); + + gtk_box_pack_start(box, GTK_WIDGET(view), true, true,0); \ No newline at end of file diff --git a/lib/animations/Untitled-1.cpp b/lib/animations/Untitled-1.cpp new file mode 100644 index 00000000..597c3cab --- /dev/null +++ b/lib/animations/Untitled-1.cpp @@ -0,0 +1,21 @@ + // boneMatrices[1] = math::mat4f(1.0, 0.0, 0.0, 0.0, 0.0, 0.26, -0.97, 0.0, 0.0, 0.97, 0.26, 0.0, 0.0, 0.0, 0.0, 1.0); + + // Log("Asset instance count : %d asset entity count %d, skin count %d skin name %s joint count @ 0 %d ", + // _asset->getAssetInstanceCount(), + // _asset->getEntityCount(), + // , + // filamentInstance->getSkinNameAt(0), filamentInstance->getJointCountAt(0)); + + // for(int i =0; i < numJoints; i++) { + // auto nameInst = _ncm->getInstance(joints[i]); + // const char* jointName = _ncm->getName(nameInst); + // if(strcmp(jointName, boneName) == 0) { + // Log("Set transform for joint %s", jointName); + // // auto boneInst = rm.getInstance(joints[i]); + // } + // } +// bool transformed = false; + // if(!transformed) { + // Log("Failed to find bone %s", boneName); + // } + // Entity root = _asset->getRoot(); \ No newline at end of file diff --git a/lib/animations/animation_builder.dart b/lib/animations/animation_builder.dart new file mode 100644 index 00000000..49e8f987 --- /dev/null +++ b/lib/animations/animation_builder.dart @@ -0,0 +1,149 @@ +import 'animations.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; + +class Animation { + final Float32List morphWeights; + final int numMorphWeights; + + final int numFrames; + final double frameLengthInMs; + + final List boneNames; + final List meshNames; + + final Float32List boneTransforms; + + Animation(this.morphWeights, this.numMorphWeights, this.boneTransforms, + this.boneNames, this.meshNames, this.numFrames, this.frameLengthInMs); +} + +class AnimationBuilder { + BoneAnimation? boneAnimation; + double _frameLengthInMs = 0; + double _duration = 0; + int _numMorphWeights = 0; + + double? _interpMorphStart; + double? _interpMorphEnd; + double? _interpMorphStartValue; + double? _interpMorphEndValue; + + final List _boneNames = []; + final List _meshNames = []; + final List _boneTransforms = []; + + Animation build() { + if (_numMorphWeights == 0 || _duration == 0 || _frameLengthInMs == 0) + throw Exception(); + + int numFrames = _duration * 1000 ~/ _frameLengthInMs; + + final _morphWeights = Float32List((numFrames * _numMorphWeights).toInt()); + + var frameStart = (_interpMorphStart! * 1000) ~/ _frameLengthInMs; + var frameEnd = (_interpMorphEnd! * 1000) ~/ _frameLengthInMs; + + for (int i = frameStart; i < frameEnd; i++) { + var linear = (i - frameStart) / frameEnd; + + var val = ((1 - linear) * _interpMorphStartValue!) + + (linear * _interpMorphEndValue!); + for (int j = 0; j < _numMorphWeights; j++) { + _morphWeights[(i * _numMorphWeights) + j] = val; + } + } + + print( + "Created morphWeights of size ${_morphWeights.length} (${_morphWeights.lengthInBytes} for ${numFrames} frames"); + + final boneTransforms = Float32List(numFrames * _boneTransforms.length * 7); + print( + "Creating bone transforms of size ${numFrames * _boneTransforms.length * 7}"); + for (int i = 0; i < numFrames; i++) { + for (int j = 0; j < _boneTransforms.length; j++) { + var frameData = _boneTransforms[j].getFrameData(i).toList(); + var rngStart = ((i * _boneTransforms.length) + j) * 7; + var rngEnd = rngStart + 7; + boneTransforms.setRange(rngStart, rngEnd, frameData); + } + print( + "frameData for frame $i ${boneTransforms.sublist(i * _boneTransforms.length * 7, (i * _boneTransforms.length * 7) + 7)}"); + } + + return Animation(_morphWeights, _numMorphWeights, boneTransforms, + _boneNames, _meshNames, numFrames, _frameLengthInMs); + } + + AnimationBuilder setFramerate(int framerate) { + _frameLengthInMs = 1000 / framerate; + return this; + } + + AnimationBuilder setDuration(double secs) { + _duration = secs; + return this; + } + + AnimationBuilder setNumMorphWeights(int numMorphWeights) { + _numMorphWeights = numMorphWeights; + return this; + } + + AnimationBuilder interpolateMorphWeights( + double start, double end, double startValue, double endValue) { + this._interpMorphStart = start; + this._interpMorphEnd = end; + this._interpMorphStartValue = startValue; + this._interpMorphEndValue = endValue; + return this; + } + + AnimationBuilder interpolateBoneTransform( + String boneName, + String meshName, + double start, + double end, + Vec3 transStart, + Vec3 transEnd, + Quaternion quatStart, + Quaternion quatEnd) { + var translations = []; + var quats = []; + var frameStart = (start * 1000) ~/ _frameLengthInMs; + var frameEnd = (end * 1000) ~/ _frameLengthInMs; + int numFrames = _duration * 1000 ~/ _frameLengthInMs; + if (frameEnd > numFrames) { + throw Exception(); + } + + for (int i = 0; i < numFrames; i++) { + if (i >= frameStart && i < frameEnd) { + var linear = (i - frameStart) / (frameEnd - frameStart); + + translations.add(Vec3( + x: ((1 - linear) * transStart.x) + (linear * transEnd.x), + y: ((1 - linear) * transStart.y) + (linear * transEnd.y), + z: ((1 - linear) * transStart.z) + (linear * transEnd.z), + )); + + quats.add(Quaternion( + x: ((1 - linear) * quatStart.x) + (linear * quatEnd.x), + y: ((1 - linear) * quatStart.y) + (linear * quatEnd.y), + z: ((1 - linear) * quatStart.z) + (linear * quatEnd.z), + w: ((1 - linear) * quatStart.w) + (linear * quatEnd.w), + )); + } else { + translations.add(Vec3()); + quats.add(Quaternion()); + } + } + + _boneTransforms.add(BoneTransform(translations, quats)); + + _boneNames.add(boneName); + _meshNames.add(meshName); + + return this; + } +} diff --git a/lib/animations/animations.dart b/lib/animations/animations.dart new file mode 100644 index 00000000..6f833454 --- /dev/null +++ b/lib/animations/animations.dart @@ -0,0 +1,69 @@ +class Vec3 { + final double x; + final double y; + final double z; + + Vec3({this.x = 0, this.y = 0, this.z = 0}); +} + +class Quaternion { + double x = 0; + double y = 0; + double z = 0; + double w = 1; + + Quaternion({this.x = 0, this.y = 0, this.z = 0, this.w = 1.0}); +} + +class BoneTransform { + final List translations; + final List quaternions; + + /// + /// The length of [translations] and [quaternions] must be the same; + /// each entry represents the Vec3/Quaternion for the given frame. + /// + BoneTransform(this.translations, this.quaternions) { + if (translations.length != quaternions.length) { + throw Exception("Length of translation/quaternion frames must match"); + } + // for (int i = 0; i < quaternions.length; i++) { + // _frameData.add(translations[i].x); + // _frameData.add(translations[i].y); + // _frameData.add(translations[i].z); + // _frameData.add(quaternions[i].x); + // _frameData.add(quaternions[i].y); + // _frameData.add(quaternions[i].z); + // _frameData.add(quaternions[i].w); + // } + } + + Iterable getFrameData(int frame) sync* { + yield translations[frame].x; + yield translations[frame].y; + yield translations[frame].z; + yield quaternions[frame].x; + yield quaternions[frame].y; + yield quaternions[frame].z; + yield quaternions[frame].w; + } +} + +class BoneAnimation { + final List boneTransforms; + final List boneNames; + final List meshNames; + + final int numFrames; + + BoneAnimation( + this.boneTransforms, this.boneNames, this.meshNames, this.numFrames); + + Iterable toFrameData() sync* { + for (int i = 0; i < numFrames; i++) { + for (int j = 0; j < boneTransforms.length; j++) { + yield* boneTransforms[j].getFrameData(i); + } + } + } +} diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 40daae45..02e3e74b 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -1,5 +1,7 @@ import 'dart:async'; import 'dart:ui'; +import 'animations/animation_builder.dart'; +import 'animations/animations.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -60,8 +62,9 @@ abstract class FilamentController { Future rotateStart(double x, double y); Future rotateUpdate(double x, double y); Future rotateEnd(); - Future applyWeights(FilamentAsset asset, List weights); - Future> getTargetNames(FilamentAsset asset, String meshName); + Future setMorphTargetWeights(FilamentAsset asset, List weights); + Future> getMorphTargetNames( + FilamentAsset asset, String meshName); Future> getAnimationNames(FilamentAsset asset); Future removeAsset(FilamentAsset asset); Future clearAssets(); @@ -77,6 +80,8 @@ abstract class FilamentController { Future setPosition(FilamentAsset asset, double x, double y, double z); Future setRotation( FilamentAsset asset, double rads, double x, double y, double z); + Future setBoneTransform(FilamentAsset asset, String boneName, String meshName, + BoneTransform transform); Future setScale(FilamentAsset asset, double scale); Future setCameraFocalLength(double focalLength); Future setCameraFocusDistance(double focusDistance); @@ -84,13 +89,11 @@ abstract class FilamentController { Future setCameraRotation(double rads, double x, double y, double z); /// - /// Set the weights of all morph targets in the mesh to the specified weights at successive frames (where each frame requires a duration of [frameLengthInMs]. - /// Accepts a list of doubles representing a sequence of "frames", stacked end-to-end. - /// Each frame is [numWeights] in length, where each entry is the weight to be applied to the morph target located at that index in the mesh primitive at that frame. - /// In other words, weights is a contiguous sequence of floats of size W*F, where W is the number of weights and F is the number of frames + /// Animates morph target weights/bone transforms (where each frame requires a duration of [frameLengthInMs]. + /// [morphWeights] is a list of doubles in frame-major format. + /// Each frame is [numWeights] in length, and each entry is the weight to be applied to the morph target located at that index in the mesh primitive at that frame. /// - Future animate(FilamentAsset asset, List data, int numWeights, - int numFrames, double frameLengthInMs); + Future setAnimation(FilamentAsset asset, Animation animation); } class PolyvoxFilamentController extends FilamentController { @@ -130,6 +133,7 @@ class PolyvoxFilamentController extends FilamentController { } void setPixelRatio(double ratio) { + print("Set pixel ratio to $ratio"); _pixelRatio = ratio; } @@ -258,15 +262,16 @@ class PolyvoxFilamentController extends FilamentController { await _channel.invokeMethod("rotateEnd"); } - Future applyWeights(FilamentAsset asset, List weights) async { - await _channel - .invokeMethod("applyWeights", [asset, Float32List.fromList(weights)]); + Future setMorphTargetWeights( + FilamentAsset asset, List weights) async { + await _channel.invokeMethod( + "setMorphTargetWeights", [asset, Float32List.fromList(weights)]); } - Future> getTargetNames( + Future> getMorphTargetNames( FilamentAsset asset, String meshName) async { var result = - (await _channel.invokeMethod("getTargetNames", [asset, meshName])) + (await _channel.invokeMethod("getMorphTargetNames", [asset, meshName])) .cast(); return result; } @@ -277,14 +282,16 @@ class PolyvoxFilamentController extends FilamentController { return result; } - Future animate(FilamentAsset asset, List weights, int numWeights, - int numFrames, double frameLengthInMs) async { - await _channel.invokeMethod("animateWeights", [ + Future setAnimation(FilamentAsset asset, Animation animation) async { + await _channel.invokeMethod("setAnimation", [ asset, - Float32List.fromList(weights), - numWeights, - numFrames, - frameLengthInMs + animation.morphWeights, + animation.numMorphWeights, + animation.boneTransforms, + animation.boneNames, + animation.meshNames, + animation.numFrames, + animation.frameLengthInMs ]); } @@ -360,6 +367,22 @@ class PolyvoxFilamentController extends FilamentController { await _channel.invokeMethod("setPosition", [asset, x, y, z]); } + Future setBoneTransform(FilamentAsset asset, String boneName, String meshName, + BoneTransform transform) async { + await _channel.invokeMethod("setBoneTransform", [ + asset, + boneName, + meshName, + transform.translations[0].x, + transform.translations[0].y, + transform.translations[0].z, + transform.quaternions[0].x, + transform.quaternions[0].y, + transform.quaternions[0].z, + transform.quaternions[0].w + ]); + } + Future setScale(FilamentAsset asset, double scale) async { await _channel.invokeMethod("setScale", [asset, scale]); } diff --git a/lib/filament_widget.dart b/lib/filament_widget.dart index 518d5f8f..1c28055c 100644 --- a/lib/filament_widget.dart +++ b/lib/filament_widget.dart @@ -96,7 +96,7 @@ class _FilamentWidgetState extends State { } var texture = Texture( textureId: widget.controller.textureId, - filterQuality: FilterQuality.none, + filterQuality: FilterQuality.high, ); return ResizeObserver( onResized: (Size oldSize, Size newSize) async { diff --git a/linux/polyvox_filament_plugin.cc b/linux/polyvox_filament_plugin.cc index 7c0c231a..7ea99d3e 100644 --- a/linux/polyvox_filament_plugin.cc +++ b/linux/polyvox_filament_plugin.cc @@ -251,6 +251,42 @@ static FlMethodResponse* _pan_end(PolyvoxFilamentPlugin* self, FlMethodCall* met return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); } +static FlMethodResponse* _set_position(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { + FlValue* args = fl_method_call_get_args(method_call); + auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0)); + + set_position( + assetPtr, + (float)fl_value_get_float(fl_value_get_list_value(args, 1)), // x + (float)fl_value_get_float(fl_value_get_list_value(args, 2)), // y + (float)fl_value_get_float(fl_value_get_list_value(args, 3)) // z + ); + g_autoptr(FlValue) result = fl_value_new_string("OK"); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); +} + +static FlMethodResponse* _set_bone_transform(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { + FlValue* args = fl_method_call_get_args(method_call); + auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0)); + auto boneName = fl_value_get_string(fl_value_get_list_value(args, 1)); + auto meshName = fl_value_get_string(fl_value_get_list_value(args, 2)); + + set_bone_transform( + assetPtr, + boneName, + meshName, + (float)fl_value_get_float(fl_value_get_list_value(args, 3)), // transX + (float)fl_value_get_float(fl_value_get_list_value(args, 4)), // transY + (float)fl_value_get_float(fl_value_get_list_value(args, 5)), // transZ + (float)fl_value_get_float(fl_value_get_list_value(args, 6)), // quatX + (float)fl_value_get_float(fl_value_get_list_value(args, 7)), // quatY + (float)fl_value_get_float(fl_value_get_list_value(args, 8)), // quatZ + (float)fl_value_get_float(fl_value_get_list_value(args, 9)) // quatW + ); + g_autoptr(FlValue) result = fl_value_new_string("OK"); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); +} + static FlMethodResponse* _set_camera_position(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { FlValue* args = fl_method_call_get_args(method_call); auto x = (float)fl_value_get_float(fl_value_get_list_value(args, 0)); @@ -335,33 +371,48 @@ static FlMethodResponse* _apply_weights(PolyvoxFilamentPlugin* self, FlMethodCal return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); } -static FlMethodResponse* _animate_weights(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { +static FlMethodResponse* _set_animation(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { FlValue* args = fl_method_call_get_args(method_call); auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0)); - auto weightsValue = fl_value_get_list_value(args, 1); + + float* const morphData = (float* const) fl_value_get_float32_list(fl_value_get_list_value(args, 1)); + + int64_t numMorphWeights = fl_value_get_int(fl_value_get_list_value(args, 2)); - float* const weights = (float* const) fl_value_get_float32_list(weightsValue); - int64_t numWeights = fl_value_get_int(fl_value_get_list_value(args, 2)); - int64_t numFrames = fl_value_get_int(fl_value_get_list_value(args, 3)); - float frameLengthInMs = fl_value_get_float(fl_value_get_list_value(args, 4)); + float* const boneData = (float* const) fl_value_get_float32_list(fl_value_get_list_value(args, 3)); + FlValue* boneNamesValue = fl_value_get_list_value(args, 4); + int64_t numBones = fl_value_get_length(boneNamesValue); + const char* boneNames[numBones]; + for(int i=0; i< numBones;i++) { + boneNames[i] = fl_value_get_string(fl_value_get_list_value(boneNamesValue, i)); + } + + FlValue* meshNamesValue = fl_value_get_list_value(args, 5); + const char* meshNames[numBones]; + for(int i=0; i< numBones;i++) { + meshNames[i] = fl_value_get_string(fl_value_get_list_value(meshNamesValue, i)); + } + + int64_t numFrames = fl_value_get_int(fl_value_get_list_value(args, 6)); + float frameLengthInMs = fl_value_get_float(fl_value_get_list_value(args, 7)); - animate_weights(assetPtr, weights, numWeights, numFrames, 1000.0f / frameLengthInMs); + set_animation(assetPtr, morphData, numMorphWeights, boneData, boneNames, meshNames, numBones, numFrames, 1000.0f / frameLengthInMs); g_autoptr(FlValue) result = fl_value_new_string("OK"); return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); } -static FlMethodResponse* _get_target_names(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { +static FlMethodResponse* _get_morph_target_names(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { FlValue* args = fl_method_call_get_args(method_call); auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0)); auto meshName = fl_value_get_string(fl_value_get_list_value(args, 1)); g_autoptr(FlValue) result = fl_value_new_list(); - auto numNames = get_target_name_count(assetPtr, meshName); + auto numNames = get_morph_target_name_count(assetPtr, meshName); for(int i = 0; i < numNames; i++) { gchar out[255]; - get_target_name(assetPtr, meshName, out, i); + get_morph_target_name(assetPtr, meshName, out, i); fl_value_append_take (result, fl_value_new_string (out)); } @@ -468,12 +519,16 @@ static void polyvox_filament_plugin_handle_method_call( response = _play_animation(self, method_call); } else if(strcmp(method, "stopAnimation") == 0) { response = _stop_animation(self, method_call); - } else if(strcmp(method, "applyWeights") == 0) { + } else if(strcmp(method, "setMorphTargetWeights") == 0) { response = _apply_weights(self, method_call); - } else if(strcmp(method, "animateWeights") == 0) { - response = _animate_weights(self, method_call); - } else if(strcmp(method, "getTargetNames") == 0) { - response = _get_target_names(self, method_call); + } else if(strcmp(method, "setAnimation") == 0) { + response = _set_animation(self, method_call); + } else if(strcmp(method, "getMorphTargetNames") == 0) { + response = _get_morph_target_names(self, method_call); + } else if(strcmp(method, "setPosition") == 0) { + response = _set_position(self, method_call); + } else if(strcmp(method, "setBoneTransform") == 0) { + response = _set_bone_transform(self, method_call); } else { response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); }