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

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

View File

@@ -0,0 +1 @@
../../../assets/

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;
}
}

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>

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>

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);

View File

@@ -0,0 +1 @@
../../../../thermion_dart/native/web/build/build/out/thermion_dart.js

View File

@@ -0,0 +1 @@
../../../../thermion_dart/native/web/build/build/out/thermion_dart.wasm

View File

@@ -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);
}
}

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) {

View File

@@ -1 +1 @@
../../../assets/thermion_dart.js ../../../../thermion_dart/native/web/build/build/out/thermion_dart.js

View File

@@ -1 +1 @@
../../../assets/thermion_dart.wasm ../../../../thermion_dart/native/web/build/build/out/thermion_dart.wasm

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

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

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:
- .*

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());
} }
} }

View File

@@ -0,0 +1,3 @@
export 'src/ffi.dart'
if (dart.library.io) 'src/ffi.dart'
if (dart.library.js_interop) 'src/js_interop.dart';

View File

@@ -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;
}
}

View File

@@ -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

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';

View File

@@ -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;
}

View File

@@ -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);
var transform = Matrix4.identity();
await imageMaterialInstance.setParameterMat4( await imageMaterialInstance.setParameterMat4(
"transform", Matrix4.identity()); "transform", transform);
backgroundImage.setMaterialInstanceAt(imageMaterialInstance); 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);

View File

@@ -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");
} }

View File

@@ -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 {

View File

@@ -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,11 +1021,16 @@ 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);
}

View File

@@ -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

View File

@@ -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;
} }
} }

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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);
} }

View File

@@ -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 {

View File

@@ -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';

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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';

View File

@@ -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 }

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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();
} }

View File

@@ -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';

View File

@@ -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

View File

@@ -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();
} }

View File

@@ -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;

View File

@@ -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]!);
}
}

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);
} }

View File

@@ -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 {

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;

View File

@@ -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 {

View File

@@ -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);
} }

View File

@@ -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';

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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",

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';

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;

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);
@@ -26,11 +29,10 @@ static void Log(const char *fmt, ...) {
#else #else
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

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]},

View File

@@ -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;

View File

@@ -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
} }

View File

@@ -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

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);

View File

@@ -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);

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,

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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"

View File

@@ -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 ;

View File

@@ -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);

View File

@@ -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,

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

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