feat! js_interop improvements
This commit is contained in:
3
thermion_dart/lib/src/bindings/bindings.dart
Normal file
3
thermion_dart/lib/src/bindings/bindings.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
export 'src/ffi.dart'
|
||||
if (dart.library.io) 'src/ffi.dart'
|
||||
if (dart.library.js_interop) 'src/js_interop.dart';
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
408
thermion_dart/lib/src/bindings/src/js_interop.dart
Normal file
408
thermion_dart/lib/src/bindings/src/js_interop.dart
Normal file
@@ -0,0 +1,408 @@
|
||||
import 'dart:async';
|
||||
export 'dart:typed_data';
|
||||
|
||||
export 'thermion_dart_js_interop.g.dart';
|
||||
export 'dart:js_interop';
|
||||
export 'dart:js_interop_unsafe';
|
||||
import 'package:thermion_dart/src/bindings/src/js_interop.dart';
|
||||
|
||||
const FILAMENT_SINGLE_THREADED = true;
|
||||
const FILAMENT_WASM = true;
|
||||
const IS_WINDOWS = false;
|
||||
|
||||
extension type _NativeLibrary(JSObject _) implements JSObject {
|
||||
static _NativeLibrary get instance =>
|
||||
NativeLibrary.instance as _NativeLibrary;
|
||||
|
||||
external JSUint8Array _emscripten_make_uint8_buffer(
|
||||
Pointer<Uint8> ptr, int length);
|
||||
external JSUint16Array _emscripten_make_uint16_buffer(
|
||||
Pointer<Uint16> ptr, int length);
|
||||
external JSInt16Array _emscripten_make_int16_buffer(
|
||||
Pointer<Int16> ptr, int length);
|
||||
external JSInt32Array _emscripten_make_int32_buffer(
|
||||
Pointer<Int32> ptr, int length);
|
||||
external JSFloat32Array _emscripten_make_f32_buffer(
|
||||
Pointer<Float32> ptr, int length);
|
||||
external JSFloat64Array _emscripten_make_f64_buffer(
|
||||
Pointer<Float64> ptr, int length);
|
||||
external Pointer _emscripten_get_byte_offset(JSObject obj);
|
||||
|
||||
external int _emscripten_stack_get_free();
|
||||
|
||||
external void _execute_queue();
|
||||
|
||||
@JS('stackSave')
|
||||
external Pointer<Void> stackSave();
|
||||
|
||||
@JS('stackRestore')
|
||||
external void stackRestore(Pointer<Void> ptr);
|
||||
}
|
||||
|
||||
extension FreeTypedData<T> on TypedData {
|
||||
void free() {
|
||||
final ptr = Pointer<Void>(this.offsetInBytes);
|
||||
ptr.free();
|
||||
}
|
||||
}
|
||||
|
||||
Pointer<T> getPointer<T extends NativeType>(TypedData data, JSObject obj) {
|
||||
late Pointer<T> ptr;
|
||||
|
||||
if (data.lengthInBytes < 32 * 1024) {
|
||||
ptr = stackAlloc(data.lengthInBytes).cast<T>();
|
||||
} else {
|
||||
ptr = malloc<T>(data.lengthInBytes);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
extension JSBackingBuffer on JSUint8Array {
|
||||
@JS('buffer')
|
||||
external JSObject buffer;
|
||||
}
|
||||
|
||||
@JS('Uint8Array')
|
||||
extension type Uint8ArrayWrapper._(JSObject _) implements JSObject {
|
||||
external Uint8ArrayWrapper(JSObject buffer, int offset, int length);
|
||||
}
|
||||
|
||||
@JS('Int8Array')
|
||||
extension type Int8ArrayWrapper._(JSObject _) implements JSObject {
|
||||
external Int8ArrayWrapper(JSObject buffer, int offset, int length);
|
||||
}
|
||||
|
||||
@JS('Uint16Array')
|
||||
extension type Uint16ArrayWrapper._(JSObject _) implements JSObject {
|
||||
external Uint16ArrayWrapper(JSObject buffer, int offset, int length);
|
||||
}
|
||||
|
||||
@JS('Int16Array')
|
||||
extension type Int16ArrayWrapper._(JSObject _) implements JSObject {
|
||||
external Int16ArrayWrapper(JSObject buffer, int offset, int length);
|
||||
}
|
||||
|
||||
@JS('Uint32Array')
|
||||
extension type Uint32ArrayWrapper._(JSObject _) implements JSObject {
|
||||
external Uint32ArrayWrapper(JSObject buffer, int offset, int length);
|
||||
}
|
||||
|
||||
@JS('Int32Array')
|
||||
extension type Int32ArrayWrapper._(JSObject _) implements JSObject {
|
||||
external Int32ArrayWrapper(JSObject buffer, int offset, int length);
|
||||
}
|
||||
|
||||
@JS('Float32Array')
|
||||
extension type Float32ArrayWrapper._(JSObject _) implements JSObject {
|
||||
external Float32ArrayWrapper(JSObject buffer, int offset, int length);
|
||||
}
|
||||
@JS('Float64Array')
|
||||
extension type Float64ArrayWrapper._(JSObject _) implements JSObject {
|
||||
external Float64ArrayWrapper(JSObject buffer, int offset, int length);
|
||||
}
|
||||
|
||||
extension Uint8ListExtension on Uint8List {
|
||||
Pointer<Uint8> get address {
|
||||
if (this.lengthInBytes == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
final ptr = getPointer<Uint8>(this, this.toJS);
|
||||
final bar =
|
||||
Uint8ArrayWrapper(NativeLibrary.instance.HEAPU8.buffer, ptr, length)
|
||||
as JSUint8Array;
|
||||
bar.toDart.setRange(0, length, this);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
extension Float32ListExtension on Float32List {
|
||||
Pointer<Float32> get address {
|
||||
final ptr = getPointer<Float32>(this, this.toJS);
|
||||
final bar =
|
||||
Float32ArrayWrapper(NativeLibrary.instance.HEAPU8.buffer, ptr, length)
|
||||
as JSFloat32Array;
|
||||
bar.toDart.setRange(0, length, this);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
extension Int16ListExtension on Int16List {
|
||||
Pointer<Int16> get address {
|
||||
if (this.lengthInBytes == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
final ptr = getPointer<Int16>(this, this.toJS);
|
||||
final bar = Int16ArrayWrapper(NativeLibrary.instance.HEAPU8, ptr, length)
|
||||
as JSInt16Array;
|
||||
bar.toDart.setRange(0, length, this);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
extension Uint16ListExtension on Uint16List {
|
||||
Pointer<Uint16> get address {
|
||||
final ptr = getPointer<Uint16>(this, this.toJS);
|
||||
final bar =
|
||||
Uint16ArrayWrapper(NativeLibrary.instance.HEAPU8.buffer, ptr, length)
|
||||
as JSUint16Array;
|
||||
bar.toDart.setRange(0, length, this);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt32ListExtension on Uint32List {
|
||||
Pointer<Uint32> get address {
|
||||
if (this.lengthInBytes == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
final ptr = getPointer<Uint32>(this, this.toJS);
|
||||
final bar = Uint32ArrayWrapper(NativeLibrary.instance.HEAPU8, ptr, length)
|
||||
as JSUint32Array;
|
||||
bar.toDart.setRange(0, length, this);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
extension Int32ListExtension on Int32List {
|
||||
Pointer<Int32> get address {
|
||||
if (this.lengthInBytes == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
final ptr = getPointer<Int32>(this, this.toJS);
|
||||
final bar = Int32ArrayWrapper(NativeLibrary.instance.HEAPU8, ptr, length)
|
||||
as JSInt32Array;
|
||||
bar.toDart.setRange(0, length, this);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
extension Int64ListExtension on Int64List {
|
||||
Pointer<Float32> get address {
|
||||
throw Exception();
|
||||
}
|
||||
|
||||
static Int64List create(int length) {
|
||||
throw Exception();
|
||||
}
|
||||
}
|
||||
|
||||
extension Float64ListExtension on Float64List {
|
||||
Pointer<Float64> get address {
|
||||
if (this.lengthInBytes == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
final ptr = getPointer<Float64>(this, this.toJS);
|
||||
final bar =
|
||||
Float64ArrayWrapper(NativeLibrary.instance.HEAPU8.buffer, ptr, length)
|
||||
as JSFloat64Array;
|
||||
bar.toDart.setRange(0, length, this);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// static Float64List create(int length) {
|
||||
// final ptr = malloc(length * 8);
|
||||
// final buffer = _NativeLibrary.instance._emscripten_make_f64_buffer(ptr.cast(), length).toDart;
|
||||
// _allocated.add(buffer);
|
||||
// return buffer;
|
||||
// }
|
||||
}
|
||||
|
||||
int sizeOf<T extends NativeType>() {
|
||||
switch (T) {
|
||||
case Float:
|
||||
return 4;
|
||||
default:
|
||||
throw Exception();
|
||||
}
|
||||
}
|
||||
|
||||
typedef IntPtrList = Int32List;
|
||||
typedef Utf8 = Char;
|
||||
typedef Float = Float32;
|
||||
typedef Double = Float64;
|
||||
typedef Bool = bool;
|
||||
|
||||
class FinalizableUint8List {
|
||||
final Pointer name;
|
||||
final Uint8List data;
|
||||
|
||||
FinalizableUint8List(this.name, this.data);
|
||||
}
|
||||
|
||||
class CallbackHolder<T extends Function> {
|
||||
final Pointer<NativeFunction<T>> pointer;
|
||||
|
||||
CallbackHolder(this.pointer);
|
||||
|
||||
void dispose() {
|
||||
pointer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
extension DPCF on DartPickCallbackFunction {
|
||||
CallbackHolder<DartPickCallbackFunction> asCallback() {
|
||||
final ptr = addFunction<DartPickCallbackFunction>(this.toJS, "viidddd");
|
||||
final cbh = CallbackHolder(ptr);
|
||||
return cbh;
|
||||
}
|
||||
}
|
||||
|
||||
extension GPFBP on void Function(int, double, double, double) {
|
||||
CallbackHolder<GizmoPickCallbackFunction> asCallback() {
|
||||
final ptr = addFunction<GizmoPickCallbackFunction>(this.toJS, "viddd");
|
||||
return CallbackHolder(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
extension VFCB on void Function() {
|
||||
CallbackHolder<void Function()> asCallback() {
|
||||
final ptr = addFunction<void Function()>(this.toJS, "v");
|
||||
return CallbackHolder(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
final _completers = <int, Completer>{};
|
||||
void Function(int) _voidCallback = (int requestId) {
|
||||
_completers[requestId]!.complete();
|
||||
_completers.remove(requestId);
|
||||
};
|
||||
|
||||
final _voidCallbackPtr = _voidCallback.addFunction();
|
||||
|
||||
Future<void> withVoidCallback(
|
||||
Function(Pointer<NativeFunction<Void Function()>>) func) async {
|
||||
final completer = Completer();
|
||||
final requestId = _completers.length;
|
||||
_completers[requestId] = completer;
|
||||
|
||||
final fn = () {
|
||||
completer.complete();
|
||||
};
|
||||
|
||||
final ptr = fn.addFunction();
|
||||
|
||||
func.call(ptr.cast());
|
||||
while (!completer.isCompleted) {
|
||||
_NativeLibrary.instance._execute_queue();
|
||||
await Future.delayed(Duration(milliseconds: 1));
|
||||
}
|
||||
await completer.future;
|
||||
}
|
||||
|
||||
Future<Pointer<T>> withPointerCallback<T extends NativeType>(
|
||||
Function(Pointer<NativeFunction<Void Function(Pointer<T>)>>) func) async {
|
||||
final completer = Completer<Pointer<T>>();
|
||||
// ignore: prefer_function_declarations_over_variables
|
||||
void Function(Pointer<T>) callback = (Pointer<T> ptr) {
|
||||
completer.complete(ptr.cast<T>());
|
||||
};
|
||||
|
||||
final onComplete_interopFnPtr = callback.addFunction();
|
||||
|
||||
func.call(onComplete_interopFnPtr.cast());
|
||||
|
||||
var ptr = await completer.future;
|
||||
onComplete_interopFnPtr.dispose();
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Future<bool> withBoolCallback(
|
||||
Function(Pointer<NativeFunction<Void Function(Bool)>>) func) async {
|
||||
final completer = Completer<bool>();
|
||||
// ignore: prefer_function_declarations_over_variables
|
||||
void Function(int) callback = (int result) {
|
||||
completer.complete(result == 1);
|
||||
};
|
||||
|
||||
final onComplete_interopFnPtr = callback.addFunction();
|
||||
|
||||
func.call(onComplete_interopFnPtr.cast());
|
||||
await completer.future;
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
Future<double> withFloatCallback(
|
||||
void Function(Pointer<NativeFunction<void Function(double)>>) func) async {
|
||||
final completer = Completer<double>();
|
||||
// ignore: prefer_function_declarations_over_variables
|
||||
void Function(double) callback = (double result) {
|
||||
completer.complete(result);
|
||||
};
|
||||
var ptr = callback.addFunction();
|
||||
func.call(ptr);
|
||||
await completer.future;
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
Future<int> withIntCallback(
|
||||
Function(Pointer<NativeFunction<Void Function(Int32)>>) func) async {
|
||||
final completer = Completer<int>();
|
||||
// ignore: prefer_function_declarations_over_variables
|
||||
void Function(int) callback = (int result) {
|
||||
completer.complete(result);
|
||||
};
|
||||
// final nativeCallable =
|
||||
// NativeCallable<Void Function(Int32)>.listener(callback);
|
||||
// func.call(nativeCallable.nativeFunction);
|
||||
await completer.future;
|
||||
// nativeCallable.close();
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
Pointer<T> allocate<T extends NativeType>(int count) {
|
||||
switch (T) {
|
||||
case PointerClass:
|
||||
return malloc(count * 4);
|
||||
default:
|
||||
throw Exception(T.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> withUInt32Callback(
|
||||
Function(Pointer<NativeFunction<Void Function(int)>>) func) async {
|
||||
final completer = Completer<int>();
|
||||
// ignore: prefer_function_declarations_over_variables
|
||||
void Function(int) callback = (int result) {
|
||||
completer.complete(result);
|
||||
};
|
||||
// final nativeCallable =
|
||||
// NativeCallable<Void Function(Uint32)>.listener(callback);
|
||||
// func.call(nativeCallable.nativeFunction);
|
||||
await completer.future;
|
||||
// nativeCallable.close();
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
Future<String> withCharPtrCallback(
|
||||
Function(Pointer<NativeFunction<Void Function(Pointer<Char>)>>)
|
||||
func) async {
|
||||
final completer = Completer<String>();
|
||||
// ignore: prefer_function_declarations_over_variables
|
||||
// void Function(Pointer<Char>) callback = (Pointer<Char> result) {
|
||||
// completer.complete(result.cast<Utf8>().toDartString());
|
||||
// };
|
||||
// final nativeCallable =
|
||||
// NativeCallable<Void Function(Pointer<Char>)>.listener(callback);
|
||||
// func.call(nativeCallable.nativeFunction);
|
||||
await completer.future;
|
||||
// nativeCallable.close();
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
extension DartBigIntExtension on int {
|
||||
BigInt get toBigInt {
|
||||
return BigInt.from(this);
|
||||
}
|
||||
}
|
||||
|
||||
Pointer stackSave() => _NativeLibrary.instance.stackSave();
|
||||
|
||||
void stackRestore(Pointer ptr) =>
|
||||
_NativeLibrary.instance.stackRestore(ptr.cast());
|
||||
|
||||
void getStackFree() {
|
||||
print(_NativeLibrary.instance._emscripten_stack_get_free());
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
6834
thermion_dart/lib/src/bindings/src/thermion_dart_js_interop.g.dart
Normal file
6834
thermion_dart/lib/src/bindings/src/thermion_dart_js_interop.g.dart
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
37
thermion_dart/lib/src/filament/src/interface/geometry.dart
Normal file
37
thermion_dart/lib/src/filament/src/interface/geometry.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:thermion_dart/src/bindings/bindings.dart';
|
||||
|
||||
import '../../../viewer/viewer.dart';
|
||||
|
||||
class Geometry {
|
||||
final Float32List vertices;
|
||||
final Uint16List indices;
|
||||
late final Float32List normals;
|
||||
late final Float32List uvs;
|
||||
final PrimitiveType primitiveType;
|
||||
|
||||
Geometry(
|
||||
this.vertices,
|
||||
this.indices, {
|
||||
Float32List? normals,
|
||||
Float32List? uvs,
|
||||
this.primitiveType = PrimitiveType.TRIANGLES,
|
||||
}) {
|
||||
this.uvs = uvs ?? Float32List(0);
|
||||
this.normals = normals ?? Float32List(0);
|
||||
if (this.uvs.length != 0 && this.uvs.length != (vertices.length ~/ 3 * 2)) {
|
||||
throw Exception(
|
||||
"Expected either ${indices.length * 2} UVs, got ${this.uvs!.length}");
|
||||
}
|
||||
}
|
||||
|
||||
void scale(double factor) {
|
||||
for (int i = 0; i < vertices.length; i++) {
|
||||
vertices[i] = vertices[i] * factor;
|
||||
}
|
||||
}
|
||||
|
||||
bool get hasNormals => normals?.isNotEmpty == true;
|
||||
bool get hasUVs => uvs?.isNotEmpty == true;
|
||||
}
|
||||
@@ -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]!);
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user