feat! js_interop improvements
This commit is contained in:
@@ -11,14 +11,8 @@ import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_in
|
||||
class ThermionFlutterPlugin {
|
||||
ThermionFlutterPlugin._();
|
||||
|
||||
static Future<ThermionViewer> createViewer(
|
||||
{ThermionFlutterOptions options =
|
||||
const ThermionFlutterOptions()}) async {
|
||||
|
||||
final viewer =
|
||||
await ThermionFlutterPlatform.instance.createViewer(options: options);
|
||||
|
||||
return viewer;
|
||||
static Future<ThermionViewer> createViewer() {
|
||||
return ThermionFlutterPlatform.instance.createViewer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ Future kDefaultResizeCallback(Size size, View view, double pixelRatio) async {
|
||||
}
|
||||
|
||||
class ThermionWidget extends StatefulWidget {
|
||||
|
||||
///
|
||||
/// The viewer whose content will be rendered into this widget.
|
||||
///
|
||||
@@ -43,7 +42,7 @@ class ThermionWidget extends StatefulWidget {
|
||||
|
||||
///
|
||||
/// If true, add an overlay showing the FPS on top of the rendered content.
|
||||
///
|
||||
///
|
||||
final bool showFpsCounter;
|
||||
|
||||
///
|
||||
@@ -67,12 +66,9 @@ class ThermionWidget extends StatefulWidget {
|
||||
class _ThermionWidgetState extends State<ThermionWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Web doesn't support imported textures yet
|
||||
if (kIsWeb) {
|
||||
throw Exception();
|
||||
// return ThermionWidgetWeb(
|
||||
// viewer: widget.viewer,
|
||||
// options: ThermionFlutterPlugin.options as ThermionFlutterWebOptions?);
|
||||
return ThermionWidgetWeb(
|
||||
viewer: widget.viewer, options: const ThermionFlutterWebOptions(importCanvasAsWidget: true));
|
||||
}
|
||||
|
||||
return ThermionTextureWidget(
|
||||
|
||||
@@ -1,37 +1,121 @@
|
||||
import 'dart:js_util';
|
||||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
import 'dart:ui_web' as ui_web;
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:thermion_flutter/thermion_flutter.dart';
|
||||
import 'package:thermion_flutter_web/thermion_flutter_web.dart';
|
||||
import 'package:thermion_flutter_web/thermion_flutter_web_options.dart';
|
||||
import 'package:web/web.dart';
|
||||
import 'package:web/web.dart' as web;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class ThermionWidgetWeb extends StatelessWidget {
|
||||
import 'resize_observer.dart';
|
||||
|
||||
class ThermionWidgetWeb extends StatefulWidget {
|
||||
final ThermionFlutterWebOptions options;
|
||||
final ThermionViewer viewer;
|
||||
|
||||
const ThermionWidgetWeb(
|
||||
{super.key, this.options = const ThermionFlutterWebOptions.empty(), required this.viewer});
|
||||
{super.key,
|
||||
this.options = const ThermionFlutterWebOptions(),
|
||||
required this.viewer});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _ThermionWidgetWebState();
|
||||
}
|
||||
|
||||
class _ThermionWidgetWebState extends State<ThermionWidgetWeb> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
_requestFrame();
|
||||
}
|
||||
|
||||
DateTime lastRender = DateTime.now();
|
||||
|
||||
void _requestFrame() async {
|
||||
Pointer? stackPtr;
|
||||
WidgetsBinding.instance.scheduleFrameCallback((d) async {
|
||||
if (stackPtr != null) {
|
||||
stackRestore(stackPtr!);
|
||||
stackPtr = null;
|
||||
}
|
||||
|
||||
var elapsed = DateTime.now().microsecondsSinceEpoch -
|
||||
lastRender.microsecondsSinceEpoch;
|
||||
// if (elapsed > 1667) {
|
||||
lastRender = DateTime.now();
|
||||
if (widget.viewer.rendering) {
|
||||
await FilamentApp.instance!.requestFrame();
|
||||
}
|
||||
// }
|
||||
stackPtr = stackSave();
|
||||
_requestFrame();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// if (_texture == null || _resizing) {
|
||||
// return widget.initial ?? Container(color: Colors.red);
|
||||
// }
|
||||
// return ResizeObserver(
|
||||
// onResized: _resizeTexture,
|
||||
// child: ThermionWidgetWeb(
|
||||
// options: widget.options as ThermionFlutterWebOptions?));
|
||||
|
||||
if (options?.importCanvasAsWidget == true) {
|
||||
return _ImageCopyingWidget();
|
||||
if (widget.options.importCanvasAsWidget) {
|
||||
return _ImageCopyingWidget(viewer: widget.viewer);
|
||||
// return _PlatformView(
|
||||
// viewer: widget.viewer,
|
||||
// );
|
||||
}
|
||||
return Container(color: const Color(0x00000000));
|
||||
}
|
||||
}
|
||||
|
||||
class _PlatformView extends StatefulWidget {
|
||||
final ThermionViewer viewer;
|
||||
|
||||
const _PlatformView({super.key, required this.viewer});
|
||||
@override
|
||||
State<StatefulWidget> createState() => _PlatformViewState();
|
||||
}
|
||||
|
||||
class _PlatformViewState extends State<_PlatformView> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
ui_web.platformViewRegistry.registerViewFactory(
|
||||
'imported-canvas',
|
||||
(int viewId, {Object? params}) {
|
||||
var canvas = web.document.getElementById("thermion_canvas");
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
var renderBox = this.context.findRenderObject() as RenderBox?;
|
||||
|
||||
_resize(Size(0, 0), renderBox!.size);
|
||||
});
|
||||
|
||||
return canvas! as Object;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _resize(Size oldSize, Size newSize) {
|
||||
var width = newSize.width.toInt();
|
||||
var height = newSize.height.toInt();
|
||||
ThermionFlutterWebPlugin.instance
|
||||
.resizeCanvas(newSize.width, newSize.height);
|
||||
widget.viewer.setViewport(width, height);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResizeObserver(
|
||||
onResized: _resize,
|
||||
child: HtmlElementView(
|
||||
viewType: 'imported-canvas',
|
||||
onPlatformViewCreated: (i) {},
|
||||
creationParams: <String, Object?>{
|
||||
'key': 'someValue',
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class _ImageCopyingWidget extends StatefulWidget {
|
||||
final ThermionViewer viewer;
|
||||
|
||||
const _ImageCopyingWidget({super.key, required this.viewer});
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _ImageCopyingWidgetState();
|
||||
@@ -39,34 +123,82 @@ class _ImageCopyingWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ImageCopyingWidgetState extends State<_ImageCopyingWidget> {
|
||||
final _logger = Logger("_ImageCopyingWidgetState");
|
||||
late final _logger = Logger(this.runtimeType.toString());
|
||||
late web.HTMLCanvasElement canvas;
|
||||
ui.Image? _img;
|
||||
double width = 0;
|
||||
double height = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
capture();
|
||||
canvas =
|
||||
web.document.getElementById("thermion_canvas") as web.HTMLCanvasElement;
|
||||
WidgetsBinding.instance.addPostFrameCallback((t) {
|
||||
_refresh(Duration.zero);
|
||||
});
|
||||
}
|
||||
|
||||
Future capture() async {
|
||||
void _refresh(Duration _) async {
|
||||
try {
|
||||
final ImageBitmap newSource = await promiseToFuture<ImageBitmap>(
|
||||
window.createImageBitmap(
|
||||
document.getElementById("canvas") as HTMLCanvasElement));
|
||||
_img = await ui_web.createImageFromImageBitmap(newSource);
|
||||
setState(() {});
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
capture();
|
||||
});
|
||||
final rb = this.context.findRenderObject() as RenderBox?;
|
||||
|
||||
if (_resizing || rb == null || rb.size.isEmpty) {
|
||||
setState(() {});
|
||||
return;
|
||||
}
|
||||
|
||||
if (canvas.width != rb.size.width || canvas.height != rb.size.height) {
|
||||
ThermionFlutterWebPlugin.instance
|
||||
.resizeCanvas(rb.size.width, rb.size.height);
|
||||
await widget.viewer
|
||||
.setViewport(rb.size.width.ceil(), rb.size.height.ceil())
|
||||
.timeout(Duration(seconds: 1));
|
||||
}
|
||||
|
||||
width = canvas.width * web.window.devicePixelRatio;
|
||||
height = canvas.height * web.window.devicePixelRatio;
|
||||
_img = await ui_web.createImageFromTextureSource(canvas,
|
||||
width: width.ceil(), height: height.ceil(), transferOwnership: true);
|
||||
|
||||
_request++;
|
||||
} catch (err) {
|
||||
_logger.severe(err);
|
||||
} finally {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
setState(() {});
|
||||
});
|
||||
WidgetsBinding.instance.scheduleFrameCallback(_refresh);
|
||||
}
|
||||
}
|
||||
|
||||
int _request = 0;
|
||||
|
||||
bool _resizing = false;
|
||||
Timer? _resizeTimer;
|
||||
|
||||
void _resize(Size oldSize, Size newSize) {
|
||||
_resizeTimer?.cancel();
|
||||
_resizing = true;
|
||||
_resizeTimer = Timer(Duration(milliseconds: 100), () {
|
||||
_resizing = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RawImage(image: _img!);
|
||||
if (_img == null) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
return ResizeObserver(
|
||||
onResized: _resize,
|
||||
child: RawImage(
|
||||
key: Key(_request.toString()),
|
||||
width: width,
|
||||
height: height,
|
||||
image: _img!,
|
||||
filterQuality: FilterQuality.high,
|
||||
isAntiAlias: false,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ class _ViewerWidgetState extends State<ViewerWidget> {
|
||||
}
|
||||
|
||||
void didUpdateWidget(ViewerWidget oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.manipulatorType != widget.manipulatorType) {
|
||||
_setViewportWidget();
|
||||
setState(() {});
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
|
||||
|
||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
@@ -43,23 +42,22 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform {
|
||||
return asset.buffer.asUint8List(asset.offsetInBytes);
|
||||
}
|
||||
|
||||
Future<ThermionViewer> createViewer({ThermionFlutterOptions? options}) async {
|
||||
|
||||
Future<ThermionViewer> createViewer() async {
|
||||
var driverPlatform = await channel.invokeMethod("getDriverPlatform");
|
||||
|
||||
var platformPtr = driverPlatform == null
|
||||
? nullptr
|
||||
: Pointer<Void>.fromAddress(driverPlatform);
|
||||
: VoidPointerClass.fromAddress(driverPlatform);
|
||||
|
||||
var sharedContext = await channel.invokeMethod("getSharedContext");
|
||||
|
||||
var sharedContextPtr = sharedContext == null
|
||||
? nullptr
|
||||
: Pointer<Void>.fromAddress(sharedContext);
|
||||
: VoidPointerClass.fromAddress(sharedContext);
|
||||
|
||||
late Backend backend;
|
||||
if (options?.backend != null) {
|
||||
switch (options!.backend) {
|
||||
if (options.backend != null) {
|
||||
switch (options.backend) {
|
||||
case Backend.VULKAN:
|
||||
if (!Platform.isWindows) {
|
||||
throw Exception("Vulkan only supported on Windows");
|
||||
@@ -93,12 +91,12 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform {
|
||||
resourceLoader: loadAsset,
|
||||
platform: platformPtr,
|
||||
sharedContext: sharedContextPtr,
|
||||
uberArchivePath: options?.uberarchivePath);
|
||||
uberArchivePath: options.uberarchivePath);
|
||||
|
||||
if (FilamentApp.instance == null) {
|
||||
await FFIFilamentApp.create(config: config);
|
||||
FilamentApp.instance!.onDestroy(() async {
|
||||
if(Platform.isWindows) {
|
||||
if (Platform.isWindows) {
|
||||
await channel.invokeMethod("destroyContext");
|
||||
}
|
||||
_swapChain = null;
|
||||
@@ -160,8 +158,9 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform {
|
||||
|
||||
_swapChain = await FilamentApp.instance!
|
||||
.createHeadlessSwapChain(descriptor.width, descriptor.height);
|
||||
|
||||
_logger.info("Created headless swapchain ${descriptor.width}x${descriptor.height}");
|
||||
|
||||
_logger.info(
|
||||
"Created headless swapchain ${descriptor.width}x${descriptor.height}");
|
||||
|
||||
await FilamentApp.instance!.register(_swapChain!, view);
|
||||
} else if (Platform.isAndroid) {
|
||||
@@ -214,7 +213,7 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform {
|
||||
PlatformTextureDescriptor texture,
|
||||
View view,
|
||||
int width,
|
||||
int height) async {
|
||||
int height) async {
|
||||
var newTexture = await createTextureAndBindToView(view, width, height);
|
||||
if (newTexture == null) {
|
||||
throw Exception();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:thermion_dart/src/filament/filament.dart';
|
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||
import 'thermion_flutter_texture.dart';
|
||||
|
||||
@@ -9,7 +8,8 @@ class ThermionFlutterOptions {
|
||||
final String? uberarchivePath;
|
||||
final Backend? backend;
|
||||
|
||||
const ThermionFlutterOptions({this.uberarchivePath = null, this.backend = null});
|
||||
const ThermionFlutterOptions(
|
||||
{this.uberarchivePath = null, this.backend = null});
|
||||
}
|
||||
|
||||
abstract class ThermionFlutterPlatform extends PlatformInterface {
|
||||
@@ -20,6 +20,29 @@ abstract class ThermionFlutterPlatform extends PlatformInterface {
|
||||
static late final ThermionFlutterPlatform _instance;
|
||||
static ThermionFlutterPlatform get instance => _instance;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
ThermionFlutterOptions? _options;
|
||||
ThermionFlutterOptions get options {
|
||||
_options ??= const ThermionFlutterOptions();
|
||||
return _options!;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void setOptions(covariant ThermionFlutterOptions options) {
|
||||
if (_options != null) {
|
||||
throw Exception(
|
||||
"Options can only be set once for the entire app lifecycle.");
|
||||
}
|
||||
_options = options;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
static set instance(ThermionFlutterPlatform instance) {
|
||||
PlatformInterface.verifyToken(instance, _token);
|
||||
_instance = instance;
|
||||
@@ -28,8 +51,9 @@ abstract class ThermionFlutterPlatform extends PlatformInterface {
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<ThermionViewer> createViewer(
|
||||
{covariant ThermionFlutterOptions? options});
|
||||
Future<ThermionViewer> createViewer() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a raw rendering surface.
|
||||
@@ -38,12 +62,16 @@ abstract class ThermionFlutterPlatform extends PlatformInterface {
|
||||
/// call this yourself. May not be supported on all platforms.
|
||||
///
|
||||
Future<PlatformTextureDescriptor> createTextureDescriptor(
|
||||
int width, int height);
|
||||
int width, int height) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
///
|
||||
/// Destroys a raw rendering surface.
|
||||
///
|
||||
Future destroyTextureDescriptor(PlatformTextureDescriptor descriptor);
|
||||
Future destroyTextureDescriptor(PlatformTextureDescriptor descriptor) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
///
|
||||
/// Create a rendering surface and binds to the given [View]
|
||||
@@ -52,17 +80,23 @@ abstract class ThermionFlutterPlatform extends PlatformInterface {
|
||||
/// call this yourself. May not be supported on all platforms.
|
||||
///
|
||||
Future<PlatformTextureDescriptor?> createTextureAndBindToView(
|
||||
View view, int width, int height);
|
||||
View view, int width, int height) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<PlatformTextureDescriptor?> resizeTexture(
|
||||
PlatformTextureDescriptor texture, View view, int width, int height);
|
||||
PlatformTextureDescriptor texture, View view, int width, int height) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future markTextureFrameAvailable(PlatformTextureDescriptor texture);
|
||||
Future markTextureFrameAvailable(PlatformTextureDescriptor texture) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +1,123 @@
|
||||
import 'dart:async';
|
||||
import 'dart:js_interop';
|
||||
import 'dart:js_interop_unsafe';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
|
||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
||||
|
||||
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||
import 'package:thermion_flutter_web/thermion_flutter_web_options.dart';
|
||||
import 'package:web/web.dart';
|
||||
|
||||
class ThermionFlutterWebPlugin extends ThermionFlutterPlatform {
|
||||
|
||||
ThermionViewerWasm? _viewer;
|
||||
late final _logger = Logger(this.runtimeType.toString());
|
||||
|
||||
static void registerWith(Registrar registrar) {
|
||||
ThermionFlutterPlatform.instance = ThermionFlutterWebPlugin();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<PlatformTextureDescriptor?> createTexture(double width, double height,
|
||||
double offsetLeft, double offsetTop, double pixelRatio) async {
|
||||
await _viewer!.destroySwapChain();
|
||||
await _viewer!.createSwapChain(width.ceil(), height.ceil());
|
||||
|
||||
final canvas = document.getElementById("canvas") as HTMLCanvasElement;
|
||||
canvas.width = (width * pixelRatio).ceil();
|
||||
canvas.height = (height * pixelRatio).ceil();
|
||||
|
||||
(canvas as HTMLElement).style.position = "fixed";
|
||||
(canvas as HTMLElement).style.zIndex = "-1";
|
||||
(canvas as HTMLElement).style.left =
|
||||
(offsetLeft * pixelRatio).ceil().toString();
|
||||
(canvas as HTMLElement).style.top =
|
||||
(offsetTop * pixelRatio).ceil().toString();
|
||||
|
||||
_viewer!
|
||||
.setViewportAndCameraProjection(width.ceil(), height.ceil(), 1.0);
|
||||
|
||||
return PlatformTextureDescriptor(null, null, 0, 0, null);
|
||||
ThermionFlutterWebOptions? _options;
|
||||
void setOptions(ThermionFlutterWebOptions options) {
|
||||
_options = options;
|
||||
}
|
||||
|
||||
@override
|
||||
Future destroyTexture(PlatformTextureDescriptor texture) async {
|
||||
// noop
|
||||
ThermionFlutterWebOptions get options {
|
||||
_options ??= const ThermionFlutterWebOptions();
|
||||
return _options!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<PlatformTextureDescriptor?> resizeTexture(PlatformTextureDescriptor texture,
|
||||
int width, int height, int offsetLeft, int offsetTop, double pixelRatio) async {
|
||||
final canvas = document.getElementById("canvas") as HTMLCanvasElement;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
(canvas as HTMLElement).style.position = "fixed";
|
||||
(canvas as HTMLElement).style.zIndex = "-1";
|
||||
(canvas as HTMLElement).style.left =
|
||||
(offsetLeft * pixelRatio).ceil().toString();
|
||||
(canvas as HTMLElement).style.top =
|
||||
(offsetTop * pixelRatio).ceil().toString();
|
||||
_viewer!.setViewportAndCameraProjection(width, height, 1.0);
|
||||
return PlatformTextureDescriptor(null, null, 0, 0, null);
|
||||
}
|
||||
static ThermionFlutterWebPlugin get instance =>
|
||||
ThermionFlutterPlatform.instance as ThermionFlutterWebPlugin;
|
||||
|
||||
Future<ThermionViewer> createViewerWithOptions(
|
||||
ThermionFlutterWebOptions options) async {
|
||||
_viewer = ThermionViewerWasm(assetPathPrefix: "/assets/");
|
||||
|
||||
final canvas = options.createCanvas
|
||||
? document.createElement("canvas") as HTMLCanvasElement?
|
||||
: document.getElementById("canvas") as HTMLCanvasElement?;
|
||||
if (canvas == null) {
|
||||
throw Exception("Could not locate or create canvas");
|
||||
static Future<Uint8List> loadAsset(String path) async {
|
||||
if (path.startsWith("file://")) {
|
||||
throw UnsupportedError("file:// URIs not supported on web");
|
||||
}
|
||||
canvas.id = "canvas";
|
||||
document.body!.appendChild(canvas);
|
||||
canvas.style.display = 'none';
|
||||
final pixelRatio = window.devicePixelRatio;
|
||||
|
||||
await _viewer!
|
||||
.initialize(1, 1, pixelRatio, uberArchivePath: options.uberarchivePath);
|
||||
return _viewer!;
|
||||
if (path.startsWith("asset://")) {
|
||||
path = path.replaceAll("asset://", "");
|
||||
}
|
||||
var asset = await rootBundle.load(path);
|
||||
return asset.buffer.asUint8List(asset.offsetInBytes);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionViewer> createViewer({String? uberarchivePath}) {
|
||||
throw Exception("Use createViewerWithOptions instead");
|
||||
Future<ThermionViewer> createViewer() async {
|
||||
HTMLCanvasElement? canvas;
|
||||
if (FilamentApp.instance == null) {
|
||||
// first, try and initialize bindings to see if the user has included thermion_dart.js manually in index.html
|
||||
try {
|
||||
NativeLibrary.initBindings("thermion_dart");
|
||||
} catch (err) {
|
||||
_logger.info(
|
||||
"Failed to find thermion_dart in window context, appending manually");
|
||||
// if not, manually add the script to the DOM
|
||||
var scriptElement =
|
||||
document.createElement("script") as HTMLScriptElement;
|
||||
scriptElement.src = "./thermion_dart.js";
|
||||
document.head!.appendChild(scriptElement);
|
||||
final completer = Completer<JSObject?>();
|
||||
scriptElement.addEventListener(
|
||||
"load",
|
||||
() {
|
||||
final constructor = globalContext
|
||||
.getProperty("thermion_dart".toJS) as JSFunction?;
|
||||
if (constructor == null) {
|
||||
_logger.severe("Failed to find JS library constructor");
|
||||
completer.complete(null);
|
||||
} else {
|
||||
final lib = constructor.callAsFunction() as JSPromise;
|
||||
lib.toDart.then((resolved) {
|
||||
completer.complete(resolved as JSObject);
|
||||
});
|
||||
}
|
||||
}.toJS);
|
||||
final lib = await completer.future;
|
||||
globalContext.setProperty("thermion_dart".toJS, lib);
|
||||
NativeLibrary.initBindings("thermion_dart");
|
||||
}
|
||||
|
||||
canvas = options.createCanvas == true
|
||||
? document.createElement("canvas") as HTMLCanvasElement?
|
||||
: document.getElementById("thermion_canvas") as HTMLCanvasElement?;
|
||||
|
||||
if (canvas == null) {
|
||||
throw Exception("Could not locate or create canvas");
|
||||
}
|
||||
canvas.id = "thermion_canvas";
|
||||
// canvas.style.display = "none";
|
||||
document.body!.appendChild(canvas);
|
||||
|
||||
(canvas as HTMLElement).style.position = "fixed";
|
||||
(canvas as HTMLElement).style.zIndex = "-1";
|
||||
|
||||
final config = FFIFilamentConfig(
|
||||
backend: Backend.OPENGL,
|
||||
resourceLoader: loadAsset,
|
||||
platform: nullptr,
|
||||
sharedContext: nullptr,
|
||||
uberArchivePath: options.uberarchivePath);
|
||||
await FFIFilamentApp.create(config: config);
|
||||
}
|
||||
|
||||
final viewer = ThermionViewerFFI(loadAssetFromUri: loadAsset);
|
||||
await viewer.initialized;
|
||||
await viewer.setViewport(canvas!.width, canvas.height);
|
||||
|
||||
var swapChain = await FilamentApp.instance!
|
||||
.createHeadlessSwapChain(canvas.width, canvas.height);
|
||||
|
||||
await FilamentApp.instance!.register(swapChain, viewer.view);
|
||||
|
||||
return viewer;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void resizeCanvas(double width, double height) async {
|
||||
_logger.info("Resizing canvas to ${width}x${height}");
|
||||
Thermion_resizeCanvas((window.devicePixelRatio * width).ceil(),
|
||||
(window.devicePixelRatio * height).ceil());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ class ThermionFlutterWebOptions extends ThermionFlutterOptions {
|
||||
final bool createCanvas;
|
||||
final bool importCanvasAsWidget;
|
||||
|
||||
ThermionFlutterWebOptions(
|
||||
const ThermionFlutterWebOptions(
|
||||
{this.importCanvasAsWidget = false,
|
||||
this.createCanvas = true,
|
||||
String? uberarchivePath})
|
||||
|
||||
@@ -24,6 +24,12 @@ dependencies:
|
||||
thermion_flutter_platform_interface: ^0.2.1-dev.20.0
|
||||
flutter_web_plugins:
|
||||
sdk: flutter
|
||||
dependency_overrides:
|
||||
thermion_flutter_platform_interface:
|
||||
path: ../thermion_flutter_platform_interface
|
||||
thermion_dart:
|
||||
path: ../../thermion_dart
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user