Skip to content

Commit

Permalink
First draft for merging structural metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
javagl committed May 1, 2024
1 parent 55e0596 commit 8a9c468
Show file tree
Hide file tree
Showing 5 changed files with 835 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,7 @@ export class EXTStructuralMetadata extends Extension {
structuralMetadataDef.schema = schemaDef;
}
const schemaUri = structuralMetadata.getSchemaUri();
if (schemaUri !== undefined) {
if (schemaUri !== null) {
structuralMetadataDef.schemaUri = schemaUri;
}

Expand Down
10 changes: 6 additions & 4 deletions src/gltf-extensions/gltfExtensions/StructuralMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const NAME = "EXT_structural_metadata";

interface IStructuralMetadata extends IProperty {
schema: Schema;
schemaUri: string;
schemaUri: string | null;
propertyTables: PropertyTable[];
propertyTextures: PropertyTexture[];
propertyAttributes: PropertyAttribute[];
Expand Down Expand Up @@ -179,6 +179,8 @@ export class StructuralMetadata extends ExtensionProperty<IStructuralMetadata> {

protected override getDefaults() {
return Object.assign(super.getDefaults(), {
schema: null,
schemaUri: null,
propertyTables: [],
propertyTextures: [],
propertyAttributes: [],
Expand All @@ -192,11 +194,11 @@ export class StructuralMetadata extends ExtensionProperty<IStructuralMetadata> {
return this.setRef("schema", schema);
}

getSchemaUri(): string {
getSchemaUri(): string | null {
return this.get("schemaUri");
}
setSchemaUri(name: string) {
return this.set("schemaUri", name);
setSchemaUri(schemaUri: string | null) {
return this.set("schemaUri", schemaUri);
}

listPropertyTables(): PropertyTable[] {
Expand Down
108 changes: 108 additions & 0 deletions src/tools/gltfExtensionsUtils/StructuralMetadataMergeUtilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// NOTE: The functions in this class are "ported" from
// https://github.com/donmccurdy/glTF-Transform/pull/1375/files
//
// The only exported function is "copyToDocument", which will be replaced
// by the `copyToDocument` functionality of glTF-Transform 4.0

import { Document } from "@gltf-transform/core";
import { Graph } from "@gltf-transform/core";
import { Property } from "@gltf-transform/core";
import { PropertyType } from "@gltf-transform/core";
import { PropertyResolver } from "@gltf-transform/core/dist/properties";

const { TEXTURE_INFO, ROOT } = PropertyType;
type PropertyConstructor = new (g: Graph<Property>) => Property;
const NO_TRANSFER_TYPES = new Set<string>([TEXTURE_INFO, ROOT]);

export function copyToDocument(
target: Document,
source: Document,
sourceProperties: Property[],
resolve?: PropertyResolver<Property>
): Map<Property, Property> {
const sourcePropertyDependencies = new Set<Property>();
for (const property of sourceProperties) {
if (NO_TRANSFER_TYPES.has(property.propertyType)) {
throw new Error(`Type "${property.propertyType}" cannot be transferred.`);
}
listPropertyDependencies(property, sourcePropertyDependencies);
}
return _copyToDocument(
target,
source,
Array.from(sourcePropertyDependencies),
resolve
);
}

function _copyToDocument(
target: Document,
source: Document,
sourceProperties: Property[],
resolve?: PropertyResolver<Property>
): Map<Property, Property> {
resolve ||= createDefaultPropertyResolver(target, source);

// Create stub classes for every Property in other Document.
const propertyMap = new Map<Property, Property>();
for (const sourceProp of sourceProperties) {
// TextureInfo copy handled by Material or ExtensionProperty.
if (
!propertyMap.has(sourceProp) &&
sourceProp.propertyType !== TEXTURE_INFO
) {
propertyMap.set(sourceProp, resolve(sourceProp));
}
}

// Assemble relationships between Properties.
for (const [sourceProp, targetProp] of propertyMap.entries()) {
targetProp.copy(sourceProp, resolve);
}

return propertyMap;
}

function createDefaultPropertyResolver(
target: Document,
source: Document
): PropertyResolver<Property> {
const propertyMap = new Map<Property, Property>([
[source.getRoot(), target.getRoot()],
]);

return (sourceProp: Property): Property => {
// TextureInfo lifecycle is bound to a Material or ExtensionProperty.
if (sourceProp.propertyType === TEXTURE_INFO) return sourceProp;

let targetProp = propertyMap.get(sourceProp);
if (!targetProp) {
// Create stub class, defer copying properties.
const PropertyClass = sourceProp.constructor as PropertyConstructor;
targetProp = new PropertyClass(target.getGraph());
propertyMap.set(sourceProp, targetProp);
}

return targetProp;
};
}

function listPropertyDependencies(
parent: Property,
visited: Set<Property>
): Set<Property> {
const graph = parent.getGraph();
const queue: Property[] = [parent];

let next: Property | undefined = undefined;
while ((next = queue.pop())) {
visited.add(next);
for (const child of graph.listChildren(next)) {
if (!visited.has(child)) {
queue.push(child);
}
}
}

return visited;
}
Loading

0 comments on commit 8a9c468

Please sign in to comment.