serializeScene function
Serializes the live Node graph rooted at root into a new
SceneDocument.
root is treated as the synthesized realization root (as returned by
realizeScene) and its children become the document's root nodes. Nodes
realized from a document keep their identity-tag ids, so a load/edit/save
cycle is rename-proof and diff-friendly; untagged (hand-built) nodes mint
fresh ids. Skins, the root's parsed animations, and lazy prefab placeholders
serialize too; a loaded lazy subtree serializes as its placeholder (the
streamed content belongs to the referenced prefab, not this document).
Components are serialized through registry (the built-ins by default); a
component no codec claims is skipped with a debug warning.
Implementation
SceneDocument serializeScene(Node root, {FsceneComponentRegistry? registry}) {
final reg = registry ?? defaultComponentRegistry();
final document = SceneDocument();
final context = SerializeContext(document);
// First pass: assign every node its id, reusing realize-time identity tags
// where present (skipping duplicates from app-side clones). Newly assigned
// ids are tagged back onto the nodes so follow-up passes (`serializeViews`
// referencing camera nodes) and future saves see stable ids.
final ids = <Node, LocalId>{};
final used = <LocalId>{};
void assign(Node node) {
final tagged = nodeFsceneId(node);
final id = tagged != null && used.add(tagged) ? tagged : document.newId();
ids[node] = id;
if (id != tagged) {
used.add(id);
tagNodeId(node, id);
}
for (final child in node.children) {
assign(child);
}
}
for (final child in root.children) {
assign(child);
}
for (final child in root.children) {
final spec = _serializeNode(child, document, reg, context, ids);
document.addNode(spec, root: true);
}
_serializeAnimations(root, document, ids);
return document;
}