Skip to content

Commit

Permalink
[Impeller Scene] Add SceneNodeValue for synchronously fetching loaded…
Browse files Browse the repository at this point in the history
… ipscenes (flutter#38913)
  • Loading branch information
bdero authored Jan 18, 2023
1 parent eb18ac0 commit 84a73d9
Showing 1 changed file with 57 additions and 10 deletions.
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

0 comments on commit 84a73d9

Please sign in to comment.