Merge branch 'master' of github.com:nmfisher/polyvox_filament
This commit is contained in:
Binary file not shown.
@@ -225,6 +225,7 @@
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:vector_math/vector_math.dart' as v;
|
||||
|
||||
import 'package:polyvox_filament/filament_controller.dart';
|
||||
@@ -21,15 +22,32 @@ class MyApp extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> 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<StatefulWidget> createState() {
|
||||
return _ExampleWidgetState();
|
||||
}
|
||||
}
|
||||
|
||||
class _ExampleWidgetState extends State<ExampleWidget> {
|
||||
late FilamentController _filamentController;
|
||||
|
||||
FilamentEntity? _cube;
|
||||
FilamentEntity? _flightHelmet;
|
||||
List<String>? _animations;
|
||||
FilamentEntity? _light;
|
||||
|
||||
final weights = List.filled(255, 0.0);
|
||||
List<String> _targetNames = [];
|
||||
List<String> _animationNames = [];
|
||||
|
||||
bool _loop = false;
|
||||
bool _vertical = false;
|
||||
bool _rendering = false;
|
||||
@@ -38,174 +56,99 @@ class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_filamentController = FilamentController(this);
|
||||
_filamentController = FilamentController();
|
||||
}
|
||||
|
||||
void onClick(int index) async {
|
||||
switch (index) {
|
||||
case -1:
|
||||
await _filamentController.initialize();
|
||||
break;
|
||||
case -2:
|
||||
bool _initialized = false;
|
||||
|
||||
bool _coneHidden = false;
|
||||
|
||||
Widget _item(void Function() onTap, String text) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
|
||||
child: Text(text)));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var children = [
|
||||
_initialized
|
||||
? Container()
|
||||
: _item(() async {
|
||||
await _filamentController.initialize();
|
||||
setState(() {
|
||||
_initialized = true;
|
||||
});
|
||||
}, "initialize"),
|
||||
_item(() {
|
||||
_filamentController.render();
|
||||
break;
|
||||
case -4:
|
||||
}, "render"),
|
||||
_item(() {
|
||||
setState(() {
|
||||
_rendering = !_rendering;
|
||||
_filamentController.setRendering(_rendering);
|
||||
});
|
||||
break;
|
||||
case -5:
|
||||
}, "Rendering: $_rendering "),
|
||||
_item(() {
|
||||
setState(() {
|
||||
_framerate = _framerate == 60 ? 30 : 60;
|
||||
_filamentController.setFrameRate(_framerate);
|
||||
});
|
||||
break;
|
||||
|
||||
case 0:
|
||||
}, "$_framerate fps"),
|
||||
_item(() {
|
||||
_filamentController.setBackgroundColor(Color(0xFF73C9FA));
|
||||
}, "set background color"),
|
||||
_item(() {
|
||||
_filamentController.setBackgroundImage('assets/background.ktx');
|
||||
break;
|
||||
case 1:
|
||||
}, "load background image"),
|
||||
_item(() {
|
||||
_filamentController
|
||||
.loadSkybox('assets/default_env/default_env_skybox.ktx');
|
||||
break;
|
||||
case -3:
|
||||
}, 'load skybox'),
|
||||
_item(() {
|
||||
_filamentController.loadIbl('assets/default_env/default_env_ibl.ktx');
|
||||
break;
|
||||
case 2:
|
||||
_filamentController.removeSkybox();
|
||||
break;
|
||||
case 3:
|
||||
_cube = _filamentController.loadGlb('assets/cube.glb');
|
||||
_animationNames = _filamentController.getAnimationNames(_cube!);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
}, 'load IBL'),
|
||||
_item(
|
||||
() {
|
||||
_filamentController.removeSkybox();
|
||||
},
|
||||
'remove skybox',
|
||||
),
|
||||
_item(() async {
|
||||
_cube = await _filamentController.loadGlb('assets/cube.glb');
|
||||
_animations = await _filamentController.getAnimationNames(_cube!);
|
||||
setState(() {});
|
||||
}, 'load cube GLB'),
|
||||
_item(() async {
|
||||
if (_coneHidden) {
|
||||
_filamentController.reveal(_cube!, "Cone");
|
||||
} else {
|
||||
_filamentController.hide(_cube!, "Cone");
|
||||
}
|
||||
setState(() {
|
||||
_coneHidden = !_coneHidden;
|
||||
});
|
||||
}, _coneHidden ? 'show cone' : 'hide cone'),
|
||||
_item(() async {
|
||||
if (_cube != null) {
|
||||
_filamentController.removeAsset(_cube!);
|
||||
}
|
||||
_cube = _filamentController.loadGltf('assets/cube.gltf', 'assets');
|
||||
break;
|
||||
case 5:
|
||||
_flightHelmet ??= _filamentController.loadGltf(
|
||||
'assets/FlightHelmet/FlightHelmet.gltf', 'assets/FlightHelmet');
|
||||
break;
|
||||
case 6:
|
||||
_filamentController.removeAsset(_cube!);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
_filamentController.setMorphTargetWeights(
|
||||
_cube!, "Cube.001", List.filled(8, 1.0));
|
||||
break;
|
||||
case 8:
|
||||
_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;
|
||||
});
|
||||
break;
|
||||
case 14:
|
||||
_filamentController.setCamera(_cube!, "Camera_Orientation");
|
||||
break;
|
||||
case 15:
|
||||
final animation = AnimationBuilder(
|
||||
controller: _filamentController,
|
||||
asset: _cube!,
|
||||
framerate: 30,
|
||||
meshName: "Cube.001")
|
||||
.setDuration(4)
|
||||
.interpolateMorphWeights(0, 4, 0, 1)
|
||||
// .interpolateBoneTransform(
|
||||
// "Bone.001",
|
||||
// "Cube.001",
|
||||
// 2,
|
||||
// 4,
|
||||
// v.Vector3.zero(),
|
||||
// v.Vector3.zero(),
|
||||
// // Vec3(x: 1, y: 1, z: 1),
|
||||
// v.Quaternion(0, 0, 0, 1),
|
||||
// v.Quaternion(1, 1, 1, 1))
|
||||
// Quaternion(x: 1, y: 1, z: 1, w: 1))
|
||||
.set();
|
||||
break;
|
||||
case 16:
|
||||
_targetNames = _filamentController.getMorphTargetNames(_cube!, "Cube");
|
||||
setState(() {});
|
||||
break;
|
||||
case 17:
|
||||
_animationNames = _filamentController.getAnimationNames(_cube!);
|
||||
setState(() {});
|
||||
|
||||
break;
|
||||
case 18:
|
||||
_filamentController.panStart(1, 1);
|
||||
_filamentController.panUpdate(1, 2);
|
||||
_filamentController.panEnd();
|
||||
break;
|
||||
case 19:
|
||||
_filamentController.panStart(1, 1);
|
||||
_filamentController.panUpdate(0, 0);
|
||||
_filamentController.panEnd();
|
||||
break;
|
||||
case 20:
|
||||
_filamentController.clearAssets();
|
||||
break;
|
||||
case 21:
|
||||
_cube =
|
||||
await _filamentController.loadGltf('assets/cube.gltf', 'assets');
|
||||
}, 'load cube GLTF'),
|
||||
_item(() async {
|
||||
_filamentController.setTexture(_cube!, "assets/background.png");
|
||||
break;
|
||||
case 22:
|
||||
}, 'swap cube texture'),
|
||||
_item(() async {
|
||||
_filamentController.transformToUnitCube(_cube!);
|
||||
break;
|
||||
case 23:
|
||||
}, 'transform to unit cube'),
|
||||
_item(() async {
|
||||
_filamentController.setPosition(_cube!, 1.0, 1.0, -1.0);
|
||||
break;
|
||||
case 24:
|
||||
_filamentController.setRotation(_cube!, pi / 2, 0.0, 1.0, 0.0);
|
||||
break;
|
||||
case 25:
|
||||
setState(() {
|
||||
_vertical = !_vertical;
|
||||
});
|
||||
break;
|
||||
case 26:
|
||||
_filamentController.setCameraPosition(0, 0, 3);
|
||||
_filamentController.setCameraRotation(0, 0, 1, 0);
|
||||
break;
|
||||
case 27:
|
||||
_framerate = _framerate == 60 ? 30 : 60;
|
||||
_filamentController.setFrameRate(_framerate);
|
||||
break;
|
||||
case 28:
|
||||
_filamentController.setBackgroundImagePosition(25, 25);
|
||||
break;
|
||||
case 29:
|
||||
_light = _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!);
|
||||
}
|
||||
break;
|
||||
case 31:
|
||||
_filamentController.clearLights();
|
||||
break;
|
||||
case 32:
|
||||
}, 'set position to 1, 1, -1'),
|
||||
_item(() async {
|
||||
var frameData = Float32List.fromList(
|
||||
List<double>.generate(120, (i) => i / 120).expand((x) {
|
||||
var vals = List<double>.filled(7, x);
|
||||
@@ -225,114 +168,268 @@ class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
|
||||
// "Cube.001",
|
||||
// BoneTransform([Vec3(x: 0, y: 0.0, z: 0.0)],
|
||||
// [Quaternion(x: 1, y: 1, z: 1, w: 1)]));
|
||||
// break;
|
||||
break;
|
||||
case 33:
|
||||
if (_coneHidden) {
|
||||
_filamentController.reveal(_cube!, "Cone");
|
||||
} else {
|
||||
_filamentController.hide(_cube!, "Cone");
|
||||
}
|
||||
setState(() {
|
||||
_coneHidden = !_coneHidden;
|
||||
});
|
||||
}, 'construct bone animation'),
|
||||
_item(() async {
|
||||
_filamentController.removeAsset(_cube!);
|
||||
}, 'remove cube'),
|
||||
_item(() async {
|
||||
_filamentController.clearAssets();
|
||||
}, 'clear all assets'),
|
||||
_item(() async {
|
||||
var names =
|
||||
await _filamentController.getMorphTargetNames(_cube!, "Cylinder");
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (ctx) {
|
||||
return Container(
|
||||
height: 100,
|
||||
width: 100,
|
||||
color: Colors.white,
|
||||
child: Text(names.join(",")));
|
||||
});
|
||||
}, "show morph target names for Cylinder"),
|
||||
_item(() {
|
||||
_filamentController.setMorphTargetWeights(
|
||||
_cube!, "Cylinder", List.filled(4, 1.0));
|
||||
}, "set Cylinder morph weights to 1"),
|
||||
_item(() {
|
||||
_filamentController.setMorphTargetWeights(
|
||||
_cube!, "Cylinder", List.filled(4, 0.0));
|
||||
}, "set Cylinder morph weights to 0.0"),
|
||||
_item(() async {
|
||||
var morphs =
|
||||
await _filamentController.getMorphTargetNames(_cube!, "Cylinder");
|
||||
final animation = AnimationBuilder(
|
||||
availableMorphs: morphs, framerate: 30, meshName: "Cylinder")
|
||||
.setDuration(4)
|
||||
.setMorphTargets(["Key 1", "Key 2"])
|
||||
.interpolateMorphWeights(0, 4, 0, 1)
|
||||
.build();
|
||||
_filamentController.setMorphAnimationData(_cube!, animation);
|
||||
}, "animate morph weights #1 and #2"),
|
||||
_item(() async {
|
||||
var morphs =
|
||||
await _filamentController.getMorphTargetNames(_cube!, "Cylinder");
|
||||
final animation = AnimationBuilder(
|
||||
availableMorphs: morphs, framerate: 30, meshName: "Cylinder")
|
||||
.setDuration(4)
|
||||
.setMorphTargets(["Key 3", "Key 4"])
|
||||
.interpolateMorphWeights(0, 4, 0, 1)
|
||||
.build();
|
||||
_filamentController.setMorphAnimationData(_cube!, animation);
|
||||
}, "animate morph weights #3 and #4"),
|
||||
_item(() {
|
||||
_filamentController.setMaterialColor(_cube!, "Cone", 0, Colors.purple);
|
||||
}, "set cone material color to purple")
|
||||
];
|
||||
if (_animations != null) {
|
||||
children.addAll(_animations!.map((a) => _item(() {
|
||||
_filamentController.playAnimation(_cube!, _animations!.indexOf(a),
|
||||
replaceActive: true, crossfade: 0.5);
|
||||
}, "play animation ${_animations!.indexOf(a)} (replace/fade)")));
|
||||
children.addAll(_animations!.map((a) => _item(() {
|
||||
_filamentController.playAnimation(_cube!, _animations!.indexOf(a),
|
||||
replaceActive: false);
|
||||
}, "play animation ${_animations!.indexOf(a)} (noreplace)")));
|
||||
}
|
||||
}
|
||||
|
||||
bool _coneHidden = false;
|
||||
|
||||
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(
|
||||
// showPerformanceOverlay: true,
|
||||
color: Colors.white,
|
||||
home: Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
body: Row(children: [
|
||||
SingleChildScrollView(
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: 20, left: 20),
|
||||
child: Row(children: [
|
||||
Expanded(
|
||||
child: 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,
|
||||
)),
|
||||
)),
|
||||
])));
|
||||
children: children
|
||||
// _item(24 () async { 'rotate by pi around Y axis'),
|
||||
// _item(5 () async { 'load flight helmet'),
|
||||
|
||||
// _item(7 () async { 'set all weights to 1'),
|
||||
// _item(8 () async { 'set all weights to 0'),
|
||||
// _item(9 () async { 'play all animations'),
|
||||
// _item(34 () async { 'play animation 0'),
|
||||
// _item(34 () async { 'play animation 0 (noreplace)'),
|
||||
// _item(35 () async { 'play animation 1'),
|
||||
// _item(34 () async { 'play animation 0 (noreplace)'),
|
||||
// _item(36 () async { 'play animation 2'),
|
||||
// _item(34 () async { 'play animation 0 (noreplace)'),
|
||||
// _item(36 () async { 'play animation 3'),
|
||||
// _item(34 () async { 'play animation 3 (noreplace)'),
|
||||
// _item(37 () async { 'stop animation 0'),
|
||||
// _item(11 () async {
|
||||
// Text(
|
||||
// _loop ? "don't loop animation" : "loop animation")),
|
||||
// _item(14 () async { 'set camera'),
|
||||
// _item(15 () async { 'animate weights'),
|
||||
// _item(16 () async { 'get target names'),
|
||||
// _item(17 () async { 'get animation names'),
|
||||
// _item(18 () async { 'pan left'),
|
||||
// _item(19 () async { 'pan right'),
|
||||
// _item(25 () async {
|
||||
// Text(_vertical ? 'set horizontal' : 'set vertical')),
|
||||
// _item(26 () async { 'set camera pos to 0,0,3'),
|
||||
// _item(27 () async { 'toggle framerate'),
|
||||
// _item(28 () async { 'set bg image pos'),
|
||||
// _item(29 () async { 'add light'),
|
||||
// _item(30 () async { 'remove light'),
|
||||
// _item(31 () async { 'clear all lights'),
|
||||
// _item(32 () async { 'set camera model matrix'),
|
||||
))),
|
||||
Container(
|
||||
width: _vertical ? 200 : 400,
|
||||
height: _vertical ? 400 : 200,
|
||||
alignment: Alignment.center,
|
||||
child: FilamentGestureDetector(
|
||||
showControlOverlay: true,
|
||||
controller: _filamentController,
|
||||
child: FilamentWidget(
|
||||
controller: _filamentController,
|
||||
)),
|
||||
),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
// case -1:
|
||||
|
||||
|
||||
// break;
|
||||
// case -2:
|
||||
// _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 -6:
|
||||
// _filamentController.setBackgroundColor(Color(0xFF73C9FA));
|
||||
// break;
|
||||
|
||||
|
||||
// case 5:
|
||||
// _flightHelmet ??= await _filamentController.loadGltf(
|
||||
// 'assets/FlightHelmet/FlightHelmet.gltf', 'assets/FlightHelmet');
|
||||
// break;
|
||||
|
||||
// case 11:
|
||||
// setState(() {
|
||||
// _loop = !_loop;
|
||||
// });
|
||||
// break;
|
||||
// case 14:
|
||||
// _filamentController.setCamera(_cube!, "Camera_Orientation");
|
||||
// break;
|
||||
// case 15:
|
||||
|
||||
// break;
|
||||
// case 17:
|
||||
// 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:
|
||||
// _filamentController.panStart(1, 1);
|
||||
// _filamentController.panUpdate(1, 2);
|
||||
// _filamentController.panEnd();
|
||||
// break;
|
||||
// case 19:
|
||||
// _filamentController.panStart(1, 1);
|
||||
// _filamentController.panUpdate(0, 0);
|
||||
// _filamentController.panEnd();
|
||||
// break;
|
||||
// case 20:
|
||||
// _filamentController.clearAssets();
|
||||
// break;
|
||||
// case 21:
|
||||
// break;
|
||||
// case 22:
|
||||
// break;
|
||||
// case 23:
|
||||
// break;
|
||||
// case 24:
|
||||
// _filamentController.setRotation(_cube!, pi / 2, 0.0, 1.0, 0.0);
|
||||
// break;
|
||||
// case 25:
|
||||
// setState(() {
|
||||
// _vertical = !_vertical;
|
||||
// });
|
||||
// break;
|
||||
// case 26:
|
||||
// _filamentController.setCameraPosition(0, 0, 3);
|
||||
// _filamentController.setCameraRotation(0, 0, 1, 0);
|
||||
// break;
|
||||
// case 27:
|
||||
// _framerate = _framerate == 60 ? 30 : 60;
|
||||
// _filamentController.setFrameRate(_framerate);
|
||||
// break;
|
||||
// case 28:
|
||||
// _filamentController.setBackgroundImagePosition(25, 25);
|
||||
// break;
|
||||
// case 29:
|
||||
// _light = await _filamentController.addLight(
|
||||
// 1, 6500, 15000000, 0, 1, 0, 0, -1, 0, true);
|
||||
// break;
|
||||
// case 30:
|
||||
// if (_light != null) {
|
||||
// _filamentController.removeLight(_light!);
|
||||
// _light = null;
|
||||
// }
|
||||
// break;
|
||||
// case 31:
|
||||
// _filamentController.clearLights();
|
||||
// break;
|
||||
// case 32:
|
||||
|
||||
// // break;
|
||||
// break;
|
||||
// case 33:
|
||||
|
||||
// break;
|
||||
// case 34:
|
||||
// var duration =
|
||||
// await _filamentController.getAnimationDuration(_cube!, 0);
|
||||
// _filamentController.playAnimation(_cube!, 0,
|
||||
// loop: false, crossfade: 0.5);
|
||||
// await Future.delayed(
|
||||
// Duration(milliseconds: (duration * 1000.0).toInt()));
|
||||
// print("animation complete");
|
||||
// // showDialog(
|
||||
// // context: context,
|
||||
// // builder: (context) {
|
||||
// // return Container(
|
||||
// // width: 100,
|
||||
// // height: 100,
|
||||
// // color: Colors.white,
|
||||
// // child: "animation complete!");
|
||||
// // });
|
||||
// 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;
|
||||
@@ -6,7 +6,7 @@ description: Demonstrates how to use the polyvox_filament plugin.
|
||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
sdk: ">=2.12.0 <4.0.0"
|
||||
|
||||
# Dependencies specify other packages that your package needs in order to work.
|
||||
# To automatically upgrade your package dependencies to the latest versions
|
||||
|
||||
@@ -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<Int8>?, UnsafeMutableRawPointer?) -> ResourceBuffer = { uri, resourcesPtr in
|
||||
|
||||
|
||||
let instance:SwiftPolyvoxFilamentPlugin = Unmanaged<SwiftPolyvoxFilamentPlugin>.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<SwiftPolyvoxFilamentPlugin>.fromOpaque(resourcesPtr!).takeUnretainedValue()
|
||||
let instance:SwiftPolyvoxFilamentPlugin = Unmanaged<SwiftPolyvoxFilamentPlugin>.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<CVPixelBuffer>? {
|
||||
@@ -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,505 @@ 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<Int32>
|
||||
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)
|
||||
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 args = call.arguments as! Array<Int32>
|
||||
createPixelBuffer(width:Int(args[0]), height:Int(args[1]))
|
||||
createDisplayLink()
|
||||
result(self.flutterTextureId)
|
||||
case "resize":
|
||||
result(self.flutterTextureId);
|
||||
case "tick":
|
||||
self.registry.textureFrameAvailable(flutterTextureId!)
|
||||
result(true)
|
||||
if(viewer == nil) {
|
||||
print("Error: cannot resize before a viewer has been created")
|
||||
result(nil);
|
||||
}
|
||||
rendering = false
|
||||
destroy_swap_chain(viewer)
|
||||
let args = call.arguments as! [Any]
|
||||
resize(width:args[0] as! Int32, height:args[1] as! Int32)
|
||||
var pixelBufferTextureId = unsafeBitCast(pixelBuffer!, to: UnsafeRawPointer.self)
|
||||
create_swap_chain(viewer, pixelBufferTextureId, UInt32(args[0] as! Int64), UInt32(args[1] as! Int64))
|
||||
update_viewport_and_camera_projection(viewer, Int32(args[0] as! Int64), Int32(args[1] as! Int64), Float(args[2] as! Double))
|
||||
rendering = true
|
||||
print("Resized to \(args[0])x\(args[1])")
|
||||
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))
|
||||
update_viewport_and_camera_projection(viewer, Int32(args[0] as! Int64), Int32(args[1] as! Int64), 1.0)
|
||||
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 "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":
|
||||
let interval = call.arguments as! Double
|
||||
displayLink!.preferredFramesPerSecond = Int(1 / interval)
|
||||
print("Set preferred frames er second to \(displayLink!.preferredFramesPerSecond)")
|
||||
let fInterval = Float(interval)
|
||||
print("Set filament interval to \(fInterval)")
|
||||
set_frame_interval(viewer, fInterval)
|
||||
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 == 5,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let entityName = args[2] as? String,
|
||||
let morphData = args[3] as? [Double],
|
||||
let numMorphWeights = args[4] as? Int32 else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for setMorphTargetWeights", details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
set_morph_target_weights(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, entityName, morphData.map { Float($0) }, Int32(numMorphWeights))
|
||||
|
||||
result(true)
|
||||
|
||||
case "setMorphAnimation":
|
||||
guard let args = call.arguments as? [Any], args.count == 8,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let entityName = args[2] as? String,
|
||||
let morphData = args[3] as? [Double],
|
||||
let morphIndices = args[4] as? [Int32],
|
||||
let numMorphTargets = args[5] as? Int32,
|
||||
let numFrames = args[6] as? Int32,
|
||||
let frameLengthInMs = args[7] as? Double else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Incorrect arguments provided for setMorphAnimation", details: nil))
|
||||
return
|
||||
}
|
||||
let frameData = morphData.map { Float($0) }
|
||||
let am = unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self)
|
||||
|
||||
let success = set_morph_animation(
|
||||
am,
|
||||
asset,
|
||||
entityName,
|
||||
frameData,
|
||||
morphIndices,
|
||||
Int32(numMorphTargets),
|
||||
Int32(numFrames),
|
||||
Float(frameLengthInMs))
|
||||
result(success)
|
||||
case "setBoneAnimation":
|
||||
guard let args = call.arguments as? [Any], args.count == 9,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let frameData = args[2] as? [Float],
|
||||
let numFrames = args[3] as? Int,
|
||||
let numBones = args[4] as? Int,
|
||||
let boneNames = args[5] as? [String],
|
||||
let meshName = args[6] as? [String],
|
||||
let numMeshTargets = args[7] as? Int,
|
||||
let frameLengthInMs = args[8] as? Float else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for set_bone_animation", details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
// // Convert boneNames and meshName to C-style strings array.
|
||||
// var cBoneNames: [UnsafePointer<CChar>?] = boneNames.map { $0.cString(using: .utf8) }
|
||||
// var cMeshName: [UnsafePointer<CChar>?] = meshName.map { $0.cString(using: .utf8) }
|
||||
//
|
||||
// set_bone_animation(assetManager, asset, UnsafeMutablePointer(&frameData), numFrames, numBones, &cBoneNames, &cMeshName, numMeshTargets, frameLengthInMs)
|
||||
|
||||
// // Clean up after conversion
|
||||
// for cStr in cBoneNames { free(UnsafeMutablePointer(mutating: cStr)) }
|
||||
// for cStr in cMeshName { free(UnsafeMutablePointer(mutating: cStr)) }
|
||||
|
||||
result(true)
|
||||
|
||||
case "playAnimation":
|
||||
guard let args = call.arguments as? [Any], args.count == 7,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let index = args[2] as? Int,
|
||||
let loop = args[3] as? Bool,
|
||||
let reverse = args[4] as? Bool,
|
||||
let replaceActive = args[5] as? Bool,
|
||||
let crossfade = args[6] as? Double else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for play_animation", details: nil))
|
||||
return
|
||||
}
|
||||
play_animation(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, Int32(index), loop, reverse, replaceActive, Float(crossfade))
|
||||
result(true)
|
||||
case "getAnimationDuration":
|
||||
guard let args = call.arguments as? [Any], args.count == 3,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let animationIndex = args[2] as? Int else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for getAnimationDuration", details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
let dur = get_animation_duration(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, Int32(animationIndex))
|
||||
result(dur)
|
||||
|
||||
case "setAnimationFrame":
|
||||
guard let args = call.arguments as? [Any], args.count == 4,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let animationIndex = args[2] as? Int,
|
||||
let animationFrame = args[3] as? Int else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for set_animation_frame", details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
set_animation_frame(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, Int32(animationIndex), Int32(animationFrame))
|
||||
result(true)
|
||||
|
||||
case "stopAnimation":
|
||||
guard let args = call.arguments as? [Any], args.count == 3,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let index = args[2] as? Int else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for stop_animation", details: nil))
|
||||
return
|
||||
}
|
||||
stop_animation(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, Int32(index))
|
||||
result(true)
|
||||
case "getAnimationCount":
|
||||
guard let args = call.arguments as? [Any], args.count == 2,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for get_animation_count", details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
let count = get_animation_count(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset)
|
||||
result(count)
|
||||
case "getAnimationNames":
|
||||
guard let args = call.arguments as? [Any], args.count == 2,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for get_animation_name", details: nil))
|
||||
return
|
||||
}
|
||||
var names:[String] = [];
|
||||
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] = []
|
||||
if count > 0 {
|
||||
for i in 0...count - 1 {
|
||||
var buffer = [CChar](repeating: 0, count: 256) // Assuming max name length of 256 for simplicity
|
||||
get_morph_target_name(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName, &buffer, Int32(i))
|
||||
names.append(String(cString:buffer))
|
||||
}
|
||||
}
|
||||
result(names)
|
||||
case "getMorphTargetNameCount":
|
||||
guard let args = call.arguments as? [Any], args.count == 3,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let meshName = args[2] as? String else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for get_morph_target_name_count", details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
let count = get_morph_target_name_count(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName)
|
||||
result(count)
|
||||
|
||||
case "removeAsset":
|
||||
remove_asset(viewer, call.arguments as! EntityId)
|
||||
result(true)
|
||||
case "clearAssets":
|
||||
clear_assets(viewer)
|
||||
result(true)
|
||||
case "setCamera":
|
||||
guard let args = call.arguments as? [Any], args.count == 2,
|
||||
let asset = args[0] as? EntityId,
|
||||
let nodeName = args[1] as? String? else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected asset and nodeName for set_camera", details: nil))
|
||||
return
|
||||
}
|
||||
let success = set_camera(viewer, asset, nodeName)
|
||||
result(success)
|
||||
|
||||
case "setCameraPosition":
|
||||
let args = call.arguments as! [Any]
|
||||
set_camera_position(viewer, Float(args[0] as! Double), Float(args[1] as! Double), Float(args[2] as! Double))
|
||||
result(true)
|
||||
|
||||
case "setCameraRotation":
|
||||
let args = call.arguments as! [Any]
|
||||
set_camera_rotation(viewer, Float(args[0] as! Double), Float(args[1] as! Double), Float(args[2] as! Double), Float(args[3] as! Double))
|
||||
result(true)
|
||||
case "setCameraModelMatrix":
|
||||
guard let matrix = call.arguments as? [Float], matrix.count == 16 else { // Assuming a 4x4 matrix
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for set_camera_model_matrix", details: nil))
|
||||
return
|
||||
}
|
||||
set_camera_model_matrix(viewer, matrix)
|
||||
result(true)
|
||||
case "setCameraFocalLength":
|
||||
set_camera_focal_length(viewer, call.arguments as! Float)
|
||||
result(true)
|
||||
case "setCameraFocusDistance":
|
||||
set_camera_focus_distance(viewer, call.arguments as! Float)
|
||||
result(true)
|
||||
case "setMaterialColor":
|
||||
guard let args = call.arguments as? [Any], args.count == 5,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let meshName = args[2] as? String,
|
||||
let materialIndex = args[3] as? Int32,
|
||||
let color = args[4] as? [Double] else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for setMaterialColor", details: nil))
|
||||
return
|
||||
}
|
||||
set_material_color(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName, materialIndex, Float(color[0]), Float(color[1]), Float(color[2]), Float(color[3]))
|
||||
result(true)
|
||||
|
||||
case "hideMesh":
|
||||
guard let args = call.arguments as? [Any], args.count == 3,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let meshName = args[2] as? String else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for hide_mesh", details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
let status = hide_mesh(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName)
|
||||
result(status)
|
||||
|
||||
case "revealMesh":
|
||||
guard let args = call.arguments as? [Any], args.count == 3,
|
||||
let assetManager = args[0] as? Int64,
|
||||
let asset = args[1] as? EntityId,
|
||||
let meshName = args[2] as? String else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Expected correct arguments for reveal_mesh", details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
let status = reveal_mesh(unsafeBitCast(assetManager, to:UnsafeMutableRawPointer.self), asset, meshName)
|
||||
result(status)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace polyvox {
|
||||
|
||||
class AssetManager {
|
||||
public:
|
||||
AssetManager(ResourceLoaderWrapper* loader,
|
||||
AssetManager(const ResourceLoaderWrapper* const loader,
|
||||
NameComponentManager *ncm,
|
||||
Engine *engine,
|
||||
Scene *scene);
|
||||
@@ -28,6 +28,7 @@ namespace polyvox {
|
||||
void remove(EntityId entity);
|
||||
void destroyAll();
|
||||
unique_ptr<vector<string>> getAnimationNames(EntityId entity);
|
||||
float getAnimationDuration(EntityId entity, int animationIndex);
|
||||
unique_ptr<vector<string>> getMorphTargetNames(EntityId entity, const char *meshName);
|
||||
void transformToUnitCube(EntityId e);
|
||||
inline void updateTransform(EntityId e);
|
||||
@@ -39,15 +40,17 @@ namespace polyvox {
|
||||
const utils::Entity* getLightEntities(EntityId e) const noexcept;
|
||||
size_t getLightEntityCount(EntityId e) const noexcept;
|
||||
void updateAnimations();
|
||||
bool setMaterialColor(EntityId e, const char* meshName, int materialInstance, const float r, const float g, const float b, const float a);
|
||||
|
||||
|
||||
bool setMorphAnimationBuffer(
|
||||
EntityId entityId,
|
||||
const char* entityName,
|
||||
const float* const morphData,
|
||||
int numMorphWeights,
|
||||
const int* const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs);
|
||||
|
||||
void setMorphTargetWeights(EntityId entityId, const char* const entityName, const float* const weights, int count);
|
||||
|
||||
bool setBoneAnimationBuffer(
|
||||
@@ -59,7 +62,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, bool replaceActive, 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 +72,7 @@ namespace polyvox {
|
||||
|
||||
private:
|
||||
AssetLoader* _assetLoader = nullptr;
|
||||
ResourceLoaderWrapper* _resourceLoaderWrapper;
|
||||
const ResourceLoaderWrapper* const _resourceLoaderWrapper;
|
||||
NameComponentManager* _ncm = nullptr;
|
||||
Engine* _engine;
|
||||
Scene* _scene;
|
||||
@@ -77,6 +80,8 @@ namespace polyvox {
|
||||
MaterialProvider* _ubershaderProvider = nullptr;
|
||||
gltfio::ResourceLoader* _gltfResourceLoader = nullptr;
|
||||
gltfio::TextureProvider* _stbDecoder = nullptr;
|
||||
gltfio::TextureProvider* _ktxDecoder = nullptr;
|
||||
|
||||
vector<SceneAsset> _assets;
|
||||
tsl::robin_map<EntityId, int> _entityIdLookup;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,43 +3,38 @@
|
||||
|
||||
#include "ResourceBuffer.hpp"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
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,13 +49,13 @@ void set_morph_target_weights(
|
||||
const float *const morphData,
|
||||
int numWeights
|
||||
);
|
||||
|
||||
bool set_morph_animation(
|
||||
void* assetManager,
|
||||
EntityId asset,
|
||||
const char *const entityName,
|
||||
const float *const morphData,
|
||||
int numMorphWeights,
|
||||
const int* const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs);
|
||||
|
||||
@@ -76,29 +70,32 @@ 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, bool replaceActive, 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);
|
||||
float get_animation_duration(void* assetManager, EntityId asset, 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);
|
||||
bool set_material_color(void* assetManager, EntityId asset, const char* meshName, int materialIndex, const float r, const float g, const float b, const float a);
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -31,12 +31,17 @@ namespace polyvox {
|
||||
|
||||
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
|
||||
|
||||
enum AnimationType {
|
||||
MORPH, BONE, GLTF
|
||||
};
|
||||
|
||||
struct AnimationStatus {
|
||||
time_point_t mStart = time_point_t::max();
|
||||
bool mLoop = false;
|
||||
bool mReverse = false;
|
||||
float mDuration = 0;
|
||||
bool mAnimating = false;
|
||||
float mDuration = 0;
|
||||
AnimationType type;
|
||||
int gltfIndex = -1;
|
||||
};
|
||||
|
||||
//
|
||||
@@ -47,7 +52,7 @@ namespace polyvox {
|
||||
int mNumFrames = -1;
|
||||
float mFrameLengthInMs = 0;
|
||||
vector<float> mFrameData;
|
||||
int mNumMorphWeights = 0;
|
||||
vector<int> mMorphIndices;
|
||||
};
|
||||
|
||||
//
|
||||
@@ -73,10 +78,14 @@ 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 containing AnimationStatus structs for the morph, bone and/or glTF animations.
|
||||
vector<AnimationStatus> mAnimations;
|
||||
|
||||
// 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 +105,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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,8 @@ static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guarantee
|
||||
* Defines the backend's feature levels.
|
||||
*/
|
||||
enum class FeatureLevel : uint8_t {
|
||||
FEATURE_LEVEL_1 = 1, //!< OpenGL ES 3.0 features (default)
|
||||
FEATURE_LEVEL_0 = 0, //!< OpenGL ES 2.0 features
|
||||
FEATURE_LEVEL_1, //!< OpenGL ES 3.0 features (default)
|
||||
FEATURE_LEVEL_2, //!< OpenGL ES 3.1 features + 16 textures units + cubemap arrays
|
||||
FEATURE_LEVEL_3 //!< OpenGL ES 3.1 features + 31 textures units + cubemap arrays
|
||||
};
|
||||
@@ -279,6 +280,15 @@ enum class UniformType : uint8_t {
|
||||
STRUCT
|
||||
};
|
||||
|
||||
/**
|
||||
* Supported constant parameter types
|
||||
*/
|
||||
enum class ConstantType : uint8_t {
|
||||
INT,
|
||||
FLOAT,
|
||||
BOOL
|
||||
};
|
||||
|
||||
enum class Precision : uint8_t {
|
||||
LOW,
|
||||
MEDIUM,
|
||||
@@ -286,6 +296,14 @@ enum class Precision : uint8_t {
|
||||
DEFAULT
|
||||
};
|
||||
|
||||
/**
|
||||
* Shader compiler priority queue
|
||||
*/
|
||||
enum class CompilerPriorityQueue : uint8_t {
|
||||
HIGH,
|
||||
LOW
|
||||
};
|
||||
|
||||
//! Texture sampler type
|
||||
enum class SamplerType : uint8_t {
|
||||
SAMPLER_2D, //!< 2D texture
|
||||
@@ -1117,7 +1135,12 @@ enum class Workaround : uint16_t {
|
||||
// the whole render pass.
|
||||
ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP,
|
||||
// for some uniform arrays, it's needed to do an initialization to avoid crash on adreno gpu
|
||||
ADRENO_UNIFORM_ARRAY_CRASH
|
||||
ADRENO_UNIFORM_ARRAY_CRASH,
|
||||
// Workaround a Metal pipeline compilation error with the message:
|
||||
// "Could not statically determine the target of a texture". See light_indirect.fs
|
||||
A8X_STATIC_TEXTURE_TARGET_ERROR,
|
||||
// Adreno drivers sometimes aren't able to blit into a layer of a texture array.
|
||||
DISABLE_BLIT_INTO_TEXTURE_ARRAY,
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -39,7 +39,6 @@ struct HwRenderTarget;
|
||||
struct HwSamplerGroup;
|
||||
struct HwStream;
|
||||
struct HwSwapChain;
|
||||
struct HwSync;
|
||||
struct HwTexture;
|
||||
struct HwTimerQuery;
|
||||
struct HwVertexBuffer;
|
||||
@@ -126,7 +125,6 @@ using RenderTargetHandle = Handle<HwRenderTarget>;
|
||||
using SamplerGroupHandle = Handle<HwSamplerGroup>;
|
||||
using StreamHandle = Handle<HwStream>;
|
||||
using SwapChainHandle = Handle<HwSwapChain>;
|
||||
using SyncHandle = Handle<HwSync>;
|
||||
using TextureHandle = Handle<HwTexture>;
|
||||
using TimerQueryHandle = Handle<HwTimerQuery>;
|
||||
using VertexBufferHandle = Handle<HwVertexBuffer>;
|
||||
|
||||
@@ -279,8 +279,8 @@ public:
|
||||
break;
|
||||
}
|
||||
|
||||
size_t bpr = bpp * stride;
|
||||
size_t bprAligned = (bpr + (alignment - 1)) & (~alignment + 1);
|
||||
size_t const bpr = bpp * stride;
|
||||
size_t const bprAligned = (bpr + (alignment - 1)) & (~alignment + 1);
|
||||
return bprAligned * height;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Invocable.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
@@ -47,6 +48,8 @@ public:
|
||||
size_t handleArenaSize = 0;
|
||||
};
|
||||
|
||||
Platform() noexcept;
|
||||
|
||||
virtual ~Platform() noexcept;
|
||||
|
||||
/**
|
||||
@@ -79,6 +82,85 @@ public:
|
||||
* thread, or if the platform does not need to perform any special processing.
|
||||
*/
|
||||
virtual bool pumpEvents() noexcept;
|
||||
|
||||
/**
|
||||
* InsertBlobFunc is an Invocable to an application-provided function that a
|
||||
* backend implementation may use to insert a key/value pair into the
|
||||
* cache.
|
||||
*/
|
||||
using InsertBlobFunc = utils::Invocable<
|
||||
void(const void* key, size_t keySize, const void* value, size_t valueSize)>;
|
||||
|
||||
/*
|
||||
* RetrieveBlobFunc is an Invocable to an application-provided function that a
|
||||
* backend implementation may use to retrieve a cached value from the
|
||||
* cache.
|
||||
*/
|
||||
using RetrieveBlobFunc = utils::Invocable<
|
||||
size_t(const void* key, size_t keySize, void* value, size_t valueSize)>;
|
||||
|
||||
/**
|
||||
* Sets the callback functions that the backend can use to interact with caching functionality
|
||||
* provided by the application.
|
||||
*
|
||||
* Cache functions may only be specified once during the lifetime of a
|
||||
* Platform. The <insert> and <retrieve> Invocables may be called at any time and
|
||||
* from any thread from the time at which setBlobFunc is called until the time that Platform
|
||||
* is destroyed. Concurrent calls to these functions from different threads is also allowed.
|
||||
*
|
||||
* @param insertBlob an Invocable that inserts a new value into the cache and associates
|
||||
* it with the given key
|
||||
* @param retrieveBlob an Invocable that retrieves from the cache the value associated with a
|
||||
* given key
|
||||
*/
|
||||
void setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept;
|
||||
|
||||
/**
|
||||
* @return true if setBlobFunc was called.
|
||||
*/
|
||||
bool hasBlobFunc() const noexcept;
|
||||
|
||||
/**
|
||||
* To insert a new binary value into the cache and associate it with a given
|
||||
* key, the backend implementation can call the application-provided callback
|
||||
* function insertBlob.
|
||||
*
|
||||
* No guarantees are made as to whether a given key/value pair is present in
|
||||
* the cache after the set call. If a different value has been associated
|
||||
* with the given key in the past then it is undefined which value, if any, is
|
||||
* associated with the key after the set call. Note that while there are no
|
||||
* guarantees, the cache implementation should attempt to cache the most
|
||||
* recently set value for a given key.
|
||||
*
|
||||
* @param key pointer to the beginning of the key data that is to be inserted
|
||||
* @param keySize specifies the size in byte of the data pointed to by <key>
|
||||
* @param value pointer to the beginning of the value data that is to be inserted
|
||||
* @param valueSize specifies the size in byte of the data pointed to by <value>
|
||||
*/
|
||||
void insertBlob(const void* key, size_t keySize, const void* value, size_t valueSize);
|
||||
|
||||
/**
|
||||
* To retrieve the binary value associated with a given key from the cache, a
|
||||
* the backend implementation can call the application-provided callback
|
||||
* function retrieveBlob.
|
||||
*
|
||||
* If the cache contains a value for the given key and its size in bytes is
|
||||
* less than or equal to <valueSize> then the value is written to the memory
|
||||
* pointed to by <value>. Otherwise nothing is written to the memory pointed
|
||||
* to by <value>.
|
||||
*
|
||||
* @param key pointer to the beginning of the key
|
||||
* @param keySize specifies the size in bytes of the binary key pointed to by <key>
|
||||
* @param value pointer to a buffer to receive the cached binary data, if it exists
|
||||
* @param valueSize specifies the size in bytes of the memory pointed to by <value>
|
||||
* @return If the cache contains a value associated with the given key then the
|
||||
* size of that binary value in bytes is returned. Otherwise 0 is returned.
|
||||
*/
|
||||
size_t retrieveBlob(const void* key, size_t keySize, void* value, size_t valueSize);
|
||||
|
||||
private:
|
||||
InsertBlobFunc mInsertBlob;
|
||||
RetrieveBlobFunc mRetrieveBlob;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -48,7 +48,15 @@ public:
|
||||
ShaderStageFlags stageFlags = ShaderStageFlags::ALL_SHADER_STAGE_FLAGS;
|
||||
};
|
||||
|
||||
struct Uniform {
|
||||
utils::CString name; // full qualified name of the uniform field
|
||||
uint16_t offset; // offset in 'uint32_t' into the uniform buffer
|
||||
uint8_t size; // >1 for arrays
|
||||
UniformType type; // uniform type
|
||||
};
|
||||
|
||||
using UniformBlockInfo = std::array<utils::CString, UNIFORM_BINDING_COUNT>;
|
||||
using UniformInfo = utils::FixedCapacityVector<Uniform>;
|
||||
using SamplerGroupInfo = std::array<SamplerGroupData, SAMPLER_BINDING_COUNT>;
|
||||
using ShaderBlob = utils::FixedCapacityVector<uint8_t>;
|
||||
using ShaderSource = std::array<ShaderBlob, SHADER_TYPE_COUNT>;
|
||||
@@ -63,6 +71,8 @@ public:
|
||||
|
||||
~Program() noexcept;
|
||||
|
||||
Program& priorityQueue(CompilerPriorityQueue priorityQueue) noexcept;
|
||||
|
||||
// sets the material name and variant for diagnostic purposes only
|
||||
Program& diagnostics(utils::CString const& name,
|
||||
utils::Invocable<utils::io::ostream&(utils::io::ostream& out)>&& logger);
|
||||
@@ -78,6 +88,14 @@ public:
|
||||
Program& uniformBlockBindings(
|
||||
utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>> const& uniformBlockBindings) noexcept;
|
||||
|
||||
// Note: This is only needed for GLES2.0, this is used to emulate UBO. This function tells
|
||||
// the program everything it needs to know about the uniforms at a given binding
|
||||
Program& uniforms(uint32_t index, UniformInfo const& uniforms) noexcept;
|
||||
|
||||
// Note: This is only needed for GLES2.0.
|
||||
Program& attributes(
|
||||
utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>> attributes) noexcept;
|
||||
|
||||
// sets the 'bindingPoint' sampler group descriptor for this program.
|
||||
// 'samplers' can be destroyed after this call.
|
||||
// This effectively associates a set of (BindingPoints, index) to a texture unit in the shader.
|
||||
@@ -93,6 +111,7 @@ public:
|
||||
Program& specializationConstants(
|
||||
utils::FixedCapacityVector<SpecializationConstant> specConstants) noexcept;
|
||||
|
||||
Program& cacheId(uint64_t cacheId) noexcept;
|
||||
|
||||
ShaderSource const& getShadersSource() const noexcept { return mShadersSource; }
|
||||
ShaderSource& getShadersSource() noexcept { return mShadersSource; }
|
||||
@@ -103,6 +122,12 @@ public:
|
||||
SamplerGroupInfo const& getSamplerGroupInfo() const { return mSamplerGroups; }
|
||||
SamplerGroupInfo& getSamplerGroupInfo() { return mSamplerGroups; }
|
||||
|
||||
auto const& getBindingUniformInfo() const { return mBindingUniformInfo; }
|
||||
auto& getBindingUniformInfo() { return mBindingUniformInfo; }
|
||||
|
||||
auto const& getAttributes() const { return mAttributes; }
|
||||
auto& getAttributes() { return mAttributes; }
|
||||
|
||||
utils::CString const& getName() const noexcept { return mName; }
|
||||
utils::CString& getName() noexcept { return mName; }
|
||||
|
||||
@@ -113,6 +138,10 @@ public:
|
||||
return mSpecializationConstants;
|
||||
}
|
||||
|
||||
uint64_t getCacheId() const noexcept { return mCacheId; }
|
||||
|
||||
CompilerPriorityQueue getPriorityQueue() const noexcept { return mPriorityQueue; }
|
||||
|
||||
private:
|
||||
friend utils::io::ostream& operator<<(utils::io::ostream& out, const Program& builder);
|
||||
|
||||
@@ -120,8 +149,12 @@ private:
|
||||
SamplerGroupInfo mSamplerGroups = {};
|
||||
ShaderSource mShadersSource;
|
||||
utils::CString mName;
|
||||
uint64_t mCacheId{};
|
||||
utils::Invocable<utils::io::ostream&(utils::io::ostream& out)> mLogger;
|
||||
utils::FixedCapacityVector<SpecializationConstant> mSpecializationConstants;
|
||||
utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>> mAttributes;
|
||||
std::array<UniformInfo, Program::UNIFORM_BINDING_COUNT> mBindingUniformInfo;
|
||||
CompilerPriorityQueue mPriorityQueue = CompilerPriorityQueue::HIGH;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -95,6 +95,19 @@ public:
|
||||
*/
|
||||
virtual void destroySwapChain(SwapChain* swapChain) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the set of buffers that must be preserved up to the call to commit().
|
||||
* The default value is TargetBufferFlags::NONE.
|
||||
* The color buffer is always preserved, however ancillary buffers, such as the depth buffer
|
||||
* are generally discarded. The preserve flags can be used to make sure those ancillary
|
||||
* buffers are preserved until the call to commit.
|
||||
*
|
||||
* @param swapChain
|
||||
* @return buffer that must be preserved
|
||||
* @see commit()
|
||||
*/
|
||||
virtual TargetBufferFlags getPreservedFlags(SwapChain* swapChain) noexcept;
|
||||
|
||||
/**
|
||||
* Called by the driver to establish the default FBO. The default implementation returns 0.
|
||||
* @return a GLuint casted to a uint32_t that is an OpenGL framebuffer object.
|
||||
@@ -254,6 +267,27 @@ public:
|
||||
* @return Transformed image.
|
||||
*/
|
||||
virtual AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if additional OpenGL contexts can be created. Default: false.
|
||||
* @return true if additional OpenGL contexts can be created.
|
||||
* @see createContext
|
||||
*/
|
||||
virtual bool isExtraContextSupported() const noexcept;
|
||||
|
||||
/**
|
||||
* Creates an OpenGL context with the same configuration than the main context and makes it
|
||||
* current to the current thread. Must not be called from the main driver thread.
|
||||
* createContext() is only supported if isExtraContextSupported() returns true.
|
||||
* These additional contexts will be automatically terminated in terminate.
|
||||
*
|
||||
* @param shared whether the new context is shared with the main context.
|
||||
* @see isExtraContextSupported()
|
||||
* @see terminate()
|
||||
*/
|
||||
virtual void createContext(bool shared);
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -50,6 +50,9 @@ protected:
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// OpenGLPlatform Interface
|
||||
|
||||
bool isExtraContextSupported() const noexcept override;
|
||||
void createContext(bool shared) override;
|
||||
|
||||
void terminate() noexcept override;
|
||||
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
@@ -57,6 +60,10 @@ protected:
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void commit(SwapChain* swapChain) noexcept override;
|
||||
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
|
||||
void destroyExternalImage(ExternalTexture* texture) noexcept override;
|
||||
void retainExternalImage(void* externalImage) noexcept override;
|
||||
bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override;
|
||||
|
||||
private:
|
||||
PlatformCocoaGLImpl* pImpl = nullptr;
|
||||
|
||||
@@ -47,6 +47,9 @@ public:
|
||||
|
||||
uint32_t createDefaultRenderTarget() noexcept override;
|
||||
|
||||
bool isExtraContextSupported() const noexcept override;
|
||||
void createContext(bool shared) override;
|
||||
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
@@ -35,8 +38,31 @@ class PlatformEGL : public OpenGLPlatform {
|
||||
public:
|
||||
|
||||
PlatformEGL() noexcept;
|
||||
bool isExtraContextSupported() const noexcept override;
|
||||
void createContext(bool shared) override;
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Helper for EGL configs and attributes parameters
|
||||
|
||||
class Config {
|
||||
public:
|
||||
Config();
|
||||
Config(std::initializer_list<std::pair<EGLint, EGLint>> list);
|
||||
EGLint& operator[](EGLint name);
|
||||
EGLint operator[](EGLint name) const;
|
||||
void erase(EGLint name) noexcept;
|
||||
EGLint const* data() const noexcept {
|
||||
return reinterpret_cast<EGLint const*>(mConfig.data());
|
||||
}
|
||||
size_t size() const noexcept {
|
||||
return mConfig.size();
|
||||
}
|
||||
private:
|
||||
std::vector<std::pair<EGLint, EGLint>> mConfig = {{ EGL_NONE, EGL_NONE }};
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Platform Interface
|
||||
|
||||
@@ -79,6 +105,8 @@ protected:
|
||||
* @param name a string giving some context on the error. Typically __func__.
|
||||
*/
|
||||
static void logEglError(const char* name) noexcept;
|
||||
static void logEglError(const char* name, EGLint error) noexcept;
|
||||
static const char* getEglErrorName(EGLint error) noexcept;
|
||||
|
||||
/**
|
||||
* Calls glGetError() to clear the current error flags. logs a warning to log.w if
|
||||
@@ -98,6 +126,8 @@ protected:
|
||||
EGLSurface mCurrentReadSurface = EGL_NO_SURFACE;
|
||||
EGLSurface mEGLDummySurface = EGL_NO_SURFACE;
|
||||
EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR;
|
||||
Config mContextAttribs;
|
||||
std::vector<EGLContext> mAdditionalContexts;
|
||||
|
||||
// supported extensions detected at runtime
|
||||
struct {
|
||||
@@ -105,13 +135,16 @@ protected:
|
||||
bool OES_EGL_image_external_essl3 = false;
|
||||
} gl;
|
||||
struct {
|
||||
bool KHR_no_config_context = false;
|
||||
bool ANDROID_recordable = false;
|
||||
bool KHR_create_context = false;
|
||||
bool KHR_gl_colorspace = false;
|
||||
bool KHR_no_config_context = false;
|
||||
} egl;
|
||||
} ext;
|
||||
|
||||
private:
|
||||
void initializeGlExtensions() noexcept;
|
||||
|
||||
private:
|
||||
EGLConfig findSwapChainConfig(uint64_t flags) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
#include "utils/unwindows.h"
|
||||
|
||||
#include <backend/platforms/OpenGLPlatform.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
@@ -46,6 +47,9 @@ protected:
|
||||
|
||||
void terminate() noexcept override;
|
||||
|
||||
bool isExtraContextSupported() const noexcept override;
|
||||
void createContext(bool shared) override;
|
||||
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
@@ -57,6 +61,8 @@ protected:
|
||||
HWND mHWnd = NULL;
|
||||
HDC mWhdc = NULL;
|
||||
PIXELFORMATDESCRIPTOR mPfd = {};
|
||||
std::vector<HGLRC> mAdditionalContexts;
|
||||
std::vector<int> mAttribs;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -19,31 +19,220 @@
|
||||
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <bluevk/BlueVK.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/PrivateImplementation.h>
|
||||
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
using SwapChain = Platform::SwapChain;
|
||||
|
||||
/**
|
||||
* Private implementation details for the provided vulkan platform.
|
||||
*/
|
||||
struct VulkanPlatformPrivate;
|
||||
|
||||
/**
|
||||
* A Platform interface that creates a Vulkan backend.
|
||||
*/
|
||||
|
||||
class VulkanPlatform : public Platform {
|
||||
class VulkanPlatform : public Platform, utils::PrivateImplementation<VulkanPlatformPrivate> {
|
||||
public:
|
||||
struct SurfaceBundle {
|
||||
void* surface;
|
||||
// On certain platforms, the extent of the surface cannot be queried from Vulkan. In those
|
||||
// situations, we allow the frontend to pass in the extent to use in creating the swap
|
||||
// chains. Platform implementation should set extent to 0 if they do not expect to set the
|
||||
// swap chain extent.
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
|
||||
/**
|
||||
* A collection of handles to objects and metadata that comprises a Vulkan context. The client
|
||||
* can instantiate this struct and pass to Engine::Builder::sharedContext if they wishes to
|
||||
* share their vulkan context. This is specifically necessary if the client wishes to override
|
||||
* the swapchain API.
|
||||
*/
|
||||
struct VulkanSharedContext {
|
||||
VkInstance instance = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
VkDevice logicalDevice = VK_NULL_HANDLE;
|
||||
uint32_t graphicsQueueFamilyIndex = 0xFFFFFFFF;
|
||||
// In the usual case, the client needs to allocate at least one more graphics queue
|
||||
// for Filament, and this index is the param to pass into vkGetDeviceQueue. In the case
|
||||
// where the gpu only has one graphics queue. Then the client needs to ensure that no
|
||||
// concurrent access can occur.
|
||||
uint32_t graphicsQueueIndex = 0xFFFFFFFF;
|
||||
};
|
||||
|
||||
// Given a Vulkan instance and native window handle, creates the platform-specific surface.
|
||||
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, void* instance,
|
||||
uint64_t flags) noexcept = 0;
|
||||
/**
|
||||
* Shorthand for the pointer to the Platform SwapChain struct, we use it also as a handle (i.e.
|
||||
* identifier for the swapchain).
|
||||
*/
|
||||
using SwapChainPtr = Platform::SwapChain*;
|
||||
|
||||
~VulkanPlatform() override;
|
||||
/**
|
||||
* Collection of images, formats, and extent (width/height) that defines the swapchain.
|
||||
*/
|
||||
struct SwapChainBundle {
|
||||
utils::FixedCapacityVector<VkImage> colors;
|
||||
VkImage depth = VK_NULL_HANDLE;
|
||||
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
};
|
||||
|
||||
VulkanPlatform();
|
||||
|
||||
~VulkanPlatform() override;
|
||||
|
||||
Driver* createDriver(void* sharedContext,
|
||||
Platform::DriverConfig const& driverConfig) noexcept override;
|
||||
|
||||
int getOSVersion() const noexcept override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ---------- Platform Customization options ----------
|
||||
/**
|
||||
* The client preference can be stored within the struct. We allow for two specification of
|
||||
* preference:
|
||||
* 1) A substring to match against `VkPhysicalDeviceProperties.deviceName`.
|
||||
* 2) Index of the device in the list as returned by vkEnumeratePhysicalDevices.
|
||||
*/
|
||||
struct GPUPreference {
|
||||
std::string deviceName;
|
||||
int8_t index = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Client can provide a preference over the GPU to use in the vulkan instance
|
||||
* @return `GPUPreference` struct that indicates the client's preference
|
||||
*/
|
||||
virtual GPUPreference getPreferredGPU() noexcept {
|
||||
return {};
|
||||
}
|
||||
// -------- End platform customization options --------
|
||||
// ----------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns whether the platform supports sRGB swapchain. This is true by default, and the client
|
||||
* needs to override this method to specify otherwise.
|
||||
* @return Whether the platform supports sRGB swapchain.
|
||||
*/
|
||||
virtual bool isSRGBSwapChainSupported() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the images handles and format of the memory backing the swapchain. This should be called
|
||||
* after createSwapChain() or after recreateIfResized().
|
||||
* @param swapchain The handle returned by createSwapChain()
|
||||
* @return An array of VkImages
|
||||
*/
|
||||
virtual SwapChainBundle getSwapChainBundle(SwapChainPtr handle);
|
||||
|
||||
/**
|
||||
* Acquire the next image for rendering. The `index` will be written with an non-negative
|
||||
* integer that the backend can use to index into the `SwapChainBundle.colors` array. The
|
||||
* corresponding VkImage will be used as the output color attachment. The client should signal
|
||||
* the `clientSignal` semaphore when the image is ready to be used by the backend.
|
||||
* @param handle The handle returned by createSwapChain()
|
||||
* @param clientSignal The semaphore that the client will signal to indicate that the backend
|
||||
* may render into the image.
|
||||
* @param index Pointer to memory that will be filled with the index that corresponding
|
||||
* to an image in the `SwapChainBundle.colors` array.
|
||||
* @return Result of acquire
|
||||
*/
|
||||
virtual VkResult acquire(SwapChainPtr handle, VkSemaphore clientSignal, uint32_t* index);
|
||||
|
||||
/**
|
||||
* Present the image corresponding to `index` to the display. The client should wait on
|
||||
* `finishedDrawing` before presenting.
|
||||
* @param handle The handle returned by createSwapChain()
|
||||
* @param index Index that corresponding to an image in the
|
||||
* `SwapChainBundle.colors` array.
|
||||
* @param finishedDrawing Backend passes in a semaphore that the client will signal to
|
||||
* indicate that the client may render into the image.
|
||||
* @return Result of present
|
||||
*/
|
||||
virtual VkResult present(SwapChainPtr handle, uint32_t index, VkSemaphore finishedDrawing);
|
||||
|
||||
/**
|
||||
* Check if the surface size has changed.
|
||||
* @param handle The handle returned by createSwapChain()
|
||||
* @return Whether the swapchain has been resized
|
||||
*/
|
||||
virtual bool hasResized(SwapChainPtr handle);
|
||||
|
||||
/**
|
||||
* Carry out a recreation of the swapchain.
|
||||
* @param handle The handle returned by createSwapChain()
|
||||
* @return Result of the recreation
|
||||
*/
|
||||
virtual VkResult recreate(SwapChainPtr handle);
|
||||
|
||||
/**
|
||||
* Create a swapchain given a platform window, or if given a null `nativeWindow`, then we
|
||||
* try to create a headless swapchain with the given `extent`.
|
||||
* @param flags Optional parameters passed to the client as defined in
|
||||
* Filament::SwapChain.h.
|
||||
* @param extent Optional width and height that indicates the size of the headless swapchain.
|
||||
* @return Result of the operation
|
||||
*/
|
||||
virtual SwapChainPtr createSwapChain(void* nativeWindow, uint64_t flags = 0,
|
||||
VkExtent2D extent = {0, 0});
|
||||
|
||||
/**
|
||||
* Destroy the swapchain.
|
||||
* @param handle The handle returned by createSwapChain()
|
||||
*/
|
||||
virtual void destroy(SwapChainPtr handle);
|
||||
|
||||
/**
|
||||
* Clean up any resources owned by the Platform. For example, if the Vulkan instance handle was
|
||||
* generated by the platform, we need to clean it up in this method.
|
||||
*/
|
||||
virtual void terminate();
|
||||
|
||||
/**
|
||||
* @return The instance (VkInstance) for the Vulkan backend.
|
||||
*/
|
||||
VkInstance getInstance() const noexcept;
|
||||
|
||||
/**
|
||||
* @return The logical device (VkDevice) that was selected as the backend device.
|
||||
*/
|
||||
VkDevice getDevice() const noexcept;
|
||||
|
||||
/**
|
||||
* @return The physical device (i.e gpu) that was selected as the backend physical device.
|
||||
*/
|
||||
VkPhysicalDevice getPhysicalDevice() const noexcept;
|
||||
|
||||
/**
|
||||
* @return The family index of the graphics queue selected for the Vulkan backend.
|
||||
*/
|
||||
uint32_t getGraphicsQueueFamilyIndex() const noexcept;
|
||||
|
||||
/**
|
||||
* @return The index of the graphics queue (if there are multiple graphics queues)
|
||||
* selected for the Vulkan backend.
|
||||
*/
|
||||
uint32_t getGraphicsQueueIndex() const noexcept;
|
||||
|
||||
/**
|
||||
* @return The queue that was selected for the Vulkan backend.
|
||||
*/
|
||||
VkQueue getGraphicsQueue() const noexcept;
|
||||
|
||||
private:
|
||||
// Platform dependent helper methods
|
||||
using ExtensionSet = std::unordered_set<std::string_view>;
|
||||
static ExtensionSet getRequiredInstanceExtensions();
|
||||
|
||||
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
|
||||
static SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
|
||||
uint64_t flags) noexcept;
|
||||
|
||||
friend struct VulkanPlatformPrivate;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
}// namespace filament::backend
|
||||
|
||||
#endif //TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H
|
||||
#endif// TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H
|
||||
|
||||
@@ -34,6 +34,7 @@ using ParameterPrecision = MaterialBuilder::ParameterPrecision;
|
||||
using OutputTarget = MaterialBuilder::OutputTarget;
|
||||
using OutputQualifier = MaterialBuilder::VariableQualifier;
|
||||
using OutputType = MaterialBuilder::OutputType;
|
||||
using ConstantType = MaterialBuilder::ConstantType;
|
||||
|
||||
// Convenience methods to convert std::string to Enum and also iterate over Enum values.
|
||||
class Enums {
|
||||
@@ -77,6 +78,7 @@ private:
|
||||
static std::unordered_map<std::string, OutputTarget> mStringToOutputTarget;
|
||||
static std::unordered_map<std::string, OutputQualifier> mStringToOutputQualifier;
|
||||
static std::unordered_map<std::string, OutputType> mStringToOutputType;
|
||||
static std::unordered_map<std::string, ConstantType> mStringToConstantType;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -141,13 +142,6 @@ protected:
|
||||
TargetLanguage targetLanguage;
|
||||
};
|
||||
std::vector<CodeGenParams> mCodeGenPermutations;
|
||||
// For finding properties and running semantic analysis, we always use the same code gen
|
||||
// permutation. This is the first permutation generated with default arguments passed to matc.
|
||||
static constexpr const CodeGenParams mSemanticCodeGenParams = {
|
||||
.shaderModel = ShaderModel::MOBILE,
|
||||
.targetApi = TargetApi::OPENGL,
|
||||
.targetLanguage = TargetLanguage::SPIRV
|
||||
};
|
||||
|
||||
// Keeps track of how many times MaterialBuilder::init() has been called without a call to
|
||||
// MaterialBuilder::shutdown(). Internally, glslang does something similar. We keep track for
|
||||
@@ -237,11 +231,14 @@ public:
|
||||
using TransparencyMode = filament::TransparencyMode;
|
||||
using SpecularAmbientOcclusion = filament::SpecularAmbientOcclusion;
|
||||
|
||||
using AttributeType = filament::backend::UniformType;
|
||||
using UniformType = filament::backend::UniformType;
|
||||
using ConstantType = filament::backend::ConstantType;
|
||||
using SamplerType = filament::backend::SamplerType;
|
||||
using SubpassType = filament::backend::SubpassType;
|
||||
using SamplerFormat = filament::backend::SamplerFormat;
|
||||
using ParameterPrecision = filament::backend::Precision;
|
||||
using Precision = filament::backend::Precision;
|
||||
using CullingMode = filament::backend::CullingMode;
|
||||
using FeatureLevel = filament::backend::FeatureLevel;
|
||||
|
||||
@@ -270,6 +267,9 @@ public:
|
||||
};
|
||||
using PreprocessorDefineList = std::vector<PreprocessorDefine>;
|
||||
|
||||
|
||||
MaterialBuilder& noSamplerValidation(bool enabled) noexcept;
|
||||
|
||||
//! Set the name of this material.
|
||||
MaterialBuilder& name(const char* name) noexcept;
|
||||
|
||||
@@ -290,6 +290,15 @@ public:
|
||||
MaterialBuilder& parameter(const char* name, size_t size, UniformType type,
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT) noexcept;
|
||||
|
||||
//! Add a constant parameter to this material.
|
||||
template<typename T>
|
||||
using is_supported_constant_parameter_t = typename std::enable_if<
|
||||
std::is_same<int32_t, T>::value ||
|
||||
std::is_same<float, T>::value ||
|
||||
std::is_same<bool, T>::value>::type;
|
||||
template<typename T, typename = is_supported_constant_parameter_t<T>>
|
||||
MaterialBuilder& constant(const char *name, ConstantType type, T defaultValue = 0);
|
||||
|
||||
/**
|
||||
* Add a sampler parameter to this material.
|
||||
*
|
||||
@@ -390,7 +399,10 @@ public:
|
||||
|
||||
MaterialBuilder& featureLevel(FeatureLevel featureLevel) noexcept;
|
||||
|
||||
//! Set the blending mode for this material.
|
||||
/**
|
||||
* Set the blending mode for this material. When set to MASKED, alpha to coverage is turned on.
|
||||
* You can override this behavior using alphaToCoverage(false).
|
||||
*/
|
||||
MaterialBuilder& blending(BlendingMode blending) noexcept;
|
||||
|
||||
/**
|
||||
@@ -436,6 +448,14 @@ public:
|
||||
*/
|
||||
MaterialBuilder& maskThreshold(float threshold) noexcept;
|
||||
|
||||
/**
|
||||
* Enables or disables alpha-to-coverage. When enabled, the coverage of a fragment is based
|
||||
* on its alpha value. This parameter is only useful when MSAA is in use. Alpha to coverage
|
||||
* is enabled automatically when the blend mode is set to MASKED; this behavior can be
|
||||
* overridden by calling alphaToCoverage(false).
|
||||
*/
|
||||
MaterialBuilder& alphaToCoverage(bool enable) noexcept;
|
||||
|
||||
//! The material output is multiplied by the shadowing factor (UNLIT model only).
|
||||
MaterialBuilder& shadowMultiplier(bool shadowMultiplier) noexcept;
|
||||
|
||||
@@ -556,7 +576,7 @@ public:
|
||||
MaterialBuilder& shaderDefine(const char* name, const char* value) noexcept;
|
||||
|
||||
//! Add a new fragment shader output variable. Only valid for materials in the POST_PROCESS domain.
|
||||
MaterialBuilder& output(VariableQualifier qualifier, OutputTarget target,
|
||||
MaterialBuilder& output(VariableQualifier qualifier, OutputTarget target, Precision precision,
|
||||
OutputType type, const char* name, int location = -1) noexcept;
|
||||
|
||||
MaterialBuilder& enableFramebufferFetch() noexcept;
|
||||
@@ -630,17 +650,28 @@ public:
|
||||
struct Output {
|
||||
Output() noexcept = default;
|
||||
Output(const char* outputName, VariableQualifier qualifier, OutputTarget target,
|
||||
OutputType type, int location) noexcept
|
||||
: name(outputName), qualifier(qualifier), target(target), type(type),
|
||||
location(location) { }
|
||||
Precision precision, OutputType type, int location) noexcept
|
||||
: name(outputName), qualifier(qualifier), target(target), precision(precision),
|
||||
type(type), location(location) { }
|
||||
|
||||
utils::CString name;
|
||||
VariableQualifier qualifier;
|
||||
OutputTarget target;
|
||||
Precision precision;
|
||||
OutputType type;
|
||||
int location;
|
||||
};
|
||||
|
||||
struct Constant {
|
||||
utils::CString name;
|
||||
ConstantType type;
|
||||
union {
|
||||
int32_t i;
|
||||
float f;
|
||||
bool b;
|
||||
} defaultValue;
|
||||
};
|
||||
|
||||
static constexpr size_t MATERIAL_PROPERTIES_COUNT = filament::MATERIAL_PROPERTIES_COUNT;
|
||||
using Property = filament::Property;
|
||||
|
||||
@@ -668,6 +699,7 @@ public:
|
||||
using ParameterList = Parameter[MAX_PARAMETERS_COUNT];
|
||||
using SubpassList = Parameter[MAX_SUBPASS_COUNT];
|
||||
using BufferList = std::vector<std::unique_ptr<filament::BufferInterfaceBlock>>;
|
||||
using ConstantList = std::vector<Constant>;
|
||||
|
||||
// returns the number of parameters declared in this material
|
||||
uint8_t getParameterCount() const noexcept { return mParameterCount; }
|
||||
@@ -683,22 +715,47 @@ public:
|
||||
|
||||
filament::UserVariantFilterMask getVariantFilter() const { return mVariantFilter; }
|
||||
|
||||
FeatureLevel getFeatureLevel() const noexcept { return mFeatureLevel; }
|
||||
/// @endcond
|
||||
|
||||
struct Attribute {
|
||||
std::string_view name;
|
||||
AttributeType type;
|
||||
MaterialBuilder::VertexAttribute location;
|
||||
std::string getAttributeName() const noexcept {
|
||||
return "mesh_" + std::string{ name };
|
||||
}
|
||||
std::string getDefineName() const noexcept {
|
||||
std::string uppercase{ name };
|
||||
transform(uppercase.cbegin(), uppercase.cend(), uppercase.begin(), ::toupper);
|
||||
return "HAS_ATTRIBUTE_" + uppercase;
|
||||
}
|
||||
};
|
||||
|
||||
using AttributeDatabase = std::array<Attribute, filament::backend::MAX_VERTEX_ATTRIBUTE_COUNT>;
|
||||
|
||||
static inline AttributeDatabase const& getAttributeDatabase() noexcept {
|
||||
return sAttributeDatabase;
|
||||
}
|
||||
|
||||
private:
|
||||
static const AttributeDatabase sAttributeDatabase;
|
||||
|
||||
void prepareToBuild(MaterialInfo& info) noexcept;
|
||||
|
||||
// Return true if the shader is syntactically and semantically valid.
|
||||
// This method finds all the properties defined in the fragment and
|
||||
// vertex shaders of the material.
|
||||
bool findAllProperties() noexcept;
|
||||
bool findAllProperties(CodeGenParams const& semanticCodeGenParams) noexcept;
|
||||
|
||||
// Multiple calls to findProperties accumulate the property sets across fragment
|
||||
// and vertex shaders in mProperties.
|
||||
bool findProperties(filament::backend::ShaderStage type,
|
||||
MaterialBuilder::PropertyList& p) noexcept;
|
||||
MaterialBuilder::PropertyList& allProperties,
|
||||
CodeGenParams const& semanticCodeGenParams) noexcept;
|
||||
|
||||
bool runSemanticAnalysis(MaterialInfo const& info) noexcept;
|
||||
bool runSemanticAnalysis(MaterialInfo const& info,
|
||||
CodeGenParams const& semanticCodeGenParams) noexcept;
|
||||
|
||||
bool checkLiteRequirements() noexcept;
|
||||
|
||||
@@ -751,6 +808,7 @@ private:
|
||||
|
||||
PropertyList mProperties;
|
||||
ParameterList mParameters;
|
||||
ConstantList mConstants;
|
||||
SubpassList mSubpasses;
|
||||
VariableList mVariables;
|
||||
OutputList mOutputs;
|
||||
@@ -791,6 +849,8 @@ private:
|
||||
bool mInstanced = false;
|
||||
bool mDepthWrite = true;
|
||||
bool mDepthWriteSet = false;
|
||||
bool mAlphaToCoverage = false;
|
||||
bool mAlphaToCoverageSet = false;
|
||||
|
||||
bool mSpecularAntiAliasing = false;
|
||||
bool mClearCoatIorChange = true;
|
||||
@@ -814,6 +874,8 @@ private:
|
||||
PreprocessorDefineList mDefines;
|
||||
|
||||
filament::UserVariantFilterMask mVariantFilter = {};
|
||||
|
||||
bool mNoSamplerValidation = false;
|
||||
};
|
||||
|
||||
} // namespace filamat
|
||||
|
||||
@@ -58,6 +58,10 @@ class Texture;
|
||||
class UTILS_PUBLIC IBLPrefilterContext {
|
||||
public:
|
||||
|
||||
enum class Kernel : uint8_t {
|
||||
D_GGX, // Trowbridge-reitz distribution
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an IBLPrefilter context.
|
||||
* @param engine filament engine to use
|
||||
@@ -109,7 +113,7 @@ public:
|
||||
* - Must be allocated with all mip levels.
|
||||
* - Must be SAMPLEABLE
|
||||
* @param outCubemap Output cubemap. If null the texture is automatically created
|
||||
* with default parameters (size of 256 with 5 levels).
|
||||
* with default parameters (size of 256 with 9 levels).
|
||||
* - Must be a cubemap
|
||||
* - Must have SAMPLEABLE and COLOR_ATTACHMENT usage bits
|
||||
* @return returns outCubemap
|
||||
@@ -123,6 +127,100 @@ public:
|
||||
filament::Material* mEquirectMaterial = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* IrradianceFilter is a GPU based implementation of the diffuse probe pre-integration filter.
|
||||
* An instance of IrradianceFilter is needed per filter configuration. A filter configuration
|
||||
* contains the filter's kernel and sample count.
|
||||
*/
|
||||
class IrradianceFilter {
|
||||
public:
|
||||
using Kernel = Kernel;
|
||||
|
||||
/**
|
||||
* Filter configuration.
|
||||
*/
|
||||
struct Config {
|
||||
uint16_t sampleCount = 1024u; //!< filter sample count (max 2048)
|
||||
Kernel kernel = Kernel::D_GGX; //!< filter kernel
|
||||
};
|
||||
|
||||
/**
|
||||
* Filtering options for the current environment.
|
||||
*/
|
||||
struct Options {
|
||||
float hdrLinear = 1024.0f; //!< no HDR compression up to this value
|
||||
float hdrMax = 16384.0f; //!< HDR compression between hdrLinear and hdrMax
|
||||
float lodOffset = 2.0f; //!< Good values are 2.0 or 3.0. Higher values help with heavily HDR inputs.
|
||||
bool generateMipmap = true; //!< set to false if the input environment map already has mipmaps
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a IrradianceFilter processor.
|
||||
* @param context IBLPrefilterContext to use
|
||||
* @param config Configuration of the filter
|
||||
*/
|
||||
IrradianceFilter(IBLPrefilterContext& context, Config config);
|
||||
|
||||
/**
|
||||
* Creates a filter with the default configuration.
|
||||
* @param context IBLPrefilterContext to use
|
||||
*/
|
||||
explicit IrradianceFilter(IBLPrefilterContext& context);
|
||||
|
||||
/**
|
||||
* Destroys all GPU resources created during initialization.
|
||||
*/
|
||||
~IrradianceFilter() noexcept;
|
||||
|
||||
IrradianceFilter(IrradianceFilter const&) = delete;
|
||||
IrradianceFilter& operator=(IrradianceFilter const&) = delete;
|
||||
IrradianceFilter(IrradianceFilter&& rhs) noexcept;
|
||||
IrradianceFilter& operator=(IrradianceFilter&& rhs) noexcept;
|
||||
|
||||
/**
|
||||
* Generates an irradiance cubemap. Mipmaps are not generated even if present.
|
||||
* @param options Options for this environment
|
||||
* @param environmentCubemap Environment cubemap (input). Can't be null.
|
||||
* This cubemap must be SAMPLEABLE and must have all its
|
||||
* levels allocated. If Options.generateMipmap is true,
|
||||
* the mipmap levels will be overwritten, otherwise
|
||||
* it is assumed that all levels are correctly initialized.
|
||||
* @param outIrradianceTexture Output irradiance texture or, if null, it is
|
||||
* automatically created with some default parameters.
|
||||
* outIrradianceTexture must be a cubemap, it must have
|
||||
* at least COLOR_ATTACHMENT and SAMPLEABLE usages.
|
||||
*
|
||||
* @return returns outIrradianceTexture
|
||||
*/
|
||||
filament::Texture* operator()(Options options,
|
||||
filament::Texture const* environmentCubemap,
|
||||
filament::Texture* outIrradianceTexture = nullptr);
|
||||
|
||||
/**
|
||||
* Generates a prefiltered cubemap.
|
||||
* @param environmentCubemap Environment cubemap (input). Can't be null.
|
||||
* This cubemap must be SAMPLEABLE and must have all its
|
||||
* levels allocated. If Options.generateMipmap is true,
|
||||
* the mipmap levels will be overwritten, otherwise
|
||||
* it is assumed that all levels are correctly initialized.
|
||||
* @param outIrradianceTexture Output irradiance texture or, if null, it is
|
||||
* automatically created with some default parameters.
|
||||
* outIrradianceTexture must be a cubemap, it must have
|
||||
* at least COLOR_ATTACHMENT and SAMPLEABLE usages.
|
||||
*
|
||||
* @return returns outReflectionsTexture
|
||||
*/
|
||||
filament::Texture* operator()(
|
||||
filament::Texture const* environmentCubemap,
|
||||
filament::Texture* outIrradianceTexture = nullptr);
|
||||
|
||||
private:
|
||||
filament::Texture* createIrradianceTexture();
|
||||
IBLPrefilterContext& mContext;
|
||||
filament::Material* mKernelMaterial = nullptr;
|
||||
filament::Texture* mKernelTexture = nullptr;
|
||||
uint32_t mSampleCount = 0u;
|
||||
};
|
||||
|
||||
/**
|
||||
* SpecularFilter is a GPU based implementation of the specular probe pre-integration filter.
|
||||
@@ -131,9 +229,7 @@ public:
|
||||
*/
|
||||
class SpecularFilter {
|
||||
public:
|
||||
enum class Kernel : uint8_t {
|
||||
D_GGX, // Trowbridge-reitz distribution
|
||||
};
|
||||
using Kernel = Kernel;
|
||||
|
||||
/**
|
||||
* Filter configuration.
|
||||
@@ -151,7 +247,7 @@ public:
|
||||
float hdrLinear = 1024.0f; //!< no HDR compression up to this value
|
||||
float hdrMax = 16384.0f; //!< HDR compression between hdrLinear and hdrMax
|
||||
float lodOffset = 1.0f; //!< Good values are 1.0 or 2.0. Higher values help with heavily HDR inputs.
|
||||
bool generateMipmap = true; //!< set to false if the environment map already has mipmaps
|
||||
bool generateMipmap = true; //!< set to false if the input environment map already has mipmaps
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -237,6 +333,7 @@ private:
|
||||
utils::Entity mCameraEntity{};
|
||||
filament::View* mView{};
|
||||
filament::Material* mIntegrationMaterial{};
|
||||
filament::Material* mIrradianceIntegrationMaterial{};
|
||||
};
|
||||
|
||||
#endif //TNT_IBL_PREFILTER_IBLPREFILTER_H
|
||||
|
||||
@@ -104,22 +104,24 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounding box of a box transformed by a rigid transform
|
||||
* Transform a Box by a linear transform and a translation.
|
||||
*
|
||||
* @param m a 3x3 matrix, the linear transform
|
||||
* @param t a float3, the translation
|
||||
* @param box the box to transform
|
||||
* @param m a 4x4 matrix that must be a rigid transform
|
||||
* @return the bounding box of the transformed box.
|
||||
* Result is undefined if \p m is not a rigid transform
|
||||
* @return the bounding box of the transformed box
|
||||
*/
|
||||
friend Box rigidTransform(Box const& box, const math::mat4f& m) noexcept;
|
||||
static Box transform(const math::mat3f& m, math::float3 const& t, const Box& box) noexcept {
|
||||
return { m * box.center + t, abs(m) * box.halfExtent };
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounding box of a box transformed by a rigid transform
|
||||
* @param box the box to transform
|
||||
* @param m a 3x3 matrix that must be a rigid transform
|
||||
* @return the bounding box of the transformed box.
|
||||
* Result is undefined if \p m is not a rigid transform
|
||||
* @deprecated Use transform() instead
|
||||
* @see transform()
|
||||
*/
|
||||
friend Box rigidTransform(Box const& box, const math::mat3f& m) noexcept;
|
||||
friend Box rigidTransform(Box const& box, const math::mat4f& m) noexcept {
|
||||
return transform(m.upperLeft(), m[3].xyz, box);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -174,7 +176,18 @@ struct UTILS_PUBLIC Aabb {
|
||||
/**
|
||||
* Returns the 8 corner vertices of the AABB.
|
||||
*/
|
||||
Corners getCorners() const;
|
||||
Corners getCorners() const {
|
||||
return Aabb::Corners{ .vertices = {
|
||||
{ min.x, min.y, min.z },
|
||||
{ max.x, min.y, min.z },
|
||||
{ min.x, max.y, min.z },
|
||||
{ max.x, max.y, min.z },
|
||||
{ min.x, min.y, max.z },
|
||||
{ max.x, min.y, max.z },
|
||||
{ min.x, max.y, max.z },
|
||||
{ max.x, max.y, max.z },
|
||||
}};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the box contains a given point.
|
||||
@@ -182,15 +195,44 @@ struct UTILS_PUBLIC Aabb {
|
||||
* @param p the point to test
|
||||
* @return the maximum signed distance to the box. Negative if p is in the box
|
||||
*/
|
||||
float contains(math::float3 p) const noexcept;
|
||||
float contains(math::float3 p) const noexcept {
|
||||
float d = min.x - p.x;
|
||||
d = std::max(d, min.y - p.y);
|
||||
d = std::max(d, min.z - p.z);
|
||||
d = std::max(d, p.x - max.x);
|
||||
d = std::max(d, p.y - max.y);
|
||||
d = std::max(d, p.z - max.z);
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an affine transformation to the AABB.
|
||||
*
|
||||
* @param m the 4x4 transformation to apply
|
||||
* @param m the 3x3 transformation to apply
|
||||
* @param t the translation
|
||||
* @return the transformed box
|
||||
*/
|
||||
Aabb transform(const math::mat4f& m) const noexcept;
|
||||
static Aabb transform(const math::mat3f& m, math::float3 const& t, const Aabb& box) noexcept {
|
||||
// Fast AABB transformation per Jim Arvo in Graphics Gems (1990).
|
||||
Aabb result{ t, t };
|
||||
for (size_t col = 0; col < 3; ++col) {
|
||||
for (size_t row = 0; row < 3; ++row) {
|
||||
const float a = m[col][row] * box.min[col];
|
||||
const float b = m[col][row] * box.max[col];
|
||||
result.min[row] += a < b ? a : b;
|
||||
result.max[row] += a < b ? b : a;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use transform() instead
|
||||
* @see transform()
|
||||
*/
|
||||
Aabb transform(const math::mat4f& m) const noexcept {
|
||||
return transform(m.upperLeft(), m[3].xyz, *this);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -191,7 +191,7 @@ private:
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* // Declares a "linear sRGB" color space.
|
||||
* ColorSpace myColorSpace = Rec709-Linear-sRGB;
|
||||
* ColorSpace myColorSpace = Rec709-Linear-D65;
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
class PartialColorSpace {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_ENGINE_H
|
||||
#define TNT_FILAMENT_ENGINE_H
|
||||
|
||||
#include <filament/FilamentAPI.h>
|
||||
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
@@ -49,6 +51,7 @@ class SwapChain;
|
||||
class Texture;
|
||||
class VertexBuffer;
|
||||
class View;
|
||||
class InstanceBuffer;
|
||||
|
||||
class LightManager;
|
||||
class RenderableManager;
|
||||
@@ -164,6 +167,7 @@ class TransformManager;
|
||||
* @see Renderer
|
||||
*/
|
||||
class UTILS_PUBLIC Engine {
|
||||
struct BuilderDetails;
|
||||
public:
|
||||
using Platform = backend::Platform;
|
||||
using Backend = backend::Backend;
|
||||
@@ -265,96 +269,124 @@ public:
|
||||
uint32_t perFrameCommandsSizeMB = FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB;
|
||||
};
|
||||
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
using CreateCallback = void(void* user, void* token);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates an instance of Engine
|
||||
*
|
||||
* @param backend Which driver backend to use.
|
||||
*
|
||||
* @param platform A pointer to an object that implements Platform. If this is
|
||||
* provided, then this object is used to create the hardware context
|
||||
* and expose platform features to it.
|
||||
*
|
||||
* If not provided (or nullptr is used), an appropriate Platform
|
||||
* is created automatically.
|
||||
*
|
||||
* All methods of this interface are called from filament's
|
||||
* render thread, which is different from the main thread.
|
||||
*
|
||||
* The lifetime of \p platform must exceed the lifetime of
|
||||
* the Engine object.
|
||||
*
|
||||
* @param sharedGLContext A platform-dependant OpenGL context used as a shared context
|
||||
* when creating filament's internal context.
|
||||
* Setting this parameter will force filament to use the OpenGL
|
||||
* implementation (instead of Vulkan for instance).
|
||||
*
|
||||
* @param config A pointer to optional parameters to specify memory size
|
||||
* configuration options. If nullptr, then defaults used.
|
||||
*
|
||||
* @return A pointer to the newly created Engine, or nullptr if the Engine couldn't be created.
|
||||
*
|
||||
* nullptr if the GPU driver couldn't be initialized, for instance if it doesn't
|
||||
* support the right version of OpenGL or OpenGL ES.
|
||||
*
|
||||
* @exception utils::PostConditionPanic can be thrown if there isn't enough memory to
|
||||
* allocate the command buffer. If exceptions are disabled, this condition if fatal and
|
||||
* this function will abort.
|
||||
*
|
||||
* \remark
|
||||
* This method is thread-safe.
|
||||
* Engine::Builder is used to create a new filament Engine.
|
||||
*/
|
||||
static Engine* create(Backend backend = Backend::DEFAULT,
|
||||
Platform* platform = nullptr, void* sharedGLContext = nullptr,
|
||||
const Config* config = nullptr);
|
||||
class Builder : public BuilderBase<BuilderDetails> {
|
||||
friend struct BuilderDetails;
|
||||
friend class FEngine;
|
||||
public:
|
||||
Builder() noexcept;
|
||||
Builder(Builder const& rhs) noexcept;
|
||||
Builder(Builder&& rhs) noexcept;
|
||||
~Builder() noexcept;
|
||||
Builder& operator=(Builder const& rhs) noexcept;
|
||||
Builder& operator=(Builder&& rhs) noexcept;
|
||||
|
||||
/**
|
||||
* @param backend Which driver backend to use
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& backend(Backend backend) noexcept;
|
||||
|
||||
/**
|
||||
* @param platform A pointer to an object that implements Platform. If this is
|
||||
* provided, then this object is used to create the hardware context
|
||||
* and expose platform features to it.
|
||||
*
|
||||
* If not provided (or nullptr is used), an appropriate Platform
|
||||
* is created automatically.
|
||||
*
|
||||
* All methods of this interface are called from filament's
|
||||
* render thread, which is different from the main thread.
|
||||
*
|
||||
* The lifetime of \p platform must exceed the lifetime of
|
||||
* the Engine object.
|
||||
*
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& platform(Platform* platform) noexcept;
|
||||
|
||||
/**
|
||||
* @param config A pointer to optional parameters to specify memory size
|
||||
* configuration options. If nullptr, then defaults used.
|
||||
*
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& config(const Config* config) noexcept;
|
||||
|
||||
/**
|
||||
* @param sharedContext A platform-dependant context used as a shared context
|
||||
* when creating filament's internal context.
|
||||
*
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& sharedContext(void* sharedContext) noexcept;
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
/**
|
||||
* Creates the filament Engine asynchronously.
|
||||
*
|
||||
* @param callback Callback called once the engine is initialized and it is safe to
|
||||
* call Engine::getEngine().
|
||||
*/
|
||||
void build(utils::Invocable<void(void* token)>&& callback) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates an instance of Engine.
|
||||
*
|
||||
* @return A pointer to the newly created Engine, or nullptr if the Engine couldn't be
|
||||
* created.
|
||||
* nullptr if the GPU driver couldn't be initialized, for instance if it doesn't
|
||||
* support the right version of OpenGL or OpenGL ES.
|
||||
*
|
||||
* @exception utils::PostConditionPanic can be thrown if there isn't enough memory to
|
||||
* allocate the command buffer. If exceptions are disabled, this condition if
|
||||
* fatal and this function will abort.
|
||||
*/
|
||||
Engine* build() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Backward compatibility helper to create an Engine.
|
||||
* @see Builder
|
||||
*/
|
||||
static inline Engine* create(Backend backend = Backend::DEFAULT,
|
||||
Platform* platform = nullptr, void* sharedContext = nullptr,
|
||||
const Config* config = nullptr) {
|
||||
return Engine::Builder()
|
||||
.backend(backend)
|
||||
.platform(platform)
|
||||
.sharedContext(sharedContext)
|
||||
.config(config)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
/**
|
||||
* A callback used with Engine::createAsync() called once the engine is initialized and it is
|
||||
* safe to call Engine::getEngine(token). This callback is invoked from an arbitrary worker
|
||||
* thread. Engine::getEngine() CANNOT be called from that thread, instead it must be called
|
||||
* from the same thread than Engine::createAsync() was called from.
|
||||
*
|
||||
* @param user User provided parameter given in createAsync().
|
||||
*
|
||||
* @param token An opaque token used to call Engine::getEngine().
|
||||
* Backward compatibility helper to create an Engine asynchronously.
|
||||
* @see Builder
|
||||
*/
|
||||
using CreateCallback = void(void* user, void* token);
|
||||
|
||||
/**
|
||||
* Creates an instance of Engine asynchronously
|
||||
*
|
||||
* @param callback Callback called once the engine is initialized and it is safe to
|
||||
* call Engine::getEngine.
|
||||
*
|
||||
* @param user A user provided pointer that is given back to callback unmodified.
|
||||
*
|
||||
* @param backend Which driver backend to use.
|
||||
*
|
||||
* @param platform A pointer to an object that implements Platform. If this is
|
||||
* provided, then this object is used to create the hardware context
|
||||
* and expose platform features to it.
|
||||
*
|
||||
* If not provided (or nullptr is used), an appropriate Platform
|
||||
* is created automatically.
|
||||
*
|
||||
* All methods of this interface are called from filament's
|
||||
* render thread, which is different from the main thread.
|
||||
*
|
||||
* The lifetime of \p platform must exceed the lifetime of
|
||||
* the Engine object.
|
||||
*
|
||||
* @param sharedGLContext A platform-dependant OpenGL context used as a shared context
|
||||
* when creating filament's internal context.
|
||||
* Setting this parameter will force filament to use the OpenGL
|
||||
* implementation (instead of Vulkan for instance).
|
||||
*
|
||||
* @param config A pointer to optional parameters to specify memory size
|
||||
* configuration options
|
||||
*/
|
||||
static void createAsync(CreateCallback callback, void* user,
|
||||
static inline void createAsync(CreateCallback callback, void* user,
|
||||
Backend backend = Backend::DEFAULT,
|
||||
Platform* platform = nullptr, void* sharedGLContext = nullptr,
|
||||
const Config* config = nullptr);
|
||||
Platform* platform = nullptr, void* sharedContext = nullptr,
|
||||
const Config* config = nullptr) {
|
||||
Engine::Builder()
|
||||
.backend(backend)
|
||||
.platform(platform)
|
||||
.sharedContext(sharedContext)
|
||||
.config(config)
|
||||
.build([callback, user](void* token) {
|
||||
callback(user, token);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an Engine* from createAsync(). This must be called from the same thread than
|
||||
@@ -371,6 +403,7 @@ public:
|
||||
static Engine* getEngine(void* token);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Destroy the Engine instance and all associated resources.
|
||||
*
|
||||
@@ -464,6 +497,21 @@ public:
|
||||
*/
|
||||
FeatureLevel getActiveFeatureLevel() const noexcept;
|
||||
|
||||
/**
|
||||
* Queries the maximum number of GPU instances that Filament creates when automatic instancing
|
||||
* is enabled. This value is also the limit for the number of transforms that can be stored in
|
||||
* an InstanceBuffer. This value may depend on the device and platform, but will remain constant
|
||||
* during the lifetime of this Engine.
|
||||
*
|
||||
* This value does not apply when using the instances(size_t) method on
|
||||
* RenderableManager::Builder.
|
||||
*
|
||||
* @return the number of max automatic instances
|
||||
* @see setAutomaticInstancingEnabled
|
||||
* @see RenderableManager::Builder::instances(size_t)
|
||||
* @see RenderableManager::Builder::instances(size_t, InstanceBuffer*)
|
||||
*/
|
||||
size_t getMaxAutomaticInstances() const noexcept;
|
||||
|
||||
/**
|
||||
* @return EntityManager used by filament
|
||||
@@ -625,8 +673,28 @@ public:
|
||||
bool destroy(const Texture* p); //!< Destroys a Texture object.
|
||||
bool destroy(const RenderTarget* p); //!< Destroys a RenderTarget object.
|
||||
bool destroy(const View* p); //!< Destroys a View object.
|
||||
bool destroy(const InstanceBuffer* p); //!< Destroys an InstanceBuffer object.
|
||||
void destroy(utils::Entity e); //!< Destroys all filament-known components from this entity
|
||||
|
||||
bool isValid(const BufferObject* p); //!< Tells whether a BufferObject object is valid
|
||||
bool isValid(const VertexBuffer* p); //!< Tells whether an VertexBuffer object is valid
|
||||
bool isValid(const Fence* p); //!< Tells whether a Fence object is valid
|
||||
bool isValid(const IndexBuffer* p); //!< Tells whether an IndexBuffer object is valid
|
||||
bool isValid(const SkinningBuffer* p); //!< Tells whether a SkinningBuffer object is valid
|
||||
bool isValid(const MorphTargetBuffer* p); //!< Tells whether a MorphTargetBuffer object is valid
|
||||
bool isValid(const IndirectLight* p); //!< Tells whether an IndirectLight object is valid
|
||||
bool isValid(const Material* p); //!< Tells whether an IndirectLight object is valid
|
||||
bool isValid(const Renderer* p); //!< Tells whether a Renderer object is valid
|
||||
bool isValid(const Scene* p); //!< Tells whether a Scene object is valid
|
||||
bool isValid(const Skybox* p); //!< Tells whether a SkyBox object is valid
|
||||
bool isValid(const ColorGrading* p); //!< Tells whether a ColorGrading object is valid
|
||||
bool isValid(const SwapChain* p); //!< Tells whether a SwapChain object is valid
|
||||
bool isValid(const Stream* p); //!< Tells whether a Stream object is valid
|
||||
bool isValid(const Texture* p); //!< Tells whether a Texture object is valid
|
||||
bool isValid(const RenderTarget* p); //!< Tells whether a RenderTarget object is valid
|
||||
bool isValid(const View* p); //!< Tells whether a View object is valid
|
||||
bool isValid(const InstanceBuffer* p); //!< Tells whether an InstanceBuffer object is valid
|
||||
|
||||
/**
|
||||
* Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) and blocks until
|
||||
* all commands to this point are executed. Note that does guarantee that the
|
||||
|
||||
98
ios/include/filament/InstanceBuffer.h
Normal file
98
ios/include/filament/InstanceBuffer.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_INSTANCEBUFFER_H
|
||||
#define TNT_FILAMENT_INSTANCEBUFFER_H
|
||||
|
||||
#include <filament/FilamentAPI.h>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
|
||||
#include <math/mathfwd.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
/**
|
||||
* InstanceBuffer holds draw (GPU) instance transforms. These can be provided to a renderable to
|
||||
* "offset" each draw instance.
|
||||
*
|
||||
* @see RenderableManager::Builder::instances(size_t, InstanceBuffer*)
|
||||
*/
|
||||
class UTILS_PUBLIC InstanceBuffer : public FilamentAPI {
|
||||
struct BuilderDetails;
|
||||
|
||||
public:
|
||||
class Builder : public BuilderBase<BuilderDetails> {
|
||||
friend struct BuilderDetails;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @param instanceCount the number of instances this InstanceBuffer will support, must be
|
||||
* >= 1 and <= \c Engine::getMaxAutomaticInstances()
|
||||
* @see Engine::getMaxAutomaticInstances
|
||||
*/
|
||||
Builder(size_t instanceCount) noexcept;
|
||||
|
||||
Builder(Builder const& rhs) noexcept;
|
||||
Builder(Builder&& rhs) noexcept;
|
||||
~Builder() noexcept;
|
||||
Builder& operator=(Builder const& rhs) noexcept;
|
||||
Builder& operator=(Builder&& rhs) noexcept;
|
||||
|
||||
/**
|
||||
* Provide an initial local transform for each instance. Each local transform is relative to
|
||||
* the transform of the associated renderable. This forms a parent-child relationship
|
||||
* between the renderable and its instances, so adjusting the renderable's transform will
|
||||
- * affect all instances.
|
||||
*
|
||||
* The array of math::mat4f must have length instanceCount, provided when constructing this
|
||||
* Builder.
|
||||
*
|
||||
* @param localTransforms an array of math::mat4f with length instanceCount, must remain
|
||||
* valid until after build() is called
|
||||
*/
|
||||
Builder& localTransforms(math::mat4f const* localTransforms) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the InstanceBuffer object and returns a pointer to it.
|
||||
*/
|
||||
InstanceBuffer* build(Engine& engine);
|
||||
|
||||
private:
|
||||
friend class FInstanceBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the instance count specified when building this InstanceBuffer.
|
||||
*/
|
||||
size_t getInstanceCount() const noexcept;
|
||||
|
||||
/**
|
||||
* Sets the local transform for each instance. Each local transform is relative to the transform
|
||||
* of the associated renderable. This forms a parent-child relationship between the renderable
|
||||
* and its instances, so adjusting the renderable's transform will affect all instances.
|
||||
*
|
||||
* @param localTransforms an array of math::mat4f with length count, need not outlive this call
|
||||
* @param count the number of local transforms
|
||||
* @param offset index of the first instance to set local transforms
|
||||
*/
|
||||
void setLocalTransforms(math::mat4f const* localTransforms, size_t count, size_t offset = 0);
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif //TNT_FILAMENT_INSTANCEBUFFER_H
|
||||
@@ -22,9 +22,11 @@
|
||||
#include <filament/MaterialEnums.h>
|
||||
#include <filament/MaterialInstance.h>
|
||||
|
||||
#include <backend/CallbackHandler.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Invocable.h>
|
||||
|
||||
#include <math/mathfwd.h>
|
||||
|
||||
@@ -105,6 +107,34 @@ public:
|
||||
*/
|
||||
Builder& package(const void* payload, size_t size);
|
||||
|
||||
template<typename T>
|
||||
using is_supported_constant_parameter_t = typename std::enable_if<
|
||||
std::is_same<int32_t, T>::value ||
|
||||
std::is_same<float, T>::value ||
|
||||
std::is_same<bool, T>::value>::type;
|
||||
|
||||
/**
|
||||
* Specialize a constant parameter specified in the material definition with a concrete
|
||||
* value for this material. Once build() is called, this constant cannot be changed.
|
||||
* Will throw an exception if the name does not match a constant specified in the
|
||||
* material definition or if the type provided does not match.
|
||||
*
|
||||
* @tparam T The type of constant parameter, either int32_t, float, or bool.
|
||||
* @param name The name of the constant parameter specified in the material definition, such
|
||||
* as "myConstant".
|
||||
* @param nameLength Length in `char` of the name parameter.
|
||||
* @param value The value to use for the constant parameter, must match the type specified
|
||||
* in the material definition.
|
||||
*/
|
||||
template<typename T, typename = is_supported_constant_parameter_t<T>>
|
||||
Builder& constant(const char* name, size_t nameLength, T value);
|
||||
|
||||
/** inline helper to provide the constant name as a null-terminated C string */
|
||||
template<typename T, typename = is_supported_constant_parameter_t<T>>
|
||||
inline Builder& constant(const char* name, T value) {
|
||||
return constant(name, strlen(name), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Material object and returns a pointer to it.
|
||||
*
|
||||
@@ -122,6 +152,60 @@ public:
|
||||
friend class FMaterial;
|
||||
};
|
||||
|
||||
using CompilerPriorityQueue = backend:: CompilerPriorityQueue;
|
||||
|
||||
/**
|
||||
* Asynchronously ensures that a subset of this Material's variants are compiled. After issuing
|
||||
* several Material::compile() calls in a row, it is recommended to call Engine::flush()
|
||||
* such that the backend can start the compilation work as soon as possible.
|
||||
* The provided callback is guaranteed to be called on the main thread after all specified
|
||||
* variants of the material are compiled. This can take hundreds of milliseconds.
|
||||
*
|
||||
* If all the material's variants are already compiled, the callback will be scheduled as
|
||||
* soon as possible, but this might take a few dozen millisecond, corresponding to how
|
||||
* many previous frames are enqueued in the backend. This also varies by backend. Therefore,
|
||||
* it is recommended to only call this method once per material shortly after creation.
|
||||
*
|
||||
* If the same variant is scheduled for compilation multiple times, the first scheduling
|
||||
* takes precedence; later scheduling are ignored.
|
||||
*
|
||||
* caveat: A consequence is that if a variant is scheduled on the low priority queue and later
|
||||
* scheduled again on the high priority queue, the later scheduling is ignored.
|
||||
* Therefore, the second callback could be called before the variant is compiled.
|
||||
* However, the first callback, if specified, will trigger as expected.
|
||||
*
|
||||
* The callback is guaranteed to be called. If the engine is destroyed while some material
|
||||
* variants are still compiling or in the queue, these will be discarded and the corresponding
|
||||
* callback will be called. In that case however the Material pointer passed to the callback
|
||||
* is guaranteed to be invalid (either because it's been destroyed by the user already, or,
|
||||
* because it's been cleaned-up by the Engine).
|
||||
*
|
||||
* @param priority Which priority queue to use, LOW or HIGH.
|
||||
* @param variants Variants to include to the compile command.
|
||||
* @param handler Handler to dispatch the callback or nullptr for the default handler
|
||||
* @param callback callback called on the main thread when the compilation is done on
|
||||
* by backend.
|
||||
*/
|
||||
void compile(CompilerPriorityQueue priority,
|
||||
UserVariantFilterMask variants,
|
||||
backend::CallbackHandler* handler = nullptr,
|
||||
utils::Invocable<void(Material*)>&& callback = {}) noexcept;
|
||||
|
||||
inline void compile(CompilerPriorityQueue priority,
|
||||
UserVariantFilterBit variants,
|
||||
backend::CallbackHandler* handler = nullptr,
|
||||
utils::Invocable<void(Material*)>&& callback = {}) noexcept {
|
||||
compile(priority, UserVariantFilterMask(variants), handler,
|
||||
std::forward<utils::Invocable<void(Material*)>>(callback));
|
||||
}
|
||||
|
||||
inline void compile(CompilerPriorityQueue priority,
|
||||
backend::CallbackHandler* handler = nullptr,
|
||||
utils::Invocable<void(Material*)>&& callback = {}) noexcept {
|
||||
compile(priority, UserVariantFilterBit::ALL, handler,
|
||||
std::forward<utils::Invocable<void(Material*)>>(callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this material. Material instances should be freed using
|
||||
* Engine::destroy(const MaterialInstance*).
|
||||
@@ -171,6 +255,9 @@ public:
|
||||
//! Indicates whether this material is double-sided.
|
||||
bool isDoubleSided() const noexcept;
|
||||
|
||||
//! Indicates whether this material uses alpha to coverage.
|
||||
bool isAlphaToCoverageEnabled() const noexcept;
|
||||
|
||||
//! Returns the alpha mask threshold used when the blending mode is set to masked.
|
||||
float getMaskThreshold() const noexcept;
|
||||
|
||||
|
||||
@@ -47,10 +47,14 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
|
||||
MaterialShaderModels = charTo64bitNum("MAT_SMDL"),
|
||||
MaterialSamplerBindings = charTo64bitNum("MAT_SAMP"),
|
||||
MaterialUniformBindings = charTo64bitNum("MAT_UNIF"),
|
||||
MaterialBindingUniformInfo = charTo64bitNum("MAT_UFRM"),
|
||||
MaterialAttributeInfo = charTo64bitNum("MAT_ATTR"),
|
||||
MaterialProperties = charTo64bitNum("MAT_PROP"),
|
||||
MaterialConstants = charTo64bitNum("MAT_CONS"),
|
||||
|
||||
MaterialName = charTo64bitNum("MAT_NAME"),
|
||||
MaterialVersion = charTo64bitNum("MAT_VERS"),
|
||||
MaterialCacheId = charTo64bitNum("MAT_UUID"),
|
||||
MaterialFeatureLevel = charTo64bitNum("MAT_FEAT"),
|
||||
MaterialShading = charTo64bitNum("MAT_SHAD"),
|
||||
MaterialBlendingMode = charTo64bitNum("MAT_BLEN"),
|
||||
@@ -67,15 +71,17 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
|
||||
MaterialReflectionMode = charTo64bitNum("MAT_REFL"),
|
||||
|
||||
MaterialRequiredAttributes = charTo64bitNum("MAT_REQA"),
|
||||
MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"),
|
||||
MaterialDoubleSidedSet = charTo64bitNum("MAT_DOSS"),
|
||||
MaterialDoubleSided = charTo64bitNum("MAT_DOSI"),
|
||||
|
||||
MaterialColorWrite = charTo64bitNum("MAT_CWRIT"),
|
||||
MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"),
|
||||
MaterialDepthWrite = charTo64bitNum("MAT_DWRIT"),
|
||||
MaterialDepthTest = charTo64bitNum("MAT_DTEST"),
|
||||
MaterialInstanced = charTo64bitNum("MAT_INSTA"),
|
||||
MaterialCullingMode = charTo64bitNum("MAT_CUMO"),
|
||||
MaterialAlphaToCoverageSet = charTo64bitNum("MAT_A2CS"),
|
||||
MaterialAlphaToCoverage = charTo64bitNum("MAT_A2CO"),
|
||||
|
||||
MaterialHasCustomDepthShader =charTo64bitNum("MAT_CSDP"),
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#define TNT_FILAMENT_MATERIAL_ENUM_H
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/BitmaskEnum.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -27,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 31;
|
||||
static constexpr size_t MATERIAL_VERSION = 41;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
@@ -232,7 +233,9 @@ enum class Property : uint8_t {
|
||||
// when adding new Properties, make sure to update MATERIAL_PROPERTIES_COUNT
|
||||
};
|
||||
|
||||
enum class UserVariantFilterBit : uint32_t {
|
||||
using UserVariantFilterMask = uint32_t;
|
||||
|
||||
enum class UserVariantFilterBit : UserVariantFilterMask {
|
||||
DIRECTIONAL_LIGHTING = 0x01,
|
||||
DYNAMIC_LIGHTING = 0x02,
|
||||
SHADOW_RECEIVER = 0x04,
|
||||
@@ -240,10 +243,12 @@ enum class UserVariantFilterBit : uint32_t {
|
||||
FOG = 0x10,
|
||||
VSM = 0x20,
|
||||
SSR = 0x40,
|
||||
ALL = 0x7F,
|
||||
};
|
||||
|
||||
using UserVariantFilterMask = uint32_t;
|
||||
|
||||
} // namespace filament
|
||||
|
||||
template<> struct utils::EnableBitMaskOperators<filament::UserVariantFilterBit>
|
||||
: public std::true_type {};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,6 +52,7 @@ class UTILS_PUBLIC MaterialInstance : public FilamentAPI {
|
||||
public:
|
||||
using CullingMode = filament::backend::CullingMode;
|
||||
using TransparencyMode = filament::TransparencyMode;
|
||||
using DepthFunc = filament::backend::SamplerCompareFunc;
|
||||
using StencilCompareFunc = filament::backend::SamplerCompareFunc;
|
||||
using StencilOperation = filament::backend::StencilOperation;
|
||||
using StencilFace = filament::backend::StencilFace;
|
||||
@@ -367,6 +368,16 @@ public:
|
||||
*/
|
||||
void setDepthCulling(bool enable) noexcept;
|
||||
|
||||
/**
|
||||
* Overrides the default depth function state that was set on the material.
|
||||
*/
|
||||
void setDepthFunc(DepthFunc depthFunc) noexcept;
|
||||
|
||||
/**
|
||||
* Returns the depth function state.
|
||||
*/
|
||||
DepthFunc getDepthFunc() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether depth culling is enabled.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
class Texture;
|
||||
@@ -151,19 +153,120 @@ struct BloomOptions {
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to control fog in the scene
|
||||
* Options to control large-scale fog in the scene
|
||||
*/
|
||||
struct FogOptions {
|
||||
float distance = 0.0f; //!< distance in world units from the camera where the fog starts ( >= 0.0 )
|
||||
float maximumOpacity = 1.0f; //!< fog's maximum opacity between 0 and 1
|
||||
float height = 0.0f; //!< fog's floor in world units
|
||||
float heightFalloff = 1.0f; //!< how fast fog dissipates with altitude
|
||||
LinearColor color = {0.5f, 0.5f, 0.5f};//!< fog's color (linear), see fogColorFromIbl
|
||||
float density = 0.1f; //!< fog's density at altitude given by 'height'
|
||||
float inScatteringStart = 0.0f; //!< distance in world units from the camera where in-scattering starts
|
||||
float inScatteringSize = -1.0f; //!< size of in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
|
||||
bool fogColorFromIbl = false; //!< Fog color will be modulated by the IBL color in the view direction.
|
||||
bool enabled = false; //!< enable or disable fog
|
||||
/**
|
||||
* Distance in world units [m] from the camera to where the fog starts ( >= 0.0 )
|
||||
*/
|
||||
float distance = 0.0f;
|
||||
|
||||
/**
|
||||
* Distance in world units [m] after which the fog calculation is disabled.
|
||||
* This can be used to exclude the skybox, which is desirable if it already contains clouds or
|
||||
* fog. The default value is +infinity which applies the fog to everything.
|
||||
*
|
||||
* Note: The SkyBox is typically at a distance of 1e19 in world space (depending on the near
|
||||
* plane distance and projection used though).
|
||||
*/
|
||||
float cutOffDistance = INFINITY;
|
||||
|
||||
/**
|
||||
* fog's maximum opacity between 0 and 1
|
||||
*/
|
||||
float maximumOpacity = 1.0f;
|
||||
|
||||
/**
|
||||
* Fog's floor in world units [m]. This sets the "sea level".
|
||||
*/
|
||||
float height = 0.0f;
|
||||
|
||||
/**
|
||||
* How fast the fog dissipates with altitude. heightFalloff has a unit of [1/m].
|
||||
* It can be expressed as 1/H, where H is the altitude change in world units [m] that causes a
|
||||
* factor 2.78 (e) change in fog density.
|
||||
*
|
||||
* A falloff of 0 means the fog density is constant everywhere and may result is slightly
|
||||
* faster computations.
|
||||
*/
|
||||
float heightFalloff = 1.0f;
|
||||
|
||||
/**
|
||||
* Fog's color is used for ambient light in-scattering, a good value is
|
||||
* to use the average of the ambient light, possibly tinted towards blue
|
||||
* for outdoors environments. Color component's values should be between 0 and 1, values
|
||||
* above one are allowed but could create a non energy-conservative fog (this is dependant
|
||||
* on the IBL's intensity as well).
|
||||
*
|
||||
* We assume that our fog has no absorption and therefore all the light it scatters out
|
||||
* becomes ambient light in-scattering and has lost all directionality, i.e.: scattering is
|
||||
* isotropic. This somewhat simulates Rayleigh scattering.
|
||||
*
|
||||
* This value is used as a tint instead, when fogColorFromIbl is enabled.
|
||||
*
|
||||
* @see fogColorFromIbl
|
||||
*/
|
||||
LinearColor color = { 1.0f, 1.0f, 1.0f };
|
||||
|
||||
/**
|
||||
* Extinction factor in [1/m] at altitude 'height'. The extinction factor controls how much
|
||||
* light is absorbed and out-scattered per unit of distance. Each unit of extinction reduces
|
||||
* the incoming light to 37% of its original value.
|
||||
*
|
||||
* Note: The extinction factor is related to the fog density, it's usually some constant K times
|
||||
* the density at sea level (more specifically at fog height). The constant K depends on
|
||||
* the composition of the fog/atmosphere.
|
||||
*
|
||||
* For historical reason this parameter is called `density`.
|
||||
*/
|
||||
float density = 0.1f;
|
||||
|
||||
/**
|
||||
* Distance in world units [m] from the camera where the Sun in-scattering starts.
|
||||
*/
|
||||
float inScatteringStart = 0.0f;
|
||||
|
||||
/**
|
||||
* Very inaccurately simulates the Sun's in-scattering. That is, the light from the sun that
|
||||
* is scattered (by the fog) towards the camera.
|
||||
* Size of the Sun in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
|
||||
* Smaller values result is a larger scattering size.
|
||||
*/
|
||||
float inScatteringSize = -1.0f;
|
||||
|
||||
/**
|
||||
* The fog color will be sampled from the IBL in the view direction and tinted by `color`.
|
||||
* Depending on the scene this can produce very convincing results.
|
||||
*
|
||||
* This simulates a more anisotropic phase-function.
|
||||
*
|
||||
* `fogColorFromIbl` is ignored when skyTexture is specified.
|
||||
*
|
||||
* @see skyColor
|
||||
*/
|
||||
bool fogColorFromIbl = false;
|
||||
|
||||
/**
|
||||
* skyTexture must be a mipmapped cubemap. When provided, the fog color will be sampled from
|
||||
* this texture, higher resolution mip levels will be used for objects at the far clip plane,
|
||||
* and lower resolution mip levels for objects closer to the camera. The skyTexture should
|
||||
* typically be heavily blurred; a typical way to produce this texture is to blur the base
|
||||
* level with a strong gaussian filter or even an irradiance filter and then generate mip
|
||||
* levels as usual. How blurred the base level is somewhat of an artistic decision.
|
||||
*
|
||||
* This simulates a more anisotropic phase-function.
|
||||
*
|
||||
* `fogColorFromIbl` is ignored when skyTexture is specified.
|
||||
*
|
||||
* @see Texture
|
||||
* @see fogColorFromIbl
|
||||
*/
|
||||
Texture* skyColor = nullptr; //!< %codegen_skip_json% %codegen_skip_javascript%
|
||||
|
||||
/**
|
||||
* Enable or disable large-scale fog
|
||||
*/
|
||||
bool enabled = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,8 +91,6 @@ public:
|
||||
/**
|
||||
* Sets a texture to a given attachment point.
|
||||
*
|
||||
* All RenderTargets must have a non-null COLOR attachment.
|
||||
*
|
||||
* When using a DEPTH attachment, it is important to always disable post-processing
|
||||
* in the View. Failing to do so will cause the DEPTH attachment to be ignored in most
|
||||
* cases.
|
||||
|
||||
@@ -45,6 +45,7 @@ class Renderer;
|
||||
class SkinningBuffer;
|
||||
class VertexBuffer;
|
||||
class Texture;
|
||||
class InstanceBuffer;
|
||||
|
||||
class FEngine;
|
||||
class FRenderPrimitive;
|
||||
@@ -119,6 +120,12 @@ public:
|
||||
public:
|
||||
enum Result { Error = -1, Success = 0 };
|
||||
|
||||
/**
|
||||
* Default render channel
|
||||
* @see Builder::channel()
|
||||
*/
|
||||
static constexpr uint8_t DEFAULT_CHANNEL = 2u;
|
||||
|
||||
/**
|
||||
* Creates a builder for renderable components.
|
||||
*
|
||||
@@ -231,10 +238,13 @@ public:
|
||||
/**
|
||||
* Set the channel this renderable is associated to. There can be 4 channels.
|
||||
* All renderables in a given channel are rendered together, regardless of anything else.
|
||||
* They are sorted as usual withing a channel.
|
||||
* They are sorted as usual within a channel.
|
||||
* Channels work similarly to priorities, except that they enforce the strongest ordering.
|
||||
*
|
||||
* @param channel clamped to the range [0..3], defaults to 0.
|
||||
* Channels 0 and 1 may not have render primitives using a material with `refractionType`
|
||||
* set to `screenspace`.
|
||||
*
|
||||
* @param channel clamped to the range [0..3], defaults to 2.
|
||||
*
|
||||
* @return Builder reference for chaining calls.
|
||||
*
|
||||
@@ -293,6 +303,14 @@ public:
|
||||
*/
|
||||
Builder& enableSkinningBuffers(bool enabled = true) noexcept;
|
||||
|
||||
/**
|
||||
* Controls if this renderable is affected by the large-scale fog.
|
||||
* @param enabled If true, enables large-scale fog on this object. Disables it otherwise.
|
||||
* True by default.
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& fog(bool enabled = true) noexcept;
|
||||
|
||||
/**
|
||||
* Enables GPU vertex skinning for up to 255 bones, 0 by default.
|
||||
*
|
||||
@@ -399,20 +417,47 @@ public:
|
||||
*/
|
||||
Builder& globalBlendOrderEnabled(size_t primitiveIndex, bool enabled) noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* Specifies the number of draw instance of this renderable. The default is 1 instance and
|
||||
* the maximum number of instances allowed is 65535. 0 is invalid.
|
||||
* Specifies the number of draw instances of this renderable. The default is 1 instance and
|
||||
* the maximum number of instances allowed is 32767. 0 is invalid.
|
||||
*
|
||||
* All instances are culled using the same bounding box, so care must be taken to make
|
||||
* sure all instances render inside the specified bounding box.
|
||||
*
|
||||
* The material must set its `instanced` parameter to `true` in order to use
|
||||
* getInstanceIndex() in the vertex or fragment shader to get the instance index and
|
||||
* possibly adjust the position or transform.
|
||||
*
|
||||
* @param instanceCount the number of instances silently clamped between 1 and 65535.
|
||||
* @param instanceCount the number of instances silently clamped between 1 and 32767.
|
||||
*/
|
||||
Builder& instances(size_t instanceCount) noexcept;
|
||||
|
||||
/**
|
||||
* Specifies the number of draw instances of this renderable and an \c InstanceBuffer
|
||||
* containing their local transforms. The default is 1 instance and the maximum number of
|
||||
* instances allowed when supplying transforms is given by
|
||||
* \c Engine::getMaxAutomaticInstances (64 on most platforms). 0 is invalid. The
|
||||
* \c InstanceBuffer must not be destroyed before this renderable.
|
||||
*
|
||||
* All instances are culled using the same bounding box, so care must be taken to make
|
||||
* sure all instances render inside the specified bounding box.
|
||||
*
|
||||
* The material must set its `instanced` parameter to `true` in order to use
|
||||
* \c getInstanceIndex() in the vertex or fragment shader to get the instance index.
|
||||
*
|
||||
* Only the \c VERTEX_DOMAIN_OBJECT vertex domain is supported.
|
||||
*
|
||||
* The local transforms of each instance can be updated with
|
||||
* \c InstanceBuffer::setLocalTransforms.
|
||||
*
|
||||
* \see InstanceBuffer
|
||||
* \see instances(size_t, * math::mat4f const*)
|
||||
* @param instanceCount the number of instances, silently clamped between 1 and
|
||||
* the result of Engine::getMaxAutomaticInstances().
|
||||
* @param instanceBuffer an InstanceBuffer containing at least instanceCount transforms
|
||||
*/
|
||||
Builder& instances(size_t instanceCount, InstanceBuffer* instanceBuffer) noexcept;
|
||||
|
||||
/**
|
||||
* Adds the Renderable component to an entity.
|
||||
*
|
||||
@@ -499,6 +544,19 @@ public:
|
||||
*/
|
||||
void setCulling(Instance instance, bool enable) noexcept;
|
||||
|
||||
/**
|
||||
* Changes whether or not the large-scale fog is applied to this renderable
|
||||
* @see Builder::fog()
|
||||
*/
|
||||
void setFogEnabled(Instance instance, bool enable) noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether large-scale fog is enabled for this renderable.
|
||||
* @return True if fog is enabled for this renderable.
|
||||
* @see Builder::fog()
|
||||
*/
|
||||
bool getFogEnabled(Instance instance) const noexcept;
|
||||
|
||||
/**
|
||||
* Enables or disables a light channel.
|
||||
* Light channel 0 is enabled by default.
|
||||
|
||||
@@ -707,6 +707,9 @@ public:
|
||||
* The viewport, projection and model matrices can be obtained from Camera. Because
|
||||
* pick() has some latency, it might be more accurate to obtain these values at the
|
||||
* time the View::pick() call is made.
|
||||
*
|
||||
* Note: if the Engine is running at FEATURE_LEVEL_0, the precision or `depth` and
|
||||
* `fragCoords.z` is only 8-bits.
|
||||
*/
|
||||
math::float3 fragCoords; //! screen space coordinates in GL convention
|
||||
};
|
||||
@@ -803,6 +806,37 @@ public:
|
||||
PickingQuery& pick(uint32_t x, uint32_t y, backend::CallbackHandler* handler,
|
||||
PickingQueryResultCallback callback) noexcept;
|
||||
|
||||
/**
|
||||
* Set the value of material global variables. There are up-to four such variable each of
|
||||
* type float4. These variables can be read in a user Material with
|
||||
* `getMaterialGlobal{0|1|2|3}()`. All variable start with a default value of { 0, 0, 0, 1 }
|
||||
*
|
||||
* @param index index of the variable to set between 0 and 3.
|
||||
* @param value new value for the variable.
|
||||
* @see getMaterialGlobal
|
||||
*/
|
||||
void setMaterialGlobal(uint32_t index, math::float4 const& value);
|
||||
|
||||
/**
|
||||
* Get the value of the material global variables.
|
||||
* All variable start with a default value of { 0, 0, 0, 1 }
|
||||
*
|
||||
* @param index index of the variable to set between 0 and 3.
|
||||
* @return current value of the variable.
|
||||
* @see setMaterialGlobal
|
||||
*/
|
||||
math::float4 getMaterialGlobal(uint32_t index) const;
|
||||
|
||||
/**
|
||||
* Get an Entity representing the large scale fog object.
|
||||
* This entity is always inherited by the View's Scene.
|
||||
*
|
||||
* It is for example possible to create a TransformManager component with this
|
||||
* Entity and apply a transformation globally on the fog.
|
||||
*
|
||||
* @return an Entity representing the large scale fog object.
|
||||
*/
|
||||
utils::Entity getFogEntity() const noexcept;
|
||||
|
||||
/**
|
||||
* List of available ambient occlusion techniques
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <math/quat.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace filament {
|
||||
namespace geometry {
|
||||
@@ -28,8 +27,7 @@ namespace geometry {
|
||||
struct TangentSpaceMeshInput;
|
||||
struct TangentSpaceMeshOutput;
|
||||
|
||||
/* WARNING: WORK-IN-PROGRESS, PLEASE DO NOT USE */
|
||||
/**
|
||||
/**
|
||||
* This class builds Filament-style TANGENTS buffers given an input mesh.
|
||||
*
|
||||
* This class enables the client to chose between several algorithms. The client can retrieve the
|
||||
@@ -140,8 +138,8 @@ public:
|
||||
*/
|
||||
Builder& operator=(Builder&& that) noexcept;
|
||||
|
||||
Builder(const Builder&) = delete;
|
||||
Builder& operator=(const Builder&) = delete;
|
||||
Builder(Builder const&) = delete;
|
||||
Builder& operator=(Builder const&) = delete;
|
||||
|
||||
/**
|
||||
* Client must provide this parameter
|
||||
@@ -155,7 +153,7 @@ public:
|
||||
* @param stride The stride for iterating through `normals`
|
||||
* @return Builder
|
||||
*/
|
||||
Builder& normals(const filament::math::float3* normals, size_t stride = 0) noexcept;
|
||||
Builder& normals(filament::math::float3 const* normals, size_t stride = 0) noexcept;
|
||||
|
||||
/**
|
||||
* @param tangents The input tangents. The `w` component is for use with
|
||||
@@ -163,25 +161,25 @@ public:
|
||||
* @param stride The stride for iterating through `tangents`
|
||||
* @return Builder
|
||||
*/
|
||||
Builder& tangents(const filament::math::float4* tangents, size_t stride = 0) noexcept;
|
||||
Builder& tangents(filament::math::float4 const* tangents, size_t stride = 0) noexcept;
|
||||
|
||||
/**
|
||||
* @param uvs The input uvs
|
||||
* @param stride The stride for iterating through `uvs`
|
||||
* @return Builder
|
||||
*/
|
||||
Builder& uvs(const filament::math::float2* uvs, size_t stride = 0) noexcept;
|
||||
Builder& uvs(filament::math::float2 const* uvs, size_t stride = 0) noexcept;
|
||||
|
||||
/**
|
||||
* @param positions The input positions
|
||||
* @param stride The stride for iterating through `positions`
|
||||
* @return Builder
|
||||
*/
|
||||
Builder& positions(const filament::math::float3* positions, size_t stride = 0) noexcept;
|
||||
Builder& positions(filament::math::float3 const* positions, size_t stride = 0) noexcept;
|
||||
|
||||
Builder& triangleCount(size_t triangleCount) noexcept;
|
||||
Builder& triangles(const filament::math::uint3* triangles) noexcept;
|
||||
Builder& triangles(const filament::math::ushort3* triangles) noexcept;
|
||||
Builder& triangles(filament::math::uint3 const* triangles) noexcept;
|
||||
Builder& triangles(filament::math::ushort3 const* triangles) noexcept;
|
||||
|
||||
Builder& algorithm(Algorithm algorithm) noexcept;
|
||||
|
||||
@@ -216,8 +214,8 @@ public:
|
||||
*/
|
||||
TangentSpaceMesh& operator=(TangentSpaceMesh&& that) noexcept;
|
||||
|
||||
TangentSpaceMesh(const TangentSpaceMesh&) = delete;
|
||||
TangentSpaceMesh& operator=(const TangentSpaceMesh&) = delete;
|
||||
TangentSpaceMesh(TangentSpaceMesh const&) = delete;
|
||||
TangentSpaceMesh& operator=(TangentSpaceMesh const&) = delete;
|
||||
|
||||
/**
|
||||
* Number of output vertices
|
||||
|
||||
@@ -142,7 +142,7 @@ class Ktx2Reader {
|
||||
|
||||
protected:
|
||||
Async() noexcept = default;
|
||||
~Async() = default;
|
||||
virtual ~Async();
|
||||
|
||||
public:
|
||||
Async(Async const&) = delete;
|
||||
|
||||
@@ -8,5 +8,5 @@ IMAGE_PACKAGE:
|
||||
IMAGE_IMAGE_OFFSET:
|
||||
.int 0
|
||||
IMAGE_IMAGE_SIZE:
|
||||
.int 44497
|
||||
.int 17687
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@ _IMAGE_PACKAGE:
|
||||
_IMAGE_IMAGE_OFFSET:
|
||||
.int 0
|
||||
_IMAGE_IMAGE_SIZE:
|
||||
.int 44497
|
||||
.int 17687
|
||||
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -430,8 +430,21 @@ constexpr TQuaternion<T> TMat33<T>::packTangentFrame(const TMat33<T>& m, size_t
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
} // namespace details
|
||||
|
||||
/**
|
||||
* Pre-scale a matrix m by the inverse of the largest scale factor to avoid large post-transform
|
||||
* magnitudes in the shader. This is useful for normal transformations, to avoid large
|
||||
* post-transform magnitudes in the shader, especially in the fragment shader, where we use
|
||||
* medium precision.
|
||||
*/
|
||||
template<typename T>
|
||||
constexpr details::TMat33<T> prescaleForNormals(const details::TMat33<T>& m) noexcept {
|
||||
return m * details::TMat33<T>(
|
||||
1.0 / std::sqrt(max(float3{length2(m[0]), length2(m[1]), length2(m[2])})));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
typedef details::TMat33<double> mat3;
|
||||
|
||||
145
ios/include/mikktspace/mikktspace.h
Normal file
145
ios/include/mikktspace/mikktspace.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/** \file mikktspace/mikktspace.h
|
||||
* \ingroup mikktspace
|
||||
*/
|
||||
/**
|
||||
* Copyright (C) 2011 by Morten S. Mikkelsen
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef __MIKKTSPACE_H__
|
||||
#define __MIKKTSPACE_H__
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Author: Morten S. Mikkelsen
|
||||
* Version: 1.0
|
||||
*
|
||||
* The files mikktspace.h and mikktspace.c are designed to be
|
||||
* stand-alone files and it is important that they are kept this way.
|
||||
* Not having dependencies on structures/classes/libraries specific
|
||||
* to the program, in which they are used, allows them to be copied
|
||||
* and used as is into any tool, program or plugin.
|
||||
* The code is designed to consistently generate the same
|
||||
* tangent spaces, for a given mesh, in any tool in which it is used.
|
||||
* This is done by performing an internal welding step and subsequently an order-independent evaluation
|
||||
* of tangent space for meshes consisting of triangles and quads.
|
||||
* This means faces can be received in any order and the same is true for
|
||||
* the order of vertices of each face. The generated result will not be affected
|
||||
* by such reordering. Additionally, whether degenerate (vertices or texture coordinates)
|
||||
* primitives are present or not will not affect the generated results either.
|
||||
* Once tangent space calculation is done the vertices of degenerate primitives will simply
|
||||
* inherit tangent space from neighboring non degenerate primitives.
|
||||
* The analysis behind this implementation can be found in my master's thesis
|
||||
* which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf
|
||||
* Note that though the tangent spaces at the vertices are generated in an order-independent way,
|
||||
* by this implementation, the interpolated tangent space is still affected by which diagonal is
|
||||
* chosen to split each quad. A sensible solution is to have your tools pipeline always
|
||||
* split quads by the shortest diagonal. This choice is order-independent and works with mirroring.
|
||||
* If these have the same length then compare the diagonals defined by the texture coordinates.
|
||||
* XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin
|
||||
* and also quad triangulator plugin.
|
||||
*/
|
||||
|
||||
|
||||
typedef int tbool;
|
||||
typedef struct SMikkTSpaceContext SMikkTSpaceContext;
|
||||
|
||||
typedef struct {
|
||||
// Returns the number of faces (triangles/quads) on the mesh to be processed.
|
||||
int (*m_getNumFaces)(const SMikkTSpaceContext * pContext);
|
||||
|
||||
// Returns the number of vertices on face number iFace
|
||||
// iFace is a number in the range {0, 1, ..., getNumFaces()-1}
|
||||
int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace);
|
||||
|
||||
// returns the position/normal/texcoord of the referenced face of vertex number iVert.
|
||||
// iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
|
||||
void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert);
|
||||
void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert);
|
||||
void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert);
|
||||
|
||||
// either (or both) of the two setTSpace callbacks can be set.
|
||||
// The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
|
||||
|
||||
// This function is used to return the tangent and fSign to the application.
|
||||
// fvTangent is a unit length vector.
|
||||
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
|
||||
// bitangent = fSign * cross(vN, tangent);
|
||||
// Note that the results are returned unindexed. It is possible to generate a new index list
|
||||
// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
|
||||
// DO NOT! use an already existing index list.
|
||||
void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
|
||||
|
||||
// This function is used to return tangent space results to the application.
|
||||
// fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their
|
||||
// true magnitudes which can be used for relief mapping effects.
|
||||
// fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent.
|
||||
// However, both are perpendicular to the vertex normal.
|
||||
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
|
||||
// fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
|
||||
// bitangent = fSign * cross(vN, tangent);
|
||||
// Note that the results are returned unindexed. It is possible to generate a new index list
|
||||
// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
|
||||
// DO NOT! use an already existing index list.
|
||||
void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
|
||||
const tbool bIsOrientationPreserving, const int iFace, const int iVert);
|
||||
} SMikkTSpaceInterface;
|
||||
|
||||
struct SMikkTSpaceContext
|
||||
{
|
||||
SMikkTSpaceInterface * m_pInterface; // initialized with callback functions
|
||||
void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call)
|
||||
};
|
||||
|
||||
// these are both thread safe!
|
||||
tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled)
|
||||
tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold);
|
||||
|
||||
|
||||
// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the
|
||||
// normal map sampler must use the exact inverse of the pixel shader transformation.
|
||||
// The most efficient transformation we can possibly do in the pixel shader is
|
||||
// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN.
|
||||
// pixel shader (fast transform out)
|
||||
// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
|
||||
// where vNt is the tangent space normal. The normal map sampler must likewise use the
|
||||
// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader.
|
||||
// sampler does (exact inverse of pixel shader):
|
||||
// float3 row0 = cross(vB, vN);
|
||||
// float3 row1 = cross(vN, vT);
|
||||
// float3 row2 = cross(vT, vB);
|
||||
// float fSign = dot(vT, row0)<0 ? -1 : 1;
|
||||
// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) );
|
||||
// where vNout is the sampled normal in some chosen 3D space.
|
||||
//
|
||||
// Should you choose to reconstruct the bitangent in the pixel shader instead
|
||||
// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also.
|
||||
// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of
|
||||
// quads as your renderer then problems will occur since the interpolated tangent spaces will differ
|
||||
// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before
|
||||
// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier.
|
||||
// However, this must be used both by the sampler and your tools/rendering pipeline.
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -141,5 +141,4 @@ inline constexpr bool any(Enum lhs) noexcept {
|
||||
return !none(lhs);
|
||||
}
|
||||
|
||||
|
||||
#endif // TNT_UTILS_BITMASKENUM_H
|
||||
|
||||
@@ -253,6 +253,12 @@ public:
|
||||
*/
|
||||
static Path getTemporaryDirectory();
|
||||
|
||||
/**
|
||||
* @return a path representing a directory where settings files can be stored,
|
||||
* it is recommended to append an app specific folder name to that path
|
||||
*/
|
||||
static Path getUserSettingsDirectory();
|
||||
|
||||
/**
|
||||
* Creates a directory denoted by the given path.
|
||||
* This is not recursive and doesn't create intermediate directories.
|
||||
|
||||
@@ -60,16 +60,19 @@ private:
|
||||
protected:
|
||||
static constexpr size_t ENTITY_INDEX = sizeof ... (Elements);
|
||||
|
||||
|
||||
public:
|
||||
using SoA = StructureOfArrays<Elements ..., Entity>;
|
||||
|
||||
using Structure = typename SoA::Structure;
|
||||
|
||||
using Instance = EntityInstanceBase::Type;
|
||||
|
||||
SingleInstanceComponentManager() noexcept {
|
||||
// We always start with a dummy entry because index=0 is reserved. The component
|
||||
// at index = 0, is guaranteed to be default-initialized.
|
||||
// Sub-classes can use this to their advantage.
|
||||
mData.push_back();
|
||||
mData.push_back(Structure{});
|
||||
}
|
||||
|
||||
SingleInstanceComponentManager(SingleInstanceComponentManager&&) noexcept {/* = default */}
|
||||
@@ -269,7 +272,7 @@ SingleInstanceComponentManager<Elements ...>::addComponent(Entity e) {
|
||||
if (!e.isNull()) {
|
||||
if (!hasComponent(e)) {
|
||||
// this is like a push_back(e);
|
||||
mData.push_back().template back<ENTITY_INDEX>() = e;
|
||||
mData.push_back(Structure{}).template back<ENTITY_INDEX>() = e;
|
||||
// index 0 is used when the component doesn't exist
|
||||
ci = Instance(mData.size() - 1);
|
||||
mInstanceMap[e] = ci;
|
||||
|
||||
@@ -41,11 +41,13 @@ class StructureOfArraysBase {
|
||||
static constexpr const size_t kArrayCount = sizeof...(Elements);
|
||||
|
||||
public:
|
||||
using SoA = StructureOfArraysBase<Allocator, Elements ...>;
|
||||
using SoA = StructureOfArraysBase<Allocator, Elements...>;
|
||||
|
||||
using Structure = std::tuple<Elements...>;
|
||||
|
||||
// Type of the Nth array
|
||||
template<size_t N>
|
||||
using TypeAt = typename std::tuple_element_t<N, std::tuple<Elements...>>;
|
||||
using TypeAt = typename std::tuple_element_t<N, Structure>;
|
||||
|
||||
// Number of arrays
|
||||
static constexpr size_t getArrayCount() noexcept { return kArrayCount; }
|
||||
@@ -57,7 +59,7 @@ public:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
class Structure;
|
||||
class IteratorValue;
|
||||
template<typename T> class Iterator;
|
||||
using iterator = Iterator<StructureOfArraysBase*>;
|
||||
using const_iterator = Iterator<StructureOfArraysBase const*>;
|
||||
@@ -69,45 +71,45 @@ public:
|
||||
* In other words, it's the return type of iterator::operator*(), and since it
|
||||
* cannot be a C++ reference (&), it's an object that acts like it.
|
||||
*/
|
||||
class StructureRef {
|
||||
friend class Structure;
|
||||
class IteratorValueRef {
|
||||
friend class IteratorValue;
|
||||
friend iterator;
|
||||
friend const_iterator;
|
||||
StructureOfArraysBase* const UTILS_RESTRICT soa;
|
||||
size_t const index;
|
||||
|
||||
StructureRef(StructureOfArraysBase* soa, size_t index) : soa(soa), index(index) { }
|
||||
IteratorValueRef(StructureOfArraysBase* soa, size_t index) : soa(soa), index(index) { }
|
||||
|
||||
// assigns a value_type to a reference (i.e. assigns to what's pointed to by the reference)
|
||||
template<size_t ... Is>
|
||||
StructureRef& assign(Structure const& rhs, std::index_sequence<Is...>);
|
||||
IteratorValueRef& assign(IteratorValue const& rhs, std::index_sequence<Is...>);
|
||||
|
||||
// assigns a value_type to a reference (i.e. assigns to what's pointed to by the reference)
|
||||
template<size_t ... Is>
|
||||
StructureRef& assign(Structure&& rhs, std::index_sequence<Is...>) noexcept;
|
||||
IteratorValueRef& assign(IteratorValue&& rhs, std::index_sequence<Is...>) noexcept;
|
||||
|
||||
// objects pointed to by reference can be swapped, so provide the special swap() function.
|
||||
friend void swap(StructureRef lhs, StructureRef rhs) {
|
||||
friend void swap(IteratorValueRef lhs, IteratorValueRef rhs) {
|
||||
lhs.soa->swap(lhs.index, rhs.index);
|
||||
}
|
||||
|
||||
public:
|
||||
// references can be created by copy-assignment only
|
||||
StructureRef(StructureRef const& rhs) noexcept : soa(rhs.soa), index(rhs.index) { }
|
||||
IteratorValueRef(IteratorValueRef const& rhs) noexcept : soa(rhs.soa), index(rhs.index) { }
|
||||
|
||||
// copy the content of a reference to the content of this one
|
||||
StructureRef& operator=(StructureRef const& rhs);
|
||||
IteratorValueRef& operator=(IteratorValueRef const& rhs);
|
||||
|
||||
// move the content of a reference to the content of this one
|
||||
StructureRef& operator=(StructureRef&& rhs) noexcept;
|
||||
IteratorValueRef& operator=(IteratorValueRef&& rhs) noexcept;
|
||||
|
||||
// copy a value_type to the content of this reference
|
||||
StructureRef& operator=(Structure const& rhs) {
|
||||
IteratorValueRef& operator=(IteratorValue const& rhs) {
|
||||
return assign(rhs, std::make_index_sequence<kArrayCount>());
|
||||
}
|
||||
|
||||
// move a value_type to the content of this reference
|
||||
StructureRef& operator=(Structure&& rhs) noexcept {
|
||||
IteratorValueRef& operator=(IteratorValue&& rhs) noexcept {
|
||||
return assign(rhs, std::make_index_sequence<kArrayCount>());
|
||||
}
|
||||
|
||||
@@ -122,36 +124,36 @@ public:
|
||||
* Internally we're using a tuple<> to store the data.
|
||||
* This object is not trivial to construct, as it copies an entry of the SoA.
|
||||
*/
|
||||
class Structure {
|
||||
friend class StructureRef;
|
||||
class IteratorValue {
|
||||
friend class IteratorValueRef;
|
||||
friend iterator;
|
||||
friend const_iterator;
|
||||
using Type = std::tuple<typename std::decay<Elements>::type...>;
|
||||
Type elements;
|
||||
|
||||
template<size_t ... Is>
|
||||
static Type init(StructureRef const& rhs, std::index_sequence<Is...>) {
|
||||
static Type init(IteratorValueRef const& rhs, std::index_sequence<Is...>) {
|
||||
return Type{ rhs.soa->template elementAt<Is>(rhs.index)... };
|
||||
}
|
||||
|
||||
template<size_t ... Is>
|
||||
static Type init(StructureRef&& rhs, std::index_sequence<Is...>) noexcept {
|
||||
static Type init(IteratorValueRef&& rhs, std::index_sequence<Is...>) noexcept {
|
||||
return Type{ std::move(rhs.soa->template elementAt<Is>(rhs.index))... };
|
||||
}
|
||||
|
||||
public:
|
||||
Structure(Structure const& rhs) = default;
|
||||
Structure(Structure&& rhs) noexcept = default;
|
||||
Structure& operator=(Structure const& rhs) = default;
|
||||
Structure& operator=(Structure&& rhs) noexcept = default;
|
||||
IteratorValue(IteratorValue const& rhs) = default;
|
||||
IteratorValue(IteratorValue&& rhs) noexcept = default;
|
||||
IteratorValue& operator=(IteratorValue const& rhs) = default;
|
||||
IteratorValue& operator=(IteratorValue&& rhs) noexcept = default;
|
||||
|
||||
// initialize and assign from a StructureRef
|
||||
Structure(StructureRef const& rhs)
|
||||
IteratorValue(IteratorValueRef const& rhs)
|
||||
: elements(init(rhs, std::make_index_sequence<kArrayCount>())) {}
|
||||
Structure(StructureRef&& rhs) noexcept
|
||||
IteratorValue(IteratorValueRef&& rhs) noexcept
|
||||
: elements(init(rhs, std::make_index_sequence<kArrayCount>())) {}
|
||||
Structure& operator=(StructureRef const& rhs) { return operator=(Structure(rhs)); }
|
||||
Structure& operator=(StructureRef&& rhs) noexcept { return operator=(Structure(rhs)); }
|
||||
IteratorValue& operator=(IteratorValueRef const& rhs) { return operator=(IteratorValue(rhs)); }
|
||||
IteratorValue& operator=(IteratorValueRef&& rhs) noexcept { return operator=(IteratorValue(rhs)); }
|
||||
|
||||
// access the elements of this value_Type (i.e. the "fields" of the structure)
|
||||
template<size_t I> TypeAt<I> const& get() const { return std::get<I>(elements); }
|
||||
@@ -174,9 +176,9 @@ public:
|
||||
Iterator(CVQualifiedSOAPointer soa, size_t index) : soa(soa), index(index) {}
|
||||
|
||||
public:
|
||||
using value_type = Structure;
|
||||
using reference = StructureRef;
|
||||
using pointer = StructureRef*; // FIXME: this should be a StructurePtr type
|
||||
using value_type = IteratorValue;
|
||||
using reference = IteratorValueRef;
|
||||
using pointer = IteratorValueRef*; // FIXME: this should be a StructurePtr type
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
@@ -335,6 +337,11 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
StructureOfArraysBase& push_back(Structure&& args) noexcept {
|
||||
ensureCapacity(mSize + 1);
|
||||
return push_back_unsafe(std::forward<Structure>(args));
|
||||
}
|
||||
|
||||
StructureOfArraysBase& push_back(Elements const& ... args) noexcept {
|
||||
ensureCapacity(mSize + 1);
|
||||
return push_back_unsafe(args...);
|
||||
@@ -349,23 +356,29 @@ public:
|
||||
struct PushBackUnsafeClosure {
|
||||
size_t last;
|
||||
std::tuple<Elements...> args;
|
||||
inline explicit PushBackUnsafeClosure(size_t last, Elements&& ... args)
|
||||
: last(last), args(std::forward<Elements>(args)...) {}
|
||||
inline explicit PushBackUnsafeClosure(size_t last, Elements const& ... args)
|
||||
: last(last), args(args...) {}
|
||||
inline explicit PushBackUnsafeClosure(size_t last, Structure&& args)
|
||||
: last(last), args(std::forward<Structure>(args)) {}
|
||||
template<size_t I>
|
||||
inline void operator()(TypeAt<I>* p) {
|
||||
new(p + last) TypeAt<I>{ std::get<I>(args) };
|
||||
}
|
||||
};
|
||||
|
||||
StructureOfArraysBase& push_back_unsafe(Structure&& args) noexcept {
|
||||
for_each_index(mArrays,
|
||||
PushBackUnsafeClosure{ mSize++, std::forward<Structure>(args) });
|
||||
return *this;
|
||||
}
|
||||
|
||||
StructureOfArraysBase& push_back_unsafe(Elements const& ... args) noexcept {
|
||||
for_each_index(mArrays, PushBackUnsafeClosure{ mSize++, args... });
|
||||
for_each_index(mArrays,
|
||||
PushBackUnsafeClosure{ mSize++, { args... } });
|
||||
return *this;
|
||||
}
|
||||
|
||||
StructureOfArraysBase& push_back_unsafe(Elements&& ... args) noexcept {
|
||||
for_each_index(mArrays, PushBackUnsafeClosure{ mSize++, std::forward<Elements>(args)... });
|
||||
for_each_index(mArrays,
|
||||
PushBackUnsafeClosure{ mSize++, { std::forward<Elements>(args)... }});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -562,8 +575,10 @@ private:
|
||||
forEach([from, to](auto p) {
|
||||
using T = typename std::decay<decltype(*p)>::type;
|
||||
// note: scalar types like int/float get initialized to zero
|
||||
for (size_t i = from; i < to; i++) {
|
||||
new(p + i) T();
|
||||
if constexpr (!std::is_trivially_default_constructible_v<T>) {
|
||||
for (size_t i = from; i < to; i++) {
|
||||
new(p + i) T();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -571,8 +586,10 @@ private:
|
||||
void destroy_each(size_t from, size_t to) noexcept {
|
||||
forEach([from, to](auto p) {
|
||||
using T = typename std::decay<decltype(*p)>::type;
|
||||
for (size_t i = from; i < to; i++) {
|
||||
p[i].~T();
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
for (size_t i = from; i < to; i++) {
|
||||
p[i].~T();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -592,15 +609,17 @@ private:
|
||||
reinterpret_cast<T*>(uintptr_t(b) + offsets[index]);
|
||||
|
||||
// for trivial cases, just call memcpy()
|
||||
if (std::is_trivially_copyable<T>::value &&
|
||||
std::is_trivially_destructible<T>::value) {
|
||||
if constexpr (std::is_trivially_copyable_v<T> &&
|
||||
std::is_trivially_destructible_v<T>) {
|
||||
memcpy(arrayPointer, p, size * sizeof(T));
|
||||
} else {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
// we move an element by using the in-place move-constructor
|
||||
new(arrayPointer + i) T(std::move(p[i]));
|
||||
// and delete them by calling the destructor directly
|
||||
p[i].~T();
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
// and delete them by calling the destructor directly
|
||||
p[i].~T();
|
||||
}
|
||||
}
|
||||
}
|
||||
index++;
|
||||
@@ -626,27 +645,27 @@ private:
|
||||
|
||||
template<typename Allocator, typename... Elements>
|
||||
inline
|
||||
typename StructureOfArraysBase<Allocator, Elements...>::StructureRef&
|
||||
StructureOfArraysBase<Allocator, Elements...>::StructureRef::operator=(
|
||||
StructureOfArraysBase::StructureRef const& rhs) {
|
||||
return operator=(Structure(rhs));
|
||||
typename StructureOfArraysBase<Allocator, Elements...>::IteratorValueRef&
|
||||
StructureOfArraysBase<Allocator, Elements...>::IteratorValueRef::operator=(
|
||||
StructureOfArraysBase::IteratorValueRef const& rhs) {
|
||||
return operator=(IteratorValue(rhs));
|
||||
}
|
||||
|
||||
template<typename Allocator, typename... Elements>
|
||||
inline
|
||||
typename StructureOfArraysBase<Allocator, Elements...>::StructureRef&
|
||||
StructureOfArraysBase<Allocator, Elements...>::StructureRef::operator=(
|
||||
StructureOfArraysBase::StructureRef&& rhs) noexcept {
|
||||
return operator=(Structure(rhs));
|
||||
typename StructureOfArraysBase<Allocator, Elements...>::IteratorValueRef&
|
||||
StructureOfArraysBase<Allocator, Elements...>::IteratorValueRef::operator=(
|
||||
StructureOfArraysBase::IteratorValueRef&& rhs) noexcept {
|
||||
return operator=(IteratorValue(rhs));
|
||||
}
|
||||
|
||||
template<typename Allocator, typename... Elements>
|
||||
template<size_t... Is>
|
||||
inline
|
||||
typename StructureOfArraysBase<Allocator, Elements...>::StructureRef&
|
||||
StructureOfArraysBase<Allocator, Elements...>::StructureRef::assign(
|
||||
StructureOfArraysBase::Structure const& rhs, std::index_sequence<Is...>) {
|
||||
// implements StructureRef& StructureRef::operator=(Structure const& rhs)
|
||||
typename StructureOfArraysBase<Allocator, Elements...>::IteratorValueRef&
|
||||
StructureOfArraysBase<Allocator, Elements...>::IteratorValueRef::assign(
|
||||
StructureOfArraysBase::IteratorValue const& rhs, std::index_sequence<Is...>) {
|
||||
// implements IteratorValueRef& IteratorValueRef::operator=(IteratorValue const& rhs)
|
||||
auto UTILS_UNUSED l = { (soa->elementAt<Is>(index) = std::get<Is>(rhs.elements), 0)... };
|
||||
return *this;
|
||||
}
|
||||
@@ -654,10 +673,10 @@ StructureOfArraysBase<Allocator, Elements...>::StructureRef::assign(
|
||||
template<typename Allocator, typename... Elements>
|
||||
template<size_t... Is>
|
||||
inline
|
||||
typename StructureOfArraysBase<Allocator, Elements...>::StructureRef&
|
||||
StructureOfArraysBase<Allocator, Elements...>::StructureRef::assign(
|
||||
StructureOfArraysBase::Structure&& rhs, std::index_sequence<Is...>) noexcept {
|
||||
// implements StructureRef& StructureRef::operator=(Structure&& rhs) noexcept
|
||||
typename StructureOfArraysBase<Allocator, Elements...>::IteratorValueRef&
|
||||
StructureOfArraysBase<Allocator, Elements...>::IteratorValueRef::assign(
|
||||
StructureOfArraysBase::IteratorValue&& rhs, std::index_sequence<Is...>) noexcept {
|
||||
// implements IteratorValueRef& IteratorValueRef::operator=(IteratorValue&& rhs) noexcept
|
||||
auto UTILS_UNUSED l = {
|
||||
(soa->elementAt<Is>(index) = std::move(std::get<Is>(rhs.elements)), 0)... };
|
||||
return *this;
|
||||
|
||||
@@ -54,6 +54,12 @@
|
||||
# define UTILS_NORETURN
|
||||
#endif
|
||||
|
||||
#if __has_attribute(fallthrough)
|
||||
# define UTILS_FALLTHROUGH [[fallthrough]]
|
||||
#else
|
||||
# define UTILS_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#if __has_attribute(visibility)
|
||||
# ifndef TNT_DEV
|
||||
# define UTILS_PRIVATE __attribute__((visibility("hidden")))
|
||||
|
||||
@@ -107,7 +107,7 @@ private:
|
||||
friend ostream& flush(ostream& s) noexcept;
|
||||
|
||||
enum type {
|
||||
SHORT, USHORT, CHAR, UCHAR, INT, UINT, LONG, ULONG, LONG_LONG, ULONG_LONG, DOUBLE,
|
||||
SHORT, USHORT, CHAR, UCHAR, INT, UINT, LONG, ULONG, LONG_LONG, ULONG_LONG, FLOAT, DOUBLE,
|
||||
LONG_DOUBLE
|
||||
};
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ using LightManager = filament::LightManager;
|
||||
void applySettings(Engine* engine, const ViewSettings& settings, View* dest);
|
||||
void applySettings(Engine* engine, const MaterialSettings& settings, MaterialInstance* dest);
|
||||
void applySettings(Engine* engine, const LightSettings& settings, IndirectLight* ibl, utils::Entity sunlight,
|
||||
utils::Entity* sceneLights, size_t sceneLightCount, LightManager* lm, Scene* scene, View* view);
|
||||
const utils::Entity* sceneLights, size_t sceneLightCount, LightManager* lm, Scene* scene, View* view);
|
||||
void applySettings(Engine* engine, const ViewerOptions& settings, Camera* camera, Skybox* skybox,
|
||||
Renderer* renderer);
|
||||
|
||||
@@ -160,6 +160,10 @@ struct DynamicLightingSettings {
|
||||
float zLightFar = 100;
|
||||
};
|
||||
|
||||
struct FogSettings {
|
||||
Texture* fogColorTexture = nullptr;
|
||||
};
|
||||
|
||||
// This defines fields in the same order as the setter methods in filament::View.
|
||||
struct ViewSettings {
|
||||
// standalone View settings
|
||||
@@ -185,6 +189,7 @@ struct ViewSettings {
|
||||
// Custom View Options
|
||||
ColorGradingSettings colorGrading;
|
||||
DynamicLightingSettings dynamicLighting;
|
||||
FogSettings fogSettings;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -204,6 +209,9 @@ struct LightSettings {
|
||||
LightManager::ShadowOptions shadowOptions;
|
||||
SoftShadowOptions softShadowOptions;
|
||||
float sunlightIntensity = 100000.0f;
|
||||
float sunlightHaloSize = 10.0f;
|
||||
float sunlightHaloFalloff = 80.0f;
|
||||
float sunlightAngularRadius = 1.9f;
|
||||
math::float3 sunlightDirection = {0.6, -1.0, -0.8};
|
||||
math::float3 sunlightColor = filament::Color::toLinear<filament::ACCURATE>({ 0.98, 0.92, 0.89});
|
||||
float iblIntensity = 30000.0f;
|
||||
@@ -214,6 +222,8 @@ struct ViewerOptions {
|
||||
float cameraAperture = 16.0f;
|
||||
float cameraSpeed = 125.0f;
|
||||
float cameraISO = 100.0f;
|
||||
float cameraNear = 0.1f;
|
||||
float cameraFar = 100.0f;
|
||||
float groundShadowStrength = 0.75f;
|
||||
bool groundPlaneEnabled = false;
|
||||
bool skyboxEnabled = true;
|
||||
|
||||
@@ -234,8 +234,6 @@ public:
|
||||
private:
|
||||
using SceneMask = gltfio::NodeManager::SceneMask;
|
||||
|
||||
void updateIndirectLight();
|
||||
|
||||
bool isRemoteMode() const { return mAsset == nullptr; }
|
||||
|
||||
void sceneSelectionUI();
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:727ae0b0182f8396c773d03595a75999c4319d910efd671351d76c31acf9727f
|
||||
size 5040760
|
||||
oid sha256:e1e044f3b3e95fee3edc6debe1a92bd012c9d65e5391e2731a93c8157bbc56d6
|
||||
size 5419176
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f372cfaffd87f10a19c711b83ab9812e3837a6c7ebfc85580c27debe170ee547
|
||||
size 1840568
|
||||
oid sha256:d824fb83a754483b0f0e9ec5f38586a957db8701908368456b3a7e8d0a687553
|
||||
size 1891912
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:57929e8746f231f84c32cfa99fb3b4858a9b8e75f447fe191dc47759b9eec8fe
|
||||
size 169376
|
||||
oid sha256:dfde12c8171576c3899fb162e65bf4b1ba259f58456dac7813f3c2c12289072d
|
||||
size 168408
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f452831b344a41be49175695b5afe6ac2b1f8d5864194d501a044928a4acad0d
|
||||
size 1190936
|
||||
oid sha256:d0ce847e34c51384069e6d813cbcd1aa3913382cb5d34654231b7de4b941882b
|
||||
size 1179768
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:aa5555078f560713f905990f4f09514cfba5b7528a9dc576a6f5d1790577aa56
|
||||
size 8222192
|
||||
oid sha256:17f1e396afdaf7bc4766f2b39ec4c31239e5caefb909a6bf53e5c4e3d888edcd
|
||||
size 8512688
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b5224a5a0db2f0eb1457eecbb4439ccd8468cf362c9bb83e997bb64426bb8e9c
|
||||
size 237120
|
||||
oid sha256:a6de84bd277fbc9582e0df6840c05368405661eec81e3e2a6dc8af40a0349234
|
||||
size 241048
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b49556c745e6bb4ffeecf7f7dd335f8437843e11d5cc959b87c2e7317500aa6d
|
||||
size 193104
|
||||
oid sha256:6b18b76e0b97a2f2fa5ead6ba3a0d2ea2051341ca1a6368058b2025ac342be81
|
||||
size 198000
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7bcd1671a33ffee2804c62a7a5b19229524645a43825a47a943ecd179a61820c
|
||||
size 110068064
|
||||
oid sha256:da27790d62d20ce89cfed64ab400a25a55b6b6fd2273f2ad2fcad842006daa83
|
||||
size 115257128
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8d9e6fe650240c455ff85fbafd3a1d38600bf7ddd6d1006f0813c27388651a22
|
||||
size 1909248
|
||||
oid sha256:c924851f26120c2ece81ffe46a22b7b9e7d599fd57d6a6092d2b0067f3202a46
|
||||
size 2163592
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:65af7056a290d8cee4a70d310dc05489479c574e5d6811746e99593c81a682f0
|
||||
size 181840
|
||||
oid sha256:f914249a9ebb0b1591607656a9657b7a964676052a663427a34590fa3b7c564b
|
||||
size 228376
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c4672339739201dd750c6072692d000ceea80e2547fbcf868364fd72b474d284
|
||||
size 11750664
|
||||
oid sha256:bc538575c4e30d0f41fd6708f6d1d3c7c3e9e157a719e7eb94914f88df82d10b
|
||||
size 12595392
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5ff97e7f4605648fc6529428211bbfda761372dc27b8a625d5ddabde6da25860
|
||||
size 138664
|
||||
oid sha256:ea61594db369d10fa6d6ce6ca4f4ad38417b6ca6f48e718b11011005508dcbc5
|
||||
size 146360
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:24bdc4d65f7dbba8349bdbd2a79e0cd8d2eae8e899f60dd81473d9724043f79f
|
||||
size 279808
|
||||
oid sha256:de37c101e8489e462b8d6e98297b8ef3aca41c95226c5c2f89998a1a1e1ded97
|
||||
size 397936
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d8d2de200dcf24aef51f0de4c67ec2b9ec52e11d790b95b3cedf1ed33dd96cdb
|
||||
size 4159392
|
||||
oid sha256:369c95d496cdc92522cdddb18e1f4a3cf58f85871036ca0a608d715de01048dc
|
||||
size 4163864
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:da81f59acfcaab798d26c0e2e77fffb4c43b00a1c98dfb6ba9d8993ebfdf46d9
|
||||
size 974968
|
||||
oid sha256:173810d56015e9b63df61204006bcfd06513d76024c34480916b43aeb1831cd4
|
||||
size 956936
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cf69b4695234b586cf8703b7e0cdc80d369deac7da76a449b376bf9532a8e720
|
||||
size 1175464
|
||||
oid sha256:ce9d5f52667351a837e4301ed9711517181aede24d7247b32dde56fb769a8b16
|
||||
size 1140504
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9b6466eae2193826b9b8523c8718f00e278d7ff5408ff13c2d196fce05fb1982
|
||||
size 388912
|
||||
oid sha256:85298bf987d5ba877142b63ba8c6e637bd227faeb9195b3f3e59fe9f461067ba
|
||||
size 370704
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e8f99dbae75e2fe0db8f7693fce76995815dc553c58018f44bb565c399e51454
|
||||
size 188624
|
||||
oid sha256:893aa4f6c44d391094931dbcc9a26eb4033a5c859abf94af3b9cf020a6a4dcfe
|
||||
size 190616
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3e7db53ca7b330403e43ec84be9fe610faa8d923e7b327d5f1d876f76cf3a833
|
||||
size 572152
|
||||
oid sha256:8d8d6f8293fc06cb8058adea3e9139d842e300e1889e18062c3c25d39089aaf8
|
||||
size 571232
|
||||
|
||||
3
ios/lib/libmikktspace.a
Normal file
3
ios/lib/libmikktspace.a
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e6c1434d302a6992db21c833ef68b63451c6a5121622e56b8952de896ebac638
|
||||
size 125840
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:780b282645aa9f9733a29de049b5b2625cce3d6e634494d847d2f9a5917c21dd
|
||||
size 251560
|
||||
oid sha256:4b5919a771c56c70d919db33b723e4285c8e5b2f49e3010e97a4a1bd071349db
|
||||
size 254376
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ff5a2e3c6282fe0c4af8237500ee46aba884fb2568cb1c1369e44aa619c17435
|
||||
size 234480
|
||||
oid sha256:418000b4a8d3de1ff617c5d2b1bc023b651f02eed2898d998dfd0cfc9443b02d
|
||||
size 198432
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7c91e3145b720f6d4d2d1beaa6c9730db627bcaa53b5495183afefaec3d0c6ec
|
||||
size 664160
|
||||
oid sha256:7d899823872dc4ed38b36c455ac4cd2dec8bf07c6f7b59e9eccf0752b73de2d6
|
||||
size 546064
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b7da234c9d5cb2f9e230b25886727348f20d987d4ac95a98dee6bcc623952a24
|
||||
size 2280400
|
||||
oid sha256:722e3ccd232aca659cf0810c4ac7c37289e5a45009da3eec49d72f43998b47a1
|
||||
size 2369928
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b6a2c66e6baa854d7a28f8c1a2840eac8234cd314592a3a8fb311aece12be170
|
||||
size 136480
|
||||
oid sha256:0ee58ba6a64e3e42a3749f53666b4a43688c5fa4da0f107f7006d60503d34488
|
||||
size 130864
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:86b54c73185d521cfda519b3aede98a0a856a634887cf6a137cc7e69189afa3d
|
||||
size 992880
|
||||
oid sha256:9ad868ab35518fa24331520d92567942d660b0958432020b2de9ac33e6575240
|
||||
size 1011088
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0af2880fbb48f85a0f9ec97b6196750c48c10f97a3d3d3e992d6b6e2674a56fc
|
||||
size 1778328
|
||||
oid sha256:1d2901b004a5d437efd94e07c15da2e2d905b7880fb7b8f51279a59cfdfa37b3
|
||||
size 1744952
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b5c1772d372e8dfbeb2b17b3d4350c12271f8d1ab48884f2d76535c9cf4747fd
|
||||
size 8984
|
||||
oid sha256:44d8bdd21fffff9b0491720a86132f5c043bf277599ce3bc9795d6a4303e7921
|
||||
size 8992
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9f7f504a3313b17e32984219a0352d4525180195b45a9e99decd485f4c38caf0
|
||||
size 5171008
|
||||
oid sha256:849c1898060222ff8e14a0db79f85f7e55553f356a484d63d577c16919fb7743
|
||||
size 3733856
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
@@ -824,10 +830,10 @@ void FilamentViewer::updateViewportAndCameraProjection(
|
||||
const double aspect = (double)width / height;
|
||||
|
||||
Camera& cam =_view->getCamera();
|
||||
cam.setLensProjection(_cameraFocalLength, aspect, kNearPlane,
|
||||
cam.setLensProjection(_cameraFocalLength, 1.0f, kNearPlane,
|
||||
kFarPlane);
|
||||
|
||||
// cam.setScaling({1.0 / aspect, 1.0});
|
||||
cam.setScaling({1.0 / aspect, 1.0});
|
||||
|
||||
Log("Set viewport to width: %d height: %d aspect %f scaleFactor : %f", width, height, aspect,
|
||||
contentScaleFactor);
|
||||
|
||||
@@ -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<void*()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<EntityId()> 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<void()> 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<void()> 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<EntityId()> 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<EntityId()> 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<bool()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void*()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void*()> 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<void()> 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<void()> 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(
|
||||
@@ -356,22 +196,20 @@ extern "C" {
|
||||
EntityId asset,
|
||||
const char* const entityName,
|
||||
const float* const morphData,
|
||||
int numMorphWeights,
|
||||
const int* const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs) {
|
||||
|
||||
//std::packaged_task<void()> lambda([=]() mutable {
|
||||
return ((AssetManager*)assetManager)->setMorphAnimationBuffer(
|
||||
asset,
|
||||
entityName,
|
||||
morphData,
|
||||
numMorphWeights,
|
||||
morphIndices,
|
||||
numMorphTargets,
|
||||
numFrames,
|
||||
frameLengthInMs
|
||||
);
|
||||
//});
|
||||
// auto fut = _tp->add_task(lambda);
|
||||
// fut.wait();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_bone_animation(
|
||||
@@ -384,7 +222,6 @@ extern "C" {
|
||||
const char** const meshNames,
|
||||
int numMeshTargets,
|
||||
float frameLengthInMs) {
|
||||
//std::packaged_task<void()> lambda([=]() mutable {
|
||||
((AssetManager*)assetManager)->setBoneAnimationBuffer(
|
||||
asset,
|
||||
frameData,
|
||||
@@ -395,10 +232,7 @@ extern "C" {
|
||||
numMeshTargets,
|
||||
frameLengthInMs
|
||||
);
|
||||
//});
|
||||
// auto fut = _tp->add_task(lambda);
|
||||
// fut.wait();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -435,13 +269,10 @@ extern "C" {
|
||||
EntityId asset,
|
||||
int index,
|
||||
bool loop,
|
||||
bool reverse) {
|
||||
|
||||
//std::packaged_task<void()> lambda([=]() mutable {
|
||||
((AssetManager*)assetManager)->playAnimation(asset, index, loop, reverse);
|
||||
//});
|
||||
// auto fut = _tp->add_task(lambda);
|
||||
// fut.wait();
|
||||
bool reverse,
|
||||
bool replaceActive,
|
||||
float crossfade) {
|
||||
((AssetManager*)assetManager)->playAnimation(asset, index, loop, reverse, replaceActive, crossfade);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_animation_frame(
|
||||
@@ -449,23 +280,19 @@ extern "C" {
|
||||
EntityId asset,
|
||||
int animationIndex,
|
||||
int animationFrame) {
|
||||
// //std::packaged_task<void()> lambda([=]() mutable {
|
||||
// ((AssetManager*)assetManager)->setAnimationFrame(asset, animationIndex, animationFrame);
|
||||
// });
|
||||
// auto fut = _tp->add_task(lambda);
|
||||
// fut.wait();
|
||||
}
|
||||
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT float get_animation_duration(void* assetManager, EntityId asset, int animationIndex) {
|
||||
return ((AssetManager*)assetManager)->getAnimationDuration(asset, animationIndex);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT int get_animation_count(
|
||||
void* assetManager,
|
||||
EntityId asset) {
|
||||
//std::packaged_task<int()> lambda([=]() mutable {
|
||||
auto names = ((AssetManager*)assetManager)->getAnimationNames(asset);
|
||||
return names->size();
|
||||
//});
|
||||
// auto fut = _tp->add_task(lambda);
|
||||
// fut.wait();
|
||||
//return fut.get();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void get_animation_name(
|
||||
@@ -474,49 +301,32 @@ extern "C" {
|
||||
char* const outPtr,
|
||||
int index
|
||||
) {
|
||||
//std::packaged_task<void()> 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<int()> lambda([=]() mutable {
|
||||
unique_ptr<vector<string>> 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<void()> lambda([=]() mutable {
|
||||
unique_ptr<vector<string>> 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<void()> 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<void()> 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) {
|
||||
@@ -527,60 +337,36 @@ extern "C" {
|
||||
// ((AssetManager*)assetManager)->setTexture();
|
||||
}
|
||||
|
||||
bool set_material_color(void* assetManager, EntityId asset, const char* meshName, int materialIndex, const float r, const float g, const float b, const float a) {
|
||||
return ((AssetManager*)assetManager)->setMaterialColor(asset, meshName, materialIndex, r, g, b, a);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void transform_to_unit_cube(void* assetManager, EntityId asset) {
|
||||
//std::packaged_task<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> 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<void()> lambda([=]() mutable {
|
||||
return ((AssetManager*)assetManager)->reveal(asset, meshName);
|
||||
//});
|
||||
// auto fut = _tp->add_task(lambda);
|
||||
// fut.wait();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void ios_dummy() {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:polyvox_filament/animations/bone_animation_data.dart';
|
||||
import 'package:polyvox_filament/animations/morph_animation_data.dart';
|
||||
import 'package:polyvox_filament/filament_controller.dart';
|
||||
|
||||
@@ -6,7 +5,6 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:vector_math/vector_math.dart';
|
||||
|
||||
class AnimationBuilder {
|
||||
final FilamentController controller;
|
||||
// BoneAnimationData? BoneAnimationData;
|
||||
double _frameLengthInMs = 0;
|
||||
double _duration = 0;
|
||||
@@ -18,26 +16,25 @@ class AnimationBuilder {
|
||||
|
||||
// List<BoneAnimationData>? _BoneAnimationDatas = null;
|
||||
|
||||
FilamentEntity asset;
|
||||
String meshName;
|
||||
late List<String> morphNames;
|
||||
late List<String> availableMorphs;
|
||||
late List<int> _morphTargets;
|
||||
|
||||
AnimationBuilder(
|
||||
{required this.controller,
|
||||
required this.asset,
|
||||
{required this.availableMorphs,
|
||||
required this.meshName,
|
||||
required int framerate}) {
|
||||
_frameLengthInMs = 1000 / framerate;
|
||||
morphNames = controller.getMorphTargetNames(asset, meshName);
|
||||
}
|
||||
|
||||
void set() {
|
||||
if (morphNames.isEmpty == 0 || _duration == 0 || _frameLengthInMs == 0)
|
||||
MorphAnimationData build() {
|
||||
if (availableMorphs.isEmpty == 0 || _duration == 0 || _frameLengthInMs == 0)
|
||||
throw Exception();
|
||||
|
||||
int numFrames = _duration * 1000 ~/ _frameLengthInMs;
|
||||
|
||||
final morphData = Float32List((numFrames * morphNames.length).toInt());
|
||||
final morphData =
|
||||
List<double>.filled((numFrames * _morphTargets.length).toInt(), 0.0);
|
||||
|
||||
var frameStart = (_interpMorphStart! * 1000) ~/ _frameLengthInMs;
|
||||
var frameEnd = (_interpMorphEnd! * 1000) ~/ _frameLengthInMs;
|
||||
@@ -47,17 +44,16 @@ class AnimationBuilder {
|
||||
|
||||
var val = ((1 - linear) * _interpMorphStartValue!) +
|
||||
(linear * _interpMorphEndValue!);
|
||||
for (int j = 0; j < morphNames.length; j++) {
|
||||
morphData[(i * morphNames.length) + j] = val;
|
||||
for (int j = 0; j < _morphTargets.length; j++) {
|
||||
morphData[(i * _morphTargets.length) + j] = val;
|
||||
}
|
||||
}
|
||||
|
||||
var morphAnimation =
|
||||
MorphAnimationData(meshName, morphData, morphNames, _frameLengthInMs);
|
||||
|
||||
controller.setMorphAnimationData(asset, morphAnimation);
|
||||
// return Tuple2<MorphAnimationData, List<BoneAnimationData>>(
|
||||
// morphAnimation, _BoneAnimationDatas!);
|
||||
return MorphAnimationData(
|
||||
meshName,
|
||||
morphData,
|
||||
_morphTargets.map((i) => availableMorphs[i]).toList(),
|
||||
_morphTargets,
|
||||
_frameLengthInMs);
|
||||
}
|
||||
|
||||
AnimationBuilder setDuration(double secs) {
|
||||
@@ -65,6 +61,11 @@ class AnimationBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
AnimationBuilder setMorphTargets(List<String> names) {
|
||||
_morphTargets = names.map((name) => availableMorphs.indexOf(name)).toList();
|
||||
return this;
|
||||
}
|
||||
|
||||
AnimationBuilder interpolateMorphWeights(
|
||||
double start, double end, double startValue, double endValue) {
|
||||
this._interpMorphStart = start;
|
||||
|
||||
@@ -32,7 +32,11 @@ class DynamicAnimation {
|
||||
}
|
||||
|
||||
var morphAnimationData = MorphAnimationData(
|
||||
meshName ?? "NULL", llf.item2, morphNames, frameLengthInMs);
|
||||
meshName ?? "NULL",
|
||||
llf.item2,
|
||||
morphNames,
|
||||
List<int>.generate(morphNames.length, (index) => index),
|
||||
frameLengthInMs);
|
||||
|
||||
final boneAnimations = <BoneAnimationData>[];
|
||||
|
||||
|
||||
@@ -9,24 +9,25 @@ import 'dart:typed_data';
|
||||
class MorphAnimationData {
|
||||
final String meshName;
|
||||
final List<String> morphNames;
|
||||
final List<int> morphIndices;
|
||||
|
||||
final Float32List data;
|
||||
final List<double> data;
|
||||
|
||||
MorphAnimationData(
|
||||
this.meshName, this.data, this.morphNames, this.frameLengthInMs) {
|
||||
MorphAnimationData(this.meshName, this.data, this.morphNames,
|
||||
this.morphIndices, this.frameLengthInMs) {
|
||||
assert(data.length == morphNames.length * numFrames);
|
||||
}
|
||||
|
||||
int get numMorphWeights => morphNames.length;
|
||||
int get numMorphTargets => morphNames.length;
|
||||
|
||||
int get numFrames => data.length ~/ numMorphWeights;
|
||||
int get numFrames => data.length ~/ numMorphTargets;
|
||||
|
||||
final double frameLengthInMs;
|
||||
|
||||
Iterable<double> getData(String morphName) sync* {
|
||||
int index = morphNames.indexOf(morphName);
|
||||
for (int i = 0; i < numFrames; i++) {
|
||||
yield data[(i * numMorphWeights) + index];
|
||||
yield data[(i * numMorphTargets) + index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Void>;
|
||||
typedef FilamentViewer = Pointer<Void>;
|
||||
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,94 @@ 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", 1.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<Void>.fromAddress(await _channel.invokeMethod("getContext"));
|
||||
final resourceLoader = Pointer<ResourceLoaderWrapper>.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<Void>.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");
|
||||
_textureIdController.add(_textureId);
|
||||
}
|
||||
|
||||
Future resize(int width, int height,
|
||||
{double contentScaleFactor = 1.0}) async {
|
||||
// await setRendering(false);
|
||||
// _textureIdController.add(null);
|
||||
// _nativeLibrary.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 setRendering(true);
|
||||
_textureId = await _channel.invokeMethod("resize",
|
||||
[width * _pixelRatio, height * _pixelRatio, contentScaleFactor]);
|
||||
_textureIdController.add(_textureId);
|
||||
}
|
||||
|
||||
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<Char>());
|
||||
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<Char>());
|
||||
await _channel.invokeMethod("loadSkybox", skyboxPath);
|
||||
}
|
||||
|
||||
void loadIbl(String lightingPath, {double intensity = 30000}) async {
|
||||
_nativeLibrary.load_ibl(
|
||||
_viewer, lightingPath.toNativeUtf8().cast<Char>(), 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 +149,7 @@ class FilamentController {
|
||||
// FOCUSED_SPOT, //!< Physically correct spot light.
|
||||
// SPOT, //!< Spot light with coupling of outer cone and illumination disabled.
|
||||
// };
|
||||
|
||||
FilamentEntity addLight(
|
||||
Future<FilamentEntity> addLight(
|
||||
int type,
|
||||
double colour,
|
||||
double intensity,
|
||||
@@ -211,94 +159,98 @@ 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<Char>(), unlit ? 1 : 0);
|
||||
Future<FilamentEntity> 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<Char>(),
|
||||
relativeResourcePath.toNativeUtf8().cast<Char>());
|
||||
Future<FilamentEntity> 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<double> weights) {
|
||||
var weightPtr = calloc<Float>(weights.length);
|
||||
for (int i = 0; i < weights.length; i++) {
|
||||
weightPtr[i] = weights[i];
|
||||
}
|
||||
|
||||
_nativeLibrary.set_morph_target_weights(_assetManager, asset,
|
||||
meshName.toNativeUtf8().cast<Char>(), weightPtr, weights.length);
|
||||
calloc.free(weightPtr);
|
||||
FilamentEntity asset, String meshName, List<double> weights) async {
|
||||
await _channel.invokeMethod("setMorphTargetWeights",
|
||||
[_assetManager, asset, meshName, weights, weights.length]);
|
||||
}
|
||||
|
||||
List<String> getMorphTargetNames(FilamentEntity asset, String meshName) {
|
||||
var meshNamePtr = meshName.toNativeUtf8().cast<Char>();
|
||||
var count = _nativeLibrary.get_morph_target_name_count(
|
||||
_assetManager, asset, meshNamePtr);
|
||||
var names = <String>[];
|
||||
for (int i = 0; i < count; i++) {
|
||||
var outPtr = calloc<Char>(255);
|
||||
_nativeLibrary.get_morph_target_name(
|
||||
_assetManager, asset, meshNamePtr, outPtr, i);
|
||||
names.add(outPtr.cast<Utf8>().toDartString());
|
||||
}
|
||||
return names;
|
||||
Future<List<String>> getMorphTargetNames(
|
||||
FilamentEntity asset, String meshName) async {
|
||||
var names = await _channel
|
||||
.invokeMethod("getMorphTargetNames", [_assetManager, asset, meshName]);
|
||||
return names.cast<String>();
|
||||
}
|
||||
|
||||
List<String> getAnimationNames(FilamentEntity asset) {
|
||||
var count = _nativeLibrary.get_animation_count(_assetManager, asset);
|
||||
var names = <String>[];
|
||||
for (int i = 0; i < count; i++) {
|
||||
var outPtr = calloc<Char>(255);
|
||||
_nativeLibrary.get_animation_name(_assetManager, asset, outPtr, i);
|
||||
names.add(outPtr.cast<Utf8>().toDartString());
|
||||
}
|
||||
return names;
|
||||
Future<List<String>> getAnimationNames(FilamentEntity asset) async {
|
||||
var names = await _channel
|
||||
.invokeMethod("getAnimationNames", [_assetManager, asset]);
|
||||
return names.cast<String>();
|
||||
}
|
||||
|
||||
Future<double> getAnimationDuration(
|
||||
FilamentEntity asset, int animationIndex) async {
|
||||
var duration = await _channel.invokeMethod(
|
||||
"getAnimationDuration", [_assetManager, asset, animationIndex]);
|
||||
return duration as double;
|
||||
}
|
||||
|
||||
///
|
||||
@@ -308,19 +260,16 @@ class FilamentController {
|
||||
///
|
||||
void setMorphAnimationData(
|
||||
FilamentEntity asset, MorphAnimationData animation) async {
|
||||
var data = calloc<Float>(animation.data.length);
|
||||
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<Char>(),
|
||||
data,
|
||||
animation.numMorphWeights,
|
||||
animation.numFrames,
|
||||
animation.frameLengthInMs);
|
||||
calloc.free(data);
|
||||
await _channel.invokeMethod("setMorphAnimation", [
|
||||
_assetManager,
|
||||
asset,
|
||||
animation.meshName,
|
||||
animation.data,
|
||||
animation.animatedMorphIndices,
|
||||
animation.numMorphTargets,
|
||||
animation.numFrames,
|
||||
animation.frameLengthInMs
|
||||
]);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -349,84 +298,93 @@ 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,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0}) async {
|
||||
await _channel.invokeMethod("playAnimation", [
|
||||
_assetManager,
|
||||
asset,
|
||||
index,
|
||||
loop ? 1 : 0,
|
||||
reverse ? 1 : 0,
|
||||
replaceActive,
|
||||
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<Char>() ?? nullptr) !=
|
||||
1) {
|
||||
if (await _channel.invokeMethod("setCamera", [asset, name]) != true) {
|
||||
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<double> matrix) async {
|
||||
@@ -435,42 +393,59 @@ 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 setMaterialColor(FilamentEntity asset, String meshName,
|
||||
int materialIndex, Color color) async {
|
||||
await _channel.invokeMethod("setMaterialColor", [
|
||||
_assetManager,
|
||||
asset,
|
||||
meshName,
|
||||
materialIndex,
|
||||
[
|
||||
color.red.toDouble() / 255.0,
|
||||
color.green.toDouble() / 255.0,
|
||||
color.blue.toDouble() / 255.0,
|
||||
color.alpha.toDouble() / 255.0
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
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<Char>()) !=
|
||||
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<Char>()) !=
|
||||
void reveal(FilamentEntity asset, String meshName) async {
|
||||
if (await _channel
|
||||
.invokeMethod("revealMesh", [_assetManager, asset, meshName]) !=
|
||||
1) {
|
||||
throw Exception("Failed to reveal mesh $meshName");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'dart:async';
|
||||
@@ -55,73 +56,98 @@ class FilamentWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _FilamentWidgetState extends State<FilamentWidget> {
|
||||
StreamSubscription? _listener;
|
||||
|
||||
StreamSubscription? _initializationListener;
|
||||
StreamSubscription? _textureIdListener;
|
||||
int? _textureId;
|
||||
bool _resizing = false;
|
||||
bool _hasViewer = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_listener = widget.controller.onInitializationRequested.listen((_) {
|
||||
_initializationListener =
|
||||
widget.controller.onInitializationRequested.listen((_) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
var size = ((context.findRenderObject()) as RenderBox).size;
|
||||
print(
|
||||
"Requesting creation of Filament back-end texture/viewer for viewport size $size");
|
||||
await widget.controller
|
||||
.createViewer(size.width.toInt(), size.height.toInt());
|
||||
print("Filament texture/viewer created.");
|
||||
_listener!.cancel();
|
||||
_listener = null;
|
||||
setState(() {
|
||||
_hasViewer = true;
|
||||
});
|
||||
|
||||
_initializationListener!.cancel();
|
||||
_initializationListener = null;
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
var size = ((context.findRenderObject()) as RenderBox).size;
|
||||
widget.controller.resize(size.width.toInt(), size.height.toInt());
|
||||
print("RESIZED IN POST FRAME CALLBACK TO $size");
|
||||
});
|
||||
setState(() {});
|
||||
});
|
||||
});
|
||||
_textureIdListener = widget.controller.textureId.listen((int? textureId) {
|
||||
setState(() {
|
||||
_textureId = textureId;
|
||||
});
|
||||
setState(() {});
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_listener?.cancel();
|
||||
_initializationListener?.cancel();
|
||||
_textureIdListener?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StreamBuilder(
|
||||
stream: widget.controller.textureId,
|
||||
builder: (ctx, AsyncSnapshot<int?> textureId) {
|
||||
if (textureId.data == null) {
|
||||
return Container();
|
||||
}
|
||||
return LayoutBuilder(builder: ((context, constraints) {
|
||||
print("constraints $constraints");
|
||||
if (_textureId == null) {
|
||||
return Container(color: Colors.transparent);
|
||||
}
|
||||
|
||||
var texture = Texture(
|
||||
key: ObjectKey("texture_${textureId.data}"),
|
||||
textureId: textureId.data!,
|
||||
filterQuality: FilterQuality.high,
|
||||
);
|
||||
return LayoutBuilder(
|
||||
builder: ((context, constraints) => SizedBox(
|
||||
height: constraints.maxHeight,
|
||||
width: constraints.maxWidth,
|
||||
child: ResizeObserver(
|
||||
onResized: (Size oldSize, Size newSize) async {
|
||||
// setState(() {
|
||||
// _resizing = true;
|
||||
// });
|
||||
var texture = Texture(
|
||||
key: ObjectKey("texture_$_textureId"),
|
||||
textureId: _textureId!,
|
||||
filterQuality: FilterQuality.high,
|
||||
);
|
||||
return SizedBox(
|
||||
height: constraints.maxHeight,
|
||||
width: constraints.maxWidth,
|
||||
child: ResizeObserver(
|
||||
onResized: (Size oldSize, Size newSize) async {
|
||||
if (!_hasViewer) {
|
||||
return;
|
||||
}
|
||||
print("RESIZE OBSERVER $newSize");
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
setState(() {
|
||||
_resizing = true;
|
||||
});
|
||||
|
||||
await widget.controller.resize(
|
||||
newSize.width.toInt(), newSize.height.toInt());
|
||||
setState(() {
|
||||
_resizing = false;
|
||||
});
|
||||
},
|
||||
child: Platform.isLinux
|
||||
? _resizing
|
||||
? Container()
|
||||
: Transform(
|
||||
alignment: Alignment.center,
|
||||
transform: Matrix4.rotationX(
|
||||
pi), // TODO - this rotation is due to OpenGL texture coordinate working in a different space from Flutter, can we move this to the C++ side somewhere?
|
||||
child: texture)
|
||||
: texture))));
|
||||
});
|
||||
await widget.controller
|
||||
.resize(newSize.width.toInt(), newSize.height.toInt());
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
setState(() {
|
||||
_resizing = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
child: Platform.isLinux
|
||||
? _resizing
|
||||
? Container()
|
||||
: Transform(
|
||||
alignment: Alignment.center,
|
||||
transform: Matrix4.rotationX(
|
||||
pi), // TODO - this rotation is due to OpenGL texture coordinate working in a different space from Flutter, can we move this to the C++ side somewhere?
|
||||
child: texture)
|
||||
: texture));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,21 +450,6 @@ class NativeLibrary {
|
||||
late final _set_frame_interval = _set_frame_intervalPtr
|
||||
.asFunction<void Function(ffi.Pointer<ffi.Void>, double)>();
|
||||
|
||||
ffi.Pointer<ffi.Void> get_renderer(
|
||||
ffi.Pointer<ffi.Void> viewer,
|
||||
) {
|
||||
return _get_renderer(
|
||||
viewer,
|
||||
);
|
||||
}
|
||||
|
||||
late final _get_rendererPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<ffi.Void> Function(
|
||||
ffi.Pointer<ffi.Void>)>>('get_renderer');
|
||||
late final _get_renderer = _get_rendererPtr
|
||||
.asFunction<ffi.Pointer<ffi.Void> Function(ffi.Pointer<ffi.Void>)>();
|
||||
|
||||
void update_viewport_and_camera_projection(
|
||||
ffi.Pointer<ffi.Void> viewer,
|
||||
int width,
|
||||
@@ -652,7 +637,8 @@ class NativeLibrary {
|
||||
int asset,
|
||||
ffi.Pointer<ffi.Char> entityName,
|
||||
ffi.Pointer<ffi.Float> morphData,
|
||||
int numMorphWeights,
|
||||
ffi.Pointer<ffi.Int> morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
double frameLengthInMs,
|
||||
) {
|
||||
@@ -661,7 +647,8 @@ class NativeLibrary {
|
||||
asset,
|
||||
entityName,
|
||||
morphData,
|
||||
numMorphWeights,
|
||||
morphIndices,
|
||||
numMorphTargets,
|
||||
numFrames,
|
||||
frameLengthInMs,
|
||||
);
|
||||
@@ -674,12 +661,13 @@ class NativeLibrary {
|
||||
EntityId,
|
||||
ffi.Pointer<ffi.Char>,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Pointer<ffi.Int>,
|
||||
ffi.Int,
|
||||
ffi.Int,
|
||||
ffi.Float)>>('set_morph_animation');
|
||||
late final _set_morph_animation = _set_morph_animationPtr.asFunction<
|
||||
int Function(ffi.Pointer<ffi.Void>, int, ffi.Pointer<ffi.Char>,
|
||||
ffi.Pointer<ffi.Float>, int, int, double)>();
|
||||
ffi.Pointer<ffi.Float>, ffi.Pointer<ffi.Int>, int, int, double)>();
|
||||
|
||||
void set_bone_animation(
|
||||
ffi.Pointer<ffi.Void> assetManager,
|
||||
@@ -735,6 +723,8 @@ class NativeLibrary {
|
||||
int index,
|
||||
int loop,
|
||||
int reverse,
|
||||
int replaceActive,
|
||||
double crossfade,
|
||||
) {
|
||||
return _play_animation(
|
||||
assetManager,
|
||||
@@ -742,15 +732,17 @@ class NativeLibrary {
|
||||
index,
|
||||
loop,
|
||||
reverse,
|
||||
replaceActive,
|
||||
crossfade,
|
||||
);
|
||||
}
|
||||
|
||||
late final _play_animationPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId, ffi.Int, ffi.Int,
|
||||
ffi.Int)>>('play_animation');
|
||||
late final _play_animation = _play_animationPtr
|
||||
.asFunction<void Function(ffi.Pointer<ffi.Void>, int, int, int, int)>();
|
||||
ffi.Int, ffi.Int, ffi.Float)>>('play_animation');
|
||||
late final _play_animation = _play_animationPtr.asFunction<
|
||||
void Function(ffi.Pointer<ffi.Void>, int, int, int, int, int, double)>();
|
||||
|
||||
void set_animation_frame(
|
||||
ffi.Pointer<ffi.Void> assetManager,
|
||||
@@ -830,6 +822,25 @@ class NativeLibrary {
|
||||
late final _get_animation_name = _get_animation_namePtr.asFunction<
|
||||
void Function(ffi.Pointer<ffi.Void>, int, ffi.Pointer<ffi.Char>, int)>();
|
||||
|
||||
double get_animation_duration(
|
||||
ffi.Pointer<ffi.Void> assetManager,
|
||||
int asset,
|
||||
int index,
|
||||
) {
|
||||
return _get_animation_duration(
|
||||
assetManager,
|
||||
asset,
|
||||
index,
|
||||
);
|
||||
}
|
||||
|
||||
late final _get_animation_durationPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Float Function(ffi.Pointer<ffi.Void>, EntityId,
|
||||
ffi.Int)>>('get_animation_duration');
|
||||
late final _get_animation_duration = _get_animation_durationPtr
|
||||
.asFunction<double Function(ffi.Pointer<ffi.Void>, int, int)>();
|
||||
|
||||
void get_morph_target_name(
|
||||
ffi.Pointer<ffi.Void> assetManager,
|
||||
int asset,
|
||||
@@ -1484,13 +1495,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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user