Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller Scene] Add ability to synchronously fetch loaded ipscene nodes #38913

Merged
merged 1 commit into from
Jan 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 57 additions & 10 deletions lib/ui/experiments/scene.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<SceneNode> 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<SceneNode>? futureSceneNode = _ipsceneRegistry[encodedKey]?.target;
final SceneNodeValue? futureSceneNode = _ipsceneRegistry[encodedKey]?.target;
if (futureSceneNode != null) {
return futureSceneNode;
}
Expand All @@ -45,14 +45,15 @@ class SceneNode extends NativeFieldWrapperClass1 {
return null;
}).then((_) => sceneNode);

_ipsceneRegistry[encodedKey] = WeakReference<Future<SceneNode>>(futureSceneNode);
return futureSceneNode;
final SceneNodeValue result = SceneNodeValue.fromFuture(futureSceneNode);
_ipsceneRegistry[encodedKey] = WeakReference<SceneNodeValue>(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) {
Expand All @@ -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<String, WeakReference<Future<SceneNode>>> _ipsceneRegistry =
<String, WeakReference<Future<SceneNode>>>{};
static final Map<String, WeakReference<SceneNodeValue>> _ipsceneRegistry =
<String, WeakReference<SceneNodeValue>>{};

static Future<void> _reinitializeScene(String assetKey) async {
final WeakReference<Future<SceneNode>>? sceneRef = _ipsceneRegistry == null
final WeakReference<SceneNodeValue>? sceneRef = _ipsceneRegistry == null
? null
: _ipsceneRegistry[assetKey];

Expand All @@ -89,7 +90,7 @@ class SceneNode extends NativeFieldWrapperClass1 {
return;
}

final Future<SceneNode>? sceneNodeFuture = sceneRef.target;
final Future<SceneNode>? sceneNodeFuture = sceneRef.target?.future;
if (sceneNodeFuture == null) {
return;
}
Expand Down Expand Up @@ -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<SceneNode> future) {
return SceneNodeValue._(future, null);
}

static SceneNodeValue fromValue(SceneNode value) {
return SceneNodeValue._(null, value);
}

final Future<SceneNode>? _future;
SceneNode? _value;

bool get isComplete {
return _value != null;
}

Future<SceneNode>? 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
Expand Down