feat! js_interop improvements

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

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