feat! js_interop improvements

This commit is contained in:
Nick Fisher
2025-05-07 17:06:38 +08:00
parent 63e2dcd0ca
commit 2f16908992
159 changed files with 12989 additions and 8377 deletions
+21
View File
@@ -0,0 +1,21 @@
name: example_web
description: A sample command-line application.
version: 1.0.0
# repository: https://github.com/my_org/my_repo
environment:
sdk: ^3.3.0
dependencies:
thermion_dart:
path: ../../../thermion_dart
native_toolchain_c: ^0.9.0
native_assets_cli: ^0.12.0
logging: ^1.3.0
dev_dependencies:
lints: ^3.0.0
test: ^1.24.0
build_runner: ^2.4.13
build_test: ^2.2.2
build_web_compilers: ^4.0.11
+1
View File
@@ -0,0 +1 @@
../../../assets/
+102
View File
@@ -0,0 +1,102 @@
import 'dart:async';
import 'dart:js_interop';
import 'dart:math';
import 'package:web/web.dart';
import 'package:logging/logging.dart';
import 'package:thermion_dart/thermion_dart.dart' hide NativeLibrary;
import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
import 'package:thermion_dart/src/filament/src/implementation/resource_loader.dart';
import 'web_input_handler.dart';
import 'package:thermion_dart/src/bindings/src/thermion_dart_js_interop.g.dart';
void main(List<String> arguments) async {
Logger.root.onRecord.listen((record) {
print(record);
});
NativeLibrary.initBindings("thermion_dart");
final canvas =
document.getElementById("thermion_canvas") as HTMLCanvasElement;
try {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
} catch (err) {
print(err.toString());
}
final config =
FFIFilamentConfig(sharedContext: nullptr.cast(), backend: Backend.OPENGL);
await FFIFilamentApp.create(config: config);
var swapChain = await FilamentApp.instance!
.createHeadlessSwapChain(canvas.width, canvas.height);
final viewer = ThermionViewerFFI(loadAssetFromUri: defaultResourceLoader);
await viewer.initialized;
await FilamentApp.instance!.setClearOptions(1.0, 0.0, 0.0, 1.0);
await FilamentApp.instance!.register(swapChain, viewer.view);
await viewer.setViewport(canvas.width, canvas.height);
await viewer.setRendering(true);
final rnd = Random();
// ignore: prefer_function_declarations_over_variables
bool resizing = false;
// ignore: prefer_function_declarations_over_variables
final resizer = () async {
if (resizing) {
return;
}
try {
resizing = true;
await viewer.setViewport(canvas.clientWidth, canvas.clientHeight);
Thermion_resizeCanvas(canvas.clientWidth, canvas.clientHeight);
} catch (err) {
print(err);
} finally {
resizing = false;
}
};
// ignore: unused_local_variable, prefer_function_declarations_over_variables
final jsWrapper = () {
var promise = resizer().toJS;
return promise;
};
window.addEventListener('resize', jsWrapper.toJS);
// // await FilamentApp.instance!.render();
// // await Future.delayed(Duration(seconds: 1));
// // await FilamentApp.instance!.setClearOptions(1.0, 1.0, 0.0, 1.0);
// // await FilamentApp.instance!.render();
// // await Future.delayed(Duration(seconds: 1));
await viewer.loadSkybox("assets/default_env_skybox.ktx");
await viewer.loadGltf("assets/cube.glb");
final camera = await viewer.getActiveCamera();
var zOffset = 10.0;
final inputHandler = DelegateInputHandler.flight(viewer);
final webInputHandler =
WebInputHandler(inputHandler: inputHandler, canvas: canvas);
await camera.lookAt(Vector3(0, 0, zOffset));
DateTime lastRender = DateTime.now();
while (true) {
var stackPtr = stackSave();
var now = DateTime.now();
await FilamentApp.instance!.requestFrame();
now = DateTime.now();
var timeSinceLast =
now.microsecondsSinceEpoch - lastRender.microsecondsSinceEpoch;
lastRender = now;
if (timeSinceLast < 1667) {
var waitFor = 1667 - timeSinceLast;
await Future.delayed(Duration(microseconds: waitFor));
}
stackRestore(stackPtr);
// inputHandler.keyDown(PhysicalKey.S);
// await camera.lookAt(Vector3(0,0,zOffset));
// zOffset +=0.1;
}
}
+35
View File
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="./thermion_dart.js"></script>
<script type="module">
try {
window.thermion_dart = await thermion_dart();
} catch(err) {
console.error(err);
}
const script = document.createElement('script')
script.src = 'example.dart.js'
document.head.append(script);
</script>
<style>
html, body {
margin:0;
padding:0;
}
canvas {
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
width:100%;
height:100%;
}
</style>
</head>
<body>
<canvas id="thermion_canvas"></canvas>
</body>
</html>
+35
View File
@@ -0,0 +1,35 @@
<html>
<head>
<script src="thermion_dart.js"></script>
<style>
html, body {
margin:0;
padding:0;
}
canvas {
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
width:100%;
height:100%;
}
</style>
</head>
<script type="module">
try {
window.thermion_dart = await thermion_dart();
} catch(err) {
console.error(err);
}
const dartModulePromise = WebAssembly.compileStreaming(fetch('example.wasm'));
const imports = {};
const dart2wasm_runtime = await import('./example.mjs');
const moduleInstance = await dart2wasm_runtime.instantiate(dartModulePromise, imports);
await dart2wasm_runtime.invoke(moduleInstance);
</script>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
+22
View File
@@ -0,0 +1,22 @@
import { readFile } from 'fs/promises';
import { compile } from './example.mjs';
import thermion_dart from './thermion_dart.js';
async function runDartWasm() {
globalThis['thermion_dart'] = await thermion_dart();
const wasmBytes = await readFile('example.wasm');
const compiledApp = await compile(wasmBytes);
const instantiatedApp = await compiledApp.instantiate({});
try {
instantiatedApp.invokeMain();
} catch(err) {
console.error("Failed");
console.error(err);
}
}
runDartWasm().catch(console.error);
+1
View File
@@ -0,0 +1 @@
../../../../thermion_dart/native/web/build/build/out/thermion_dart.js
+1
View File
@@ -0,0 +1 @@
../../../../thermion_dart/native/web/build/build/out/thermion_dart.wasm
@@ -0,0 +1,233 @@
import 'dart:js_interop';
import 'package:web/web.dart' as web;
import 'package:thermion_dart/thermion_dart.dart';
class WebInputHandler {
final DelegateInputHandler inputHandler;
final web.HTMLCanvasElement canvas;
late double pixelRatio;
final Map<int, Vector2> _touchPositions = {};
WebInputHandler({
required this.inputHandler,
required this.canvas,
}) {
pixelRatio = web.window.devicePixelRatio;
_initializeEventListeners();
}
void _initializeEventListeners() {
canvas.addEventListener('mousedown', _onMouseDown.toJS);
canvas.addEventListener('mousemove', _onMouseMove.toJS);
canvas.addEventListener('mouseup', _onMouseUp.toJS);
canvas.addEventListener('wheel', _onMouseWheel.toJS);
web.window.addEventListener('keydown', _onKeyDown.toJS);
web.window.addEventListener('keyup', _onKeyUp.toJS);
canvas.addEventListener('touchstart', _onTouchStart.toJS);
canvas.addEventListener('touchmove', _onTouchMove.toJS);
canvas.addEventListener('touchend', _onTouchEnd.toJS);
canvas.addEventListener('touchcancel', _onTouchCancel.toJS);
}
void _onMouseDown(web.MouseEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final isMiddle = event.button == 1;
inputHandler.onPointerDown(localPos, isMiddle);
event.preventDefault();
}
void _onMouseMove(web.MouseEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final delta = Vector2(event.movementX ?? 0, event.movementY ?? 0);
final isMiddle = event.buttons & 4 != 0;
inputHandler.onPointerMove(localPos, delta, isMiddle);
event.preventDefault();
}
void _onMouseUp(web.MouseEvent event) {
final isMiddle = event.button == 1;
inputHandler.onPointerUp(isMiddle);
event.preventDefault();
}
void _onMouseWheel(web.WheelEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final delta = event.deltaY;
inputHandler.onPointerScroll(localPos, delta);
event.preventDefault();
}
void _onKeyDown(web.KeyboardEvent event) {
PhysicalKey? key;
switch (event.code) {
case 'KeyW':
key = PhysicalKey.W;
break;
case 'KeyA':
key = PhysicalKey.A;
break;
case 'KeyS':
key = PhysicalKey.S;
break;
case 'KeyD':
key = PhysicalKey.D;
break;
}
if (key != null) inputHandler.keyDown(key);
event.preventDefault();
}
void _onKeyUp(web.KeyboardEvent event) {
PhysicalKey? key;
switch (event.code) {
case 'KeyW':
key = PhysicalKey.W;
break;
case 'KeyA':
key = PhysicalKey.A;
break;
case 'KeyS':
key = PhysicalKey.S;
break;
case 'KeyD':
key = PhysicalKey.D;
break;
}
if (key != null) inputHandler.keyUp(key);
event.preventDefault();
}
void _onTouchStart(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
final pos = _getLocalPositionFromTouch(touch);
_touchPositions[touch.identifier] = pos;
}
final touchCount = event.touches.toList().length;
if (touchCount == 1) {
final touch = event.touches.toList().first;
final pos = _getLocalPositionFromTouch(touch);
inputHandler.onPointerDown(pos, false);
}
_handleScaleStart(touchCount, null);
event.preventDefault();
}
void _onTouchMove(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
final id = touch.identifier;
final currPos = _getLocalPositionFromTouch(touch);
final prevPos = _touchPositions[id];
if (prevPos != null) {
final delta = currPos - prevPos;
inputHandler.onPointerMove(currPos, delta, false);
}
_touchPositions[id] = currPos;
}
final touchCount = event.touches.toList().length;
if (touchCount >= 2) {
final touches = event.touches.toList().toList();
final touch0 = touches[0];
final touch1 = touches[1];
final pos0 = _getLocalPositionFromTouch(touch0);
final pos1 = _getLocalPositionFromTouch(touch1);
final prevPos0 = _touchPositions[touch0.identifier];
final prevPos1 = _touchPositions[touch1.identifier];
if (prevPos0 != null && prevPos1 != null) {
final prevDist = (prevPos0 - prevPos1).length;
final currDist = (pos0 - pos1).length;
final scale = currDist / prevDist;
final focalPoint = (pos0 + pos1) * 0.5;
inputHandler.onScaleUpdate(
focalPoint,
Vector2(0, 0),
0.0,
0.0,
scale,
touchCount,
0.0,
null,
);
}
}
event.preventDefault();
}
void _onTouchEnd(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
_touchPositions.remove(touch.identifier);
}
final touchCount = event.touches.toList().length;
inputHandler.onScaleEnd(touchCount, 0.0);
event.preventDefault();
}
void _onTouchCancel(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
_touchPositions.remove(touch.identifier);
}
final touchCount = event.touches.toList().length;
inputHandler.onScaleEnd(touchCount, 0.0);
event.preventDefault();
}
void _handleScaleStart(int pointerCount, Duration? sourceTimestamp) {
inputHandler.onScaleStart(Vector2.zero(), pointerCount, sourceTimestamp);
}
Vector2 _getLocalPositionFromEvent(web.Event event) {
final rect = canvas.getBoundingClientRect();
double clientX = 0, clientY = 0;
if (event is web.MouseEvent) {
clientX = event.clientX.toDouble();
clientY = event.clientY.toDouble();
} else if (event is web.TouchEvent) {
final touch = event.touches.toList().firstOrNull;
if (touch != null) {
clientX = touch.clientX;
clientY = touch.clientY;
}
}
return Vector2(
(clientX - rect.left) * pixelRatio,
(clientY - rect.top) * pixelRatio,
);
}
Vector2 _getLocalPositionFromTouch(web.Touch touch) {
final rect = canvas.getBoundingClientRect();
return Vector2(
(touch.clientX - rect.left) * pixelRatio,
(touch.clientY - rect.top) * pixelRatio,
);
}
void dispose() {
canvas.removeEventListener('mousedown', _onMouseDown.toJS);
canvas.removeEventListener('mousemove', _onMouseMove.toJS);
canvas.removeEventListener('mouseup', _onMouseUp.toJS);
canvas.removeEventListener('wheel', _onMouseWheel.toJS);
web.window.removeEventListener('keydown', _onKeyDown.toJS);
web.window.removeEventListener('keyup', _onKeyUp.toJS);
canvas.removeEventListener('touchstart', _onTouchStart.toJS);
canvas.removeEventListener('touchmove', _onTouchMove.toJS);
canvas.removeEventListener('touchend', _onTouchEnd.toJS);
canvas.removeEventListener('touchcancel', _onTouchCancel.toJS);
}
}
+8 -16
View File
@@ -2,19 +2,6 @@
<html> <html>
<head> <head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF"> <base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8"> <meta charset="UTF-8">
@@ -37,12 +24,17 @@
const serviceWorkerVersion = null; const serviceWorkerVersion = null;
</script> </script>
<script src="flutter.js" defer></script> <script src="flutter.js" defer></script>
<script type="text/javascript" src="./thermion_dart.js"></script>
<script type="module">
try {
window.thermion_dart = await thermion_dart();
} catch(err) {
console.error(err);
}
</script>
</head> </head>
<body> <body>
<canvas id="canvas"></canvas>
<div id="flutter-container"></div> <div id="flutter-container"></div>
<script type="text/javascript"> <script type="text/javascript">
window.addEventListener('load', function (ev) { window.addEventListener('load', function (ev) {
@@ -1 +1 @@
../../../assets/thermion_dart.js ../../../../thermion_dart/native/web/build/build/out/thermion_dart.js
@@ -1 +1 @@
../../../assets/thermion_dart.wasm ../../../../thermion_dart/native/web/build/build/out/thermion_dart.wasm
+64
View File
@@ -49,3 +49,67 @@ cmake --build . --target tinyexr --config Release
cmake --build . --target imageio --config Release cmake --build . --target imageio --config Release
cmake --build . --config Debug cmake --build . --config Debug
``` ```
# Web
By default, Filament WASM builds are single-threaded with no support for `-pthread` (`WEBGL_PTHREADS=0`).
This won't work with our current implementation, since at least `-pthread` is needed to support running Filament on a dedicated (non-main) render thread.
However, the multi-threaded Filament WASM build (`WEBGL_PTHREADS=1`, which sets `-pthread`) doesn't work with our current setup (which uses an OffscreenCanvas without proxying, effectively locking the context to a single thread).
To work around, we need to adjust the Filament build configuration to build:
1) a single-threaded library
2) but with `-pthread` enabled
```
./build.sh -p desktop release
mkdir -p out/cmake-webgl-release
cd out/cmake-webgl-release
ln -s ../cmake-release/tools
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DWEBGL=1 \
-DWEBGL_PTHREADS=1 \
-DFILAMENT_SKIP_SAMPLES=1 \
-DZLIB_INCLUDE_DIR=../../../../third_party/libz \
-DCMAKE_TOOLCHAIN_FILE="${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" \
-DCMAKE_C_FLAGS="-pthread" \
-DCMAKE_CXX_FLAGS="-pthread" \
-DIS_HOST_PLATFORM=0 -DZ_HAVE_UNISTD_H=1 -DUSE_ZLIB=1 -DIMPORT_EXECUTABLES_DIR=out \
../../
ninja;
mkdir imageio
cd imageio
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DWEBGL=1 \
-DWEBGL_PTHREADS=1 \
-DFILAMENT_SKIP_SAMPLES=1 \
-DZLIB_INCLUDE_DIR=../../../../third_party/libz \
-DCMAKE_TOOLCHAIN_FILE="${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" \
-DCMAKE_C_FLAGS="-pthread" \
-DCMAKE_CXX_FLAGS="-pthread" \
-DZ_HAVE_UNISTD_H=1 -DUSE_ZLIB=1 -DIMPORT_EXECUTABLES_DIR=out -DCMAKE_CXX_FLAGS="-I../../../libs/image/include -I../../../libs/utils/include -I../../../libs/math/include -I../../../third_party/tinyexr -I../../../third_party/libpng -I../../../third_party/basisu/encoder" \
../../../libs/imageio
ninja
cd ..
mkdir thirdparty/
cd thirdparty/
#find . -type f -exec file {} \; | grep "text" | cut -d: -f1 | xargs dos2unix
for lib in tinyexr libpng libz; do
mkdir -p $lib;
pushd $lib;
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DWEBGL=1 \
-DWEBGL_PTHREADS=1 \
-DFILAMENT_SKIP_SAMPLES=1 \
-DZLIB_INCLUDE_DIR=../../../../third_party/libz \
-DCMAKE_C_FLAGS="-pthread -Wno-reserved-identifier" \
-DCMAKE_CXX_FLAGS="-pthread -Wno-reserved-identifier" \
../../../../third_party/$lib;
ninja;
popd;
done
+2 -7
View File
@@ -1,11 +1,9 @@
output: '../lib/src/viewer/src/ffi/src/thermion_dart.g.dart' output: '../lib/src/bindings/src/thermion_dart_ffi.g.dart'
headers: headers:
entry-points: entry-points:
- '../native/include/c_api/*.h' - '../native/include/c_api/*.h'
- '../native/include/ResourceBuffer.h'
include-directives: include-directives:
- '../native/include/c_api/*.h' - '../native/include/c_api/*.h'
- '../native/include/ResourceBuffer.h'
ffi-native: ffi-native:
assetId: package:thermion_dart/thermion_dart.dart assetId: package:thermion_dart/thermion_dart.dart
ignore-source-errors: true ignore-source-errors: true
@@ -16,7 +14,4 @@ functions:
enums: enums:
as-int: as-int:
include: include:
- TPrimitiveType - .*
- TPixelDataFormat
- TPixelDataType
+9 -14
View File
@@ -1,15 +1,11 @@
output: '../lib/thermion_dart/compatibility/web/thermion_dart.g.dart' output: '../lib/src/bindings/src/thermion_dart_js_interop.g.dart'
headers: headers:
entry-points: entry-points:
- '../native/web/include/ThermionFlutterWebApi.h' - '../native/web/include/ThermionWebApi.h'
- '../native/include/ThermionDartFFIApi.h' - '../native/include/c_api/*.h'
- '../native/include/ThermionDartApi.h'
- '../native/include/ResourceBuffer.h'
include-directives: include-directives:
- '../native/web/include/ThermionFlutterWebApi.h' - '../native/web/include/ThermionWebApi.h'
- '../native/include/ThermionDartFFIApi.h' - '../native/include/c_api/*.h'
- '../native/include/ThermionDartApi.h'
- '../native/include/ResourceBuffer.h'
compiler-opts: compiler-opts:
- "-D__EMSCRIPTEN__" - "-D__EMSCRIPTEN__"
structs: structs:
@@ -20,9 +16,8 @@ unions:
dependency-only: opaque dependency-only: opaque
exclude: exclude:
- '.*' - '.*'
globals:
exclude:
- '.*'
ffi-native:
assetId: thermion_dart
ignore-source-errors: true ignore-source-errors: true
enums:
as-int:
include:
- .*
+7 -8
View File
@@ -1,8 +1,9 @@
import 'dart:io'; import 'dart:io';
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:native_assets_cli/code_assets_builder.dart';
import 'package:native_assets_cli/native_assets_cli.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart'; import 'package:native_toolchain_c/native_toolchain_c.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
@@ -25,6 +26,7 @@ void main(List<String> args) async {
final packageName = input.packageName; final packageName = input.packageName;
final outputDirectory = input.outputDirectory; final outputDirectory = input.outputDirectory;
final targetOS = config.code.targetOS; final targetOS = config.code.targetOS;
final targetArchitecture = config.code.targetArchitecture; final targetArchitecture = config.code.targetArchitecture;
var logPath = path.join( var logPath = path.join(
pkgRootFilePath, ".dart_tool", "thermion_dart", "log", "build.log"); pkgRootFilePath, ".dart_tool", "thermion_dart", "log", "build.log");
@@ -258,9 +260,8 @@ void main(List<String> args) async {
package: "thermion_dart", package: "thermion_dart",
name: "libc++_shared.so", name: "libc++_shared.so",
linkMode: DynamicLoadingBundled(), linkMode: DynamicLoadingBundled(),
os: targetOS,
file: stlPath.uri, file: stlPath.uri,
architecture: targetArchitecture); );
output.assets.addEncodedAsset(libcpp.encode()); output.assets.addEncodedAsset(libcpp.encode());
} }
@@ -274,9 +275,8 @@ void main(List<String> args) async {
package: packageName, package: packageName,
name: "thermion_dart.lib", name: "thermion_dart.lib",
linkMode: DynamicLoadingBundled(), linkMode: DynamicLoadingBundled(),
os: targetOS,
file: importLib.uri, file: importLib.uri,
architecture: targetArchitecture); );
output.assets.addEncodedAsset(libthermion.encode()); output.assets.addEncodedAsset(libthermion.encode());
for (final dir in ["windows/vulkan"]) { for (final dir in ["windows/vulkan"]) {
@@ -298,9 +298,8 @@ void main(List<String> args) async {
package: packageName, package: packageName,
name: "include/$dir/${path.basename(file.path)}", name: "include/$dir/${path.basename(file.path)}",
linkMode: DynamicLoadingBundled(), linkMode: DynamicLoadingBundled(),
os: targetOS,
file: file.uri, file: file.uri,
architecture: targetArchitecture); );
output.assets.addEncodedAsset(include.encode()); output.assets.addEncodedAsset(include.encode());
} }
} }
@@ -0,0 +1,3 @@
export 'src/ffi.dart'
if (dart.library.io) 'src/ffi.dart'
if (dart.library.js_interop) 'src/js_interop.dart';
@@ -1,29 +1,89 @@
export 'thermion_dart_ffi.g.dart';
export 'dart:typed_data';
import 'dart:async'; import 'dart:async';
import 'dart:ffi'; import 'dart:io';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:ffi/ffi.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
export 'package:ffi/ffi.dart'; export 'package:ffi/ffi.dart';
export 'dart:ffi'; export 'dart:ffi' hide Size;
export 'thermion_dart.g.dart';
final allocator = calloc; const FILAMENT_SINGLE_THREADED = false;
const FILAMENT_WASM = false;
bool get IS_WINDOWS => Platform.isWindows;
void using(Pointer ptr, Future Function(Pointer ptr) function) async { class NativeLibrary {
await function.call(ptr); static void initBindings(String name) {
allocator.free(ptr); throw Exception();
}
} }
Future<void> withVoidCallback2(Function() func) async { typedef IntPtrList = Int64List;
final completer = Completer(); typedef Float64 = Double;
void Function() callback = () { typedef PointerClass<T extends NativeType> = Pointer<T>;
func.call(); typedef VoidPointerClass = Pointer<Void>;
completer.complete();
}; class CallbackHolder<T extends Function> {
final nativeCallable = NativeCallable<Void Function()>.listener(callback); final NativeCallable<T> nativeCallable;
RenderThread_addTask(nativeCallable.nativeFunction);
await completer.future; Pointer<NativeFunction<T>> get pointer => nativeCallable.nativeFunction;
nativeCallable.close();
CallbackHolder(this.nativeCallable);
void dispose() {
nativeCallable.close();
}
}
Pointer<T> allocate<T extends NativeType>(int count) {
return calloc.allocate<T>(count * sizeOf<Pointer>());
}
void free(Pointer ptr) {
calloc.free(ptr);
}
Pointer stackSave() {
throw Exception();
}
void stackRestore(Pointer ptr) {
throw Exception();
}
class FinalizableUint8List implements Finalizable {
final Pointer name;
final Uint8List data;
FinalizableUint8List(this.name, this.data);
}
extension GPFBP on void Function(int, double, double, double) {
CallbackHolder<GizmoPickCallbackFunction> asCallback() {
var nativeCallable =
NativeCallable<GizmoPickCallbackFunction>.listener(this);
return CallbackHolder(nativeCallable);
}
}
CallbackHolder<PickCallbackFunction> makePickCallbackFunctionPointer(
DartPickCallbackFunction fn) {
final nc = NativeCallable<PickCallbackFunction>.listener(fn);
final cbh = CallbackHolder(nc);
return cbh;
}
extension VFB on void Function() {
CallbackHolder<Void Function()> asCallback() {
var nativeCallable = NativeCallable<Void Function()>.listener(this);
return CallbackHolder(nativeCallable);
}
}
extension PCBF on DartPickCallbackFunction {
CallbackHolder<PickCallbackFunction> asCallback() {
var nativeCallable = NativeCallable<PickCallbackFunction>.listener(this);
return CallbackHolder(nativeCallable);
}
} }
Future<void> withVoidCallback( Future<void> withVoidCallback(
@@ -75,7 +135,8 @@ Future<double> withFloatCallback(
void Function(double) callback = (double result) { void Function(double) callback = (double result) {
completer.complete(result); completer.complete(result);
}; };
final nativeCallable = NativeCallable<Void Function(Float)>.listener(callback); final nativeCallable =
NativeCallable<Void Function(Float)>.listener(callback);
func.call(nativeCallable.nativeFunction); func.call(nativeCallable.nativeFunction);
await completer.future; await completer.future;
nativeCallable.close(); nativeCallable.close();
@@ -127,3 +188,15 @@ Future<String> withCharPtrCallback(
nativeCallable.close(); nativeCallable.close();
return completer.future; return completer.future;
} }
extension FreeTypedData<T> on TypedData {
void free() {
// noop
}
}
extension DartBigIntExtension on int {
int get toBigInt {
return this;
}
}
@@ -0,0 +1,408 @@
import 'dart:async';
export 'dart:typed_data';
export 'thermion_dart_js_interop.g.dart';
export 'dart:js_interop';
export 'dart:js_interop_unsafe';
import 'package:thermion_dart/src/bindings/src/js_interop.dart';
const FILAMENT_SINGLE_THREADED = true;
const FILAMENT_WASM = true;
const IS_WINDOWS = false;
extension type _NativeLibrary(JSObject _) implements JSObject {
static _NativeLibrary get instance =>
NativeLibrary.instance as _NativeLibrary;
external JSUint8Array _emscripten_make_uint8_buffer(
Pointer<Uint8> ptr, int length);
external JSUint16Array _emscripten_make_uint16_buffer(
Pointer<Uint16> ptr, int length);
external JSInt16Array _emscripten_make_int16_buffer(
Pointer<Int16> ptr, int length);
external JSInt32Array _emscripten_make_int32_buffer(
Pointer<Int32> ptr, int length);
external JSFloat32Array _emscripten_make_f32_buffer(
Pointer<Float32> ptr, int length);
external JSFloat64Array _emscripten_make_f64_buffer(
Pointer<Float64> ptr, int length);
external Pointer _emscripten_get_byte_offset(JSObject obj);
external int _emscripten_stack_get_free();
external void _execute_queue();
@JS('stackSave')
external Pointer<Void> stackSave();
@JS('stackRestore')
external void stackRestore(Pointer<Void> ptr);
}
extension FreeTypedData<T> on TypedData {
void free() {
final ptr = Pointer<Void>(this.offsetInBytes);
ptr.free();
}
}
Pointer<T> getPointer<T extends NativeType>(TypedData data, JSObject obj) {
late Pointer<T> ptr;
if (data.lengthInBytes < 32 * 1024) {
ptr = stackAlloc(data.lengthInBytes).cast<T>();
} else {
ptr = malloc<T>(data.lengthInBytes);
}
return ptr;
}
extension JSBackingBuffer on JSUint8Array {
@JS('buffer')
external JSObject buffer;
}
@JS('Uint8Array')
extension type Uint8ArrayWrapper._(JSObject _) implements JSObject {
external Uint8ArrayWrapper(JSObject buffer, int offset, int length);
}
@JS('Int8Array')
extension type Int8ArrayWrapper._(JSObject _) implements JSObject {
external Int8ArrayWrapper(JSObject buffer, int offset, int length);
}
@JS('Uint16Array')
extension type Uint16ArrayWrapper._(JSObject _) implements JSObject {
external Uint16ArrayWrapper(JSObject buffer, int offset, int length);
}
@JS('Int16Array')
extension type Int16ArrayWrapper._(JSObject _) implements JSObject {
external Int16ArrayWrapper(JSObject buffer, int offset, int length);
}
@JS('Uint32Array')
extension type Uint32ArrayWrapper._(JSObject _) implements JSObject {
external Uint32ArrayWrapper(JSObject buffer, int offset, int length);
}
@JS('Int32Array')
extension type Int32ArrayWrapper._(JSObject _) implements JSObject {
external Int32ArrayWrapper(JSObject buffer, int offset, int length);
}
@JS('Float32Array')
extension type Float32ArrayWrapper._(JSObject _) implements JSObject {
external Float32ArrayWrapper(JSObject buffer, int offset, int length);
}
@JS('Float64Array')
extension type Float64ArrayWrapper._(JSObject _) implements JSObject {
external Float64ArrayWrapper(JSObject buffer, int offset, int length);
}
extension Uint8ListExtension on Uint8List {
Pointer<Uint8> get address {
if (this.lengthInBytes == 0) {
return nullptr;
}
final ptr = getPointer<Uint8>(this, this.toJS);
final bar =
Uint8ArrayWrapper(NativeLibrary.instance.HEAPU8.buffer, ptr, length)
as JSUint8Array;
bar.toDart.setRange(0, length, this);
return ptr;
}
}
extension Float32ListExtension on Float32List {
Pointer<Float32> get address {
final ptr = getPointer<Float32>(this, this.toJS);
final bar =
Float32ArrayWrapper(NativeLibrary.instance.HEAPU8.buffer, ptr, length)
as JSFloat32Array;
bar.toDart.setRange(0, length, this);
return ptr;
}
}
extension Int16ListExtension on Int16List {
Pointer<Int16> get address {
if (this.lengthInBytes == 0) {
return nullptr;
}
final ptr = getPointer<Int16>(this, this.toJS);
final bar = Int16ArrayWrapper(NativeLibrary.instance.HEAPU8, ptr, length)
as JSInt16Array;
bar.toDart.setRange(0, length, this);
return ptr;
}
}
extension Uint16ListExtension on Uint16List {
Pointer<Uint16> get address {
final ptr = getPointer<Uint16>(this, this.toJS);
final bar =
Uint16ArrayWrapper(NativeLibrary.instance.HEAPU8.buffer, ptr, length)
as JSUint16Array;
bar.toDart.setRange(0, length, this);
return ptr;
}
}
extension UInt32ListExtension on Uint32List {
Pointer<Uint32> get address {
if (this.lengthInBytes == 0) {
return nullptr;
}
final ptr = getPointer<Uint32>(this, this.toJS);
final bar = Uint32ArrayWrapper(NativeLibrary.instance.HEAPU8, ptr, length)
as JSUint32Array;
bar.toDart.setRange(0, length, this);
return ptr;
}
}
extension Int32ListExtension on Int32List {
Pointer<Int32> get address {
if (this.lengthInBytes == 0) {
return nullptr;
}
final ptr = getPointer<Int32>(this, this.toJS);
final bar = Int32ArrayWrapper(NativeLibrary.instance.HEAPU8, ptr, length)
as JSInt32Array;
bar.toDart.setRange(0, length, this);
return ptr;
}
}
extension Int64ListExtension on Int64List {
Pointer<Float32> get address {
throw Exception();
}
static Int64List create(int length) {
throw Exception();
}
}
extension Float64ListExtension on Float64List {
Pointer<Float64> get address {
if (this.lengthInBytes == 0) {
return nullptr;
}
final ptr = getPointer<Float64>(this, this.toJS);
final bar =
Float64ArrayWrapper(NativeLibrary.instance.HEAPU8.buffer, ptr, length)
as JSFloat64Array;
bar.toDart.setRange(0, length, this);
return ptr;
}
// static Float64List create(int length) {
// final ptr = malloc(length * 8);
// final buffer = _NativeLibrary.instance._emscripten_make_f64_buffer(ptr.cast(), length).toDart;
// _allocated.add(buffer);
// return buffer;
// }
}
int sizeOf<T extends NativeType>() {
switch (T) {
case Float:
return 4;
default:
throw Exception();
}
}
typedef IntPtrList = Int32List;
typedef Utf8 = Char;
typedef Float = Float32;
typedef Double = Float64;
typedef Bool = bool;
class FinalizableUint8List {
final Pointer name;
final Uint8List data;
FinalizableUint8List(this.name, this.data);
}
class CallbackHolder<T extends Function> {
final Pointer<NativeFunction<T>> pointer;
CallbackHolder(this.pointer);
void dispose() {
pointer.dispose();
}
}
extension DPCF on DartPickCallbackFunction {
CallbackHolder<DartPickCallbackFunction> asCallback() {
final ptr = addFunction<DartPickCallbackFunction>(this.toJS, "viidddd");
final cbh = CallbackHolder(ptr);
return cbh;
}
}
extension GPFBP on void Function(int, double, double, double) {
CallbackHolder<GizmoPickCallbackFunction> asCallback() {
final ptr = addFunction<GizmoPickCallbackFunction>(this.toJS, "viddd");
return CallbackHolder(ptr);
}
}
extension VFCB on void Function() {
CallbackHolder<void Function()> asCallback() {
final ptr = addFunction<void Function()>(this.toJS, "v");
return CallbackHolder(ptr);
}
}
final _completers = <int, Completer>{};
void Function(int) _voidCallback = (int requestId) {
_completers[requestId]!.complete();
_completers.remove(requestId);
};
final _voidCallbackPtr = _voidCallback.addFunction();
Future<void> withVoidCallback(
Function(Pointer<NativeFunction<Void Function()>>) func) async {
final completer = Completer();
final requestId = _completers.length;
_completers[requestId] = completer;
final fn = () {
completer.complete();
};
final ptr = fn.addFunction();
func.call(ptr.cast());
while (!completer.isCompleted) {
_NativeLibrary.instance._execute_queue();
await Future.delayed(Duration(milliseconds: 1));
}
await completer.future;
}
Future<Pointer<T>> withPointerCallback<T extends NativeType>(
Function(Pointer<NativeFunction<Void Function(Pointer<T>)>>) func) async {
final completer = Completer<Pointer<T>>();
// ignore: prefer_function_declarations_over_variables
void Function(Pointer<T>) callback = (Pointer<T> ptr) {
completer.complete(ptr.cast<T>());
};
final onComplete_interopFnPtr = callback.addFunction();
func.call(onComplete_interopFnPtr.cast());
var ptr = await completer.future;
onComplete_interopFnPtr.dispose();
return ptr;
}
Future<bool> withBoolCallback(
Function(Pointer<NativeFunction<Void Function(Bool)>>) func) async {
final completer = Completer<bool>();
// ignore: prefer_function_declarations_over_variables
void Function(int) callback = (int result) {
completer.complete(result == 1);
};
final onComplete_interopFnPtr = callback.addFunction();
func.call(onComplete_interopFnPtr.cast());
await completer.future;
return completer.future;
}
Future<double> withFloatCallback(
void Function(Pointer<NativeFunction<void Function(double)>>) func) async {
final completer = Completer<double>();
// ignore: prefer_function_declarations_over_variables
void Function(double) callback = (double result) {
completer.complete(result);
};
var ptr = callback.addFunction();
func.call(ptr);
await completer.future;
return completer.future;
}
Future<int> withIntCallback(
Function(Pointer<NativeFunction<Void Function(Int32)>>) func) async {
final completer = Completer<int>();
// ignore: prefer_function_declarations_over_variables
void Function(int) callback = (int result) {
completer.complete(result);
};
// final nativeCallable =
// NativeCallable<Void Function(Int32)>.listener(callback);
// func.call(nativeCallable.nativeFunction);
await completer.future;
// nativeCallable.close();
return completer.future;
}
Pointer<T> allocate<T extends NativeType>(int count) {
switch (T) {
case PointerClass:
return malloc(count * 4);
default:
throw Exception(T.toString());
}
}
Future<int> withUInt32Callback(
Function(Pointer<NativeFunction<Void Function(int)>>) func) async {
final completer = Completer<int>();
// ignore: prefer_function_declarations_over_variables
void Function(int) callback = (int result) {
completer.complete(result);
};
// final nativeCallable =
// NativeCallable<Void Function(Uint32)>.listener(callback);
// func.call(nativeCallable.nativeFunction);
await completer.future;
// nativeCallable.close();
return completer.future;
}
Future<String> withCharPtrCallback(
Function(Pointer<NativeFunction<Void Function(Pointer<Char>)>>)
func) async {
final completer = Completer<String>();
// ignore: prefer_function_declarations_over_variables
// void Function(Pointer<Char>) callback = (Pointer<Char> result) {
// completer.complete(result.cast<Utf8>().toDartString());
// };
// final nativeCallable =
// NativeCallable<Void Function(Pointer<Char>)>.listener(callback);
// func.call(nativeCallable.nativeFunction);
await completer.future;
// nativeCallable.close();
return completer.future;
}
extension DartBigIntExtension on int {
BigInt get toBigInt {
return BigInt.from(this);
}
}
Pointer stackSave() => _NativeLibrary.instance.stackSave();
void stackRestore(Pointer ptr) =>
_NativeLibrary.instance.stackRestore(ptr.cast());
void getStackFree() {
print(_NativeLibrary.instance._emscripten_stack_get_free());
}
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -1,4 +1,4 @@
export 'src/filament_app.dart'; export 'src/interface/filament_app.dart';
export 'src/engine.dart'; export 'src/interface/engine.dart';
export 'src/layers.dart'; export 'src/interface/layers.dart';
export 'src/light_options.dart'; export 'src/interface/light_options.dart';
@@ -1,32 +0,0 @@
import 'dart:typed_data';
import '../../viewer/viewer.dart';
class Geometry {
final Float32List vertices;
final Uint16List indices;
final Float32List normals;
final Float32List uvs;
final PrimitiveType primitiveType;
Geometry(
this.vertices,
List<int> indices, {
Float32List? normals,
Float32List? uvs,
this.primitiveType = PrimitiveType.TRIANGLES,
}) : indices = Uint16List.fromList(indices),
normals = normals ?? Float32List(0),
uvs = uvs ?? Float32List(0) {
assert(this.uvs.length == 0 || this.uvs.length == (vertices.length ~/ 3 * 2), "Expected either zero or ${indices.length * 2} UVs, got ${this.uvs.length}");
}
void scale(double factor) {
for (int i = 0; i < vertices.length; i++) {
vertices[i] = vertices[i] * factor;
}
}
bool get hasNormals => normals.isNotEmpty;
bool get hasUVs => uvs.isNotEmpty;
}
@@ -2,11 +2,11 @@ import 'dart:typed_data';
import 'package:vector_math/vector_math_64.dart' as v64; import 'package:vector_math/vector_math_64.dart' as v64;
import 'package:animation_tools_dart/src/bone_animation_data.dart'; import 'package:animation_tools_dart/src/bone_animation_data.dart';
import 'package:animation_tools_dart/src/morph_animation_data.dart'; import 'package:animation_tools_dart/src/morph_animation_data.dart';
import 'package:thermion_dart/src/filament/src/layers.dart'; import 'package:thermion_dart/src/filament/src/interface/layers.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; import 'package:thermion_dart/src/bindings/bindings.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_asset.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_scene.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_texture.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
class BackgroundImage extends ThermionAsset { class BackgroundImage extends ThermionAsset {
@@ -47,10 +47,12 @@ class BackgroundImage extends ThermionAsset {
var backgroundImage = var backgroundImage =
await viewer.createGeometry(GeometryHelper.fullscreenQuad()); await viewer.createGeometry(GeometryHelper.fullscreenQuad());
await imageMaterialInstance.setParameterInt("showImage", 0); await imageMaterialInstance.setParameterInt("showImage", 0);
await imageMaterialInstance.setParameterMat4( var transform = Matrix4.identity();
"transform", Matrix4.identity());
backgroundImage.setMaterialInstanceAt(imageMaterialInstance); await imageMaterialInstance.setParameterMat4(
"transform", transform);
await backgroundImage.setMaterialInstanceAt(imageMaterialInstance);
await scene.add(backgroundImage as FFIAsset); await scene.add(backgroundImage as FFIAsset);
return BackgroundImage._( return BackgroundImage._(
backgroundImage, scene, null, null, imageMaterialInstance); backgroundImage, scene, null, null, imageMaterialInstance);
@@ -1,13 +1,8 @@
import 'dart:typed_data';
import 'package:animation_tools_dart/animation_tools_dart.dart'; import 'package:animation_tools_dart/animation_tools_dart.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:thermion_dart/src/filament/src/layers.dart';
import 'package:thermion_dart/src/utils/src/matrix.dart'; import 'package:thermion_dart/src/utils/src/matrix.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_material.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart' as v64; import 'package:vector_math/vector_math_64.dart' as v64;
@@ -52,15 +47,31 @@ class FFIAsset extends ThermionAsset {
entity = SceneAsset_getEntity(asset); entity = SceneAsset_getEntity(asset);
} }
Int32List? _childEntities;
/// ///
/// ///
/// ///
@override @override
Future<List<ThermionEntity>> getChildEntities() async { Future<List<ThermionEntity>> getChildEntities() async {
var count = SceneAsset_getChildEntityCount(asset); if (_childEntities == null) {
var children = Int32List(count); var count = SceneAsset_getChildEntityCount(asset);
SceneAsset_getChildEntities(asset, children.address); var childEntities = Int32List(count);
return children; late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
if (count > 0) {
SceneAsset_getChildEntities(asset, childEntities.address);
}
_childEntities = Int32List.fromList(childEntities);
childEntities.free();
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
}
}
return _childEntities!;
} }
/// ///
@@ -118,24 +129,32 @@ class FFIAsset extends ThermionAsset {
@override @override
Future<FFIAsset> createInstance( Future<FFIAsset> createInstance(
{covariant List<MaterialInstance>? materialInstances = null}) async { {covariant List<MaterialInstance>? materialInstances = null}) async {
var created = await withPointerCallback<TSceneAsset>((cb) { var ptrList = IntPtrList(materialInstances?.length ?? 0);
var ptrList = Int64List(materialInstances?.length ?? 0); late Pointer stackPtr;
if (materialInstances != null && materialInstances.isNotEmpty) { if (FILAMENT_WASM) {
ptrList.setRange( //stackPtr = stackSave();
0, }
materialInstances.length,
materialInstances
.cast<FFIMaterialInstance>()
.map((mi) => mi.pointer.address)
.toList());
}
if (materialInstances != null && materialInstances.isNotEmpty) {
ptrList.setRange(
0,
materialInstances.length,
materialInstances
.cast<FFIMaterialInstance>()
.map((mi) => mi.pointer.address)
.toList());
}
var created = await withPointerCallback<TSceneAsset>((cb) {
SceneAsset_createInstanceRenderThread( SceneAsset_createInstanceRenderThread(
asset, asset, ptrList.address.cast(), materialInstances?.length ?? 0, cb);
ptrList.address.cast<Pointer<TMaterialInstance>>(),
materialInstances?.length ?? 0,
cb);
}); });
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
ptrList.free();
}
if (created == FILAMENT_ASSET_ERROR) { if (created == FILAMENT_ASSET_ERROR) {
throw Exception("Failed to create instance"); throw Exception("Failed to create instance");
} }
@@ -251,6 +270,13 @@ class FFIAsset extends ThermionAsset {
/// ///
ThermionAsset? boundingBoxAsset; ThermionAsset? boundingBoxAsset;
///
///
///
Future dispose() async {
_childEntities?.free();
}
/// ///
/// ///
/// ///
@@ -326,14 +352,14 @@ class FFIAsset extends ThermionAsset {
vertices[23] = max[2]; // v7 vertices[23] = max[2]; // v7
// Indices for lines (24 indices for 12 lines) // Indices for lines (24 indices for 12 lines)
final indices = [ final indices = Uint16List.fromList([
// Bottom face // Bottom face
0, 1, 1, 2, 2, 3, 3, 0, 0, 1, 1, 2, 2, 3, 3, 0,
// Top face // Top face
4, 5, 5, 6, 6, 7, 7, 4, 4, 5, 5, 6, 6, 7, 7, 4,
// Vertical edges // Vertical edges
0, 4, 1, 5, 2, 6, 3, 7 0, 4, 1, 5, 2, 6, 3, 7
]; ]);
// Create unlit material instance for the wireframe // Create unlit material instance for the wireframe
final materialInstancePtr = final materialInstancePtr =
@@ -366,6 +392,10 @@ class FFIAsset extends ThermionAsset {
TransformManager_setParent(Engine_getTransformManager(app.engine), TransformManager_setParent(Engine_getTransformManager(app.engine),
boundingBoxAsset!.entity, entity, false); boundingBoxAsset!.entity, entity, false);
geometry.uvs?.free();
geometry.normals?.free();
geometry.vertices.free();
geometry.indices.free();
} }
return boundingBoxAsset!; return boundingBoxAsset!;
} }
@@ -461,7 +491,7 @@ class FFIAsset extends ThermionAsset {
if (weights.isEmpty) { if (weights.isEmpty) {
throw Exception("Weights must not be empty"); throw Exception("Weights must not be empty");
} }
var weightsPtr = allocator<Float>(weights.length); var weightsPtr = allocate<Float>(weights.length);
for (int i = 0; i < weights.length; i++) { for (int i = 0; i < weights.length; i++) {
weightsPtr[i] = weights[i]; weightsPtr[i] = weights[i];
@@ -470,7 +500,7 @@ class FFIAsset extends ThermionAsset {
AnimationManager_setMorphTargetWeightsRenderThread( AnimationManager_setMorphTargetWeightsRenderThread(
animationManager, entity, weightsPtr, weights.length, cb); animationManager, entity, weightsPtr, weights.length, cb);
}); });
allocator.free(weightsPtr); free(weightsPtr);
if (!success) { if (!success) {
throw Exception( throw Exception(
@@ -489,13 +519,13 @@ class FFIAsset extends ThermionAsset {
var count = AnimationManager_getMorphTargetNameCount( var count = AnimationManager_getMorphTargetNameCount(
animationManager, asset, entity); animationManager, asset, entity);
var outPtr = allocator<Char>(255); var outPtr = allocate<Char>(255);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
AnimationManager_getMorphTargetName( AnimationManager_getMorphTargetName(
animationManager, asset, entity, outPtr, i); animationManager, asset, entity, outPtr, i);
names.add(outPtr.cast<Utf8>().toDartString()); names.add(outPtr.cast<Utf8>().toDartString());
} }
allocator.free(outPtr); free(outPtr);
return names.cast<String>(); return names.cast<String>();
} }
@@ -505,9 +535,9 @@ class FFIAsset extends ThermionAsset {
Future<List<String>> getBoneNames({int skinIndex = 0}) async { Future<List<String>> getBoneNames({int skinIndex = 0}) async {
var count = var count =
AnimationManager_getBoneCount(animationManager, asset, skinIndex); AnimationManager_getBoneCount(animationManager, asset, skinIndex);
var out = allocator<Pointer<Char>>(count); var out = allocate<PointerClass<Char>>(count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
out[i] = allocator<Char>(255); out[i] = allocate<Char>(255);
} }
AnimationManager_getBoneNames(animationManager, asset, out, skinIndex); AnimationManager_getBoneNames(animationManager, asset, out, skinIndex);
@@ -516,6 +546,10 @@ class FFIAsset extends ThermionAsset {
var namePtr = out[i]; var namePtr = out[i];
names.add(namePtr.cast<Utf8>().toDartString()); names.add(namePtr.cast<Utf8>().toDartString());
} }
for (int i = 0; i < count; i++) {
free(out[i]);
}
free(out);
return names; return names;
} }
@@ -527,12 +561,12 @@ class FFIAsset extends ThermionAsset {
var animationCount = var animationCount =
AnimationManager_getAnimationCount(animationManager, asset); AnimationManager_getAnimationCount(animationManager, asset);
var names = <String>[]; var names = <String>[];
var outPtr = allocator<Char>(255); var outPtr = allocate<Char>(255);
for (int i = 0; i < animationCount; i++) { for (int i = 0; i < animationCount; i++) {
AnimationManager_getAnimationName(animationManager, asset, outPtr, i); AnimationManager_getAnimationName(animationManager, asset, outPtr, i);
names.add(outPtr.cast<Utf8>().toDartString()); names.add(outPtr.cast<Utf8>().toDartString());
} }
allocator.free(outPtr); free(outPtr);
return names; return names;
} }
@@ -636,6 +670,9 @@ class FFIAsset extends ThermionAsset {
animation.numFrames, animation.numFrames,
animation.frameLengthInMs); animation.frameLengthInMs);
frameData.data.free();
indices.free();
if (!result) { if (!result) {
throw Exception("Failed to set morph animation data for ${meshName}"); throw Exception("Failed to set morph animation data for ${meshName}");
} }
@@ -659,7 +696,7 @@ class FFIAsset extends ThermionAsset {
throw UnimplementedError("TODO - support skinIndex != 0 "); throw UnimplementedError("TODO - support skinIndex != 0 ");
} }
var boneNames = await getBoneNames(); var boneNames = await getBoneNames();
var restLocalTransformsRaw = allocator<Float>(boneNames.length * 16); var restLocalTransformsRaw = allocate<Float>(boneNames.length * 16);
AnimationManager_getRestLocalTransforms(animationManager, asset, skinIndex, AnimationManager_getRestLocalTransforms(animationManager, asset, skinIndex,
restLocalTransformsRaw, boneNames.length); restLocalTransformsRaw, boneNames.length);
@@ -671,11 +708,11 @@ class FFIAsset extends ThermionAsset {
} }
restLocalTransforms.add(Matrix4.fromList(values)); restLocalTransforms.add(Matrix4.fromList(values));
} }
allocator.free(restLocalTransformsRaw); free(restLocalTransformsRaw);
var numFrames = animation.frameData.length; var numFrames = animation.frameData.length;
var data = allocator<Float>(numFrames * 16); var data = allocate<Float>(numFrames * 16);
var bones = await Future.wait(List<Future<ThermionEntity>>.generate( var bones = await Future.wait(List<Future<ThermionEntity>>.generate(
boneNames.length, (i) => getBone(i))); boneNames.length, (i) => getBone(i)));
@@ -720,8 +757,7 @@ class FFIAsset extends ThermionAsset {
baseTransform * (worldInverse * frameTransform * world); baseTransform * (worldInverse * frameTransform * world);
} }
for (int j = 0; j < 16; j++) { for (int j = 0; j < 16; j++) {
data.elementAt((frameNum * 16) + j).value = data[(frameNum * 16) + j] = newLocalTransform.storage[j];
newLocalTransform.storage[j];
} }
} }
@@ -737,25 +773,41 @@ class FFIAsset extends ThermionAsset {
fadeInInSecs, fadeInInSecs,
maxDelta); maxDelta);
} }
allocator.free(data); free(data);
} }
/// ///
/// ///
/// ///
Future<Matrix4> getLocalTransform({ThermionEntity? entity}) async { Future<Matrix4> getLocalTransform({ThermionEntity? entity}) async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
entity ??= this.entity; entity ??= this.entity;
return double4x4ToMatrix4( final transform = double4x4ToMatrix4(
TransformManager_getLocalTransform(app.transformManager, entity)); TransformManager_getLocalTransform(app.transformManager, entity));
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
}
return transform;
} }
/// ///
/// ///
/// ///
Future<Matrix4> getWorldTransform({ThermionEntity? entity}) async { Future<Matrix4> getWorldTransform({ThermionEntity? entity}) async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
entity ??= this.entity; entity ??= this.entity;
return double4x4ToMatrix4( var transform = double4x4ToMatrix4(
TransformManager_getWorldTransform(app.transformManager, entity)); TransformManager_getWorldTransform(app.transformManager, entity));
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
}
return transform;
} }
/// ///
@@ -786,10 +838,19 @@ class FFIAsset extends ThermionAsset {
/// ///
Future<Matrix4> getInverseBindMatrix(int boneIndex, Future<Matrix4> getInverseBindMatrix(int boneIndex,
{int skinIndex = 0}) async { {int skinIndex = 0}) async {
var matrix = Float32List(16); late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
var matrixIn = Float32List(16);
AnimationManager_getInverseBindMatrix( AnimationManager_getInverseBindMatrix(
animationManager, asset, skinIndex, boneIndex, matrix.address); animationManager, asset, skinIndex, boneIndex, matrixIn.address);
return Matrix4.fromList(matrix); var matrixOut = Matrix4.fromList(matrixIn);
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
matrixIn.free();
}
return matrixOut;
} }
/// ///
@@ -813,7 +874,7 @@ class FFIAsset extends ThermionAsset {
if (skinIndex != 0) { if (skinIndex != 0) {
throw UnimplementedError("TOOD"); throw UnimplementedError("TOOD");
} }
final ptr = allocator<Float>(16); final ptr = allocate<Float>(16);
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
ptr[i] = transform.storage[i]; ptr[i] = transform.storage[i];
} }
@@ -822,7 +883,7 @@ class FFIAsset extends ThermionAsset {
animationManager, entity, skinIndex, boneIndex, ptr, cb); animationManager, entity, skinIndex, boneIndex, ptr, cb);
}); });
allocator.free(ptr); free(ptr);
if (!result) { if (!result) {
throw Exception("Failed to set bone transform"); throw Exception("Failed to set bone transform");
} }
@@ -1,12 +1,7 @@
import 'dart:ffi'; import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
import 'dart:typed_data';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
import 'package:thermion_dart/src/filament/src/layers.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import '../../../../utils/src/matrix.dart'; import '../../../utils/src/matrix.dart';
class FFICamera extends Camera { class FFICamera extends Camera {
final Pointer<TCamera> camera; final Pointer<TCamera> camera;
@@ -31,7 +26,15 @@ class FFICamera extends Camera {
/// ///
/// ///
Future<Matrix4> getModelMatrix() async { Future<Matrix4> getModelMatrix() async {
return double4x4ToMatrix4(Camera_getModelMatrix(camera)); late Pointer stackPtr;
if (FILAMENT_WASM) {
stackPtr = stackSave();
}
final modelMatrix = double4x4ToMatrix4(Camera_getModelMatrix(camera));
if (FILAMENT_WASM) {
stackRestore(stackPtr);
}
return modelMatrix;
} }
/// ///
@@ -39,8 +42,16 @@ class FFICamera extends Camera {
/// ///
@override @override
Future<Matrix4> getProjectionMatrix() async { Future<Matrix4> getProjectionMatrix() async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
var matrixStruct = Camera_getProjectionMatrix(camera); var matrixStruct = Camera_getProjectionMatrix(camera);
return double4x4ToMatrix4(matrixStruct); final pMat = double4x4ToMatrix4(matrixStruct);
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
}
return pMat;
} }
/// ///
@@ -48,8 +59,17 @@ class FFICamera extends Camera {
/// ///
@override @override
Future<Matrix4> getCullingProjectionMatrix() async { Future<Matrix4> getCullingProjectionMatrix() async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
var matrixStruct = Camera_getCullingProjectionMatrix(camera); var matrixStruct = Camera_getCullingProjectionMatrix(camera);
return double4x4ToMatrix4(matrixStruct); final cpMat = double4x4ToMatrix4(matrixStruct);
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
}
return cpMat;
} }
@override @override
@@ -81,7 +101,15 @@ class FFICamera extends Camera {
/// ///
@override @override
Future setModelMatrix(Matrix4 matrix) async { Future setModelMatrix(Matrix4 matrix) async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
stackPtr = stackSave();
}
Camera_setModelMatrix(camera, matrix.storage.address); Camera_setModelMatrix(camera, matrix.storage.address);
if (FILAMENT_WASM) {
stackRestore(stackPtr);
matrix.storage.free();
}
} }
@override @override
@@ -122,6 +150,10 @@ class FFICamera extends Camera {
/// ///
/// ///
Future<Frustum> getFrustum() async { Future<Frustum> getFrustum() async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
var out = Float64List(24); var out = Float64List(24);
Camera_getFrustum(camera, out.address); Camera_getFrustum(camera, out.address);
@@ -132,19 +164,31 @@ class FFICamera extends Camera {
frustum.plane3.setFromComponents(out[12], out[13], out[14], out[15]); frustum.plane3.setFromComponents(out[12], out[13], out[14], out[15]);
frustum.plane4.setFromComponents(out[16], out[17], out[18], out[19]); frustum.plane4.setFromComponents(out[16], out[17], out[18], out[19]);
frustum.plane5.setFromComponents(out[20], out[21], out[22], out[23]); frustum.plane5.setFromComponents(out[20], out[21], out[22], out[23]);
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
out.free();
}
return frustum; return frustum;
} }
@override @override
Future<Matrix4> getViewMatrix() async { Future<Matrix4> getViewMatrix() async {
return double4x4ToMatrix4(Camera_getViewMatrix(camera)); late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
final matrix = double4x4ToMatrix4(Camera_getViewMatrix(camera));
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
}
return matrix;
} }
@override @override
Future setProjection(Projection projection, double left, double right, Future setProjection(Projection projection, double left, double right,
double bottom, double top, double near, double far) async { double bottom, double top, double near, double far) async {
Camera_setProjection(camera, TProjection.values[projection.index], left, Camera_setProjection(
right, bottom, top, near, far); camera, projection.index, left, right, bottom, top, near, far);
} }
Future destroy() async { Future destroy() async {
@@ -1,26 +1,23 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:thermion_dart/src/filament/src/scene.dart'; import 'package:thermion_dart/src/filament/src/interface/scene.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_asset.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_gizmo.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_gizmo.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_material.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_render_target.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_scene.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_swapchain.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_texture.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_view.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_view.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'resource_loader.dart';
typedef RenderCallback = Pointer<NativeFunction<Void Function(Pointer<Void>)>>; typedef RenderCallback = Pointer<NativeFunction<Void Function(Pointer<Void>)>>;
class FFIFilamentConfig extends FilamentConfig<RenderCallback, Pointer<Void>> { class FFIFilamentConfig extends FilamentConfig<RenderCallback, Pointer<Void>> {
FFIFilamentConfig( FFIFilamentConfig(
{required super.resourceLoader, {super.resourceLoader = null,
super.backend = Backend.DEFAULT, super.backend = Backend.DEFAULT,
super.platform = null, super.platform = null,
super.sharedContext = null, super.sharedContext = null,
@@ -38,9 +35,9 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
final Pointer<TRenderTicker> renderTicker; final Pointer<TRenderTicker> renderTicker;
final Pointer<TNameComponentManager> nameComponentManager; final Pointer<TNameComponentManager> nameComponentManager;
final Future<Uint8List> Function(String uri) resourceLoader; late final Future<Uint8List> Function(String uri) resourceLoader;
late final _logger = Logger(this.runtimeType.toString()); static final _logger = Logger("FFIFilamentApp");
FFIFilamentApp( FFIFilamentApp(
this.engine, this.engine,
@@ -52,7 +49,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
this.ubershaderMaterialProvider, this.ubershaderMaterialProvider,
this.renderTicker, this.renderTicker,
this.nameComponentManager, this.nameComponentManager,
this.resourceLoader) Future<Uint8List> Function(String uri)? resourceLoader)
: super( : super(
engine: engine, engine: engine,
gltfAssetLoader: gltfAssetLoader, gltfAssetLoader: gltfAssetLoader,
@@ -60,15 +57,13 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
transformManager: transformManager, transformManager: transformManager,
lightManager: lightManager, lightManager: lightManager,
renderableManager: renderableManager, renderableManager: renderableManager,
ubershaderMaterialProvider: ubershaderMaterialProvider) {} ubershaderMaterialProvider: ubershaderMaterialProvider) {
this.resourceLoader = resourceLoader ?? defaultResourceLoader;
static Future<Uint8List> _defaultResourceLoader(String path) {
print("Loading file $path");
return File(path).readAsBytes();
} }
static Future create({FFIFilamentConfig? config}) async { static Future create({FFIFilamentConfig? config}) async {
config ??= FFIFilamentConfig(resourceLoader: _defaultResourceLoader); config ??= FFIFilamentConfig();
if (FilamentApp.instance != null) { if (FilamentApp.instance != null) {
await FilamentApp.instance!.destroy(); await FilamentApp.instance!.destroy();
} }
@@ -78,7 +73,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
final engine = await withPointerCallback<TEngine>((cb) => final engine = await withPointerCallback<TEngine>((cb) =>
Engine_createRenderThread( Engine_createRenderThread(
TBackend.values[config!.backend.index].index, config!.backend.value,
config.platform ?? nullptr, config.platform ?? nullptr,
config.sharedContext ?? nullptr, config.sharedContext ?? nullptr,
config.stereoscopicEyeCount, config.stereoscopicEyeCount,
@@ -96,7 +91,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
final lightManager = Engine_getLightManager(engine); final lightManager = Engine_getLightManager(engine);
final renderableManager = Engine_getRenderableManager(engine); final renderableManager = Engine_getRenderableManager(engine);
final renderTicker = RenderTicker_create(renderer); final renderTicker = RenderTicker_create(engine, renderer);
RenderThread_setRenderTicker(renderTicker); RenderThread_setRenderTicker(renderTicker);
@@ -113,18 +108,25 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
renderTicker, renderTicker,
nameComponentManager, nameComponentManager,
config.resourceLoader); config.resourceLoader);
_logger.info("Initialization complete");
} }
final _swapChains = <FFISwapChain, List<FFIView>>{}; final _swapChains = <FFISwapChain, List<FFIView>>{};
final viewsPtr = calloc<Pointer<TView>>(255); late Pointer<PointerClass<TView>> viewsPtr =
allocate<PointerClass>(255).cast();
/// ///
/// ///
/// ///
Future updateRenderOrder() async { Future updateRenderOrder() async {
_logger.info("updateRenderOrder");
if (_swapChains.length == 0) {
_logger.warning("No swapchains, ignoring updateRenderOrder");
}
for (final swapChain in _swapChains.keys) { for (final swapChain in _swapChains.keys) {
final views = _swapChains[swapChain]; final views = _swapChains[swapChain];
if (views == null) { if (views == null) {
_logger.info("No views found for swapchain $swapChain");
continue; continue;
} }
@@ -137,6 +139,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
} }
RenderTicker_setRenderable( RenderTicker_setRenderable(
renderTicker, swapChain.swapChain, viewsPtr, numRenderable); renderTicker, swapChain.swapChain, viewsPtr, numRenderable);
_logger.info("Updated render order, $numRenderable renderable views");
} }
} }
@@ -227,7 +230,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
RenderThread_destroy(); RenderThread_destroy();
RenderTicker_destroy(renderTicker); RenderTicker_destroy(renderTicker);
calloc.free(viewsPtr); free(viewsPtr);
FilamentApp.instance = null; FilamentApp.instance = null;
for (final callback in _onDestroy) { for (final callback in _onDestroy) {
await callback.call(); await callback.call();
@@ -242,6 +245,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
Future destroyAsset(covariant FFIAsset asset) async { Future destroyAsset(covariant FFIAsset asset) async {
await withVoidCallback( await withVoidCallback(
(cb) => SceneAsset_destroyRenderThread(asset.asset, cb)); (cb) => SceneAsset_destroyRenderThread(asset.asset, cb));
await asset.dispose();
} }
/// ///
@@ -298,8 +302,8 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
levels, levels,
bitmask, bitmask,
importedTextureHandle ?? 0, importedTextureHandle ?? 0,
TTextureSamplerType.values[textureSamplerType.index], textureSamplerType.index,
TTextureFormat.values[textureFormat.index], textureFormat.index,
cb); cb);
}); });
if (texturePtr == nullptr) { if (texturePtr == nullptr) {
@@ -324,24 +328,17 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
TextureCompareMode compareMode = TextureCompareMode.NONE, TextureCompareMode compareMode = TextureCompareMode.NONE,
TextureCompareFunc compareFunc = TextureCompareFunc.LESS_EQUAL}) async { TextureCompareFunc compareFunc = TextureCompareFunc.LESS_EQUAL}) async {
final samplerPtr = TextureSampler_create(); final samplerPtr = TextureSampler_create();
TextureSampler_setMinFilter( TextureSampler_setMinFilter(samplerPtr, minFilter.index);
samplerPtr, TSamplerMinFilter.values[minFilter.index]); TextureSampler_setMagFilter(samplerPtr, magFilter.index);
TextureSampler_setMagFilter( TextureSampler_setWrapModeS(samplerPtr, wrapS.index);
samplerPtr, TSamplerMagFilter.values[magFilter.index]); TextureSampler_setWrapModeT(samplerPtr, wrapT.index);
TextureSampler_setWrapModeS( TextureSampler_setWrapModeR(samplerPtr, wrapR.index);
samplerPtr, TSamplerWrapMode.values[wrapS.index]);
TextureSampler_setWrapModeT(
samplerPtr, TSamplerWrapMode.values[wrapT.index]);
TextureSampler_setWrapModeR(
samplerPtr, TSamplerWrapMode.values[wrapR.index]);
if (anisotropy > 0) { if (anisotropy > 0) {
TextureSampler_setAnisotropy(samplerPtr, anisotropy); TextureSampler_setAnisotropy(samplerPtr, anisotropy);
} }
TextureSampler_setCompareMode( TextureSampler_setCompareMode(
samplerPtr, samplerPtr, compareMode.index, compareFunc.index);
TSamplerCompareMode.values[compareMode.index],
TSamplerCompareFunc.values[compareFunc.index]);
return FFITextureSampler(samplerPtr); return FFITextureSampler(samplerPtr);
} }
@@ -351,11 +348,20 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
/// ///
Future<LinearImage> decodeImage(Uint8List data) async { Future<LinearImage> decodeImage(Uint8List data) async {
final name = "image"; final name = "image";
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
var ptr = Image_decode( var ptr = Image_decode(
data.address, data.address,
data.length, data.length,
name.toNativeUtf8().cast<Char>(), name.toNativeUtf8().cast<Char>(),
); );
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
data.free();
}
if (ptr == nullptr) { if (ptr == nullptr) {
throw Exception("Failed to decode image"); throw Exception("Failed to decode image");
} }
@@ -374,9 +380,17 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
/// ///
/// ///
Future<Material> createMaterial(Uint8List data) async { Future<Material> createMaterial(Uint8List data) async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
var ptr = await withPointerCallback<TMaterial>((cb) { var ptr = await withPointerCallback<TMaterial>((cb) {
Engine_buildMaterialRenderThread(engine, data.address, data.length, cb); Engine_buildMaterialRenderThread(engine, data.address, data.length, cb);
}); });
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
data.free();
}
return FFIMaterial(ptr, this); return FFIMaterial(ptr, this);
} }
@@ -420,6 +434,11 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
bool hasSheen = false, bool hasSheen = false,
bool hasIOR = false, bool hasIOR = false,
bool hasVolume = false}) async { bool hasVolume = false}) async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
final key = Struct.create<TMaterialKey>(); final key = Struct.create<TMaterialKey>();
key.doubleSided = doubleSided; key.doubleSided = doubleSided;
@@ -464,6 +483,10 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
MaterialProvider_createMaterialInstanceRenderThread( MaterialProvider_createMaterialInstanceRenderThread(
ubershaderMaterialProvider, key.address, cb); ubershaderMaterialProvider, key.address, cb);
}); });
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
}
if (materialInstance == nullptr) { if (materialInstance == nullptr) {
throw Exception("Failed to create material instance"); throw Exception("Failed to create material instance");
} }
@@ -506,7 +529,8 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
final swapchain = _swapChains.keys.first; final swapchain = _swapChains.keys.first;
final view = _swapChains[swapchain]!.first; final view = _swapChains[swapchain]!.first;
await withBoolCallback((cb) { await withBoolCallback((cb) {
Renderer_beginFrameRenderThread(renderer, swapchain.swapChain, 0, cb); Renderer_beginFrameRenderThread(
renderer, swapchain.swapChain, 0.toBigInt, cb);
}); });
await withVoidCallback((cb) { await withVoidCallback((cb) {
Renderer_renderRenderThread( Renderer_renderRenderThread(
@@ -515,10 +539,16 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
cb, cb,
); );
}); });
await withVoidCallback((cb) { await withVoidCallback((cb) {
Renderer_endFrameRenderThread(renderer, cb); Renderer_endFrameRenderThread(renderer, cb);
}); });
if (FILAMENT_SINGLE_THREADED) {
await withVoidCallback((cb) => Engine_executeRenderThread(engine, cb));
} else {
await withVoidCallback(
(cb) => Engine_flushAndWaitRenderThread(engine, cb));
}
} }
/// ///
@@ -581,19 +611,8 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
for (final hook in _hooks) { for (final hook in _hooks) {
await hook.call(); await hook.call();
} }
final completer = Completer();
final callback = NativeCallable<Void Function()>.listener(() { RenderThread_requestFrameAsync();
completer.complete(true);
});
RenderThread_requestFrame(callback.nativeFunction.cast());
try {
await completer.future.timeout(Duration(seconds: 1));
} catch (err) {
print("WARNING - render call timed out");
}
} }
/// ///
@@ -669,7 +688,6 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
PixelDataFormat pixelDataFormat = PixelDataFormat.RGBA, PixelDataFormat pixelDataFormat = PixelDataFormat.RGBA,
PixelDataType pixelDataType = PixelDataType.FLOAT, PixelDataType pixelDataType = PixelDataType.FLOAT,
Future Function(View)? beforeRender}) async { Future Function(View)? beforeRender}) async {
if (swapChain == null) { if (swapChain == null) {
if (_swapChains.isEmpty) { if (_swapChains.isEmpty) {
throw Exception("No swapchains registered"); throw Exception("No swapchains registered");
@@ -683,7 +701,8 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
await updateRenderOrder(); await updateRenderOrder();
await withBoolCallback((cb) { await withBoolCallback((cb) {
Renderer_beginFrameRenderThread(renderer, swapChain!.swapChain, 0, cb); Renderer_beginFrameRenderThread(
renderer, swapChain!.swapChain, 0.toBigInt, cb);
}); });
final views = <FFIView>[]; final views = <FFIView>[];
if (view != null) { if (view != null) {
@@ -720,6 +739,8 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
: view.renderTarget!.renderTarget, : view.renderTarget!.renderTarget,
// TPixelDataFormat.PIXELDATAFORMAT_RGBA, // TPixelDataFormat.PIXELDATAFORMAT_RGBA,
// TPixelDataType.PIXELDATATYPE_UBYTE, // TPixelDataType.PIXELDATATYPE_UBYTE,
// TPixelDataFormat.fromValue(pixelDataFormat.value),
// TPixelDataType.fromValue(pixelDataType.value),
pixelDataFormat.value, pixelDataFormat.value,
pixelDataType.value, pixelDataType.value,
pixelBuffer.address, pixelBuffer.address,
@@ -734,7 +755,11 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
}); });
await withVoidCallback((cb) { await withVoidCallback((cb) {
Engine_flushAndWaitRenderThead(engine, cb); if (FILAMENT_SINGLE_THREADED) {
Engine_executeRenderThread(engine, cb);
} else {
Engine_flushAndWaitRenderThread(engine, cb);
}
}); });
return pixelBuffers; return pixelBuffers;
} }
@@ -759,70 +784,96 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
int layer = 0, int layer = 0,
String? relativeResourcePath, String? relativeResourcePath,
bool loadResourcesAsync = false}) async { bool loadResourcesAsync = false}) async {
if (relativeResourcePath != null && !relativeResourcePath.endsWith("/")) {
relativeResourcePath = "$relativeResourcePath/";
}
var gltfResourceLoader = await withPointerCallback<TGltfResourceLoader>(
(cb) => GltfResourceLoader_createRenderThread(engine,
relativeResourcePath?.toNativeUtf8().cast<Char>() ?? nullptr, cb));
var filamentAsset = await withPointerCallback<TFilamentAsset>((cb) =>
GltfAssetLoader_loadRenderThread(engine, gltfAssetLoader, data.address,
data.length, numInstances, cb));
if (filamentAsset == nullptr) {
throw Exception("An error occurred loading the asset");
}
var resourceUris = FilamentAsset_getResourceUris(filamentAsset);
var resourceUriCount = FilamentAsset_getResourceUriCount(filamentAsset);
final resources = <FinalizableUint8List>[]; final resources = <FinalizableUint8List>[];
try {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
for (int i = 0; i < resourceUriCount; i++) { loadResourcesAsync = FILAMENT_SINGLE_THREADED;
final resourceUriDart = resourceUris[i].cast<Utf8>().toDartString();
final resourceData = await resourceLoader(relativeResourcePath == null
? resourceUriDart
: "$relativeResourcePath/$resourceUriDart");
resources.add(FinalizableUint8List(resourceUris[i], resourceData)); if (relativeResourcePath != null && !relativeResourcePath.endsWith("/")) {
relativeResourcePath = "$relativeResourcePath/";
await withVoidCallback((cb) => }
GltfResourceLoader_addResourceDataRenderThread( var gltfResourceLoader = await withPointerCallback<TGltfResourceLoader>(
gltfResourceLoader, (cb) => GltfResourceLoader_createRenderThread(
resourceUris[i], engine,
resourceData.address, relativeResourcePath?.toNativeUtf8().cast<Char>() ?? nullptr,
resourceData.lengthInBytes,
cb)); cb));
}
if (loadResourcesAsync) { var filamentAsset = await withPointerCallback<TFilamentAsset>((cb) =>
final result = await withBoolCallback((cb) => GltfResourceLoader_asyncBeginLoadRenderThread(gltfResourceLoader, filamentAsset, cb)); GltfAssetLoader_loadRenderThread(engine, gltfAssetLoader,
if(!result) { data.address, data.length, numInstances, cb));
throw Exception("Failed to begin async loading");
if (filamentAsset == nullptr) {
throw Exception("An error occurred loading the asset");
} }
GltfResourceLoader_asyncUpdateLoadRenderThread(gltfResourceLoader); var resourceUris = FilamentAsset_getResourceUris(filamentAsset);
var resourceUriCount = FilamentAsset_getResourceUriCount(filamentAsset);
for (int i = 0; i < resourceUriCount; i++) {
final resourceUriDart = resourceUris[i].cast<Utf8>().toDartString();
final resourceData = await resourceLoader(relativeResourcePath == null
? resourceUriDart
: "$relativeResourcePath/$resourceUriDart");
resources.add(FinalizableUint8List(resourceUris[i], resourceData));
await withVoidCallback((cb) =>
GltfResourceLoader_addResourceDataRenderThread(
gltfResourceLoader,
resourceUris[i],
resourceData.address,
resourceData.lengthInBytes,
cb));
}
if (loadResourcesAsync) {
final result = await withBoolCallback((cb) =>
GltfResourceLoader_asyncBeginLoadRenderThread(
gltfResourceLoader, filamentAsset, cb));
if (!result) {
throw Exception("Failed to begin async loading");
}
var progress = await withFloatCallback((cb) => GltfResourceLoader_asyncGetLoadProgressRenderThread(gltfResourceLoader, cb));
while(progress < 1.0) {
GltfResourceLoader_asyncUpdateLoadRenderThread(gltfResourceLoader); GltfResourceLoader_asyncUpdateLoadRenderThread(gltfResourceLoader);
progress = await withFloatCallback((cb) => GltfResourceLoader_asyncGetLoadProgressRenderThread(gltfResourceLoader, cb));
var progress = await withFloatCallback((cb) =>
GltfResourceLoader_asyncGetLoadProgressRenderThread(
gltfResourceLoader, cb));
while (progress < 1.0) {
GltfResourceLoader_asyncUpdateLoadRenderThread(gltfResourceLoader);
progress = await withFloatCallback((cb) =>
GltfResourceLoader_asyncGetLoadProgressRenderThread(
gltfResourceLoader, cb));
}
} else {
final result = await withBoolCallback((cb) =>
GltfResourceLoader_loadResourcesRenderThread(
gltfResourceLoader, filamentAsset, cb));
if (!result) {
throw Exception("Failed to load resources");
}
} }
} else {
final result = await withBoolCallback((cb) => final asset = await withPointerCallback<TSceneAsset>((cb) =>
GltfResourceLoader_loadResourcesRenderThread( SceneAsset_createFromFilamentAssetRenderThread(engine,
gltfResourceLoader, filamentAsset, cb)); gltfAssetLoader, nameComponentManager, filamentAsset, cb));
if (!result) {
throw Exception("Failed to load resources"); await withVoidCallback((cb) => GltfResourceLoader_destroyRenderThread(
engine, gltfResourceLoader, cb));
return FFIAsset(asset, this, animationManager.cast<TAnimationManager>());
} finally {
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
data.free();
for (final resource in resources) {
resource.data.free();
}
} }
} }
final asset = await withPointerCallback<TSceneAsset>((cb) =>
SceneAsset_createFromFilamentAssetRenderThread(
engine, gltfAssetLoader, nameComponentManager, filamentAsset, cb));
await withVoidCallback((cb) =>
GltfResourceLoader_destroyRenderThread(engine, gltfResourceLoader, cb));
return FFIAsset(asset, this, animationManager.cast<TAnimationManager>());
} }
Future destroyView(covariant FFIView view) async { Future destroyView(covariant FFIView view) async {
@@ -833,12 +884,13 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
} }
await withVoidCallback( await withVoidCallback(
(cb) => Engine_destroyViewRenderThread(engine, view.view, cb)); (cb) => Engine_destroyViewRenderThread(engine, view.view, cb));
for(final swapchain in _swapChains.keys) { for (final swapchain in _swapChains.keys) {
if(_swapChains[swapchain]!.contains(view)) { if (_swapChains[swapchain]!.contains(view)) {
_swapChains[swapchain]!.remove(view); _swapChains[swapchain]!.remove(view);
continue; continue;
} }
} }
await view.dispose();
} }
Future destroyScene(covariant FFIScene scene) async { Future destroyScene(covariant FFIScene scene) async {
@@ -847,9 +899,8 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
} }
Future<Pointer<TColorGrading>> createColorGrading(ToneMapper mapper) async { Future<Pointer<TColorGrading>> createColorGrading(ToneMapper mapper) async {
return withPointerCallback<TColorGrading>((cb) => return withPointerCallback<TColorGrading>(
ColorGrading_createRenderThread( (cb) => ColorGrading_createRenderThread(engine, mapper.index, cb));
engine, TToneMapping.values[mapper.index], cb));
} }
FFIMaterial? _gizmoMaterial; FFIMaterial? _gizmoMaterial;
@@ -859,6 +910,11 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
/// ///
Future<GizmoAsset> createGizmo(covariant FFIView view, Future<GizmoAsset> createGizmo(covariant FFIView view,
Pointer animationManager, GizmoType gizmoType) async { Pointer animationManager, GizmoType gizmoType) async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
if (_gizmoMaterial == null) { if (_gizmoMaterial == null) {
final materialPtr = await withPointerCallback<TMaterial>((cb) { final materialPtr = await withPointerCallback<TMaterial>((cb) {
Material_createGizmoMaterialRenderThread(engine, cb); Material_createGizmoMaterialRenderThread(engine, cb);
@@ -867,7 +923,8 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
} }
var gltfResourceLoader = await withPointerCallback<TGltfResourceLoader>( var gltfResourceLoader = await withPointerCallback<TGltfResourceLoader>(
(cb) => GltfResourceLoader_createRenderThread(engine, nullptr, cb)); (cb) =>
GltfResourceLoader_createRenderThread(engine, nullptr.cast(), cb));
final gizmo = await withPointerCallback<TGizmo>((cb) { final gizmo = await withPointerCallback<TGizmo>((cb) {
Gizmo_createRenderThread( Gizmo_createRenderThread(
@@ -877,7 +934,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
nameComponentManager, nameComponentManager,
view.view, view.view,
_gizmoMaterial!.pointer, _gizmoMaterial!.pointer,
TGizmoType.values[gizmoType.index], gizmoType.index,
cb); cb);
}); });
if (gizmo == nullptr) { if (gizmo == nullptr) {
@@ -889,11 +946,17 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
SceneAsset_getChildEntities( SceneAsset_getChildEntities(
gizmo.cast<TSceneAsset>(), gizmoEntities.address); gizmo.cast<TSceneAsset>(), gizmoEntities.address);
return FFIGizmo(gizmo.cast<TSceneAsset>(), this, final gizmoAsset = FFIGizmo(gizmo.cast<TSceneAsset>(), this,
animationManager.cast<TAnimationManager>(), animationManager.cast<TAnimationManager>(),
view: view, view: view,
entities: gizmoEntities.toSet() entities: gizmoEntities.toSet()
..add(SceneAsset_getEntity(gizmo.cast<TSceneAsset>()))); ..add(SceneAsset_getEntity(gizmo.cast<TSceneAsset>())));
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
gizmoEntities.free();
}
return gizmoAsset;
} }
/// ///
@@ -905,19 +968,24 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
{List<MaterialInstance>? materialInstances, {List<MaterialInstance>? materialInstances,
bool keepData = false, bool keepData = false,
bool addToScene = true}) async { bool addToScene = true}) async {
var assetPtr = await withPointerCallback<TSceneAsset>((callback) { late Pointer stackPtr;
var ptrList = Int64List(materialInstances?.length ?? 0); if (FILAMENT_WASM) {
if (materialInstances != null && materialInstances.isNotEmpty) { //stackPtr = stackSave();
ptrList.setRange( }
0,
materialInstances.length,
materialInstances
.cast<FFIMaterialInstance>()
.map((mi) => mi.pointer.address)
.toList());
}
return SceneAsset_createGeometryRenderThread( final ptrList = IntPtrList(materialInstances?.length ?? 0);
if (materialInstances != null) {
ptrList.setRange(
0,
materialInstances.length,
materialInstances
.cast<FFIMaterialInstance>()
.map((mi) => mi.pointer.address)
.toList());
}
var assetPtr = await withPointerCallback<TSceneAsset>((callback) {
var ptr = SceneAsset_createGeometryRenderThread(
engine, engine,
geometry.vertices.address, geometry.vertices.address,
geometry.vertices.length, geometry.vertices.length,
@@ -928,10 +996,20 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
geometry.indices.address, geometry.indices.address,
geometry.indices.length, geometry.indices.length,
geometry.primitiveType.index, geometry.primitiveType.index,
ptrList.address.cast<Pointer<TMaterialInstance>>(), ptrList.address.cast(),
ptrList.length, ptrList.length ?? 0,
callback); callback);
return ptr;
}); });
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
ptrList?.free();
geometry.vertices.free();
geometry.normals?.free();
geometry.uvs?.free();
}
if (assetPtr == nullptr) { if (assetPtr == nullptr) {
throw Exception("Failed to create geometry"); throw Exception("Failed to create geometry");
} }
@@ -943,7 +1021,12 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
/// ///
/// ///
Future flush() async { Future flush() async {
await withVoidCallback((cb) => Engine_flushAndWaitRenderThead(engine, cb)); if (FILAMENT_SINGLE_THREADED) {
await withVoidCallback((cb) => Engine_executeRenderThread(engine, cb));
} else {
await withVoidCallback(
(cb) => Engine_flushAndWaitRenderThread(engine, cb));
}
} }
final _onDestroy = <Future Function()>[]; final _onDestroy = <Future Function()>[];
@@ -955,10 +1038,3 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
_onDestroy.add(callback); _onDestroy.add(callback);
} }
} }
class FinalizableUint8List implements Finalizable {
final Pointer name;
final Uint8List data;
FinalizableUint8List(this.name, this.data);
}
@@ -1,29 +1,19 @@
import 'dart:async'; import 'dart:async';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; import 'package:thermion_dart/src/bindings/bindings.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_asset.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'ffi_view.dart'; import 'ffi_view.dart';
class FFIGizmo extends FFIAsset implements GizmoAsset { class FFIGizmo extends FFIAsset implements GizmoAsset {
final Set<ThermionEntity> entities; final Set<ThermionEntity> entities;
late NativeCallable<GizmoPickCallbackFunction> _nativeCallback;
late final CallbackHolder<GizmoPickCallbackFunction> _callbackHolder;
void Function(GizmoPickResultType axis, Vector3 coords)? _callback; void Function(GizmoPickResultType axis, Vector3 coords)? _callback;
late FFIView view; late FFIView view;
void _onPickResult(int resultType, double x, double y, double z) {
_callback?.call(GizmoPickResultType.values[resultType], Vector3(x, y, z));
}
bool isNonPickable(ThermionEntity entity) {
throw UnimplementedError();
// return SceneManager_isGridEntity(sceneManager, entity);
}
bool isGizmoEntity(ThermionEntity entity) => entities.contains(entity);
FFIGizmo( FFIGizmo(
super.asset, super.asset,
super.app, super.app,
@@ -32,10 +22,38 @@ class FFIGizmo extends FFIAsset implements GizmoAsset {
required this.view, required this.view,
required this.entities, required this.entities,
}) { }) {
_nativeCallback =
NativeCallable<GizmoPickCallbackFunction>.listener(_onPickResult); _callbackHolder = _onPickResult.asCallback();
} }
///
///
///
Future dispose() async {
_callbackHolder.dispose();
}
void _onPickResult(int resultType, double x, double y, double z) {
final type = switch(resultType) {
TGizmoPickResultType.AxisX => GizmoPickResultType.AxisX,
TGizmoPickResultType.AxisY => GizmoPickResultType.AxisY,
TGizmoPickResultType.AxisZ => GizmoPickResultType.AxisZ,
TGizmoPickResultType.None => GizmoPickResultType.None,
TGizmoPickResultType.Parent => GizmoPickResultType.Parent,
_ => throw UnsupportedError(resultType.toString())
};
_callback?.call(type, Vector3(x, y, z));
}
bool isNonPickable(ThermionEntity entity) {
throw UnimplementedError();
// return SceneManager_isGridEntity(sceneManager, entity);
}
bool isGizmoEntity(ThermionEntity entity) => entities.contains(entity);
@override @override
Future removeStencilHighlight() async { Future removeStencilHighlight() async {
throw Exception("Not supported for gizmo"); throw Exception("Not supported for gizmo");
@@ -58,13 +76,18 @@ class FFIGizmo extends FFIAsset implements GizmoAsset {
final viewport = await view.getViewport(); final viewport = await view.getViewport();
y = viewport.height - y; y = viewport.height - y;
Gizmo_pick(asset.cast<TGizmo>(), x, y, _nativeCallback.nativeFunction); Gizmo_pick(asset.cast<TGizmo>(), x, y, _callbackHolder.pointer);
} }
@override @override
Future highlight(Axis axis) async { Future highlight(Axis axis) async {
Gizmo_unhighlight(asset.cast<TGizmo>()); Gizmo_unhighlight(asset.cast<TGizmo>());
Gizmo_highlight(asset.cast<TGizmo>(), TGizmoAxis.values[axis.index]); final tAxis = switch(axis) {
Axis.X => TGizmoAxis.X,
Axis.Y => TGizmoAxis.Y,
Axis.Z => TGizmoAxis.Z
};
Gizmo_highlight(asset.cast<TGizmo>(), tAxis);
} }
@override @override
@@ -1,9 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
import 'package:thermion_dart/src/filament/src/implementation/ffi_texture.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
class FFIMaterial extends Material { class FFIMaterial extends Material {
@@ -73,7 +70,11 @@ class FFIMaterialInstance extends MaterialInstance {
@override @override
Future setParameterFloat3Array(String name, List<Vector3> array) async { Future setParameterFloat3Array(String name, List<Vector3> array) async {
final ptr = name.toNativeUtf8(allocator: calloc).cast<Char>(); late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
final ptr = name.toNativeUtf8().cast<Char>();
final data = Float64List(array.length * 3); final data = Float64List(array.length * 3);
int i = 0; int i = 0;
for (final item in array) { for (final item in array) {
@@ -84,7 +85,11 @@ class FFIMaterialInstance extends MaterialInstance {
} }
MaterialInstance_setParameterFloat3Array( MaterialInstance_setParameterFloat3Array(
pointer, ptr, data.address, array.length * 3); pointer, ptr, data.address, array.length * 3);
calloc.free(ptr);
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
data.free();
}
} }
@override @override
@@ -102,45 +107,38 @@ class FFIMaterialInstance extends MaterialInstance {
@override @override
Future setDepthFunc(SamplerCompareFunction depthFunc) async { Future setDepthFunc(SamplerCompareFunction depthFunc) async {
MaterialInstance_setDepthFunc( MaterialInstance_setDepthFunc(pointer, depthFunc.index);
pointer, TSamplerCompareFunc.values[depthFunc.index]);
} }
@override @override
Future setStencilCompareFunction(SamplerCompareFunction func, Future setStencilCompareFunction(SamplerCompareFunction func,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async { [StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilCompareFunction( MaterialInstance_setStencilCompareFunction(pointer, func.index, face.index);
pointer,
TSamplerCompareFunc.values[func.index],
TStencilFace.values[face.index]);
} }
@override @override
Future setStencilOpDepthFail(StencilOperation op, Future setStencilOpDepthFail(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async { [StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilOpDepthFail(pointer, MaterialInstance_setStencilOpDepthFail(pointer, op.index, face.index);
TStencilOperation.values[op.index], TStencilFace.values[face.index]);
} }
@override @override
Future setStencilOpDepthStencilPass(StencilOperation op, Future setStencilOpDepthStencilPass(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async { [StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilOpDepthStencilPass(pointer, MaterialInstance_setStencilOpDepthStencilPass(
TStencilOperation.values[op.index], TStencilFace.values[face.index]); pointer, op.index, face.index);
} }
@override @override
Future setStencilOpStencilFail(StencilOperation op, Future setStencilOpStencilFail(StencilOperation op,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async { [StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilOpStencilFail(pointer, MaterialInstance_setStencilOpStencilFail(pointer, op.index, face.index);
TStencilOperation.values[op.index], TStencilFace.values[face.index]);
} }
@override @override
Future setStencilReferenceValue(int value, Future setStencilReferenceValue(int value,
[StencilFace face = StencilFace.FRONT_AND_BACK]) async { [StencilFace face = StencilFace.FRONT_AND_BACK]) async {
MaterialInstance_setStencilReferenceValue( MaterialInstance_setStencilReferenceValue(pointer, value, face.index);
pointer, value, TStencilFace.values[face.index]);
} }
@override @override
@@ -150,8 +148,8 @@ class FFIMaterialInstance extends MaterialInstance {
@override @override
Future setCullingMode(CullingMode cullingMode) async { Future setCullingMode(CullingMode cullingMode) async {
MaterialInstance_setCullingMode( MaterialInstance_setCullingMode(pointer, cullingMode.index);
pointer, TCullingMode.values[cullingMode.index]); ;
} }
@override @override
@@ -177,8 +175,7 @@ class FFIMaterialInstance extends MaterialInstance {
@override @override
Future setTransparencyMode(TransparencyMode mode) async { Future setTransparencyMode(TransparencyMode mode) async {
MaterialInstance_setTransparencyMode( MaterialInstance_setTransparencyMode(pointer, mode.index);
pointer, TTransparencyMode.values[mode.index]);
} }
@override @override
@@ -196,13 +193,7 @@ class FFIMaterialInstance extends MaterialInstance {
@override @override
Future setParameterMat4(String name, Matrix4 matrix) async { Future setParameterMat4(String name, Matrix4 matrix) async {
final completer = Completer(); MaterialInstance_setParameterMat4(
final func = () { pointer, name.toNativeUtf8().cast<Char>(), matrix.storage.address);
MaterialInstance_setParameterMat4(pointer, name.toNativeUtf8().cast<Char>(), matrix.storage.address);
completer.complete();
};
final nativeCallable = NativeCallable<Void Function()>.listener(func);
RenderThread_addTask(nativeCallable.nativeFunction);
await completer.future;
} }
} }
@@ -1,6 +1,6 @@
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; import 'package:thermion_dart/src/bindings/bindings.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_texture.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
class FFIRenderTarget extends RenderTarget { class FFIRenderTarget extends RenderTarget {
@@ -1,6 +1,6 @@
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_asset.dart';
import 'package:thermion_dart/src/filament/src/scene.dart'; import 'package:thermion_dart/src/filament/src/interface/scene.dart';
import 'callbacks.dart'; import 'package:thermion_dart/src/bindings/bindings.dart';
class FFIScene extends Scene { class FFIScene extends Scene {
final Pointer<TScene> scene; final Pointer<TScene> scene;
@@ -1,4 +1,4 @@
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; import 'package:thermion_dart/src/bindings/bindings.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
class FFISwapChain extends SwapChain { class FFISwapChain extends SwapChain {
@@ -1,6 +1,6 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; import 'package:thermion_dart/src/bindings/bindings.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
class FFITexture extends Texture { class FFITexture extends Texture {
@@ -11,13 +11,15 @@ class FFITexture extends Texture {
Future<void> setLinearImage(covariant FFILinearImage image, Future<void> setLinearImage(covariant FFILinearImage image,
PixelDataFormat format, PixelDataType type) async { PixelDataFormat format, PixelDataType type) async {
final tPixelDataFormat = format.value;
final tPixelDataType = type.value;
final result = await withBoolCallback((cb) { final result = await withBoolCallback((cb) {
Texture_loadImageRenderThread( Texture_loadImageRenderThread(
_engine, _engine,
pointer, pointer,
image.pointer, image.pointer,
format.index, tPixelDataFormat,
type.index, tPixelDataType,
cb); cb);
}); });
@@ -114,28 +116,29 @@ class FFITexture extends Texture {
Uint8List buffer, Uint8List buffer,
PixelDataFormat format, PixelDataFormat format,
PixelDataType type) async { PixelDataType type) async {
final success = await withBoolCallback((cb) { throw UnimplementedError();
Texture_setImageWithDepthRenderThread( // final success = await withBoolCallback((cb) {
_engine, // Texture_setImageWithDepthRenderThread(
pointer, // _engine,
level, // pointer,
buffer.address, // level,
buffer.lengthInBytes, // buffer.address,
0, // buffer.lengthInBytes,
0, // 0,
zOffset, // 0,
width, // zOffset,
height, // width,
channels, // height,
depth, // channels,
format.index, // depth,
type.index, // format.index,
cb); // type.index,
}); // cb);
// });
if (!success) { // if (!success) {
throw Exception("Failed to set image"); // throw Exception("Failed to set image");
} // }
} }
@override @override
@@ -171,16 +174,12 @@ class FFILinearImage extends LinearImage {
[String name = "image"]) async { [String name = "image"]) async {
final namePtr = name.toNativeUtf8(); final namePtr = name.toNativeUtf8();
try { final imagePtr = await withPointerCallback<TLinearImage>((cb) {
final imagePtr = await withPointerCallback<TLinearImage>((cb) { Image_decodeRenderThread(
Image_decodeRenderThread( data.address, data.lengthInBytes, namePtr.cast(), cb);
data.address, data.lengthInBytes, namePtr.cast(), cb); });
});
return FFILinearImage(imagePtr); return FFILinearImage(imagePtr);
} finally {
calloc.free(namePtr);
}
} }
Future<void> destroy() async { Future<void> destroy() async {
@@ -2,12 +2,12 @@ import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:thermion_dart/src/filament/src/scene.dart'; import 'package:thermion_dart/src/filament/src/interface/scene.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_render_target.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_scene.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'callbacks.dart';
import 'ffi_camera.dart'; import 'ffi_camera.dart';
class FFIView extends View { class FFIView extends View {
@@ -24,14 +24,24 @@ class FFIView extends View {
FFIRenderTarget? renderTarget; FFIRenderTarget? renderTarget;
late CallbackHolder<PickCallbackFunction> _onPickResultHolder;
FFIView(this.view, this.app) { FFIView(this.view, this.app) {
final renderTargetPtr = View_getRenderTarget(view); final renderTargetPtr = View_getRenderTarget(view);
if (renderTargetPtr != nullptr) { if (renderTargetPtr != nullptr) {
renderTarget = FFIRenderTarget(renderTargetPtr, app); renderTarget = FFIRenderTarget(renderTargetPtr, app);
} }
_onPickResultCallable = _onPickResultHolder =
NativeCallable<PickCallbackFunction>.listener(_onPickResult); _onPickResult.asCallback();
}
///
///
///
Future dispose() async {
_onPickResultHolder.dispose();
} }
/// ///
@@ -76,7 +86,7 @@ class FFIView extends View {
@override @override
Future<Viewport> getViewport() async { Future<Viewport> getViewport() async {
TViewport vp = View_getViewport(view); final vp = View_getViewport(view);
return Viewport(vp.left, vp.bottom, vp.width, vp.height); return Viewport(vp.left, vp.bottom, vp.width, vp.height);
} }
@@ -141,7 +151,7 @@ class FFIView extends View {
@override @override
Future setRenderQuality(QualityLevel quality) async { Future setRenderQuality(QualityLevel quality) async {
View_setRenderQuality(view, TQualityLevel.values[quality.index]); View_setRenderQuality(view, quality.index);
} }
Future setScene(covariant FFIScene scene) async { Future setScene(covariant FFIScene scene) async {
@@ -154,7 +164,7 @@ class FFIView extends View {
} }
Future setBlendMode(BlendMode blendMode) async { Future setBlendMode(BlendMode blendMode) async {
View_setBlendMode(view, TBlendMode.values[blendMode.index]); View_setBlendMode(view, blendMode.index);
} }
@override @override
@@ -168,7 +178,6 @@ class FFIView extends View {
static int kMaxPickRequests = 1024; static int kMaxPickRequests = 1024;
final _pickRequests = List<({void Function(PickResult) handler, int x, int y})?>.generate(kMaxPickRequests, (idx) => null); final _pickRequests = List<({void Function(PickResult) handler, int x, int y})?>.generate(kMaxPickRequests, (idx) => null);
late NativeCallable<PickCallbackFunction> _onPickResultCallable;
/// ///
/// ///
@@ -184,7 +193,7 @@ class FFIView extends View {
y = viewport.height - y; y = viewport.height - y;
View_pick( View_pick(
view, pickRequestId, x, y, _onPickResultCallable.nativeFunction); view, pickRequestId, x, y, _onPickResultHolder.pointer);
} }
@@ -1,6 +1,6 @@
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; import 'package:thermion_dart/src/bindings/bindings.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_asset.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
class GridOverlay extends FFIAsset { class GridOverlay extends FFIAsset {
@@ -0,0 +1,3 @@
export 'resource_loader_io.dart'
if (dart.library.io) 'resource_loader_io.dart'
if (dart.library.js_interop) 'resource_loader_js.dart';
@@ -0,0 +1,8 @@
import 'dart:io';
import 'package:thermion_dart/thermion_dart.dart';
Future<Uint8List> defaultResourceLoader(String path) {
print("Loading file $path");
return File(path).readAsBytes();
}
@@ -0,0 +1,11 @@
import 'package:thermion_dart/thermion_dart.dart';
import 'package:http/http.dart' as http;
Future<Uint8List> defaultResourceLoader(String path) async {
if(path.startsWith("file://")) {
throw Exception("Unsupported URI : $path");
}
final response = await http.get(Uri.parse(path));
return response.bodyBytes;
}
@@ -1,7 +1,7 @@
library; library;
import 'package:animation_tools_dart/animation_tools_dart.dart'; import 'package:animation_tools_dart/animation_tools_dart.dart';
import 'package:thermion_dart/src/filament/src/layers.dart'; import 'package:thermion_dart/src/filament/src/interface/layers.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
export 'geometry.dart'; export 'geometry.dart';
@@ -1,4 +1,4 @@
import 'package:thermion_dart/src/filament/src/layers.dart'; import 'package:thermion_dart/src/filament/src/interface/layers.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
enum Projection { Perspective, Orthographic } enum Projection { Perspective, Orthographic }
@@ -1,15 +1,11 @@
import 'dart:typed_data'; import 'package:thermion_dart/src/filament/src/interface/scene.dart';
import 'package:thermion_dart/src/filament/src/engine.dart';
import 'package:thermion_dart/src/filament/src/scene.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
class FilamentConfig<T, U> { class FilamentConfig<T, U> {
final Backend backend; final Backend backend;
final T? renderCallback; final T? renderCallback;
final U? renderCallbackOwner; final U? renderCallbackOwner;
final Future<Uint8List> Function(String) resourceLoader; Future<Uint8List> Function(String)? resourceLoader;
final U? platform; final U? platform;
final U? sharedContext; final U? sharedContext;
final String? uberArchivePath; final String? uberArchivePath;
@@ -0,0 +1,37 @@
import 'dart:typed_data';
import 'package:thermion_dart/src/bindings/bindings.dart';
import '../../../viewer/viewer.dart';
class Geometry {
final Float32List vertices;
final Uint16List indices;
late final Float32List normals;
late final Float32List uvs;
final PrimitiveType primitiveType;
Geometry(
this.vertices,
this.indices, {
Float32List? normals,
Float32List? uvs,
this.primitiveType = PrimitiveType.TRIANGLES,
}) {
this.uvs = uvs ?? Float32List(0);
this.normals = normals ?? Float32List(0);
if (this.uvs.length != 0 && this.uvs.length != (vertices.length ~/ 3 * 2)) {
throw Exception(
"Expected either ${indices.length * 2} UVs, got ${this.uvs!.length}");
}
}
void scale(double factor) {
for (int i = 0; i < vertices.length; i++) {
vertices[i] = vertices[i] * factor;
}
}
bool get hasNormals => normals?.isNotEmpty == true;
bool get hasUVs => uvs?.isNotEmpty == true;
}
@@ -25,4 +25,7 @@ abstract class GizmoAsset extends ThermionAsset {
Future unhighlight(); Future unhighlight();
bool isNonPickable(ThermionEntity entity); bool isNonPickable(ThermionEntity entity);
bool isGizmoEntity(ThermionEntity entity); bool isGizmoEntity(ThermionEntity entity);
Future dispose();
} }
@@ -1,5 +1,3 @@
import 'dart:typed_data';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
@@ -1,4 +1,4 @@
import '../../viewer/viewer.dart'; import '../../../viewer/viewer.dart';
/// The result of a picking operation (see [ThermionViewer.pick] for more details). /// The result of a picking operation (see [ThermionViewer.pick] for more details).
/// [x] and [y] refer to the original screen coordinates used to call [pick]; this should /// [x] and [y] refer to the original screen coordinates used to call [pick]; this should
@@ -1,5 +1,5 @@
import 'package:thermion_dart/src/filament/src/layers.dart'; import 'package:thermion_dart/src/filament/src/interface/layers.dart';
import 'package:thermion_dart/src/filament/src/scene.dart'; import 'package:thermion_dart/src/filament/src/interface/scene.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
enum BlendMode { enum BlendMode {
@@ -57,7 +57,10 @@ abstract class View {
Future pick(int x, int y, void Function(PickResult) resultHandler); Future pick(int x, int y, void Function(PickResult) resultHandler);
///
///
///
Future dispose();
} }
@@ -78,12 +78,8 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
final camera = await view.getCamera(); final camera = await view.getCamera();
final viewport = await view.getViewport();
var viewMatrix = await camera.getViewMatrix();
var modelMatrix = await camera.getModelMatrix(); var modelMatrix = await camera.getModelMatrix();
var projectionMatrix = await camera.getProjectionMatrix();
var inverseProjectionMatrix = projectionMatrix.clone()..invert();
Vector3 currentPosition = modelMatrix.getTranslation(); Vector3 currentPosition = modelMatrix.getTranslation();
Vector3 forward = modelMatrix.forward; Vector3 forward = modelMatrix.forward;
@@ -1,30 +0,0 @@
import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
import '../../viewer/src/ffi/src/thermion_dart.g.dart';
class DartResourceLoader {
static final _assets = <int, Pointer>{};
static void loadResource(Pointer<Char> uri, Pointer<ResourceBuffer> out) {
try {
var data = File(uri.cast<Utf8>().toDartString().replaceAll("file://", ""))
.readAsBytesSync();
var ptr = calloc<Uint8>(data.lengthInBytes);
ptr.asTypedList(data.lengthInBytes).setRange(0, data.lengthInBytes, data);
out.ref.data = ptr.cast<Void>();
out.ref.size = data.lengthInBytes;
out.ref.id = _assets.length;
_assets[out.ref.id] = ptr;
} catch (err) {
print(err);
out.ref.size = -1;
}
}
static void freeResource(ResourceBuffer rb) {
calloc.free(_assets[rb.id]!);
}
}
+14 -16
View File
@@ -1,13 +1,11 @@
import 'dart:math'; import 'dart:math' ;
import 'dart:typed_data';
import '../../../thermion_dart.dart'; import '../../../thermion_dart.dart';
class GeometryHelper { class GeometryHelper {
static Geometry fullscreenQuad() { static Geometry fullscreenQuad() {
final vertices = final vertices = Float32List.fromList([-1.0, -1.0, 1.0, 3.0, -1.0, 1.0, -1.0, 3.0, 1.0]);
Float32List.fromList([-1.0, -1.0, 1.0, 3.0, -1.0, 1.0, -1.0, 3.0, 1.0]); final indices = Uint16List.fromList([0, 1, 2]);
final indices = [0, 1, 2];
return Geometry(vertices, indices); return Geometry(vertices, indices);
} }
@@ -56,7 +54,7 @@ class GeometryHelper {
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null; Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null; Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
return Geometry(vertices, indices, normals: _normals, uvs: _uvs); return Geometry(vertices, Uint16List.fromList(indices), normals: _normals, uvs: _uvs);
} }
static Geometry cube( static Geometry cube(
@@ -236,7 +234,7 @@ class GeometryHelper {
20, 21, 22, 20, 22, 23 // 4,0,3,4,3,7 20, 21, 22, 20, 22, 23 // 4,0,3,4,3,7
]; ];
return Geometry(vertices, indices, normals: _normals, uvs: _uvs); return Geometry(vertices, Uint16List.fromList(indices), normals: _normals, uvs: _uvs);
} }
// Helper function to flip the Y coordinate of UV coordinates (y = 1.0 - y) // Helper function to flip the Y coordinate of UV coordinates (y = 1.0 - y)
@@ -316,7 +314,7 @@ class GeometryHelper {
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null; Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null; Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
return Geometry(vertices, indices, normals: _normals, uvs: _uvs); return Geometry(vertices, Uint16List.fromList(indices), normals: _normals, uvs: _uvs);
} }
static Geometry conic( static Geometry conic(
@@ -440,7 +438,7 @@ class GeometryHelper {
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null; Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null; Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
return Geometry(vertices, indices, normals: _normals, uvs: _uvs); return Geometry(vertices, Uint16List.fromList(indices), normals: _normals, uvs: _uvs);
} }
static Geometry plane( static Geometry plane(
@@ -493,14 +491,14 @@ class GeometryHelper {
]) ])
: null; : null;
List<int> indices = [ final indices = Uint16List.fromList([
0, 0,
1, 1,
2, 2,
0, 0,
2, 2,
3, 3,
]; ]);
return Geometry(vertices, indices, normals: _normals, uvs: _uvs); return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
} }
@@ -640,7 +638,7 @@ class GeometryHelper {
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null; Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null; Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
return Geometry(vertices, indices, return Geometry(vertices, Uint16List.fromList(indices),
normals: _normals, uvs: _uvs, primitiveType: PrimitiveType.LINES); normals: _normals, uvs: _uvs, primitiveType: PrimitiveType.LINES);
} }
@@ -794,7 +792,7 @@ class GeometryHelper {
]) ])
: null; : null;
final indices = [ final indices = Uint16List.fromList([
// Front face // Front face
0, 1, 2, 0, 2, 3, 0, 1, 2, 0, 2, 3,
// Back face // Back face
@@ -807,7 +805,7 @@ class GeometryHelper {
16, 17, 18, 16, 18, 19, 16, 17, 18, 16, 18, 19,
// Left face // Left face
20, 21, 22, 20, 22, 23 20, 21, 22, 20, 22, 23
]; ]);
return Geometry(vertices, indices, normals: _normals, uvs: _uvs); return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
} }
@@ -865,7 +863,7 @@ class GeometryHelper {
: null; : null;
// Define indices for triangular faces // Define indices for triangular faces
List<int> indices = [ Uint16List indices = Uint16List.fromList([
// Bottom face (rectangle) // Bottom face (rectangle)
0, 1, 2, 0, 1, 2,
0, 2, 3, 0, 2, 3,
@@ -883,7 +881,7 @@ class GeometryHelper {
// Back rectangular face // Back rectangular face
2, 3, 4, 2, 3, 4,
2, 4, 5, 2, 4, 5,
]; ]);
return Geometry(vertices, indices, normals: _normals, uvs: _uvs); return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
} }
@@ -1,6 +1,7 @@
import 'dart:math'; import 'dart:math';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:image/image.dart' as img; import 'package:image/image.dart' as img;
import 'package:thermion_dart/thermion_dart.dart';
Future<Uint8List> pixelBufferToBmp(Uint8List pixelBuffer, int width, int height, Future<Uint8List> pixelBufferToBmp(Uint8List pixelBuffer, int width, int height,
{bool hasAlpha = true, bool isFloat = false}) async { {bool hasAlpha = true, bool isFloat = false}) async {
+10 -7
View File
@@ -1,9 +1,8 @@
// Helper function to convert double4x4 to Matrix4 import 'package:thermion_dart/src/bindings/bindings.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
import 'dart:ffi';
Matrix4 double4x4ToMatrix4(double4x4 mat) { Matrix4 double4x4ToMatrix4(double4x4 mat) {
return Matrix4.fromList([ return Matrix4.fromList([
mat.col1[0], mat.col1[0],
mat.col1[1], mat.col1[1],
@@ -26,12 +25,16 @@ Matrix4 double4x4ToMatrix4(double4x4 mat) {
double4x4 matrix4ToDouble4x4(Matrix4 mat) { double4x4 matrix4ToDouble4x4(Matrix4 mat) {
final out = Struct.create<double4x4>(); final out = Struct.create<double4x4>();
Array<Float64> col1 =out.col1;
Array<Float64> col2 = out.col2;
Array<Float64> col3 =out.col3;
Array<Float64> col4= out.col4;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
out.col1[i] = mat.storage[i]; col1[i] = mat.storage[i];
out.col2[i] = mat.storage[i + 4]; col2[i] = mat.storage[i + 4];
out.col3[i] = mat.storage[i + 8]; col3[i] = mat.storage[i + 8];
out.col4[i] = mat.storage[i + 12]; col4[i] = mat.storage[i + 12];
} }
return out; return out;
@@ -1,9 +1,9 @@
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_render_target.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_scene.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_view.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_view.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
class TextureProjection { class TextureProjection {
@@ -1,20 +1,15 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'package:thermion_dart/src/filament/src/implementation/background_image.dart';
import 'dart:typed_data'; import '../../../../filament/src/implementation/ffi_asset.dart';
import 'package:thermion_dart/src/filament/src/light_options.dart'; import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/background_image.dart'; import '../../../../filament/src/implementation/ffi_scene.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart'; import '../../../../filament/src/implementation/grid_overlay.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart';
import 'package:thermion_dart/src/filament/src/layers.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/grid_overlay.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart' as v64; import 'package:vector_math/vector_math_64.dart' as v64;
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'callbacks.dart'; import '../../../../filament/src/implementation/ffi_camera.dart';
import 'ffi_camera.dart'; import '../../../../filament/src/implementation/ffi_view.dart';
import 'ffi_view.dart';
const FILAMENT_ASSET_ERROR = 0; const FILAMENT_ASSET_ERROR = 0;
@@ -50,6 +45,7 @@ class ThermionViewerFFI extends ThermionViewer {
/// ///
/// ///
Future setViewport(int width, int height) async { Future setViewport(int width, int height) async {
print("Setting viewport to ${width}x${height}");
await view.setViewport(width.toInt(), height.toInt()); await view.setViewport(width.toInt(), height.toInt());
for (final camera in _cameras) { for (final camera in _cameras) {
@@ -121,8 +117,15 @@ class ThermionViewerFFI extends ThermionViewer {
/// ///
@override @override
Future render() async { Future render() async {
await withVoidCallback( await withVoidCallback((cb) =>
(cb) => RenderTicker_renderRenderThread(app.renderTicker, 0, cb)); RenderTicker_renderRenderThread(app.renderTicker, 0.toBigInt, cb));
if (FILAMENT_SINGLE_THREADED) {
await withVoidCallback(
(cb) => Engine_executeRenderThread(app.engine, cb));
} else {
await withVoidCallback(
(cb) => Engine_flushAndWaitRenderThread(app.engine, cb));
}
} }
double _msPerFrame = 1000.0 / 60.0; double _msPerFrame = 1000.0 / 60.0;
@@ -248,11 +251,21 @@ class ThermionViewerFFI extends ThermionViewer {
/// ///
@override @override
Future loadIbl(String lightingPath, {double intensity = 30000}) async { Future loadIbl(String lightingPath, {double intensity = 30000}) async {
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
var data = await loadAssetFromUri(lightingPath); var data = await loadAssetFromUri(lightingPath);
indirectLight = await withPointerCallback<TIndirectLight>((cb) { indirectLight = await withPointerCallback<TIndirectLight>((cb) {
Engine_buildIndirectLightRenderThread( Engine_buildIndirectLightRenderThread(
app.engine, data.address, data.length, intensity, cb, nullptr); app.engine, data.address, data.length, intensity, cb, nullptr);
}); });
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
data.free();
}
data.free();
Scene_setIndirectLight(scene.scene, indirectLight!); Scene_setIndirectLight(scene.scene, indirectLight!);
} }
@@ -264,7 +277,18 @@ class ThermionViewerFFI extends ThermionViewer {
if (indirectLight == null) { if (indirectLight == null) {
throw Exception("No IBL loaded"); throw Exception("No IBL loaded");
} }
late Pointer stackPtr;
if (FILAMENT_WASM) {
//stackPtr = stackSave();
}
IndirectLight_setRotation(indirectLight!, rotationMatrix.storage.address); IndirectLight_setRotation(indirectLight!, rotationMatrix.storage.address);
if (FILAMENT_WASM) {
//stackRestore(stackPtr);
rotationMatrix.storage.free();
}
} }
/// ///
@@ -303,8 +327,8 @@ class ThermionViewerFFI extends ThermionViewer {
/// ///
@override @override
Future<ThermionEntity> addDirectLight(DirectLight directLight) async { Future<ThermionEntity> addDirectLight(DirectLight directLight) async {
var entity = LightManager_createLight(app.engine, app.lightManager, var entity = LightManager_createLight(
TLightType.values[directLight.type.index]); app.engine, app.lightManager, directLight.type.index);
if (entity == FILAMENT_ASSET_ERROR) { if (entity == FILAMENT_ASSET_ERROR) {
throw Exception("Failed to add light to scene"); throw Exception("Failed to add light to scene");
} }
@@ -446,8 +470,6 @@ class ThermionViewerFFI extends ThermionViewer {
@override @override
Future setPostProcessing(bool enabled) async { Future setPostProcessing(bool enabled) async {
View_setPostProcessing(view.view, enabled); View_setPostProcessing(view.view, enabled);
await withVoidCallback(
(cb) => Engine_flushAndWaitRenderThead(app.engine, cb));
} }
/// ///
@@ -478,10 +500,9 @@ class ThermionViewerFFI extends ThermionViewer {
/// ///
@override @override
Future setAntiAliasing(bool msaa, bool fxaa, bool taa) async { Future setAntiAliasing(bool msaa, bool fxaa, bool taa) async {
if (Platform.isWindows && msaa) { if (!FILAMENT_SINGLE_THREADED && IS_WINDOWS && msaa) {
throw Exception("MSAA is not currently supported on Windows"); throw Exception("MSAA is not currently supported on Windows");
} }
View_setAntiAliasing(view.view, msaa, fxaa, taa); View_setAntiAliasing(view.view, msaa, fxaa, taa);
} }
@@ -1,7 +1,7 @@
import 'package:thermion_dart/src/filament/src/layers.dart'; import 'package:thermion_dart/src/filament/src/interface/layers.dart';
import 'package:thermion_dart/src/filament/src/light_options.dart'; import 'package:thermion_dart/src/filament/src/interface/light_options.dart';
import '../../filament/src/shared_types.dart'; import '../../filament/src/interface/shared_types.dart';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
import 'dart:async'; import 'dart:async';
@@ -1,317 +0,0 @@
import 'dart:typed_data';
import 'package:thermion_dart/src/filament/src/light_options.dart';
import 'package:thermion_dart/thermion_dart.dart';
class ThermionViewerStub extends ThermionViewer {
@override
Future<ThermionEntity> addDirectLight(DirectLight light) {
// TODO: implement addDirectLight
throw UnimplementedError();
}
@override
Future addToScene(covariant ThermionAsset asset) {
// TODO: implement addToScene
throw UnimplementedError();
}
@override
Future clearBackgroundImage({bool destroy = false}) {
// TODO: implement clearBackgroundImage
throw UnimplementedError();
}
@override
Future<Camera> createCamera() {
// TODO: implement createCamera
throw UnimplementedError();
}
@override
Future<ThermionAsset> createGeometry(Geometry geometry,
{List<MaterialInstance>? materialInstances,
bool keepData = false,
bool addToScene = true}) {
// TODO: implement createGeometry
throw UnimplementedError();
}
@override
Future destroyAsset(ThermionAsset asset) {
// TODO: implement destroyAsset
throw UnimplementedError();
}
@override
Future destroyAssets() {
// TODO: implement destroyAssets
throw UnimplementedError();
}
@override
Future destroyCamera(covariant Camera camera) {
// TODO: implement destroyCamera
throw UnimplementedError();
}
@override
Future destroyLights() {
// TODO: implement destroyLights
throw UnimplementedError();
}
@override
Future dispose() {
// TODO: implement dispose
throw UnimplementedError();
}
@override
Future<Camera> getActiveCamera() {
// TODO: implement getActiveCamera
throw UnimplementedError();
}
@override
int getCameraCount() {
// TODO: implement getCameraCount
throw UnimplementedError();
}
@override
Future<GizmoAsset> getGizmo(GizmoType type) {
// TODO: implement getGizmo
throw UnimplementedError();
}
@override
Future<Aabb3> getRenderableBoundingBox(ThermionEntity entity) {
// TODO: implement getRenderableBoundingBox
throw UnimplementedError();
}
@override
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity) {
// TODO: implement getViewportBoundingBox
throw UnimplementedError();
}
@override
// TODO: implement initialized
Future<bool> get initialized => throw UnimplementedError();
@override
Future<ThermionAsset> loadGltf(String path,
{bool addToScene = true,
int numInstances = 1,
bool keepData = false,
String? relativeResourcePath}) {
// TODO: implement loadGltf
throw UnimplementedError();
}
@override
Future loadIbl(String lightingPath, {double intensity = 30000}) {
// TODO: implement loadIbl
throw UnimplementedError();
}
@override
Future loadSkybox(String skyboxPath) {
// TODO: implement loadSkybox
throw UnimplementedError();
}
@override
// TODO: implement msPerFrame
double get msPerFrame => throw UnimplementedError();
@override
void onDispose(Future Function() callback) {
// TODO: implement onDispose
}
@override
Future pick(int x, int y, void Function(PickResult p1) resultHandler) {
// TODO: implement pick
throw UnimplementedError();
}
@override
Future removeFromScene(covariant ThermionAsset asset) {
// TODO: implement removeFromScene
throw UnimplementedError();
}
@override
Future removeIbl() {
// TODO: implement removeIbl
throw UnimplementedError();
}
@override
Future removeLight(ThermionEntity light) {
// TODO: implement removeLight
throw UnimplementedError();
}
@override
Future removeSkybox() {
// TODO: implement removeSkybox
throw UnimplementedError();
}
@override
Future render() {
// TODO: implement render
throw UnimplementedError();
}
@override
// TODO: implement rendering
bool get rendering => throw UnimplementedError();
@override
Future rotateIbl(Matrix3 rotation) {
// TODO: implement rotateIbl
throw UnimplementedError();
}
@override
Future setActiveCamera(covariant Camera camera) {
// TODO: implement setActiveCamera
throw UnimplementedError();
}
@override
Future setAntiAliasing(bool msaa, bool fxaa, bool taa) {
// TODO: implement setAntiAliasing
throw UnimplementedError();
}
@override
Future setBackgroundColor(double r, double g, double b, double alpha) {
// TODO: implement setBackgroundColor
throw UnimplementedError();
}
@override
Future setBackgroundImage(String path, {bool fillHeight = false}) {
// TODO: implement setBackgroundImage
throw UnimplementedError();
}
@override
Future setBackgroundImagePosition(double x, double y, {bool clamp = false}) {
// TODO: implement setBackgroundImagePosition
throw UnimplementedError();
}
@override
Future setBloom(bool enabled, double strength) {
// TODO: implement setBloom
throw UnimplementedError();
}
@override
Future setFrameRate(int framerate) {
// TODO: implement setFrameRate
throw UnimplementedError();
}
@override
Future setGridOverlayVisibility(bool visible) {
// TODO: implement setGridOverlayVisibility
throw UnimplementedError();
}
@override
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction) {
// TODO: implement setLightDirection
throw UnimplementedError();
}
@override
Future setLightPosition(
ThermionEntity lightEntity, double x, double y, double z) {
// TODO: implement setLightPosition
throw UnimplementedError();
}
@override
Future setPostProcessing(bool enabled) {
// TODO: implement setPostProcessing
throw UnimplementedError();
}
@override
Future setPriority(ThermionEntity entityId, int priority) {
// TODO: implement setPriority
throw UnimplementedError();
}
@override
Future setRendering(bool render) {
// TODO: implement setRendering
throw UnimplementedError();
}
@override
Future setShadowType(ShadowType shadowType) {
// TODO: implement setShadowType
throw UnimplementedError();
}
@override
Future setShadowsEnabled(bool enabled) {
// TODO: implement setShadowsEnabled
throw UnimplementedError();
}
@override
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale) {
// TODO: implement setSoftShadowOptions
throw UnimplementedError();
}
@override
Future setToneMapping(ToneMapper mapper) {
// TODO: implement setToneMapping
throw UnimplementedError();
}
@override
Future setViewFrustumCulling(bool enabled) {
// TODO: implement setViewFrustumCulling
throw UnimplementedError();
}
@override
Future setViewport(int width, int height) {
// TODO: implement setViewport
throw UnimplementedError();
}
@override
// TODO: implement view
View get view => throw UnimplementedError();
@override
Future setLayerVisibility(VisibilityLayers layer, bool visible) {
// TODO: implement setLayerVisibility
throw UnimplementedError();
}
@override
Future<ThermionAsset> loadGltfFromBuffer(Uint8List data,
{
String? relativeResourcePath,
int numInstances = 1,
bool keepData = false,
int priority = 4,
int layer = 0,
bool loadResourcesAsync = false,
}) {
throw UnimplementedError();
}
}
@@ -3,7 +3,7 @@ library thermion_flutter_js;
import 'dart:js_interop'; import 'dart:js_interop';
import '../../../../filament/src/shared_types.dart'; import '../../../../filament/src/interface/shared_types.dart';
/// ///
/// An extension type on [JSObject] that represents a /// An extension type on [JSObject] that represents a
@@ -1,77 +0,0 @@
import 'package:vector_math/vector_math_64.dart';
import '../../thermion_viewer_base.dart';
class ThermionWasmCamera extends Camera {
final int pointer;
ThermionWasmCamera(this.pointer);
@override
Future setProjectionMatrixWithCulling(
Matrix4 projectionMatrix, double near, double far) {
// TODO: implement setProjectionMatrixWithCulling
throw UnimplementedError();
}
@override
Future<Matrix4> getModelMatrix() {
// TODO: implement getModelMatrix
throw UnimplementedError();
}
@override
Future setLensProjection({double near = kNear, double far = kFar, double aspect = 1.0, double focalLength = kFocalLength}) {
// TODO: implement setLensProjection
throw UnimplementedError();
}
@override
Future setTransform(Matrix4 transform) {
// TODO: implement setTransform
throw UnimplementedError();
}
@override
ThermionEntity getEntity() {
// TODO: implement getEntity
throw UnimplementedError();
}
@override
Future setModelMatrix(Matrix4 matrix) {
// TODO: implement setModelMatrix
throw UnimplementedError();
}
@override
Future<double> getCullingFar() {
// TODO: implement getCullingFar
throw UnimplementedError();
}
@override
Future<double> getFocalLength() {
// TODO: implement getFocalLength
throw UnimplementedError();
}
@override
Future<double> getNear() {
// TODO: implement getNear
throw UnimplementedError();
}
@override
Future<Matrix4> getViewMatrix() {
// TODO: implement getViewMatrix
throw UnimplementedError();
}
@override
Future setProjection(Projection projection, double left, double right, double bottom, double top, double near, double far) {
// TODO: implement setProjection
throw UnimplementedError();
}
}
@@ -1,147 +0,0 @@
import 'package:vector_math/vector_math_64.dart';
import '../../../viewer.dart';
class ThermionWasmMaterialInstance extends MaterialInstance {
final int pointer;
ThermionWasmMaterialInstance(this.pointer);
@override
Future setParameterFloat2(String name, double x, double y) {
// TODO: implement setParameterFloat2
throw UnimplementedError();
}
@override
Future setParameterFloat(String name, double x) {
// TODO: implement setParameterFloat
throw UnimplementedError();
}
@override
Future setDepthFunc(SamplerCompareFunction depthFunc) {
// TODO: implement setDepthFunc
throw UnimplementedError();
}
@override
Future setParameterFloat4(String name, double x, double y, double z, double w) {
// TODO: implement setParameterFloat4
throw UnimplementedError();
}
@override
Future setParameterInt(String name, int value) {
// TODO: implement setParameterInt
throw UnimplementedError();
}
@override
Future setDepthCullingEnabled(enabled) {
// TODO: implement setDepthCullingEnabled
throw UnimplementedError();
}
@override
Future setDepthWriteEnabled(enabled) {
// TODO: implement setDepthWriteEnabled
throw UnimplementedError();
}
@override
Future setStencilCompareFunction(SamplerCompareFunction func, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilCompareFunction
throw UnimplementedError();
}
@override
Future setStencilOpDepthFail(StencilOperation op, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilOpDepthFail
throw UnimplementedError();
}
@override
Future setStencilOpDepthStencilPass(StencilOperation op, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilOpDepthStencilPass
throw UnimplementedError();
}
@override
Future setStencilOpStencilFail(StencilOperation op, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilOpStencilFail
throw UnimplementedError();
}
@override
Future setStencilReferenceValue(int value, [StencilFace face = StencilFace.FRONT_AND_BACK]) {
// TODO: implement setStencilReferenceValue
throw UnimplementedError();
}
@override
Future<bool> isStencilWriteEnabled() {
// TODO: implement isStencilWriteEnabled
throw UnimplementedError();
}
@override
Future setCullingMode(CullingMode cullingMode) {
// TODO: implement setCullingMode
throw UnimplementedError();
}
@override
Future setStencilWriteEnabled(bool enabled) {
// TODO: implement setStencilWriteEnabled
throw UnimplementedError();
}
@override
Future dispose() {
// TODO: implement dispose
throw UnimplementedError();
}
@override
Future setParameterBool(String name, bool value) {
// TODO: implement setParameterBool
throw UnimplementedError();
}
@override
Future setParameterFloat3(String name, double x, double y, double z) {
// TODO: implement setParameterFloat3
throw UnimplementedError();
}
@override
Future setParameterFloat3Array(String name, List<Vector3> data) {
// TODO: implement setParameterFloat3Array
throw UnimplementedError();
}
@override
Future setParameterTexture(String name, covariant Texture texture, covariant TextureSampler sampler) {
// TODO: implement setParameterTexture
throw UnimplementedError();
}
@override
Future setStencilReadMask(int mask) {
// TODO: implement setStencilReadMask
throw UnimplementedError();
}
@override
Future setStencilWriteMask(int mask) {
// TODO: implement setStencilWriteMask
throw UnimplementedError();
}
@override
Future setTransparencyMode(TransparencyMode mode) {
// TODO: implement setTransparencyMode
throw UnimplementedError();
}
}
@@ -19,29 +19,29 @@
// import 'camera.dart'; // import 'camera.dart';
// import 'material_instance.dart'; // import 'material_instance.dart';
// extension type _EmscriptenModule(JSObject _) implements JSObject { extension type _EmscriptenModule(JSObject _) implements JSObject {
// external JSAny? ccall(String name, String returnType, external JSAny? ccall(String name, String returnType,
// JSArray<JSString> argTypes, JSArray<JSAny?> args, JSAny? opts); JSArray<JSString> argTypes, JSArray<JSAny?> args, JSAny? opts);
// external JSNumber _malloc(int numBytes); external JSNumber _malloc(int numBytes);
// external void _free(JSNumber addr); external void _free(JSNumber addr);
// external JSNumber stackAlloc(int numBytes); external JSNumber stackAlloc(int numBytes);
// external JSAny getValue(JSNumber addr, String llvmType); external JSAny getValue(JSNumber addr, String llvmType);
// external void setValue(JSNumber addr, JSNumber value, String llvmType); external void setValue(JSNumber addr, JSNumber value, String llvmType);
// external JSString intArrayToString(JSAny ptr); external JSString intArrayToString(JSAny ptr);
// external JSString UTF8ToString(JSAny ptr); external JSString UTF8ToString(JSAny ptr);
// external void stringToUTF8( external void stringToUTF8(
// JSString str, JSNumber ptr, JSNumber maxBytesToWrite); JSString str, JSNumber ptr, JSNumber maxBytesToWrite);
// external void writeArrayToMemory(JSUint8Array data, JSNumber ptr); external void writeArrayToMemory(JSUint8Array data, JSNumber ptr);
// external JSNumber addFunction(JSFunction f, String signature); external JSNumber addFunction(JSFunction f, String signature);
// external void removeFunction(JSNumber f); external void removeFunction(JSNumber f);
// external JSAny get ALLOC_STACK; external JSAny get ALLOC_STACK;
// external JSAny get HEAPU32; external JSAny get HEAPU32;
// external JSAny get HEAP32; external JSAny get HEAP32;
// } }
// typedef ThermionViewerImpl = ThermionViewerWasm; // typedef ThermionViewerImpl = ThermionViewerWasm;
@@ -80,7 +80,6 @@
// _module = module as _EmscriptenModule; // _module = module as _EmscriptenModule;
// } // }
// } // }
// void _setAssetPathPrefix(String assetPathPrefix) { // void _setAssetPathPrefix(String assetPathPrefix) {
// _module!.ccall( // _module!.ccall(
// "thermion_dart_web_set_asset_path_prefix", // "thermion_dart_web_set_asset_path_prefix",
+3 -6
View File
@@ -1,9 +1,6 @@
library thermion_viewer; library thermion_viewer;
export 'src/thermion_viewer_base.dart'; export 'src/thermion_viewer_base.dart';
export '../filament/src/filament_app.dart'; export '../filament/src/interface/filament_app.dart';
export 'src/thermion_viewer_stub.dart' export 'src/ffi/src/thermion_viewer_ffi.dart';
if (dart.library.io) 'src/ffi/thermion_viewer_ffi.dart' export '../filament/src/interface/shared_types.dart';
if (dart.library.js_interop) 'src/web_wasm/thermion_viewer_web_wasm.dart';
export '../filament/src/shared_types.dart';
+2
View File
@@ -1,7 +1,9 @@
library filament_dart; library filament_dart;
export 'dart:typed_data';
export 'package:vector_math/vector_math_64.dart' hide Colors; export 'package:vector_math/vector_math_64.dart' hide Colors;
export 'src/viewer/viewer.dart'; export 'src/viewer/viewer.dart';
export 'src/input/input.dart'; export 'src/input/input.dart';
export 'src/utils/utils.dart'; export 'src/utils/utils.dart';
export 'src/filament/filament.dart'; export 'src/filament/filament.dart';
export 'src/bindings/bindings.dart' hide Aabb2, Aabb3;
+7 -7
View File
@@ -1,8 +1,8 @@
#pragma once #pragma once
#ifndef FLUTTER_FILAMENT_LOG_H #ifdef __EMSCRIPTEN__
#define FLUTTER_FILAMENT_LOG_H #include <emscripten/console.h>
#endif
#ifdef __OBJC__ #ifdef __OBJC__
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#elif defined __ANDROID__ #elif defined __ANDROID__
@@ -14,6 +14,9 @@
#include <iostream> #include <iostream>
#endif #endif
#ifdef __EMSCRIPTEN__
#define Log(...) emscripten_console_logf(__VA_ARGS__);
#else
static void Log(const char *fmt, ...) { static void Log(const char *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
@@ -27,10 +30,9 @@ static void Log(const char *fmt, ...) {
vprintf(fmt, args); vprintf(fmt, args);
std::cout << std::endl; std::cout << std::endl;
#endif #endif
va_end(args); va_end(args);
} }
#endif
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) #define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
@@ -61,5 +63,3 @@ static void Log(const char *fmt, ...) {
#endif #endif
#define ERROR(fmt, ...) Log("Error: %s:%d " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) #define ERROR(fmt, ...) Log("Error: %s:%d " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__)
#endif
+1 -1
View File
@@ -17,7 +17,7 @@ static filament::math::mat4f convert_double_to_mat4f(double* data)
// Helper function to convert filament::math::mat4 to double4x4 // Helper function to convert filament::math::mat4 to double4x4
static double4x4 convert_mat4_to_double4x4(const filament::math::mat4 &mat) static double4x4 convert_mat4_to_double4x4(const filament::math::mat4 &mat)
{ {
return double4x4{ return double4x4 {
{mat[0][0], mat[0][1], mat[0][2], mat[0][3]}, {mat[0][0], mat[0][1], mat[0][2], mat[0][3]},
{mat[1][0], mat[1][1], mat[1][2], mat[1][3]}, {mat[1][0], mat[1][1], mat[1][2], mat[1][3]},
{mat[2][0], mat[2][1], mat[2][2], mat[2][3]}, {mat[2][0], mat[2][1], mat[2][2], mat[2][3]},
@@ -29,7 +29,9 @@ namespace thermion
{ {
public: public:
RenderTicker(filament::Renderer *renderer) : mRenderer(renderer) { } RenderTicker(
filament::Engine *engine,
filament::Renderer *renderer) : mEngine(engine), mRenderer(renderer) { }
~RenderTicker(); ~RenderTicker();
/// @brief /// @brief
@@ -55,6 +57,7 @@ namespace thermion
private: private:
std::mutex mMutex; std::mutex mMutex;
filament::Engine *mEngine = nullptr;
filament::Renderer *mRenderer = nullptr; filament::Renderer *mRenderer = nullptr;
std::vector<AnimationManager*> mAnimationManagers; std::vector<AnimationManager*> mAnimationManagers;
std::vector<std::pair<filament::SwapChain*, std::vector<filament::View*>>> mRenderable; std::vector<std::pair<filament::SwapChain*, std::vector<filament::View*>>> mRenderable;
@@ -5,6 +5,7 @@ extern "C"
{ {
#endif #endif
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "APIExport.h" #include "APIExport.h"
@@ -156,6 +157,7 @@ extern "C"
GIZMO_TYPE_TRANSLATION, GIZMO_TYPE_TRANSLATION,
GIZMO_TYPE_ROTATION GIZMO_TYPE_ROTATION
}; };
typedef enum TGizmoType TGizmoType;
enum TPrimitiveType { enum TPrimitiveType {
// don't change the enums values (made to match GL) // don't change the enums values (made to match GL)
@@ -165,11 +167,12 @@ extern "C"
PRIMITIVETYPE_TRIANGLES = 4, //!< triangles PRIMITIVETYPE_TRIANGLES = 4, //!< triangles
PRIMITIVETYPE_TRIANGLE_STRIP = 5 //!< triangle strip PRIMITIVETYPE_TRIANGLE_STRIP = 5 //!< triangle strip
}; };
typedef enum TPrimitiveType TPrimitiveType;
EMSCRIPTEN_KEEPALIVE extern uint64_t TSWAP_CHAIN_CONFIG_TRANSPARENT; extern uint64_t TSWAP_CHAIN_CONFIG_TRANSPARENT;
EMSCRIPTEN_KEEPALIVE extern uint64_t TSWAP_CHAIN_CONFIG_READABLE; extern uint64_t TSWAP_CHAIN_CONFIG_READABLE;
EMSCRIPTEN_KEEPALIVE extern uint64_t TSWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER; extern uint64_t TSWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER;
EMSCRIPTEN_KEEPALIVE extern uint64_t TSWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER; extern uint64_t TSWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER;
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -1,5 +1,5 @@
#ifndef _API_EXPORT_H #pragma once
#define _API_EXPORT_H
#ifdef _WIN32 #ifdef _WIN32
#ifdef IS_DLL #ifdef IS_DLL
#define EMSCRIPTEN_KEEPALIVE __declspec(dllimport) #define EMSCRIPTEN_KEEPALIVE __declspec(dllimport)
@@ -44,4 +44,3 @@
#if defined(__APPLE__) || defined(__EMSCRIPTEN__) #if defined(__APPLE__) || defined(__EMSCRIPTEN__)
#include <stddef.h> #include <stddef.h>
#endif #endif
#endif
+23 -22
View File
@@ -13,37 +13,38 @@ enum TProjection {
Perspective, Perspective,
Orthographic Orthographic
}; };
typedef enum TProjection TProjection;
// Camera methods // Camera methods
EMSCRIPTEN_KEEPALIVE void Camera_setExposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity); void Camera_setExposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getModelMatrix(TCamera *const camera); double4x4 Camera_getModelMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getViewMatrix(TCamera *const camera); double4x4 Camera_getViewMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getProjectionMatrix(TCamera *const camera); double4x4 Camera_getProjectionMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getCullingProjectionMatrix(TCamera *const camera); double4x4 Camera_getCullingProjectionMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE void Camera_getFrustum(TCamera *camera, double* out); void Camera_getFrustum(TCamera *camera, double* out);
EMSCRIPTEN_KEEPALIVE void Camera_setProjectionMatrix(TCamera *camera, double *matrix, double near, double far); void Camera_setProjectionMatrix(TCamera *camera, double *matrix, double near, double far);
EMSCRIPTEN_KEEPALIVE void Camera_setProjectionFromFov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal); void Camera_setProjectionFromFov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal);
EMSCRIPTEN_KEEPALIVE double Camera_getFocalLength(TCamera *const camera); double Camera_getFocalLength(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getViewMatrix(TCamera *const camera); double4x4 Camera_getViewMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getModelMatrix(TCamera* camera); double4x4 Camera_getModelMatrix(TCamera* camera);
EMSCRIPTEN_KEEPALIVE void Camera_lookAt(TCamera* camera, double3 eye, double3 focus, double3 up); void Camera_lookAt(TCamera* camera, double3 eye, double3 focus, double3 up);
EMSCRIPTEN_KEEPALIVE double Camera_getNear(TCamera *camera); double Camera_getNear(TCamera *camera);
EMSCRIPTEN_KEEPALIVE double Camera_getCullingFar(TCamera *camera); double Camera_getCullingFar(TCamera *camera);
EMSCRIPTEN_KEEPALIVE float Camera_getFov(TCamera *camera, bool horizontal); float Camera_getFov(TCamera *camera, bool horizontal);
EMSCRIPTEN_KEEPALIVE double Camera_getFocusDistance(TCamera *camera); double Camera_getFocusDistance(TCamera *camera);
EMSCRIPTEN_KEEPALIVE void Camera_setFocusDistance(TCamera *camera, float focusDistance); void Camera_setFocusDistance(TCamera *camera, float focusDistance);
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling( void Camera_setCustomProjectionWithCulling(
TCamera* camera, TCamera* camera,
double4x4 projectionMatrix, double4x4 projectionMatrix,
double near, double near,
double far double far
); );
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera* camera, double *tModelMatrix); void Camera_setModelMatrix(TCamera* camera, double *tModelMatrix);
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength); void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength);
EMSCRIPTEN_KEEPALIVE EntityId Camera_getEntity(TCamera* camera); EntityId Camera_getEntity(TCamera* camera);
EMSCRIPTEN_KEEPALIVE void Camera_setProjection(TCamera *const tCamera, TProjection projection, double left, double right, void Camera_setProjection(TCamera *const tCamera, TProjection projection, double left, double right,
double bottom, double top, double bottom, double top,
double near, double far); double near, double far);
@@ -18,6 +18,7 @@ enum TBackend {
BACKEND_METAL = 3, //!< Selects the Metal driver if the platform supports it (default on MacOS/iOS). BACKEND_METAL = 3, //!< Selects the Metal driver if the platform supports it (default on MacOS/iOS).
BACKEND_NOOP = 4, //!< Selects the no-op driver for testing purposes. BACKEND_NOOP = 4, //!< Selects the no-op driver for testing purposes.
}; };
typedef enum TBackend TBackend;
EMSCRIPTEN_KEEPALIVE TEngine *Engine_create( EMSCRIPTEN_KEEPALIVE TEngine *Engine_create(
TBackend backend, TBackend backend,
@@ -50,6 +51,7 @@ EMSCRIPTEN_KEEPALIVE void Engine_destroyTexture(TEngine *tEngine, TTexture *tTex
EMSCRIPTEN_KEEPALIVE TFence *Engine_createFence(TEngine *tEngine); EMSCRIPTEN_KEEPALIVE TFence *Engine_createFence(TEngine *tEngine);
EMSCRIPTEN_KEEPALIVE void Engine_destroyFence(TEngine *tEngine, TFence *tFence); EMSCRIPTEN_KEEPALIVE void Engine_destroyFence(TEngine *tEngine, TFence *tFence);
EMSCRIPTEN_KEEPALIVE void Engine_flushAndWait(TEngine *tEngine); EMSCRIPTEN_KEEPALIVE void Engine_flushAndWait(TEngine *tEngine);
EMSCRIPTEN_KEEPALIVE void Engine_execute(TEngine *tEngine);
EMSCRIPTEN_KEEPALIVE TMaterial *Engine_buildMaterial(TEngine *tEngine, const uint8_t* materialData, size_t length); EMSCRIPTEN_KEEPALIVE TMaterial *Engine_buildMaterial(TEngine *tEngine, const uint8_t* materialData, size_t length);
EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterial(TEngine *tEngine, TMaterial *tMaterial); EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterial(TEngine *tEngine, TMaterial *tMaterial);
+3 -1
View File
@@ -13,9 +13,11 @@ extern "C"
enum TGizmoAxis { X, Y, Z }; enum TGizmoAxis { X, Y, Z };
enum TGizmoPickResultType { AxisX, AxisY, AxisZ, Parent, None }; enum TGizmoPickResultType { AxisX, AxisY, AxisZ, Parent, None };
typedef enum TGizmoPickResultType TGizmoPickResultType;
typedef enum TGizmoAxis TGizmoAxis;
typedef void (*GizmoPickCallback)(TGizmoPickResultType resultType, float x, float y, float z); typedef void (*GizmoPickCallback)(TGizmoPickResultType resultType, float x, float y, float z);
void Gizmo_dummy(TGizmoPickResultType t);
EMSCRIPTEN_KEEPALIVE TGizmo *Gizmo_create( EMSCRIPTEN_KEEPALIVE TGizmo *Gizmo_create(
TEngine *tEngine, TEngine *tEngine,
TGltfAssetLoader *assetLoader, TGltfAssetLoader *assetLoader,
@@ -16,6 +16,7 @@ extern "C"
LIGHT_TYPE_FOCUSED_SPOT, LIGHT_TYPE_FOCUSED_SPOT,
LIGHT_TYPE_SPOT LIGHT_TYPE_SPOT
}; };
typedef enum TLightType TLightType;
EMSCRIPTEN_KEEPALIVE void LightManager_setPosition(TLightManager *tLightManager, EntityId light, double x, double y, double z); EMSCRIPTEN_KEEPALIVE void LightManager_setPosition(TLightManager *tLightManager, EntityId light, double x, double y, double z);
EMSCRIPTEN_KEEPALIVE void LightManager_setDirection(TLightManager *tLightManager, EntityId light, double x, double y, double z); EMSCRIPTEN_KEEPALIVE void LightManager_setDirection(TLightManager *tLightManager, EntityId light, double x, double y, double z);
@@ -21,6 +21,7 @@ extern "C"
A, //!< Always. Depth / stencil testing is deactivated. A, //!< Always. Depth / stencil testing is deactivated.
N //!< Never. The depth / stencil test always fails. N //!< Never. The depth / stencil test always fails.
}; };
typedef enum TSamplerCompareFunc TSamplerCompareFunc;
// StencilOperation equivalent // StencilOperation equivalent
enum TStencilOperation enum TStencilOperation
@@ -34,6 +35,7 @@ extern "C"
DECR_WRAP, // Decrement the current value without saturation DECR_WRAP, // Decrement the current value without saturation
INVERT // Invert the current value INVERT // Invert the current value
}; };
typedef enum TStencilOperation TStencilOperation;
enum TStencilFace enum TStencilFace
{ {
@@ -41,6 +43,7 @@ extern "C"
STENCIL_FACE_BACK = 2, STENCIL_FACE_BACK = 2,
STENCIL_FACE_FRONT_AND_BACK = 3 STENCIL_FACE_FRONT_AND_BACK = 3
}; };
typedef enum TStencilFace TStencilFace;
enum TCullingMode enum TCullingMode
{ {
@@ -49,6 +52,7 @@ extern "C"
CULLING_MODE_BACK, CULLING_MODE_BACK,
CULLING_MODE_FRONT_AND_BACK CULLING_MODE_FRONT_AND_BACK
}; };
typedef enum TCullingMode TCullingMode;
enum TTransparencyMode { enum TTransparencyMode {
//! the transparent object is drawn honoring the raster state //! the transparent object is drawn honoring the raster state
@@ -66,6 +70,7 @@ extern "C"
*/ */
TWO_PASSES_TWO_SIDES TWO_PASSES_TWO_SIDES
}; };
typedef enum TTransparencyMode TTransparencyMode;
EMSCRIPTEN_KEEPALIVE TMaterialInstance *Material_createInstance(TMaterial *tMaterial); EMSCRIPTEN_KEEPALIVE TMaterialInstance *Material_createInstance(TMaterial *tMaterial);
EMSCRIPTEN_KEEPALIVE TMaterial *Material_createImageMaterial(TEngine *tEngine); EMSCRIPTEN_KEEPALIVE TMaterial *Material_createImageMaterial(TEngine *tEngine);
@@ -8,7 +8,7 @@ extern "C"
{ {
#endif #endif
EMSCRIPTEN_KEEPALIVE TRenderTicker *RenderTicker_create(TRenderer *tRenderer); EMSCRIPTEN_KEEPALIVE TRenderTicker *RenderTicker_create(TEngine *tEngine, TRenderer *tRenderer);
EMSCRIPTEN_KEEPALIVE void RenderTicker_destroy(TRenderTicker *tRenderTicker); EMSCRIPTEN_KEEPALIVE void RenderTicker_destroy(TRenderTicker *tRenderTicker);
EMSCRIPTEN_KEEPALIVE void RenderTicker_addAnimationManager(TRenderTicker *tRenderTicker, TAnimationManager *tAnimationManager); EMSCRIPTEN_KEEPALIVE void RenderTicker_addAnimationManager(TRenderTicker *tRenderTicker, TAnimationManager *tAnimationManager);
EMSCRIPTEN_KEEPALIVE void RenderTicker_removeAnimationManager(TRenderTicker *tRenderTicker, TAnimationManager *tAnimationManager); EMSCRIPTEN_KEEPALIVE void RenderTicker_removeAnimationManager(TRenderTicker *tRenderTicker, TAnimationManager *tAnimationManager);
@@ -3,6 +3,7 @@
#include "APIExport.h" #include "APIExport.h"
#include "APIBoundaryTypes.h" #include "APIBoundaryTypes.h"
#include "TMaterialInstance.h" #include "TMaterialInstance.h"
#include "TTexture.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
@@ -20,6 +20,8 @@ enum TTextureSamplerType
SAMPLER_CUBEMAP_ARRAY=5 SAMPLER_CUBEMAP_ARRAY=5
}; };
typedef enum TTextureSamplerType TTextureSamplerType;
enum TTextureFormat enum TTextureFormat
{ {
// 8-bits per element // 8-bits per element
@@ -157,6 +159,7 @@ enum TTextureFormat
TEXTUREFORMAT_RGBA_BPTC_UNORM, // BC7 TEXTUREFORMAT_RGBA_BPTC_UNORM, // BC7
TEXTUREFORMAT_SRGB_ALPHA_BPTC_UNORM // BC7 sRGB TEXTUREFORMAT_SRGB_ALPHA_BPTC_UNORM // BC7 sRGB
}; };
typedef enum TTextureFormat TTextureFormat;
//! Pixel Data Format //! Pixel Data Format
enum TPixelDataFormat { enum TPixelDataFormat {
@@ -173,6 +176,7 @@ enum TPixelDataFormat {
PIXELDATAFORMAT_DEPTH_STENCIL, //!< Two Depth (24-bits) + Stencil (8-bits) channels PIXELDATAFORMAT_DEPTH_STENCIL, //!< Two Depth (24-bits) + Stencil (8-bits) channels
PIXELDATAFORMAT_ALPHA //! One Alpha channel, float PIXELDATAFORMAT_ALPHA //! One Alpha channel, float
}; };
typedef enum TPixelDataFormat TPixelDataFormat;
enum TPixelDataType { enum TPixelDataType {
PIXELDATATYPE_UBYTE, //!< unsigned byte PIXELDATATYPE_UBYTE, //!< unsigned byte
@@ -188,6 +192,7 @@ enum TPixelDataType {
PIXELDATATYPE_USHORT_565, //!< unsigned int (16-bit), encodes 3 RGB channels PIXELDATATYPE_USHORT_565, //!< unsigned int (16-bit), encodes 3 RGB channels
PIXELDATATYPE_UINT_2_10_10_10_REV, //!< unsigned normalized 10 bits RGB, 2 bits alpha PIXELDATATYPE_UINT_2_10_10_10_REV, //!< unsigned normalized 10 bits RGB, 2 bits alpha
}; };
typedef enum TPixelDataType TPixelDataType;
enum TTextureUsage { enum TTextureUsage {
TEXTURE_USAGE_NONE = 0x0000, TEXTURE_USAGE_NONE = 0x0000,
@@ -202,6 +207,7 @@ enum TTextureUsage {
TEXTURE_USAGE_PROTECTED = 0x0100, //!< Texture can be used the destination of a blit() TEXTURE_USAGE_PROTECTED = 0x0100, //!< Texture can be used the destination of a blit()
TEXTURE_USAGE_DEFAULT = TEXTURE_USAGE_UPLOADABLE | TEXTURE_USAGE_SAMPLEABLE //!< Default texture usage TEXTURE_USAGE_DEFAULT = TEXTURE_USAGE_UPLOADABLE | TEXTURE_USAGE_SAMPLEABLE //!< Default texture usage
}; };
typedef enum TTextureUsage TTextureUsage;
EMSCRIPTEN_KEEPALIVE TTexture *Texture_build(TEngine *engine, EMSCRIPTEN_KEEPALIVE TTexture *Texture_build(TEngine *engine,
uint32_t width, uint32_t width,
@@ -268,6 +274,7 @@ enum TSamplerWrapMode {
WRAP_REPEAT, // Repeat wrapping mode WRAP_REPEAT, // Repeat wrapping mode
WRAP_MIRRORED_REPEAT // Mirrored repeat wrapping mode WRAP_MIRRORED_REPEAT // Mirrored repeat wrapping mode
}; };
typedef enum TSamplerWrapMode TSamplerWrapMode;
enum TSamplerMinFilter { enum TSamplerMinFilter {
FILTER_NEAREST, // Nearest filtering FILTER_NEAREST, // Nearest filtering
@@ -277,16 +284,19 @@ enum TSamplerMinFilter {
FILTER_NEAREST_MIPMAP_LINEAR, // Nearest mipmap linear filtering FILTER_NEAREST_MIPMAP_LINEAR, // Nearest mipmap linear filtering
FILTER_LINEAR_MIPMAP_LINEAR // Linear mipmap linear filtering FILTER_LINEAR_MIPMAP_LINEAR // Linear mipmap linear filtering
}; };
typedef enum TSamplerMinFilter TSamplerMinFilter;
enum TSamplerMagFilter { enum TSamplerMagFilter {
MAG_FILTER_NEAREST, // Nearest filtering MAG_FILTER_NEAREST, // Nearest filtering
MAG_FILTER_LINEAR // Linear filtering MAG_FILTER_LINEAR // Linear filtering
}; };
typedef enum TSamplerMagFilter TSamplerMagFilter;
enum TSamplerCompareMode { enum TSamplerCompareMode {
COMPARE_MODE_NONE, // No comparison COMPARE_MODE_NONE, // No comparison
COMPARE_MODE_COMPARE_TO_TEXTURE // Compare to texture COMPARE_MODE_COMPARE_TO_TEXTURE // Compare to texture
}; };
typedef enum TSamplerCompareMode TSamplerCompareMode;
typedef TSamplerCompareFunc TTextureSamplerCompareFunc ; typedef TSamplerCompareFunc TTextureSamplerCompareFunc ;
@@ -23,6 +23,7 @@ enum TToneMapping
FILMIC, FILMIC,
LINEAR LINEAR
}; };
typedef enum TToneMapping TToneMapping;
// copied from Options.h // copied from Options.h
enum TQualityLevel { enum TQualityLevel {
@@ -31,11 +32,13 @@ enum TQualityLevel {
HIGH, HIGH,
ULTRA ULTRA
}; };
typedef enum TQualityLevel TQualityLevel;
enum TBlendMode { enum TBlendMode {
OPAQUE, OPAQUE,
TRANSLUCENT TRANSLUCENT
}; };
typedef enum TBlendMode TBlendMode;
// View // View
EMSCRIPTEN_KEEPALIVE TViewport View_getViewport(TView *view); EMSCRIPTEN_KEEPALIVE TViewport View_getViewport(TView *view);
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "TEngine.h"
#include "TView.h" #include "TView.h"
#include "TTexture.h" #include "TTexture.h"
#include "TMaterialProvider.h" #include "TMaterialProvider.h"
@@ -10,20 +11,20 @@ namespace thermion
extern "C" extern "C"
{ {
#endif #endif
typedef void (*VoidCallback)();
typedef int32_t EntityId; typedef int32_t EntityId;
typedef void (*FilamentRenderCallback)(void *const owner); typedef void (*FilamentRenderCallback)(void *const owner);
EMSCRIPTEN_KEEPALIVE void RenderThread_create(); void RenderThread_create();
EMSCRIPTEN_KEEPALIVE void RenderThread_destroy(); void RenderThread_destroy();
EMSCRIPTEN_KEEPALIVE void RenderThread_requestFrame(void (*onComplete)()); void RenderThread_requestFrameAsync();
EMSCRIPTEN_KEEPALIVE void RenderThread_setRenderTicker(TRenderTicker *tRenderTicker); void RenderThread_setRenderTicker(TRenderTicker *tRenderTicker);
EMSCRIPTEN_KEEPALIVE void RenderThread_addTask(void (*task)()); void RenderThread_addTask(void (*task)());
EMSCRIPTEN_KEEPALIVE void RenderTicker_renderRenderThread(TRenderTicker *tRenderTicker, uint64_t frameTimeInNanos, void (*onComplete)()); void RenderTicker_renderRenderThread(TRenderTicker *tRenderTicker, uint64_t frameTimeInNanos, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void AnimationManager_createRenderThread(TEngine *tEngine, TScene *tScene, void (*onComplete)(TAnimationManager *)); void AnimationManager_createRenderThread(TEngine *tEngine, TScene *tScene, void (*onComplete)(TAnimationManager *));
EMSCRIPTEN_KEEPALIVE void Engine_createRenderThread( void Engine_createRenderThread(
TBackend backend, TBackend backend,
void* platform, void* platform,
void* sharedContext, void* sharedContext,
@@ -31,22 +32,22 @@ namespace thermion
bool disableHandleUseAfterFreeCheck, bool disableHandleUseAfterFreeCheck,
void (*onComplete)(TEngine *) void (*onComplete)(TEngine *)
); );
EMSCRIPTEN_KEEPALIVE void Engine_createRendererRenderThread(TEngine *tEngine, void (*onComplete)(TRenderer *)); void Engine_createRendererRenderThread(TEngine *tEngine, void (*onComplete)(TRenderer *));
EMSCRIPTEN_KEEPALIVE void Engine_createSwapChainRenderThread(TEngine *tEngine, void *window, uint64_t flags, void (*onComplete)(TSwapChain *)); void Engine_createSwapChainRenderThread(TEngine *tEngine, void *window, uint64_t flags, void (*onComplete)(TSwapChain *));
EMSCRIPTEN_KEEPALIVE void Engine_createHeadlessSwapChainRenderThread(TEngine *tEngine, uint32_t width, uint32_t height, uint64_t flags, void (*onComplete)(TSwapChain *)); void Engine_createHeadlessSwapChainRenderThread(TEngine *tEngine, uint32_t width, uint32_t height, uint64_t flags, void (*onComplete)(TSwapChain *));
EMSCRIPTEN_KEEPALIVE void Engine_createCameraRenderThread(TEngine* tEngine, void (*onComplete)(TCamera *)); void Engine_createCameraRenderThread(TEngine* tEngine, void (*onComplete)(TCamera *));
EMSCRIPTEN_KEEPALIVE void Engine_createViewRenderThread(TEngine *tEngine, void (*onComplete)(TView *)); void Engine_createViewRenderThread(TEngine *tEngine, void (*onComplete)(TView *));
EMSCRIPTEN_KEEPALIVE void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t *materialData, size_t length, void (*onComplete)(TMaterial *)); void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t *materialData, size_t length, void (*onComplete)(TMaterial *));
EMSCRIPTEN_KEEPALIVE void Engine_destroyRenderThread(TEngine *tEngine, void (*onComplete)()); void Engine_destroyRenderThread(TEngine *tEngine, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroySwapChainRenderThread(TEngine *tEngine, TSwapChain *tSwapChain, void (*onComplete)()); void Engine_destroySwapChainRenderThread(TEngine *tEngine, TSwapChain *tSwapChain, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyViewRenderThread(TEngine *tEngine, TView *tView, void (*onComplete)()); void Engine_destroyViewRenderThread(TEngine *tEngine, TView *tView, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroySceneRenderThread(TEngine *tEngine, TScene *tScene, void (*onComplete)()); void Engine_destroySceneRenderThread(TEngine *tEngine, TScene *tScene, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyColorGradingRenderThread(TEngine *tEngine, TColorGrading *tColorGrading, void (*onComplete)()); void Engine_destroyColorGradingRenderThread(TEngine *tEngine, TColorGrading *tColorGrading, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, void (*onComplete)()); void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialInstanceRenderThread(TEngine *tEngine, TMaterialInstance *tMaterialInstance, void (*onComplete)()); void Engine_destroyMaterialInstanceRenderThread(TEngine *tEngine, TMaterialInstance *tMaterialInstance, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroySkyboxRenderThread(TEngine *tEngine, TSkybox *tSkybox, void (*onComplete)()); void Engine_destroySkyboxRenderThread(TEngine *tEngine, TSkybox *tSkybox, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyIndirectLightRenderThread(TEngine *tEngine, TIndirectLight *tIndirectLight, void (*onComplete)()); void Engine_destroyIndirectLightRenderThread(TEngine *tEngine, TIndirectLight *tIndirectLight, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Texture_buildRenderThread(TEngine *engine, void Texture_buildRenderThread(TEngine *engine,
uint32_t width, uint32_t width,
uint32_t height, uint32_t height,
uint32_t depth, uint32_t depth,
@@ -58,19 +59,20 @@ namespace thermion
void (*onComplete)(TTexture*) void (*onComplete)(TTexture*)
); );
EMSCRIPTEN_KEEPALIVE void Engine_destroyTextureRenderThread(TEngine *engine, TTexture* tTexture, void (*onComplete)()); void Engine_destroyTextureRenderThread(TEngine *engine, TTexture* tTexture, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_createFenceRenderThread(TEngine *tEngine, void (*onComplete)(TFence*)); void Engine_createFenceRenderThread(TEngine *tEngine, void (*onComplete)(TFence*));
EMSCRIPTEN_KEEPALIVE void Engine_destroyFenceRenderThread(TEngine *tEngine, TFence *tFence, void (*onComplete)()); void Engine_destroyFenceRenderThread(TEngine *tEngine, TFence *tFence, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_flushAndWaitRenderThead(TEngine *tEngine, void (*onComplete)()); void Engine_flushAndWaitRenderThread(TEngine *tEngine, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_buildSkyboxRenderThread(TEngine *tEngine, uint8_t *skyboxData, size_t length, void (*onComplete)(TSkybox *), void (*onTextureUploadComplete)()); void Engine_executeRenderThread(TEngine *tEngine, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_buildIndirectLightRenderThread(TEngine *tEngine, uint8_t *iblData, size_t length, float intensity, void (*onComplete)(TIndirectLight *), void (*onTextureUploadComplete)()); void Engine_buildSkyboxRenderThread(TEngine *tEngine, uint8_t *skyboxData, size_t length, void (*onComplete)(TSkybox *), void (*onTextureUploadComplete)());
void Engine_buildIndirectLightRenderThread(TEngine *tEngine, uint8_t *iblData, size_t length, float intensity, void (*onComplete)(TIndirectLight *), void (*onTextureUploadComplete)());
EMSCRIPTEN_KEEPALIVE void Renderer_setClearOptionsRenderThread(TRenderer *tRenderer, double clearR, double clearG, double clearB, double clearA, uint8_t clearStencil, bool clear, bool discard, void (*onComplete)()); void Renderer_setClearOptionsRenderThread(TRenderer *tRenderer, double clearR, double clearG, double clearB, double clearA, uint8_t clearStencil, bool clear, bool discard, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Renderer_beginFrameRenderThread(TRenderer *tRenderer, TSwapChain *tSwapChain, uint64_t frameTimeInNanos, void (*onComplete)(bool)); void Renderer_beginFrameRenderThread(TRenderer *tRenderer, TSwapChain *tSwapChain, uint64_t frameTimeInNanos, void (*onComplete)(bool));
EMSCRIPTEN_KEEPALIVE void Renderer_endFrameRenderThread(TRenderer *tRenderer, void (*onComplete)()); void Renderer_endFrameRenderThread(TRenderer *tRenderer, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Renderer_renderRenderThread(TRenderer *tRenderer, TView *tView, void (*onComplete)()); void Renderer_renderRenderThread(TRenderer *tRenderer, TView *tView, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Renderer_renderStandaloneViewRenderThread(TRenderer *tRenderer, TView *tView, void (*onComplete)()); void Renderer_renderStandaloneViewRenderThread(TRenderer *tRenderer, TView *tView, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Renderer_readPixelsRenderThread( void Renderer_readPixelsRenderThread(
TRenderer *tRenderer, TRenderer *tRenderer,
TView *tView, TView *tView,
TRenderTarget *tRenderTarget, TRenderTarget *tRenderTarget,
@@ -78,29 +80,29 @@ namespace thermion
TPixelDataType tPixelDataType, TPixelDataType tPixelDataType,
uint8_t *out, uint8_t *out,
size_t outLength, size_t outLength,
void (*onComplete)()); VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance *)); void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance *));
EMSCRIPTEN_KEEPALIVE void Material_createImageMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *)); void Material_createImageMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *));
EMSCRIPTEN_KEEPALIVE void Material_createGizmoMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *)); void Material_createGizmoMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *));
EMSCRIPTEN_KEEPALIVE void ColorGrading_createRenderThread(TEngine *tEngine, TToneMapping toneMapping, void (*callback)(TColorGrading *)); void ColorGrading_createRenderThread(TEngine *tEngine, TToneMapping toneMapping, void (*callback)(TColorGrading *));
EMSCRIPTEN_KEEPALIVE void View_setColorGradingRenderThread(TView *tView, TColorGrading *tColorGrading, void (*callback)()); void View_setColorGradingRenderThread(TView *tView, TColorGrading *tColorGrading, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, bool enabled, double strength, void (*callback)()); void View_setBloomRenderThread(TView *tView, bool enabled, double strength, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void View_setCameraRenderThread(TView *tView, TCamera *tCamera, void (*callback)()); void View_setCameraRenderThread(TView *tView, TCamera *tCamera, VoidCallback onComplete);
FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback); FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
EMSCRIPTEN_KEEPALIVE void SceneAsset_destroyRenderThread(TSceneAsset *tSceneAsset, void (*onComplete)()); void SceneAsset_destroyRenderThread(TSceneAsset *tSceneAsset, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void SceneAsset_createFromFilamentAssetRenderThread( void SceneAsset_createFromFilamentAssetRenderThread(
TEngine *tEngine, TEngine *tEngine,
TGltfAssetLoader *tAssetLoader, TGltfAssetLoader *tAssetLoader,
TNameComponentManager *tNameComponentManager, TNameComponentManager *tNameComponentManager,
TFilamentAsset *tFilamentAsset, TFilamentAsset *tFilamentAsset,
void (*onComplete)(TSceneAsset *) void (*onComplete)(TSceneAsset *)
); );
EMSCRIPTEN_KEEPALIVE void SceneAsset_createInstanceRenderThread(TSceneAsset *asset, TMaterialInstance **tMaterialInstances, int materialInstanceCount, void (*callback)(TSceneAsset *)); void SceneAsset_createInstanceRenderThread(TSceneAsset *asset, TMaterialInstance **tMaterialInstances, int materialInstanceCount, void (*callback)(TSceneAsset *));
EMSCRIPTEN_KEEPALIVE void SceneAsset_createGeometryRenderThread( void SceneAsset_createGeometryRenderThread(
TEngine *tEngine, TEngine *tEngine,
float *vertices, float *vertices,
uint32_t numVertices, uint32_t numVertices,
@@ -115,14 +117,14 @@ namespace thermion
int materialInstanceCount, int materialInstanceCount,
void (*callback)(TSceneAsset *) void (*callback)(TSceneAsset *)
); );
EMSCRIPTEN_KEEPALIVE void MaterialProvider_createMaterialInstanceRenderThread(TMaterialProvider *tMaterialProvider, TMaterialKey *tKey, void (*callback)(TMaterialInstance *)); void MaterialProvider_createMaterialInstanceRenderThread(TMaterialProvider *tMaterialProvider, TMaterialKey *tKey, void (*callback)(TMaterialInstance *));
EMSCRIPTEN_KEEPALIVE void AnimationManager_updateBoneMatricesRenderThread( void AnimationManager_updateBoneMatricesRenderThread(
TAnimationManager *tAnimationManager, TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset, TSceneAsset *sceneAsset,
void (*callback)(bool)); void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void AnimationManager_setMorphTargetWeightsRenderThread( void AnimationManager_setMorphTargetWeightsRenderThread(
TAnimationManager *tAnimationManager, TAnimationManager *tAnimationManager,
EntityId entityId, EntityId entityId,
const float *const morphData, const float *const morphData,
@@ -130,16 +132,16 @@ namespace thermion
void (*callback)(bool)); void (*callback)(bool));
// Image methods // Image methods
EMSCRIPTEN_KEEPALIVE void Image_createEmptyRenderThread(uint32_t width, uint32_t height, uint32_t channel, void (*onComplete)(TLinearImage *)); void Image_createEmptyRenderThread(uint32_t width, uint32_t height, uint32_t channel, void (*onComplete)(TLinearImage *));
EMSCRIPTEN_KEEPALIVE void Image_decodeRenderThread(uint8_t* data, size_t length, const char* name, void (*onComplete)(TLinearImage *)); void Image_decodeRenderThread(uint8_t* data, size_t length, const char* name, void (*onComplete)(TLinearImage *));
EMSCRIPTEN_KEEPALIVE void Image_getBytesRenderThread(TLinearImage *tLinearImage, void (*onComplete)(float *)); void Image_getBytesRenderThread(TLinearImage *tLinearImage, void (*onComplete)(float *));
EMSCRIPTEN_KEEPALIVE void Image_destroyRenderThread(TLinearImage *tLinearImage, void (*onComplete)()); void Image_destroyRenderThread(TLinearImage *tLinearImage, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Image_getWidthRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t)); void Image_getWidthRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t));
EMSCRIPTEN_KEEPALIVE void Image_getHeightRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t)); void Image_getHeightRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t));
EMSCRIPTEN_KEEPALIVE void Image_getChannelsRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t)); void Image_getChannelsRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t));
EMSCRIPTEN_KEEPALIVE void Texture_loadImageRenderThread( void Texture_loadImageRenderThread(
TEngine *tEngine, TEngine *tEngine,
TTexture *tTexture, TTexture *tTexture,
TLinearImage *tImage, TLinearImage *tImage,
@@ -147,7 +149,7 @@ namespace thermion
TPixelDataType pixelDataType, TPixelDataType pixelDataType,
void (*onComplete)(bool) void (*onComplete)(bool)
); );
EMSCRIPTEN_KEEPALIVE void Texture_setImageRenderThread( void Texture_setImageRenderThread(
TEngine *tEngine, TEngine *tEngine,
TTexture *tTexture, TTexture *tTexture,
uint32_t level, uint32_t level,
@@ -160,7 +162,7 @@ namespace thermion
uint32_t pixelDataType, uint32_t pixelDataType,
void (*onComplete)(bool) void (*onComplete)(bool)
); );
EMSCRIPTEN_KEEPALIVE void Texture_setImageWithDepthRenderThread( void Texture_setImageWithDepthRenderThread(
TEngine *tEngine, TEngine *tEngine,
TTexture *tTexture, TTexture *tTexture,
uint32_t level, uint32_t level,
@@ -177,8 +179,8 @@ namespace thermion
uint32_t pixelDataType, uint32_t pixelDataType,
void (*onComplete)(bool) void (*onComplete)(bool)
); );
EMSCRIPTEN_KEEPALIVE void RenderTarget_getColorTextureRenderThread(TRenderTarget *tRenderTarget, void (*onComplete)(TTexture *)); void RenderTarget_getColorTextureRenderThread(TRenderTarget *tRenderTarget, void (*onComplete)(TTexture *));
EMSCRIPTEN_KEEPALIVE void RenderTarget_createRenderThread( void RenderTarget_createRenderThread(
TEngine *tEngine, TEngine *tEngine,
uint32_t width, uint32_t width,
uint32_t height, uint32_t height,
@@ -186,16 +188,16 @@ namespace thermion
TTexture *depth, TTexture *depth,
void (*onComplete)(TRenderTarget *) void (*onComplete)(TRenderTarget *)
); );
EMSCRIPTEN_KEEPALIVE void RenderTarget_destroyRenderThread( void RenderTarget_destroyRenderThread(
TEngine *tEngine, TEngine *tEngine,
TRenderTarget *tRenderTarget, TRenderTarget *tRenderTarget,
void (*onComplete)() VoidCallback onComplete
); );
// TextureSampler methods // TextureSampler methods
EMSCRIPTEN_KEEPALIVE void TextureSampler_createRenderThread(void (*onComplete)(TTextureSampler*)); void TextureSampler_createRenderThread(void (*onComplete)(TTextureSampler*));
EMSCRIPTEN_KEEPALIVE void TextureSampler_createWithFilteringRenderThread( void TextureSampler_createWithFilteringRenderThread(
TSamplerMinFilter minFilter, TSamplerMinFilter minFilter,
TSamplerMagFilter magFilter, TSamplerMagFilter magFilter,
TSamplerWrapMode wrapS, TSamplerWrapMode wrapS,
@@ -203,53 +205,53 @@ namespace thermion
TSamplerWrapMode wrapR, TSamplerWrapMode wrapR,
void (*onComplete)(TTextureSampler*) void (*onComplete)(TTextureSampler*)
); );
EMSCRIPTEN_KEEPALIVE void TextureSampler_createWithComparisonRenderThread( void TextureSampler_createWithComparisonRenderThread(
TSamplerCompareMode compareMode, TSamplerCompareMode compareMode,
TSamplerCompareFunc compareFunc, TSamplerCompareFunc compareFunc,
void (*onComplete)(TTextureSampler*) void (*onComplete)(TTextureSampler*)
); );
EMSCRIPTEN_KEEPALIVE void TextureSampler_setMinFilterRenderThread( void TextureSampler_setMinFilterRenderThread(
TTextureSampler* sampler, TTextureSampler* sampler,
TSamplerMinFilter filter, TSamplerMinFilter filter,
void (*onComplete)() VoidCallback onComplete
); );
EMSCRIPTEN_KEEPALIVE void TextureSampler_setMagFilterRenderThread( void TextureSampler_setMagFilterRenderThread(
TTextureSampler* sampler, TTextureSampler* sampler,
TSamplerMagFilter filter, TSamplerMagFilter filter,
void (*onComplete)() VoidCallback onComplete
); );
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeSRenderThread( void TextureSampler_setWrapModeSRenderThread(
TTextureSampler* sampler, TTextureSampler* sampler,
TSamplerWrapMode mode, TSamplerWrapMode mode,
void (*onComplete)() VoidCallback onComplete
); );
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeTRenderThread( void TextureSampler_setWrapModeTRenderThread(
TTextureSampler* sampler, TTextureSampler* sampler,
TSamplerWrapMode mode, TSamplerWrapMode mode,
void (*onComplete)() VoidCallback onComplete
); );
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeRRenderThread( void TextureSampler_setWrapModeRRenderThread(
TTextureSampler* sampler, TTextureSampler* sampler,
TSamplerWrapMode mode, TSamplerWrapMode mode,
void (*onComplete)() VoidCallback onComplete
); );
EMSCRIPTEN_KEEPALIVE void TextureSampler_setAnisotropyRenderThread( void TextureSampler_setAnisotropyRenderThread(
TTextureSampler* sampler, TTextureSampler* sampler,
double anisotropy, double anisotropy,
void (*onComplete)() VoidCallback onComplete
); );
EMSCRIPTEN_KEEPALIVE void TextureSampler_setCompareModeRenderThread( void TextureSampler_setCompareModeRenderThread(
TTextureSampler* sampler, TTextureSampler* sampler,
TSamplerCompareMode mode, TSamplerCompareMode mode,
TTextureSamplerCompareFunc func, TTextureSamplerCompareFunc func,
void (*onComplete)() VoidCallback onComplete
); );
EMSCRIPTEN_KEEPALIVE void TextureSampler_destroyRenderThread( void TextureSampler_destroyRenderThread(
TTextureSampler* sampler, TTextureSampler* sampler,
void (*onComplete)() VoidCallback onComplete
); );
EMSCRIPTEN_KEEPALIVE void AnimationManager_setBoneTransformRenderThread( void AnimationManager_setBoneTransformRenderThread(
TAnimationManager *tAnimationManager, TAnimationManager *tAnimationManager,
EntityId asset, EntityId asset,
int skinIndex, int skinIndex,
@@ -257,18 +259,18 @@ namespace thermion
const float *const transform, const float *const transform,
void (*callback)(bool)); void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void AnimationManager_resetToRestPoseRenderThread(TAnimationManager *tAnimationManager, EntityId entityId, void (*callback)()); void AnimationManager_resetToRestPoseRenderThread(TAnimationManager *tAnimationManager, EntityId entityId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void GltfAssetLoader_createRenderThread(TEngine *tEngine, TMaterialProvider *tMaterialProvider, void (*callback)(TGltfAssetLoader *)); void GltfAssetLoader_createRenderThread(TEngine *tEngine, TMaterialProvider *tMaterialProvider, void (*callback)(TGltfAssetLoader *));
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_createRenderThread(TEngine *tEngine, const char* relativeResourcePath, void (*callback)(TGltfResourceLoader *)); void GltfResourceLoader_createRenderThread(TEngine *tEngine, const char* relativeResourcePath, void (*callback)(TGltfResourceLoader *));
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_destroyRenderThread(TEngine *tEngine, TGltfResourceLoader *tResourceLoader, void (*callback)()); void GltfResourceLoader_destroyRenderThread(TEngine *tEngine, TGltfResourceLoader *tResourceLoader, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_loadResourcesRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool)); void GltfResourceLoader_loadResourcesRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_addResourceDataRenderThread(TGltfResourceLoader *tGltfResourceLoader, const char *uri, uint8_t *data, size_t length, void (*callback)()); void GltfResourceLoader_addResourceDataRenderThread(TGltfResourceLoader *tGltfResourceLoader, const char *uri, uint8_t *data, size_t length, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_asyncBeginLoadRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool)); void GltfResourceLoader_asyncBeginLoadRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_asyncUpdateLoadRenderThread(TGltfResourceLoader *tGltfResourceLoader); void GltfResourceLoader_asyncUpdateLoadRenderThread(TGltfResourceLoader *tGltfResourceLoader);
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_asyncGetLoadProgressRenderThread(TGltfResourceLoader *tGltfResourceLoader, void (*callback)(float)); void GltfResourceLoader_asyncGetLoadProgressRenderThread(TGltfResourceLoader *tGltfResourceLoader, void (*callback)(float));
EMSCRIPTEN_KEEPALIVE void GltfAssetLoader_loadRenderThread( void GltfAssetLoader_loadRenderThread(
TEngine *tEngine, TEngine *tEngine,
TGltfAssetLoader *tAssetLoader, TGltfAssetLoader *tAssetLoader,
uint8_t *data, uint8_t *data,
@@ -276,8 +278,8 @@ namespace thermion
uint8_t numInstances, uint8_t numInstances,
void (*callback)(TFilamentAsset *) void (*callback)(TFilamentAsset *)
); );
EMSCRIPTEN_KEEPALIVE void Scene_addFilamentAssetRenderThread(TScene* tScene, TFilamentAsset *tAsset, void (*callback)()); void Scene_addFilamentAssetRenderThread(TScene* tScene, TFilamentAsset *tAsset, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Gizmo_createRenderThread( void Gizmo_createRenderThread(
TEngine *tEngine, TEngine *tEngine,
TGltfAssetLoader *tAssetLoader, TGltfAssetLoader *tAssetLoader,
TGltfResourceLoader *tGltfResourceLoader, TGltfResourceLoader *tGltfResourceLoader,
@@ -3,11 +3,15 @@
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus
extern "C" { extern "C" {
#endif
extern const uint8_t CAPTURE_UV_PACKAGE[]; extern const uint8_t CAPTURE_UV_PACKAGE[];
extern int CAPTURE_UV_CAPTURE_UV_OFFSET; extern int CAPTURE_UV_CAPTURE_UV_OFFSET;
extern int CAPTURE_UV_CAPTURE_UV_SIZE; extern int CAPTURE_UV_CAPTURE_UV_SIZE;
#ifdef __cplusplus
} }
#endif
#define CAPTURE_UV_CAPTURE_UV_DATA (CAPTURE_UV_PACKAGE + CAPTURE_UV_CAPTURE_UV_OFFSET) #define CAPTURE_UV_CAPTURE_UV_DATA (CAPTURE_UV_PACKAGE + CAPTURE_UV_CAPTURE_UV_OFFSET)
#endif #endif
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -3,11 +3,15 @@
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus
extern "C" { extern "C" {
#endif
extern const uint8_t GRID_PACKAGE[]; extern const uint8_t GRID_PACKAGE[];
extern int GRID_GRID_OFFSET; extern int GRID_GRID_OFFSET;
extern int GRID_GRID_SIZE; extern int GRID_GRID_SIZE;
#ifdef __cplusplus
} }
#endif
#define GRID_GRID_DATA (GRID_PACKAGE + GRID_GRID_OFFSET) #define GRID_GRID_DATA (GRID_PACKAGE + GRID_GRID_OFFSET)
#endif #endif
Binary file not shown.
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More