blob: 3f2b2422daf45e01cbd892ff549c64ae0b600a84 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of dart.ui;
/// A composable [SceneNode].
class SceneNode extends NativeFieldWrapperClass1 {
@pragma('vm:entry-point')
SceneNode._create() {
_constructor();
}
String? _debugName;
/// Creates a scene node from the asset with key [assetKey].
///
/// 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 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 SceneNodeValue? futureSceneNode = _ipsceneRegistry[encodedKey]?.target;
if (futureSceneNode != null) {
return futureSceneNode;
}
}
final SceneNode sceneNode = SceneNode._create();
final Future<SceneNode> futureSceneNode = _futurize((_Callback<void> callback) {
final String error = sceneNode._initFromAsset(assetKey, callback);
if (error.isNotEmpty) {
return error;
}
assert(() {
sceneNode._debugName = assetKey;
return true;
}());
return null;
}).then((_) => sceneNode);
final SceneNodeValue result = SceneNodeValue.fromFuture(futureSceneNode);
_ipsceneRegistry[encodedKey] = WeakReference<SceneNodeValue>(result);
return result;
}
static SceneNodeValue fromTransform(Float64List matrix4) {
final SceneNode sceneNode = SceneNode._create();
sceneNode._initFromTransform(matrix4);
return SceneNodeValue.fromValue(sceneNode);
}
void addChild(SceneNode sceneNode) {
_addChild(sceneNode);
}
void setTransform(Float64List matrix4) {
_setTransform(matrix4);
}
void setAnimationState(String animationName, bool playing, bool loop, double weight, double timeScale) {
_setAnimationState(animationName, playing, loop, weight, timeScale);
}
void seekAnimation(String animationName, double time) {
_seekAnimation(animationName, time);
}
// This is a cache of ipscene-backed scene nodes that have been loaded via
// 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<SceneNodeValue>> _ipsceneRegistry =
<String, WeakReference<SceneNodeValue>>{};
static Future<void> _reinitializeScene(String assetKey) async {
final WeakReference<SceneNodeValue>? sceneRef = _ipsceneRegistry == null
? null
: _ipsceneRegistry[assetKey];
// If a scene for the asset isn't already registered, then there's no
// need to reinitialize it.
if (sceneRef == null) {
return;
}
final Future<SceneNode>? sceneNodeFuture = sceneRef.target?.future;
if (sceneNodeFuture == null) {
return;
}
final SceneNode sceneNode = await sceneNodeFuture;
await _futurize((_Callback<void> callback) {
final String error = sceneNode._initFromAsset(assetKey, callback);
if (error.isNotEmpty) {
return error;
}
return null;
});
}
@Native<Void Function(Handle)>(symbol: 'SceneNode::Create')
external void _constructor();
@Native<Handle Function(Pointer<Void>, Handle, Handle)>(symbol: 'SceneNode::initFromAsset')
external String _initFromAsset(String assetKey, _Callback<void> completionCallback);
@Native<Void Function(Pointer<Void>, Handle)>(symbol: 'SceneNode::initFromTransform')
external void _initFromTransform(Float64List matrix4);
@Native<Void Function(Pointer<Void>, Handle)>(symbol: 'SceneNode::AddChild')
external void _addChild(SceneNode sceneNode);
@Native<Void Function(Pointer<Void>, Handle)>(symbol: 'SceneNode::SetTransform')
external void _setTransform(Float64List matrix4);
@Native<Void Function(Pointer<Void>, Handle, Bool, Bool, Double, Double)>(symbol: 'SceneNode::SetAnimationState')
external void _setAnimationState(String animationName, bool playing, bool loop, double weight, double timeScale);
@Native<Void Function(Pointer<Void>, Handle, Double)>(symbol: 'SceneNode::SeekAnimation')
external void _seekAnimation(String animationName, double time);
/// Returns a fresh instance of [SceneShader].
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
/// [SceneNode.sceneShader] method.
class SceneShader extends Shader {
SceneShader._(SceneNode node, { String? debugName }) : _debugName = debugName, super._() {
_constructor(node);
}
// ignore: unused_field
final String? _debugName;
void setCameraTransform(Float64List matrix4) {
_setCameraTransform(matrix4);
}
/// Releases the native resources held by the [SceneShader].
///
/// After this method is called, calling methods on the shader, or attaching
/// it to a [Paint] object will fail with an exception. Calling [dispose]
/// twice will also result in an exception being thrown.
@override
void dispose() {
super.dispose();
_dispose();
}
@Native<Void Function(Handle, Handle)>(symbol: 'SceneShader::Create')
external void _constructor(SceneNode node);
@Native<Void Function(Pointer<Void>, Handle)>(symbol: 'SceneShader::SetCameraTransform')
external void _setCameraTransform(Float64List matrix4);
@Native<Void Function(Pointer<Void>)>(symbol: 'SceneShader::Dispose')
external void _dispose();
}