From 84a73d92ffc40db10c23670bd97bd74d7451fce5 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 18 Jan 2023 03:40:04 -0800 Subject: [PATCH] [Impeller Scene] Add SceneNodeValue for synchronously fetching loaded ipscenes (#38913) --- lib/ui/experiments/scene.dart | 67 +++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/lib/ui/experiments/scene.dart b/lib/ui/experiments/scene.dart index abe610caccff7..73e689b532d62 100644 --- a/lib/ui/experiments/scene.dart +++ b/lib/ui/experiments/scene.dart @@ -17,14 +17,14 @@ class SceneNode extends NativeFieldWrapperClass1 { /// The asset must be a file produced as the output of the `scenec` importer. /// The constructed object should then be reused via the [shader] /// method to create [Shader] objects that can be used by [Shader.paint]. - static Future fromAsset(String assetKey) { + static SceneNodeValue fromAsset(String assetKey) { // The flutter tool converts all asset keys with spaces into URI // encoded paths (replacing ' ' with '%20', for example). We perform // the same encoding here so that users can load assets with the same // key they have written in the pubspec. final String encodedKey = Uri(path: Uri.encodeFull(assetKey)).path; { - final Future? futureSceneNode = _ipsceneRegistry[encodedKey]?.target; + final SceneNodeValue? futureSceneNode = _ipsceneRegistry[encodedKey]?.target; if (futureSceneNode != null) { return futureSceneNode; } @@ -45,14 +45,15 @@ class SceneNode extends NativeFieldWrapperClass1 { return null; }).then((_) => sceneNode); - _ipsceneRegistry[encodedKey] = WeakReference>(futureSceneNode); - return futureSceneNode; + final SceneNodeValue result = SceneNodeValue.fromFuture(futureSceneNode); + _ipsceneRegistry[encodedKey] = WeakReference(result); + return result; } - static SceneNode fromTransform(Float64List matrix4) { + static SceneNodeValue fromTransform(Float64List matrix4) { final SceneNode sceneNode = SceneNode._create(); sceneNode._initFromTransform(matrix4); - return sceneNode; + return SceneNodeValue.fromValue(sceneNode); } void addChild(SceneNode sceneNode) { @@ -75,11 +76,11 @@ class SceneNode extends NativeFieldWrapperClass1 { // SceneNode.fromAsset. It holds weak references to the SceneNodes so that the // case where an in-use ipscene is requested again can be fast, but scenes // that are no longer referenced are not retained because of the cache. - static final Map>> _ipsceneRegistry = - >>{}; + static final Map> _ipsceneRegistry = + >{}; static Future _reinitializeScene(String assetKey) async { - final WeakReference>? sceneRef = _ipsceneRegistry == null + final WeakReference? sceneRef = _ipsceneRegistry == null ? null : _ipsceneRegistry[assetKey]; @@ -89,7 +90,7 @@ class SceneNode extends NativeFieldWrapperClass1 { return; } - final Future? sceneNodeFuture = sceneRef.target; + final Future? sceneNodeFuture = sceneRef.target?.future; if (sceneNodeFuture == null) { return; } @@ -129,6 +130,52 @@ class SceneNode extends NativeFieldWrapperClass1 { SceneShader sceneShader() => SceneShader._(this, debugName: _debugName); } +class SceneNodeValue { + SceneNodeValue._(this._future, this._value) { + _future?.then((SceneNode result) => _value = result); + } + + static SceneNodeValue fromFuture(Future future) { + return SceneNodeValue._(future, null); + } + + static SceneNodeValue fromValue(SceneNode value) { + return SceneNodeValue._(null, value); + } + + final Future? _future; + SceneNode? _value; + + bool get isComplete { + return _value != null; + } + + Future? get future { + return _future; + } + + SceneNode? get value { + return _value; + } + + /// Calls `callback` when the `SceneNode` has finished initializing. If the + /// initialization is already finished, `callback` is called synchronously. + SceneNodeValue whenComplete(void Function(SceneNode) callback) { + if (_value == null && _future == null) { + return this; + } + + if (_value != null) { + callback(_value!); + return this; + } + + // _future != null + _future!.then((SceneNode node) => callback(node)); + return this; + } +} + /// A [Shader] generated from a [SceneNode]. /// /// Instances of this class can be obtained from the