Skip to content

Commit

Permalink
[cli] Handle conflicting URIs during merge() (#677)
Browse files Browse the repository at this point in the history
  • Loading branch information
donmccurdy authored Sep 8, 2022
1 parent 8988825 commit 106cdbe
Showing 1 changed file with 51 additions and 8 deletions.
59 changes: 51 additions & 8 deletions packages/cli/src/transforms/merge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import fs from 'fs';
import { Document, FileUtils, ImageUtils, NodeIO, Transform } from '@gltf-transform/core';
import { unpartition } from '@gltf-transform/functions';
import {
Document,
FileUtils,
ImageUtils,
NodeIO,
Transform,
Texture,
Buffer,
PropertyType,
} from '@gltf-transform/core';
import { dedup, unpartition } from '@gltf-transform/functions';

const NAME = 'merge';

Expand All @@ -13,8 +22,8 @@ export interface MergeOptions {
const merge = (options: MergeOptions): Transform => {
const { paths, io } = options;

return async (doc: Document): Promise<void> => {
const logger = doc.getLogger();
return async (document: Document): Promise<void> => {
const logger = document.getLogger();

for (let i = 0; i < paths.length; i++) {
const path = paths[i];
Expand All @@ -24,21 +33,28 @@ const merge = (options: MergeOptions): Transform => {
const basename = FileUtils.basename(path);
const extension = FileUtils.extension(path).toLowerCase();
if (['png', 'jpg', 'jpeg', 'webp', 'ktx2'].includes(extension)) {
doc.createTexture(basename)
document
.createTexture(basename)
.setImage(fs.readFileSync(path))
.setMimeType(ImageUtils.extensionToMimeType(extension))
.setURI(basename + '.' + extension);
} else if (['gltf', 'glb'].includes(extension)) {
doc.merge(renameScenes(basename, await io.read(path)));
document.merge(renameScenes(basename, await io.read(path)));
} else {
throw new Error(`Unknown file extension: "${extension}".`);
}
}

doc.getRoot().setDefaultScene(doc.getRoot().listScenes()[0]);
document.getRoot().setDefaultScene(document.getRoot().listScenes()[0]);

// De-duplicate textures, then ensure that all remaining textures and buffers
// have unique URIs. See https://github.com/donmccurdy/glTF-Transform/issues/586.
await document.transform(dedup({ propertyTypes: [PropertyType.TEXTURE] }));
createUniqueURIs(document.getRoot().listBuffers());
createUniqueURIs(document.getRoot().listTextures());

if (!options.partition) {
await doc.transform(unpartition());
await document.transform(unpartition());
}

logger.debug(`${NAME}: Complete.`);
Expand All @@ -57,4 +73,31 @@ function renameScenes(name: string, document: Document): Document {
return document;
}

/** Replaces conflicting URIs to ensure all URIs are unique. */
function createUniqueURIs(resources: Buffer[] | Texture[]): void {
const total = {} as Record<string, number>;
const used = {} as Record<string, boolean>;

for (const resource of resources) {
const uri = resource.getURI();
if (!uri) continue;
if (!total[uri]) total[uri] = 0;
total[uri]++;
used[uri] = false;
}

for (const resource of resources) {
let uri = resource.getURI();
if (!uri || total[uri] === 1) continue;

const extension = FileUtils.extension(uri);
const prefix = uri.replace(new RegExp(`\\.${extension}`), '');
for (let i = 2; used[uri]; i++) {
uri = `${prefix}_${i++}.${extension}`;
}
resource.setURI(uri);
used[uri] = true;
}
}

export { merge };

0 comments on commit 106cdbe

Please sign in to comment.