diff --git a/source/server/utils/merge/index.ts b/source/server/utils/merge/index.ts index 9c8efadc..4176db1e 100644 --- a/source/server/utils/merge/index.ts +++ b/source/server/utils/merge/index.ts @@ -14,13 +14,18 @@ export { /** * like `diff()` but dereferences a document's pointers first to make a cleaner diff - * @returns + * @see diff */ export function diffDoc(from:IDocument,to:IDocument){ return diff( toPointers(from), toPointers(to)); } - +/** + * like `apply()` but dereferences a document's pointers first to make a cleaner diff, then re-references the result + * @see apply + * @see fromPointers + * @see toPointers + */ export function applyDoc(from:IDocument, diff:Diff){ return fromPointers(apply(toPointers(from), diff)); } diff --git a/source/server/utils/merge/pointers.ts b/source/server/utils/merge/pointers.ts index e7a055bc..d2ababe5 100644 --- a/source/server/utils/merge/pointers.ts +++ b/source/server/utils/merge/pointers.ts @@ -5,10 +5,14 @@ import { ISetup } from "../schema/setup.js"; import { DerefDocument, DerefNode, DerefScene } from "./types.js"; +type DocumentCollections = keyof Omit; /** * Dereference all indexed values into pointers in a SVX document * It effectively forgets about all unreachable nodes (scenes, setups, etc...). + * + * It's something of an emulation of what DPO-voyager does when building a scene graph from a document. + * See CVScene.ts and CVNode.ts in voyager. */ export function toPointers(src :IDocument) :DerefDocument { const nodes = src.nodes?.map(iNode=>{ @@ -72,8 +76,10 @@ export function toPointers(src :IDocument) :DerefDocument { export function fromPointers({asset, scene} :DerefDocument): IDocument{ - - let collections = { + //The output document + let document :Required = { + asset, + scene: -1, "scenes": [] as IScene[], "nodes": [] as INode[], "cameras": [] as ICamera[], @@ -81,8 +87,7 @@ export function fromPointers({asset, scene} :DerefDocument): IDocument{ "models": [] as IModel[], "metas": [] as IMeta[], "setups": [] as ISetup[], - - } as const; + }; function appendScene(scene :DerefScene){ @@ -96,12 +101,12 @@ export function fromPointers({asset, scene} :DerefDocument): IDocument{ for(let key of ["setup", "meta"] as const){ const value = scene[key]; if(!value) continue; - let colKey = key+"s" as keyof typeof collections; - const idx = collections[colKey].length; - collections[colKey].push(value as any); + let colKey = key+"s" as DocumentCollections; + const idx = document[colKey]!.length; + document[colKey]!.push(value as any); iScene[key] = idx as any; } - return collections.scenes.push(iScene) - 1; + return document.scenes.push(iScene) - 1; } function appendNode(node :DerefNode){ @@ -110,7 +115,7 @@ export function fromPointers({asset, scene} :DerefDocument): IDocument{ if(node.name) iNode.name = node.name; //Push to collection before appending children because that's a more "natural" order to have - const idx = collections.nodes.push(iNode) - 1; + const idx = document.nodes.push(iNode) - 1; if(node.children?.length){ iNode.children = node.children.map((child)=>appendNode(child)); @@ -125,28 +130,23 @@ export function fromPointers({asset, scene} :DerefDocument): IDocument{ for(let key of ["camera", "light", "model", "meta"] as const){ const value = node[key]; if(!value) continue; - let colKey = key+"s" as keyof typeof collections; - const idx = collections[colKey].length; - collections[colKey].push(value as any); + let colKey = key+"s" as DocumentCollections; + const idx = document[colKey].length; + document[colKey].push(value as any); iNode[key] = idx as any; } return idx; } - let sceneIndex = appendScene(scene); + document.scene = appendScene(scene); - let out :IDocument = { - asset, - scene: sceneIndex, - ...collections, - }; - - for(let key in out){ - let v = out[key as keyof typeof out]; - if(typeof v === "undefined" || (Array.isArray(v) && v.length == 0)) delete out[key as keyof typeof out]; + //Remove empty collections + for(let key in document){ + let v = document[key as keyof typeof document]; + if(typeof v === "undefined" || (Array.isArray(v) && v.length == 0)) delete document[key as keyof typeof document]; } - return out; + return document; } \ No newline at end of file