Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53b8d352da | ||
|
|
2553d854e9 | ||
|
|
7f9c5a0f2d | ||
|
|
7718885781 | ||
|
|
5bf21ceaf9 |
@@ -1,3 +1,4 @@
|
|||||||
## 0.0.1
|
## 0.5.0
|
||||||
|
|
||||||
* TODO: Describe initial release.
|
* Replaced `isReadyForScene` Future in `FilamentController` with the `Stream<bool>` `hasViewer`.
|
||||||
|
* Rendering is set to false when the app is hidden, inactive or paused; on resume, this will be set to the value it held prior to being hidden/inactive/paused.
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ Cross-platform, 3D PBR rendering and animation for [Flutter](https://github.com/
|
|||||||
|
|
||||||
Wraps the [the Filament rendering library](https://github.com/google/filament).
|
Wraps the [the Filament rendering library](https://github.com/google/filament).
|
||||||
|
|
||||||
Powers the Polyvox and odd-io engines.
|
Powers the [Polyvox](https://polyvox.app) and [odd-io](https://github.com/odd-io/) engines.
|
||||||
|
|
||||||
This is still in beta: bugs/missing features are to be expected.
|
This is still in beta: bugs/missing features are to be expected.
|
||||||
|
|
||||||
|
|
||||||
https://github.com/nmfisher/polyvox_filament/assets/7238578/abaed1c8-c97b-4999-97b2-39e85e0fa7dd
|
https://github.com/nmfisher/polyvox_filament/assets/7238578/abaed1c8-c97b-4999-97b2-39e85e0fa7dd
|
||||||
|
|
||||||
|
|
||||||
@@ -21,19 +20,19 @@ https://github.com/nmfisher/polyvox_filament/assets/7238578/abaed1c8-c97b-4999-9
|
|||||||
|Animation|✅ Embedded glTF skinning animations<br/>✅ Embedded glTF morph animations<br/> ✅ Runtime/dynamic morph animations<br/> ⚠️ Runtime/dynamic skinning animations <br/>
|
|Animation|✅ Embedded glTF skinning animations<br/>✅ Embedded glTF morph animations<br/> ✅ Runtime/dynamic morph animations<br/> ⚠️ Runtime/dynamic skinning animations <br/>
|
||||||
|Entity manipulation|✅ Viewport selection<br/>⚠️ Entity/transform parenting (planned)<br/> ⚠️ Transform manipulation (mouse/gesture to rotate/translate/scale object) (partial)<br/>⚠️ Runtime material changes (planned)|
|
|Entity manipulation|✅ Viewport selection<br/>⚠️ Entity/transform parenting (planned)<br/> ⚠️ Transform manipulation (mouse/gesture to rotate/translate/scale object) (partial)<br/>⚠️ Runtime material changes (planned)|
|
||||||
|
|
||||||
Special thanks to odd-io for sponsoring work on supporting Windows, raycasting, testing and documentation.
|
Special thanks to [odd-io](https://github.com/odd-io/) for sponsoring work on supporting Windows, raycasting, testing and documentation.
|
||||||
|
|
||||||
PRs are welcome but please create a placeholder PR to discuss before writing any code. This will help with feature planning, avoid clashes with existing work and keep the project structure consistent.
|
PRs are welcome but please create a placeholder PR to discuss before writing any code. This will help with feature planning, avoid clashes with existing work and keep the project structure consistent.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
This package is currently only tested on Flutter >= `3.16.0-0.2.pre`, so you will need to first switch to the `beta` channel:
|
This package requires Flutter >= `3.16.0-0.2.pre`, so you will need to first switch to the `beta` channel:
|
||||||
|
|
||||||
```
|
```
|
||||||
flutter channel beta
|
flutter channel beta
|
||||||
flutter upgrade
|
flutter upgrade
|
||||||
```
|
```
|
||||||
Earlier versions have specific issues that will prevent them from working on Windows/MacOS!
|
There are specific issues with earlier versions on Windows/MacOS (mobile should actually be fine, so if you want to experiment on your own you're free to remove the minimum version from `pubspec.yaml`).
|
||||||
|
|
||||||
Next, clone this repository and pull the latest binaries from Git LFS:
|
Next, clone this repository and pull the latest binaries from Git LFS:
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ class ExampleWidget extends StatefulWidget {
|
|||||||
|
|
||||||
class _ExampleWidgetState extends State<ExampleWidget> {
|
class _ExampleWidgetState extends State<ExampleWidget> {
|
||||||
FilamentController? _filamentController;
|
FilamentController? _filamentController;
|
||||||
|
|
||||||
FilamentEntity? _shapes;
|
FilamentEntity? _shapes;
|
||||||
FilamentEntity? _flightHelmet;
|
FilamentEntity? _flightHelmet;
|
||||||
List<String>? _animations;
|
List<String>? _animations;
|
||||||
@@ -65,10 +64,13 @@ class _ExampleWidgetState extends State<ExampleWidget> {
|
|||||||
bool _coneHidden = false;
|
bool _coneHidden = false;
|
||||||
bool _frustumCulling = true;
|
bool _frustumCulling = true;
|
||||||
|
|
||||||
|
StreamSubscription? _hasViewerListener;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
_pickResultListener?.cancel();
|
_pickResultListener?.cancel();
|
||||||
|
_hasViewerListener?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _item(void Function() onTap, String text) {
|
Widget _item(void Function() onTap, String text) {
|
||||||
@@ -92,9 +94,10 @@ class _ExampleWidgetState extends State<ExampleWidget> {
|
|||||||
picked = _filamentController!.getNameForEntity(entityId!);
|
picked = _filamentController!.getNameForEntity(entityId!);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
_filamentController!.isReadyForScene.then((readyForScene) {
|
_hasViewerListener =
|
||||||
|
_filamentController!.hasViewer.listen((bool hasViewer) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_readyForScene = readyForScene;
|
_readyForScene = hasViewer;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,20 +8,32 @@ typedef FilamentEntity = int;
|
|||||||
|
|
||||||
enum ToneMapper { ACES, FILMIC, LINEAR }
|
enum ToneMapper { ACES, FILMIC, LINEAR }
|
||||||
|
|
||||||
class TextureDetails {
|
class TextureDetails {
|
||||||
final int textureId;
|
final int textureId;
|
||||||
final int width;
|
final int width;
|
||||||
final int height;
|
final int height;
|
||||||
|
|
||||||
TextureDetails({required this.textureId, required this.width, required this.height});
|
TextureDetails(
|
||||||
|
{required this.textureId, required this.width, required this.height});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class FilamentController {
|
abstract class FilamentController {
|
||||||
|
///
|
||||||
Future get isReadyForScene;
|
/// The Flutter texture ID and dimensions for current texture in use.
|
||||||
|
/// This is only used by [FilamentWidget]; you shouldn't need to access directly yourself.
|
||||||
|
///
|
||||||
TextureDetails? get textureDetails;
|
TextureDetails? get textureDetails;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// A stream to indicate whether a FilamentViewer is available.
|
||||||
|
/// [FilamentWidget] will (asynchronously) create a [FilamentViewer] after being inserted into the widget hierarchy;
|
||||||
|
/// listen to this stream beforehand to perform any work necessary once the viewer is available.
|
||||||
|
/// [FilamentWidget] may also destroy/recreate the viewer on certain lifecycle events (e.g. backgrounding a mobile app);
|
||||||
|
/// listen for any corresponding [false]/[true] events to perform related work.
|
||||||
|
/// Note this is not a broadcast stream; only one listener can be registered and events will be buffered.
|
||||||
|
///
|
||||||
|
Stream<bool> get hasViewer;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The result(s) of calling [pick] (see below).
|
/// The result(s) of calling [pick] (see below).
|
||||||
/// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick].
|
/// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick].
|
||||||
@@ -66,7 +78,6 @@ abstract class FilamentController {
|
|||||||
///
|
///
|
||||||
Future destroyViewer();
|
Future destroyViewer();
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Destroys the specified backing texture. You probably want to call [destroy] instead of this; this is exposed mostly for lifecycle changes which are handled by FilamentWidget.
|
/// Destroys the specified backing texture. You probably want to call [destroy] instead of this; this is exposed mostly for lifecycle changes which are handled by FilamentWidget.
|
||||||
///
|
///
|
||||||
@@ -82,7 +93,7 @@ abstract class FilamentController {
|
|||||||
/// This will dispatch a request to the native platform to create a hardware texture (Metal on iOS, OpenGL on Linux, GLES on Android and Windows) and a FilamentViewer (the main interface for manipulating the 3D scene) .
|
/// This will dispatch a request to the native platform to create a hardware texture (Metal on iOS, OpenGL on Linux, GLES on Android and Windows) and a FilamentViewer (the main interface for manipulating the 3D scene) .
|
||||||
/// 4) The FilamentController will notify FilamentWidget that a texture is available
|
/// 4) The FilamentController will notify FilamentWidget that a texture is available
|
||||||
/// 5) The FilamentWidget will replace the empty Container with a Texture widget
|
/// 5) The FilamentWidget will replace the empty Container with a Texture widget
|
||||||
/// If you need to wait until a FilamentViewer has been created, [await] the [isReadyForScene] Future.
|
/// If you need to wait until a FilamentViewer has been created, listen to the [viewer] stream.
|
||||||
///
|
///
|
||||||
void createViewer(int width, int height);
|
void createViewer(int width, int height);
|
||||||
|
|
||||||
|
|||||||
@@ -16,18 +16,17 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
|
|
||||||
double _pixelRatio = 1.0;
|
double _pixelRatio = 1.0;
|
||||||
|
|
||||||
Completer _isReadyForScene = Completer();
|
|
||||||
Future get isReadyForScene => _isReadyForScene.future;
|
|
||||||
|
|
||||||
late Pointer<Void>? _assetManager;
|
late Pointer<Void>? _assetManager;
|
||||||
|
|
||||||
late NativeLibrary _lib;
|
late NativeLibrary _lib;
|
||||||
|
|
||||||
Pointer<Void>? _viewer;
|
Pointer<Void>? _viewer;
|
||||||
|
|
||||||
|
|
||||||
final String? uberArchivePath;
|
final String? uberArchivePath;
|
||||||
|
|
||||||
|
Stream<bool> get hasViewer => _hasViewerController.stream;
|
||||||
|
final _hasViewerController = StreamController<bool>();
|
||||||
|
|
||||||
Stream<FilamentEntity> get pickResult => _pickResultController.stream;
|
Stream<FilamentEntity> get pickResult => _pickResultController.stream;
|
||||||
final _pickResultController = StreamController<FilamentEntity>.broadcast();
|
final _pickResultController = StreamController<FilamentEntity>.broadcast();
|
||||||
|
|
||||||
@@ -99,12 +98,12 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
|
|
||||||
_assetManager = null;
|
_assetManager = null;
|
||||||
_lib.destroy_filament_viewer_ffi(viewer!);
|
_lib.destroy_filament_viewer_ffi(viewer!);
|
||||||
_isReadyForScene = Completer();
|
_hasViewerController.add(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future destroyTexture() async {
|
Future destroyTexture() async {
|
||||||
if(textureDetails != null) {
|
if (textureDetails != null) {
|
||||||
await _channel.invokeMethod("destroyTexture", textureDetails!.textureId);
|
await _channel.invokeMethod("destroyTexture", textureDetails!.textureId);
|
||||||
}
|
}
|
||||||
print("Texture destroyed");
|
print("Texture destroyed");
|
||||||
@@ -118,14 +117,11 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
throw Exception(
|
throw Exception(
|
||||||
"Viewer already exists, make sure you call destroyViewer first");
|
"Viewer already exists, make sure you call destroyViewer first");
|
||||||
}
|
}
|
||||||
if(textureDetails != null) {
|
if (textureDetails != null) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Texture already exists, make sure you call destroyTexture first");
|
"Texture already exists, make sure you call destroyTexture first");
|
||||||
}
|
}
|
||||||
if (_isReadyForScene.isCompleted) {
|
|
||||||
throw Exception(
|
|
||||||
"Do not call createViewer when a viewer has already been created without calling destroyViewer");
|
|
||||||
}
|
|
||||||
var loader = Pointer<ResourceLoaderWrapper>.fromAddress(
|
var loader = Pointer<ResourceLoaderWrapper>.fromAddress(
|
||||||
await _channel.invokeMethod("getResourceLoaderWrapper"));
|
await _channel.invokeMethod("getResourceLoaderWrapper"));
|
||||||
if (loader == nullptr) {
|
if (loader == nullptr) {
|
||||||
@@ -140,7 +136,6 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
await _channel.invokeMethod("createTexture", [size.width, size.height]);
|
await _channel.invokeMethod("createTexture", [size.width, size.height]);
|
||||||
var flutterTextureId = textures[0];
|
var flutterTextureId = textures[0];
|
||||||
|
|
||||||
|
|
||||||
// void* on iOS (pointer to pixel buffer), void* on Android (pointer to native window), null on Windows/macOS
|
// void* on iOS (pointer to pixel buffer), void* on Android (pointer to native window), null on Windows/macOS
|
||||||
var surfaceAddress = textures[1] as int? ?? 0;
|
var surfaceAddress = textures[1] as int? ?? 0;
|
||||||
|
|
||||||
@@ -192,8 +187,9 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
|
|
||||||
_assetManager = _lib.get_asset_manager(_viewer!);
|
_assetManager = _lib.get_asset_manager(_viewer!);
|
||||||
|
|
||||||
_isReadyForScene.complete(true);
|
textureDetails = TextureDetails(
|
||||||
textureDetails = TextureDetails(textureId: flutterTextureId!, width: width, height: height);
|
textureId: flutterTextureId!, width: width, height: height);
|
||||||
|
_hasViewerController.add(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -259,23 +255,22 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
/// # Given we don't do this on other platforms, I'm OK to stick with the existing solution for the time being.
|
/// # Given we don't do this on other platforms, I'm OK to stick with the existing solution for the time being.
|
||||||
/// ############################################################################
|
/// ############################################################################
|
||||||
///
|
///
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future resize(int width, int height, {double scaleFactor = 1.0}) async {
|
Future resize(int width, int height, {double scaleFactor = 1.0}) async {
|
||||||
|
// we defer to the FilamentWidget to ensure that every call to [resize] is synchronized
|
||||||
// we defer to the FilamentWidget to ensure that every call to [resize] is synchronized
|
|
||||||
// so this exception should never be thrown (right?)
|
// so this exception should never be thrown (right?)
|
||||||
if(textureDetails == null) {
|
if (textureDetails == null) {
|
||||||
throw Exception("Resize currently underway, ignoring");
|
throw Exception("Resize currently underway, ignoring");
|
||||||
}
|
}
|
||||||
|
|
||||||
var _textureDetails = textureDetails;
|
var _textureDetails = textureDetails;
|
||||||
|
|
||||||
textureDetails = null;
|
textureDetails = null;
|
||||||
|
|
||||||
_lib.set_rendering_ffi(_viewer!, false);
|
_lib.set_rendering_ffi(_viewer!, false);
|
||||||
|
|
||||||
if(_textureDetails != null) {
|
if (_textureDetails != null) {
|
||||||
if (_viewer != null) {
|
if (_viewer != null) {
|
||||||
_lib.destroy_swap_chain_ffi(_viewer!);
|
_lib.destroy_swap_chain_ffi(_viewer!);
|
||||||
}
|
}
|
||||||
@@ -288,7 +283,6 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
|
|
||||||
print("Size after pixel ratio : $width x $height ");
|
print("Size after pixel ratio : $width x $height ");
|
||||||
|
|
||||||
|
|
||||||
var textures = await _channel
|
var textures = await _channel
|
||||||
.invokeMethod("createTexture", [newSize.width, newSize.height]);
|
.invokeMethod("createTexture", [newSize.width, newSize.height]);
|
||||||
|
|
||||||
@@ -306,19 +300,18 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
if (nativeTexture != 0) {
|
if (nativeTexture != 0) {
|
||||||
assert(surfaceAddress == 0);
|
assert(surfaceAddress == 0);
|
||||||
print("Creating render target from native texture $nativeTexture");
|
print("Creating render target from native texture $nativeTexture");
|
||||||
_lib.create_render_target_ffi(
|
_lib.create_render_target_ffi(_viewer!, nativeTexture,
|
||||||
_viewer!, nativeTexture, newSize.width.toInt(), newSize.height.toInt());
|
newSize.width.toInt(), newSize.height.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
_lib.update_viewport_and_camera_projection_ffi(
|
_lib.update_viewport_and_camera_projection_ffi(
|
||||||
_viewer!, newSize.width.toInt(), newSize.height.toInt(), 1.0);
|
_viewer!, newSize.width.toInt(), newSize.height.toInt(), 1.0);
|
||||||
|
|
||||||
await setRendering(_rendering);
|
await setRendering(_rendering);
|
||||||
textureDetails = TextureDetails(textureId: textures[0]!, width: width, height: height);
|
textureDetails =
|
||||||
|
TextureDetails(textureId: textures[0]!, width: width, height: height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future clearBackgroundImage() async {
|
Future clearBackgroundImage() async {
|
||||||
if (_viewer == null) {
|
if (_viewer == null) {
|
||||||
|
|||||||
@@ -120,8 +120,8 @@ class FilamentControllerMethodChannel extends FilamentController {
|
|||||||
|
|
||||||
bool _resizing = false;
|
bool _resizing = false;
|
||||||
|
|
||||||
|
Future<TextureDetails> resize(int width, int height,
|
||||||
Future<TextureDetails> resize(int width, int height, {double scaleFactor = 1.0}) async {
|
{double scaleFactor = 1.0}) async {
|
||||||
throw Exception();
|
throw Exception();
|
||||||
_resizing = true;
|
_resizing = true;
|
||||||
_textureId = await _channel.invokeMethod(
|
_textureId = await _channel.invokeMethod(
|
||||||
@@ -670,12 +670,16 @@ class FilamentControllerMethodChannel extends FilamentController {
|
|||||||
// TODO: implement getNameForEntity
|
// TODO: implement getNameForEntity
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// TODO: implement textureDetails
|
// TODO: implement textureDetails
|
||||||
TextureDetails? get textureDetails => throw UnimplementedError();
|
TextureDetails? get textureDetails => throw UnimplementedError();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// TODO: implement rendering
|
// TODO: implement rendering
|
||||||
bool get rendering => throw UnimplementedError();
|
bool get rendering => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement hasViewer
|
||||||
|
Stream<bool> get hasViewer => throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,8 +168,9 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
|||||||
// debug mode does need a longer timeout.
|
// debug mode does need a longer timeout.
|
||||||
_resizeTimer?.cancel();
|
_resizeTimer?.cancel();
|
||||||
|
|
||||||
_resizeTimer = Timer(const Duration(milliseconds: kReleaseMode ? 20 : 100), () async {
|
_resizeTimer =
|
||||||
if(!mounted) {
|
Timer(const Duration(milliseconds: kReleaseMode ? 20 : 100), () async {
|
||||||
|
if (!mounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var size = ((context.findRenderObject()) as RenderBox).size;
|
var size = ((context.findRenderObject()) as RenderBox).size;
|
||||||
@@ -209,41 +210,42 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case AppLifecycleState.detached:
|
case AppLifecycleState.detached:
|
||||||
print("Detached");
|
print("Detached");
|
||||||
|
if (!_wasRenderingOnInactive) {
|
||||||
if (widget.controller.textureDetails != null) {
|
_wasRenderingOnInactive = widget.controller.rendering;
|
||||||
await widget.controller.destroyViewer();
|
|
||||||
await widget.controller.destroyTexture();
|
|
||||||
}
|
}
|
||||||
|
await widget.controller.setRendering(false);
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.hidden:
|
case AppLifecycleState.hidden:
|
||||||
print("Hidden");
|
print("Hidden");
|
||||||
if (Platform.isIOS && widget.controller.textureDetails != null) {
|
if (!_wasRenderingOnInactive) {
|
||||||
await widget.controller.destroyViewer();
|
_wasRenderingOnInactive = widget.controller.rendering;
|
||||||
await widget.controller.destroyTexture();
|
|
||||||
}
|
}
|
||||||
|
await widget.controller.setRendering(false);
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.inactive:
|
case AppLifecycleState.inactive:
|
||||||
print("Inactive");
|
print("Inactive");
|
||||||
|
if (!_wasRenderingOnInactive) {
|
||||||
|
_wasRenderingOnInactive = widget.controller.rendering;
|
||||||
|
}
|
||||||
// on Windows in particular, restoring a window after minimizing stalls the renderer (and the whole application) for a considerable length of time.
|
// on Windows in particular, restoring a window after minimizing stalls the renderer (and the whole application) for a considerable length of time.
|
||||||
// disabling rendering on minimize seems to fix the issue (so I wonder if there's some kind of command buffer that's filling up while the window is minimized).
|
// disabling rendering on minimize seems to fix the issue (so I wonder if there's some kind of command buffer that's filling up while the window is minimized).
|
||||||
_wasRenderingOnInactive = widget.controller.rendering;
|
|
||||||
await widget.controller.setRendering(false);
|
await widget.controller.setRendering(false);
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.paused:
|
case AppLifecycleState.paused:
|
||||||
print("Paused");
|
print("Paused");
|
||||||
|
if (!_wasRenderingOnInactive) {
|
||||||
|
_wasRenderingOnInactive = widget.controller.rendering;
|
||||||
|
}
|
||||||
|
await widget.controller.setRendering(false);
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.resumed:
|
case AppLifecycleState.resumed:
|
||||||
print("Resumed");
|
print("Resumed");
|
||||||
if (!Platform.isWindows) {
|
|
||||||
if (widget.controller.textureDetails == null) {
|
|
||||||
var size = ((context.findRenderObject()) as RenderBox).size;
|
|
||||||
widget.controller
|
|
||||||
.createViewer(size.width.ceil(), size.height.ceil());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await _resize();
|
|
||||||
}
|
|
||||||
await widget.controller.setRendering(_wasRenderingOnInactive);
|
await widget.controller.setRendering(_wasRenderingOnInactive);
|
||||||
|
await _resize();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_lastState = state;
|
_lastState = state;
|
||||||
@@ -274,7 +276,7 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> {
|
|||||||
|
|
||||||
return Stack(children: [
|
return Stack(children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Platform.isLinux || Platform.isWindows
|
child: Platform.isLinux || Platform.isWindows
|
||||||
? Transform(
|
? Transform(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
transform: Matrix4.rotationX(
|
transform: Matrix4.rotationX(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: polyvox_filament
|
name: polyvox_filament
|
||||||
description: A Flutter plugin to wrap the Filament rendering engine.
|
description: A Flutter plugin to wrap the Filament rendering engine.
|
||||||
version: 0.0.1
|
version: 0.5.0
|
||||||
homepage:
|
homepage:
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
Reference in New Issue
Block a user