add integration tests and update README

This commit is contained in:
Nick Fisher
2023-10-12 21:48:44 +08:00
parent 80388c059d
commit 8358c0b236
32 changed files with 427 additions and 75 deletions

View File

@@ -1,46 +1,38 @@
# Flutter Filament
Cross-platform, Physically-based rendering inside Flutter applications.
Cross-platform, 3D PBR rendering and animation for Flutter.
Flutter plugin wrapping the Filament renderer https://github.com/google/filament.
Wraps the [the Filament rendering library](https://github.com/google/filament).
Powers the Polyvox and odd-io engines.
# Sponsors
|Feature|Supported|
|---|---|
|glTF|Partial - see Known Issues|
|glb|✅|
|Camera movement (mouse/finger gesture)|✅|
|Skinning|✅|
|Morph targets|✅|
|Runtime material changes|Partial|
|Viewport entity selection|✅|
|Entity transform manipulation (mouse/finger gesture)|Partial|
|Entity/transform parenting|Planned|
|Entity material manipulation|Partial|
Thank you to odd-io for sponsoring work on supporting Windows, raycasting, testing and documentation.
Special thanks to odd-io for sponsoring work on supporting Windows, raycasting, testing and documentation.
# Overview
PRs are welcome but please create a placeholder PR to discuss before writing any code. This will help avoid
## Versioning
## Getting Started
This package is currently only tested on Flutter `3.15.0-15.2.pre`, so you will need to first switch to the `beta` channel:
Last tested on Flutter `3.15.0-15.2.pre`. This is on the Flutter beta channel, so run:
```
flutter channel beta
flutter upgrade
```
||Android|iOS|MacOS|Windows|Linux|WebGL
|---|---|---|---|---|---||
|Filament|v1.43.1 (arm64/armeabi-v7a/x86/x86_64)|v1.43.1* (arm64)|v1.43.1 (arm64)|v1.32.4 (x86_64)|TODO**|TODO***|
|Flutter||3.15.0-15.2.pre|3.15.0-15.2.pre|3.15.0-15.2.pre
* iOS release build has a skybox bug so the debug versions are currently shipped on iOS
** (Waiting for https://github.com/google/filament/issues/7078 to be resolved before upgrading, not sure exactly when the bug was introduced but it was somewhere between v1.32.4 and v1.40.0)
*** Texture widget not currently supported on web in Flutter.
## Features
|Feature|Supported|
|---|---|
|glTF|Y|
|glb|Y|
# Basic Setup
## Clone flutter_filament
This plugin is not yet published to pub.dev. To use in your project, simply clone the repository and pull the latest binaries from Git LFS:
Next, clone this repository and pull the latest binaries from Git LFS:
```
cd $HOME
@@ -48,17 +40,17 @@ git clone <repo> && cd flutter_filament
git lfs pull
```
You *do not need to build Filament yourself*. The repository is bundled with all necessary headers/static libraries (`windows/lib`, `ios/lib`, `macos/lib` and `linux/lib`) and the Flutter plugin has been configured to link at build time.
(these instructions will be updated after the plugin is published to pub.dev).
> [!NOTE]
> You *do not need to build Filament yourself*. The repository is bundled with all necessary headers/static libraries (`windows/lib`, `ios/lib`, `macos/lib` and `linux/lib`) and the Flutter plugin has been configured to link at build time.
If you want to run the example project to check:
Run the example project to check:
```
cd example && flutter run -d <macos/windows/Your iPhone/etc>
```
## Add dependency
Add the plugin as a dependency in the pubspec.yaml for your application:
To use the plugin in your own project, add the plugin to your pubspec.yaml:
```
name: your_project
@@ -71,11 +63,11 @@ dependencies:
path: <path where you cloned the repository>
```
# Basic Usage
## Basic Usage
See the `example` project for a complete sample of the below steps.
## Creating the viewport widget and controller
### Creating the viewport widget and controller
To embed a viewport in your app, create an instance of `FilamentControllerFFI` somewhere in your app:
@@ -147,12 +139,12 @@ You can also pass a URI to indicate that the glTF file should be loaded from the
var entity = _filamentController.loadGlb("file:///tmp/bob.glb");
```
The return type `FilamentEntity` is simply an integer handle that be used to manipulate the entity in the scene.
For example, to remove the asset:
The return type `FilamentEntity` is simply an integer handle that be used to manipulate the entity in the scene. For example, to remove the asset:
```
_filamentController.removeAsset(entity);
entity = null; // see note* below
```
* Removing an entity from the scene will invalidate the corresponding `FilamentEntity` handle, so ensure you don't retain any references to it after calling `removeAsset` or `clearAssets`. Removing one `FilamentEntity` does not invalidate/change any other `FilamentEntity` handles; you can continue to safely manipulate these via the `FilamentController`.
To set the world space position of the asset:
```
@@ -161,7 +153,6 @@ _filamentController.setPositon(entity, 1.0, 1.0, 1.0);
On desktop, you can also click any renderable object in the viewport to retrieve its associated FilamentEntity (see below).
Whenever an entity is removed from the scene (or you've called another method that clears all entities), the corresponding `FilamentEntity` handle(s) are invalidated and should not be used.
### Camera movement
@@ -257,7 +248,36 @@ uberz -TSHADINGMODEL=lit -TBLENDING=opaque -o lit_opaque_43.uberz lit_opaque
(note that the number in the filename corresponds to the Material version, not the Filament version. Not every Filament version requires a new Material version).
## Versioning
||Android|iOS|MacOS|Windows|Linux|WebGL|
|---|---|---|---|---|---||
|Filament|v1.43.1 (arm64/armeabi-v7a/x86/x86_64)|v1.43.1* (arm64)|v1.43.1 (arm64)|v1.32.4 (x86_64)|TODO**|TODO***|
|Flutter||3.15.0-15.2.pre|3.15.0-15.2.pre|3.15.0-15.2.pre
* iOS release build has a skybox bug so the debug versions are currently shipped on iOS
** (Waiting for https://github.com/google/filament/issues/7078 to be resolved before upgrading, not sure exactly when the bug was introduced but it was somewhere between v1.32.4 and v1.40.0)
*** Texture widget not currently supported on web in Flutter.
## Testing
We automate testing by running the example project on actual iOS/Android/MacOS/Windows devices and executing various operations.
Eventually we want to compare screenshots after each operation to a set of goldens for every platform.
Currently this is only possible on iOS (see https://github.com/flutter/flutter/issues/123063 and https://github.com/flutter/flutter/issues/127306).
To re-generate the golden screenshots for a given device:
```
./regenerate_goldens.sh <your_device_id>
```
To run the tests and compare against those goldens:
```
./compare_goldens.sh <your_device_id>
```
The results will depend on the actual device used to generate the golden, therefore if you are using a different device (which is likely), your results may not be the same. This is expected.
# Building Filament from source

View File

@@ -3,3 +3,19 @@ assets/BusterDrone filter=lfs diff=lfs merge=lfs -text
assets/FlightHelmet filter=lfs diff=lfs merge=lfs -text
assets/lit_opaque_32.uberz filter=lfs diff=lfs merge=lfs -text
windows/lib/**/*.* filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/12_Settonemappingtolinear.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/3_loadIBL.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/6_zoomin.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/13_Movecameratoasset.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/14_movecamerato.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/7_rotate.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/9_transformtounitcube.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/0_fresh.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/10_setshapespositionto.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/2_loadskybox.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/4_Renderingfalse.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/8_pan.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/11_Disablefrustumculling.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/15_setcameratofirstcamerainshapesGLB.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/1_createviewerdefaultubershader.png filter=lfs diff=lfs merge=lfs -text
integration_test/goldens/ios/5_loadshapesGLB.png filter=lfs diff=lfs merge=lfs -text

View File

@@ -0,0 +1,9 @@
#!/bin/bash
device=$1
if [ -z "$device" ]; then
echo "Usage: $0 <device_id>"
exit 1;
fi
rm integration_test/goldens/{ios,macos,windows,android}/diffs/*.png
flutter drive --driver=test_driver/integration_test.dart -d $1 --target=integration_test/plugin_integration_test.dart

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:556955b3ea80e461ab1d19de856276b286e964ea6ffbf5b4f788b03b4d1f1d41
size 258315

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7eaf3e2e5faab0fff2947e6747f44a29a27441fed30dfa5af586f5d18e4c313f
size 1876179

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1abf2fbc19655ce0d99f15a5659268a16c1ef6d2cf2554e07b70fc06505c22e1
size 1867991

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:91f82e50232a672de1604da9555c4a62996c577a9ec9d7a037dfcc989b27a2c2
size 1743987

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3c4408b417f5e6fd119c0d7edc6cfd66d44fb1d6d1f03943b7485ab131d3fcbb
size 2283182

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4347cade24c7c55b0ca449b3a346fa4bae0fc8c43ca0018d622b8393ad4d7f5c
size 1957365

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:eb73e1d9d7c5dfa5cef180d1f1d930da417f9b164e237399c8a7394dd60415e8
size 1892497

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4f7d232df983168399a0aae4b5424d6493ce460794101015f05c07a929268698
size 310421

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:891223fabbace04e3394dd15852180e443460111cf96a92b7f3a45d5600318cf
size 306407

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:df8157a13a07023837f36645a517a77e837fa5983ddd3a92b883cf96b8098f65
size 304380

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4e85d3916e42afe77a9854c3297d5d85ce1fa8f973883f5d48bf5efd99bf60e9
size 309699

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ad4b4bd59ff6ffa870d3fffb0f9151ccc51392906a6fbdc8832e31b4965c64d6
size 300230

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a297bad3e356e06fb68c53b8718a72924dfd88ca2c5ed1f486fffe5780c77084
size 1944342

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:19bc90955c575a28d9b8e4112c24fe9b65f3ba6df7a3579f036761fe6a54d065
size 1937031

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:72b73825e31bf5d6ae3c880a17fe578f9351749d68a9b1fc710b838985b833fa
size 1938760

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a3a78e7ec65d33d62105938de4a14f50a91ed4009beed588f17379ad3d7df9b6
size 1941399

View File

@@ -1,25 +1,152 @@
// This is a basic Flutter integration test.
//
// Since integration tests run in a full Flutter application, they can interact
// with the host side of a plugin implementation, unlike Dart unit tests.
//
// For more information about Flutter integration tests, please see
// https://docs.flutter.dev/cookbook/testing/integration/introduction
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:polyvox_filament/polyvox_filament.dart';
import 'package:golden_toolkit/golden_toolkit.dart';
import 'package:polyvox_filament/widgets/filament_widget.dart';
import '../lib/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized()
as IntegrationTestWidgetsFlutterBinding;
testWidgets('getPlatformVersion test', (WidgetTester tester) async {
final PolyvoxFilament plugin = PolyvoxFilament();
final String? version = await plugin.getPlatformVersion();
// The version string depends on the host platform running the test, so
// just assert that some non-empty string is returned.
expect(version?.isNotEmpty, true);
late String platformIdentifier;
if (Platform.isIOS) {
platformIdentifier = "ios";
} else if (Platform.isAndroid) {
platformIdentifier = "android";
} else if (Platform.isMacOS) {
platformIdentifier = "macos";
} else if (Platform.isWindows) {
platformIdentifier = "windows";
} else if (Platform.isLinux) {
platformIdentifier = "linux";
} else {
throw Exception("Unexpected platform");
}
int _counter = 0;
Future _snapshot(WidgetTester tester, Device device, String label,
[int seconds = 0]) async {
for (int i = 0; i < seconds; i++) {
await Future.delayed(Duration(seconds: 1));
await tester.pumpAndSettle();
}
await Future.delayed(Duration(milliseconds: 100));
await tester.pumpAndSettle();
var screenshotPath = '$platformIdentifier/${_counter}_$label';
if (Platform.isIOS) {
// this is currently hanging on Android
// see https://github.com/flutter/flutter/issues/127306
// it is also not yet implemented on Windows or MacOS
await binding.convertFlutterSurfaceToImage();
final bytes = await binding.takeScreenshot(screenshotPath);
}
_counter++;
}
late Device device;
Future tap(WidgetTester tester, String label, [int seconds = 0]) async {
var target = find.text(label).first;
await tester.dragUntilVisible(
target,
find.byType(SingleChildScrollView),
// widget you want to scroll
const Offset(0, 500), // delta to move
duration: Duration(milliseconds: 10));
await tester.tap(target);
await _snapshot(
tester, device, label.replaceAll(RegExp("[ -:]"), ""), seconds);
}
Future<void> pumpUntilFound(
WidgetTester tester,
Finder finder, {
Duration timeout = const Duration(seconds: 30),
}) async {
bool timerDone = false;
final timer = Timer(
timeout, () => throw TimeoutException("Pump until has timed out"));
while (timerDone != true) {
await tester.pump();
final found = tester.any(finder);
if (found) {
timerDone = true;
}
}
timer.cancel();
}
testGoldens('test', (WidgetTester tester) async {
app.main();
await pumpUntilFound(tester, find.byType(app.ExampleWidget));
device = Device(size: Size(800, 600), name: "desktop");
await _snapshot(tester, device, "fresh");
await tap(tester, "create viewer (default ubershader)", 4);
await tap(tester, "load skybox");
await tap(tester, "load IBL");
await tap(tester, "Rendering: false");
await tap(tester, "load shapes GLB");
final Offset pointerLocation =
tester.getCenter(find.byType(FilamentWidget));
TestPointer testPointer = TestPointer(1, PointerDeviceKind.mouse);
// scroll/zoom
testPointer.hover(pointerLocation);
await tester.sendEventToBinding(testPointer.scroll(const Offset(0.0, 1.0)));
await tester.pumpAndSettle();
await tester.sendEventToBinding(testPointer.scroll(const Offset(0.0, 1.0)));
await tester.pumpAndSettle();
await _snapshot(tester, device, "zoomin");
// rotate
testPointer =
TestPointer(1, PointerDeviceKind.mouse, null, kTertiaryButton);
testPointer.hover(pointerLocation);
await tester.sendEventToBinding(testPointer.down(pointerLocation));
await tester.pumpAndSettle();
await tester.sendEventToBinding(
testPointer.move(pointerLocation + Offset(10.0, 10.0)));
await tester.pumpAndSettle();
await tester.sendEventToBinding(
testPointer.move(pointerLocation + Offset(20.0, 20.0)));
await tester.pumpAndSettle();
await tester.sendEventToBinding(testPointer.up());
await _snapshot(tester, device, "rotate", 2);
// pan
testPointer = TestPointer(1, PointerDeviceKind.mouse, null, kPrimaryButton);
testPointer.hover(pointerLocation);
await tester.sendEventToBinding(testPointer.down(pointerLocation));
await tester
.sendEventToBinding(testPointer.move(pointerLocation + Offset(0, 1.0)));
for (int i = 0; i < 60; i++) {
await tester.sendEventToBinding(testPointer
.move(pointerLocation + Offset(i.toDouble() * 2, i.toDouble() * 2)));
await tester.pumpAndSettle();
}
await tester.sendEventToBinding(testPointer.up());
await tester.pumpAndSettle();
await _snapshot(tester, device, "pan");
await tap(tester, "transform to unit cube");
await tap(tester, "set shapes position to 1, 1, -1");
await tap(tester, "Disable frustum culling");
await tap(tester, "Set tone mapping to linear");
await tap(tester, "Move camera to asset");
await tap(tester, "move camera to 1, 1, -1");
await tap(tester, 'set camera to first camera in shapes GLB');
});
}

View File

@@ -1,21 +1,34 @@
PODS:
- Flutter (1.0.0)
- integration_test (0.0.1):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- polyvox_filament (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- polyvox_filament (from `.symlinks/plugins/polyvox_filament/ios`)
EXTERNAL SOURCES:
Flutter:
:path: Flutter
integration_test:
:path: ".symlinks/plugins/integration_test/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
polyvox_filament:
:path: ".symlinks/plugins/polyvox_filament/ios"
SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
polyvox_filament: 99047b2e0d56e073f5db603dd6152a1598c2a345
integration_test: 13825b8a9334a850581300559b8839134b124670
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
polyvox_filament: 35fece7761e74c973afd80fe3aa0ca225eaace32
PODFILE CHECKSUM: 7adbc9d59f05e1b01f554ea99b6c79e97f2214a2

View File

@@ -138,6 +138,7 @@
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
F9FAB8A67CF505858CCDA424 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -249,6 +250,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
F9FAB8A67CF505858CCDA424 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */

View File

@@ -48,7 +48,7 @@ class _ExampleWidgetState extends State<ExampleWidget> {
List<String>? _animations;
FilamentEntity? _light;
late StreamSubscription _pickResultListener;
StreamSubscription? _pickResultListener;
String? picked;
final weights = List.filled(255, 0.0);
@@ -63,19 +63,10 @@ class _ExampleWidgetState extends State<ExampleWidget> {
bool _coneHidden = false;
bool _frustumCulling = true;
@override
void initState() {
getApplicationSupportDirectory().then((dir) {
print(dir);
});
super.initState();
}
@override
void dispose() {
super.dispose();
_pickResultListener.cancel();
_pickResultListener?.cancel();
}
Widget _item(void Function() onTap, String text) {
@@ -136,7 +127,7 @@ class _ExampleWidgetState extends State<ExampleWidget> {
_rendering = !_rendering;
_filamentController!.setRendering(_rendering);
});
}, "Rendering: $_rendering "),
}, "Rendering: $_rendering"),
_item(() {
setState(() {
_framerate = _framerate == 60 ? 30 : 60;
@@ -207,8 +198,8 @@ class _ExampleWidgetState extends State<ExampleWidget> {
_filamentController!.setPosition(_shapes!, 1.0, 1.0, -1.0);
}, 'set shapes position to 1, 1, -1'),
_item(() async {
_filamentController!.setPosition(_shapes!, 1.0, 1.0, -1.0);
}, 'move camera to shapes position'),
_filamentController!.setCameraPosition(1.0, 1.0, -1.0);
}, 'move camera to 1, 1, -1'),
_item(() async {
var frameData = Float32List.fromList(
List<double>.generate(120, (i) => i / 120).expand((x) {
@@ -350,7 +341,7 @@ class _ExampleWidgetState extends State<ExampleWidget> {
right: 0,
height: 200,
child: Container(
color: Colors.white,
color: Colors.white.withOpacity(0.75),
child: SingleChildScrollView(
child: Wrap(children: children
// _item(24 () async { 'rotate by pi around Y axis'),

View File

@@ -1,21 +1,28 @@
PODS:
- FlutterMacOS (1.0.0)
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- polyvox_filament (0.0.1):
- FlutterMacOS
DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- polyvox_filament (from `Flutter/ephemeral/.symlinks/plugins/polyvox_filament/macos`)
EXTERNAL SOURCES:
FlutterMacOS:
:path: Flutter/ephemeral
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
polyvox_filament:
:path: Flutter/ephemeral/.symlinks/plugins/polyvox_filament/macos
SPEC CHECKSUMS:
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
polyvox_filament: 59a161de3df49c867bc2003d4ff73b8a304d2feb
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
polyvox_filament: 9aa36ae5e5654ff1576534086cbd618b239b75d6
PODFILE CHECKSUM: 9cc8fc8fc62b1d9a89fd6f974ad4157b35254030

View File

@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<false/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>

View File

@@ -28,5 +28,7 @@
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>com.apple.security.app-sandbox</key>
<false/>
</dict>
</plist>

View File

@@ -26,7 +26,12 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
integration_test:
sdk: flutter
flutter_lints: ^1.0.0
golden_toolkit: ^0.15.0
crypto:
image_compare: ^1.1.2
# For information on the generic Dart part of this file, see the

View File

@@ -0,0 +1,8 @@
#!/bin/bash
device=$1
if [ -z "$device" ]; then
echo "Usage: $0 <device_id>"
exit 1;
fi
flutter drive --driver=test_driver/integration_test_update_goldens.dart -d $1 --target=integration_test/plugin_integration_test.dart

View File

@@ -0,0 +1,58 @@
import 'dart:io';
import 'package:integration_test/integration_test_driver_extended.dart';
import 'package:image_compare/image_compare.dart';
Future<void> main() async {
await integrationDriver(
onScreenshot: (
String screenshotName,
List<int> screenshotBytes, [
Map<String, Object?>? args,
]) async {
final dir = screenshotName.split("/")[0];
final name = screenshotName.split("/")[1];
final File golden = await File('integration_test/goldens/$dir/$name.png');
if (!golden.existsSync()) {
throw Exception(
"Golden image doesn't exist yet. Make sure you have run integraton_test_update_goldens.dart first");
}
var result = await compareImages(
src1: screenshotBytes,
src2: golden.readAsBytesSync(),
algorithm: ChiSquareDistanceHistogram());
print(result);
// TODO - it would be preferable to use Flutter's GoldenFileComparator here, e.g.
//
// ```var comparator = LocalFileComparator(testImage.uri);
// comparator.compare(imageBytes, golden)
// comparator.getFailureFile(failure, golden, basedir)
// var result = await comparator.compare(
// Uint8List.fromList(screenshotBytes), golden.uri);
// if (!result.passed) {
// for (var key in result.diffs!.keys) {
// var byteData = await result.diffs![key]!.toByteData();
// File('integration_test/goldens/$dir/diffs/$name.png')
// .writeAsBytesSync(
// byteData!.buffer.asUint8List(byteData!.offsetInBytes));
// }
// return false;
// }```
// but this is only available via a Flutter shell which is currently unavailable (this script is run as a plain Dart file I guess).
// let's revisit if/when this changes
// see https://github.com/flutter/flutter/issues/51890 and https://github.com/flutter/flutter/issues/103222
if (result > 0.005) {
File('integration_test/goldens/$dir/diffs/$name.png')
.writeAsBytesSync(screenshotBytes);
return false;
}
return true;
},
);
}

View File

@@ -0,0 +1,22 @@
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:integration_test/integration_test_driver_extended.dart';
Future<void> main() async {
await integrationDriver(
onScreenshot: (
String screenshotName,
List<int> screenshotBytes, [
Map<String, Object?>? args,
]) async {
final dir = screenshotName.split("/")[0];
final name = screenshotName.split("/")[1];
final File image = await File('integration_test/goldens/$dir/$name.png')
.create(recursive: true);
image.writeAsBytesSync(screenshotBytes);
return true;
},
);
}

View File

@@ -198,9 +198,16 @@ class FilamentControllerFFI extends FilamentController {
///
@override
Future resize(int width, int height, {double scaleFactor = 1.0}) async {
if (_textureId == null) {
print("No texture created, ignoring call to resize.");
return;
}
_resizing = true;
setRendering(false);
_lib.destroy_swap_chain(_viewer!);
if (_viewer != null) {
_lib.destroy_swap_chain(_viewer!);
}
await destroyTexture();
size = ui.Size(width * _pixelRatio, height * _pixelRatio);

View File

@@ -183,6 +183,7 @@ class _FilamentWidgetState extends State<FilamentWidget> {
_resizeTimer?.cancel();
_resizeTimer = Timer(Duration(milliseconds: 500), () async {
print("Resizing to $newSize");
await widget.controller
.resize(newSize.width.toInt(), newSize.height.toInt());
WidgetsBinding.instance.addPostFrameCallback((_) async {