From 2258c074917dc1232035f0233ece5f43ae4644e1 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Sat, 8 Jun 2019 13:50:21 -0400 Subject: [PATCH] Dont duplicate resources --- lib/writeResources.js | 54 +++- .../CesiumTexturedBoxTest0FS.glsl | 18 ++ .../CesiumTexturedBoxTest0VS.glsl | 15 + .../Image.png | Bin 0 -> 5383 bytes .../box-shared-image-references-separate.bin | Bin 0 -> 840 bytes .../box-shared-image-references-separate.gltf | 262 ++++++++++++++++ .../box-shared-image-references.gltf | 279 ++++++++++++++++++ specs/lib/writeResourcesSpec.js | 49 +++ 8 files changed, 665 insertions(+), 12 deletions(-) create mode 100644 specs/data/2.0/box-shared-image-references-separate/CesiumTexturedBoxTest0FS.glsl create mode 100644 specs/data/2.0/box-shared-image-references-separate/CesiumTexturedBoxTest0VS.glsl create mode 100644 specs/data/2.0/box-shared-image-references-separate/Image.png create mode 100644 specs/data/2.0/box-shared-image-references-separate/box-shared-image-references-separate.bin create mode 100644 specs/data/2.0/box-shared-image-references-separate/box-shared-image-references-separate.gltf create mode 100644 specs/data/2.0/box-shared-image-references/box-shared-image-references.gltf diff --git a/lib/writeResources.js b/lib/writeResources.js index f7ea215a..9750c401 100644 --- a/lib/writeResources.js +++ b/lib/writeResources.js @@ -43,15 +43,18 @@ function writeResources(gltf, options) { options.separateShaders = defaultValue(options.separateShaders, false); options.dataUris = defaultValue(options.dataUris, false); + // Remember which of the resources have been written, so we can re-use them. + const writtenResourceMap = {}; + ForEach.image(gltf, function(image, i) { - writeImage(gltf, image, i, options); + writeImage(gltf, image, i, writtenResourceMap, options); ForEach.compressedImage(image, function(compressedImage) { writeImage(gltf, compressedImage, i, options); }); }); ForEach.shader(gltf, function(shader, i) { - writeShader(gltf, shader, i, options); + writeShader(gltf, shader, i, writtenResourceMap, options); }); // Buffers need to be written last because images and shaders may write to new buffers @@ -68,7 +71,7 @@ function writeBuffer(gltf, buffer, i, options) { if (defined(options.bufferStorage) && !options.separateBuffers) { writeBufferStorage(buffer, options); } else { - writeResource(gltf, buffer, i, options.separateBuffers, true, '.bin', options); + writeResource(gltf, buffer, i, options.separateBuffers, true, '.bin', undefined, options); } } @@ -79,26 +82,26 @@ function writeBufferStorage(buffer, options) { options.bufferStorage.buffer = combinedBuffer; } -function writeImage(gltf, image, i, options) { +function writeImage(gltf, image, i, writtenResourceMap, options) { const extension = getImageExtension(image.extras._pipeline.source); - writeResource(gltf, image, i, options.separateTextures, options.dataUris, extension, options); + writeResource(gltf, image, i, options.separateTextures, options.dataUris, extension, writtenResourceMap, options); if (defined(image.bufferView)) { // Preserve the image mime type when writing to a buffer view image.mimeType = mime.getType(extension); } } -function writeShader(gltf, shader, i, options) { - writeResource(gltf, shader, i, options.separateShaders, options.dataUris, '.glsl', options); +function writeShader(gltf, shader, i, writtenResourceMap, options) { + writeResource(gltf, shader, i, options.separateShaders, options.dataUris, '.glsl', writtenResourceMap, options); } -function writeResource(gltf, object, index, separate, dataUris, extension, options) { +function writeResource(gltf, object, index, separate, dataUris, extension, writtenResourceMap, options) { if (separate) { - writeFile(gltf, object, index, extension, options); + writeFile(gltf, object, index, extension, writtenResourceMap, options); } else if (dataUris) { writeDataUri(object, extension); } else { - writeBufferView(gltf, object); + writeBufferView(gltf, object, writtenResourceMap); } } @@ -109,13 +112,26 @@ function writeDataUri(object, extension) { object.uri = 'data:' + mimeType + ';base64,' + source.toString('base64'); } -function writeBufferView(gltf, object) { +function writeBufferView(gltf, object, writtenResourceMap) { delete object.uri; + + // If we've written this resource before, re-use the bufferView + const originalPathOrBufferView = defaultValue(object.extras._pipeline.absolutePath, object.bufferView); + if (defined(originalPathOrBufferView) && defined(writtenResourceMap[originalPathOrBufferView])) { + object.bufferView = writtenResourceMap[originalPathOrBufferView]; + return; + } + let source = object.extras._pipeline.source; if (typeof source === 'string') { source = Buffer.from(source); } object.bufferView = addBuffer(gltf, source); + + // Save the bufferView so we can re-use it later + if (defined(originalPathOrBufferView)) { + writtenResourceMap[originalPathOrBufferView] = object.bufferView; + } } function getProgram(gltf, shaderIndex) { @@ -179,12 +195,26 @@ function getRelativePath(gltf, object, index, extension, options) { return relativePath; } -function writeFile(gltf, object, index, extension, options) { +function writeFile(gltf, object, index, extension, writtenResourceMap, options) { + const bufferView = object.bufferView; delete object.bufferView; + + // If we've written this resource before, re-use the uri + const originalPathOrBufferView = defaultValue(object.extras._pipeline.absolutePath, bufferView); + if (defined(originalPathOrBufferView) && defined(writtenResourceMap[originalPathOrBufferView])) { + object.uri = writtenResourceMap[originalPathOrBufferView]; + return; + } + const source = object.extras._pipeline.source; const relativePath = getRelativePath(gltf, object, index, extension, options); object.uri = relativePath; if (defined(options.separateResources)) { options.separateResources[relativePath] = source; } + + // Save the uri so we can re-use it later + if (defined(originalPathOrBufferView)) { + writtenResourceMap[originalPathOrBufferView] = object.uri; + } } diff --git a/specs/data/2.0/box-shared-image-references-separate/CesiumTexturedBoxTest0FS.glsl b/specs/data/2.0/box-shared-image-references-separate/CesiumTexturedBoxTest0FS.glsl new file mode 100644 index 00000000..782e1f41 --- /dev/null +++ b/specs/data/2.0/box-shared-image-references-separate/CesiumTexturedBoxTest0FS.glsl @@ -0,0 +1,18 @@ +precision highp float; +varying vec3 v_normal; +varying vec2 v_texcoord0; +uniform sampler2D u_diffuse; +uniform vec4 u_specular; +uniform float u_shininess; +void main(void) { +vec3 normal = normalize(v_normal); +vec4 color = vec4(0., 0., 0., 0.); +vec4 diffuse = vec4(0., 0., 0., 1.); +vec4 specular; +diffuse = texture2D(u_diffuse, v_texcoord0); +specular = u_specular; +diffuse.xyz *= max(dot(normal,vec3(0.,0.,1.)), 0.); +color.xyz += diffuse.xyz; +color = vec4(color.rgb * diffuse.a, diffuse.a); +gl_FragColor = color; +} diff --git a/specs/data/2.0/box-shared-image-references-separate/CesiumTexturedBoxTest0VS.glsl b/specs/data/2.0/box-shared-image-references-separate/CesiumTexturedBoxTest0VS.glsl new file mode 100644 index 00000000..cacc9ed9 --- /dev/null +++ b/specs/data/2.0/box-shared-image-references-separate/CesiumTexturedBoxTest0VS.glsl @@ -0,0 +1,15 @@ +precision highp float; +attribute vec3 a_position; +attribute vec3 a_normal; +varying vec3 v_normal; +uniform mat3 u_normalMatrix; +uniform mat4 u_modelViewMatrix; +uniform mat4 u_projectionMatrix; +attribute vec2 a_texcoord0; +varying vec2 v_texcoord0; +void main(void) { +vec4 pos = u_modelViewMatrix * vec4(a_position,1.0); +v_normal = u_normalMatrix * a_normal; +v_texcoord0 = a_texcoord0; +gl_Position = u_projectionMatrix * pos; +} diff --git a/specs/data/2.0/box-shared-image-references-separate/Image.png b/specs/data/2.0/box-shared-image-references-separate/Image.png new file mode 100644 index 0000000000000000000000000000000000000000..d3a626a4d7ca0cacd144ddc73b4daff021c88930 GIT binary patch literal 5383 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 literal 0 HcmV?d00001 diff --git a/specs/data/2.0/box-shared-image-references-separate/box-shared-image-references-separate.bin b/specs/data/2.0/box-shared-image-references-separate/box-shared-image-references-separate.bin new file mode 100644 index 0000000000000000000000000000000000000000..022fbecd1e5143f0499f48ba7b91a24063804372 GIT binary patch literal 840 zcmb7=3l4)Y3_~CL|JeU?9Jtvy%5E}Fwk;kFs;VJaCChQ_hEU)M6hGj7XJxu-dG33r zi{qR!an5UHgf6YVd(K7DOEa#WJ)dgzW6xwI9Zp}}=W9%yY3FK>aH=8oz?}xoioT~6 z{<%|^&C-v+b@_VVZMR3@D)FWD|H^;gA^7c^gub*;x*u5j>jie7#FuVoqSNfYW5SdfbHkJcOIEB6OE% { beforeEach(async () => { gltf = fsExtra.readJsonSync(gltfPath); gltfWebp = fsExtra.readJsonSync(gltfWebpPath); gltfWebpSeparate = fsExtra.readJsonSync(gltfWebpSeparatePath); + gltfSharedImageReferences = fsExtra.readJsonSync(gltfSharedImageReferencesPath); + gltfSharedImageReferencesSeparate = fsExtra.readJsonSync(gltfSharedImageReferencesSeparatePath); await readResources(gltf); await readResources(gltfWebp); await readResources(gltfWebpSeparate, { resourceDirectory: path.dirname(gltfWebpSeparatePath) }); + await readResources(gltfSharedImageReferences); + await readResources(gltfSharedImageReferencesSeparate, { + resourceDirectory: path.dirname(gltfSharedImageReferencesSeparatePath) + }); }); it('writes embedded resources', () => { @@ -181,4 +191,43 @@ describe('writeResources', () => { // There should be a new bufferView for the WebP, and one for the fallback image. expect(gltfWebpSeparate.bufferViews.length).toBe(originalBufferViewsLength + 2); }); + + it('does not duplicate multiple references to the same buffer view', async () => { + const originalBufferViewsLength = gltfSharedImageReferences.bufferViews.length; + writeResources(gltfSharedImageReferences); + expect(gltfSharedImageReferences.bufferViews.length).toBe(originalBufferViewsLength); + expect(gltfSharedImageReferences.images[0].bufferView).toBe(gltfSharedImageReferences.images[1].bufferView); + }); + + it('does not duplicate multiple references to the same buffer view when saving separate resources', async () => { + const separateResources = {}; + const options = { + separateBuffers: true, + separateTextures: true, + separateShaders: true, + separateResources: separateResources + }; + writeResources(gltfSharedImageReferences, options); + expect(gltfSharedImageReferences.images[0].uri).toBeDefined(); + expect(gltfSharedImageReferences.images[0].uri).toBe(gltfSharedImageReferences.images[1].uri); + }); + + it('does not duplicate multiple references to the same uri', async () => { + writeResources(gltfSharedImageReferencesSeparate); + expect(gltfSharedImageReferencesSeparate.images[0].bufferView).toBeDefined(); + expect(gltfSharedImageReferencesSeparate.images[0].bufferView).toBe(gltfSharedImageReferencesSeparate.images[1].bufferView); + }); + + it('does not duplicate multiple references to the same uri when saving separate resources', async () => { + const separateResources = {}; + const options = { + separateBuffers: true, + separateTextures: true, + separateShaders: true, + separateResources: separateResources + }; + writeResources(gltfSharedImageReferencesSeparate, options); + expect(gltfSharedImageReferencesSeparate.images[0].uri).toBeDefined(); + expect(gltfSharedImageReferencesSeparate.images[0].uri).toBe(gltfSharedImageReferencesSeparate.images[1].uri); + }); });