diff --git a/lib/loadMtl.js b/lib/loadMtl.js index 96a39b3..c2cfb62 100644 --- a/lib/loadMtl.js +++ b/lib/loadMtl.js @@ -224,13 +224,26 @@ function loadMaterialTexture(material, name, textureOptions, mtlDirectory, textu var texturePromise = texturePromiseMap[texturePath]; if (!defined(texturePromise)) { + var shallowPath = path.resolve(path.join(mtlDirectory, path.basename(texturePath))); if (options.secure && outsideDirectory(texturePath, mtlDirectory)) { - options.logger('Could not read texture file at ' + texturePath + ' because it is outside of the mtl directory and the secure flag is true. This texture will be ignored.'); - texturePromise = Promise.resolve(); + // Try looking for the texture in the same directory as the obj + options.logger('Texture file is outside of the mtl directory and the secure flag is true. Attempting to read the texture file from within the obj directory instead.'); + texturePromise = loadTexture(shallowPath, textureOptions) + .catch(function(error) { + options.logger(error.message); + options.logger('Could not read texture file at ' + shallowPath + '. This texture will be ignored'); + }); } else { texturePromise = loadTexture(texturePath, textureOptions) - .catch(function() { - options.logger('Could not read texture file at ' + texturePath + '. This texture will be ignored.'); + .catch(function(error) { + // Try looking for the texture in the same directory as the obj + options.logger(error.message); + options.logger('Could not read texture file at ' + texturePath + '. Attempting to read the texture file from within the obj directory instead.'); + return loadTexture(shallowPath, textureOptions); + }) + .catch(function(error) { + options.logger(error.message); + options.logger('Could not read texture file at ' + shallowPath + '. This texture will be ignored.'); }); } texturePromiseMap[texturePath] = texturePromise; diff --git a/lib/loadObj.js b/lib/loadObj.js index 643efaf..70f8380 100644 --- a/lib/loadObj.js +++ b/lib/loadObj.js @@ -535,16 +535,33 @@ function loadMtls(mtlPaths, objPath, options) { var materials = []; return Promise.map(mtlPaths, function(mtlPath) { mtlPath = path.resolve(objDirectory, mtlPath); + var shallowPath = path.resolve(path.join(objDirectory, path.basename(mtlPath))); if (options.secure && outsideDirectory(mtlPath, objDirectory)) { - options.logger('Could not read mtl file at ' + mtlPath + ' because it is outside of the obj directory and the secure flag is true. Using default material instead.'); - return; + // Try looking for the .mtl in the same directory as the obj + options.logger('The material file is outside of the obj directory and the secure flag is true. Attempting to read the material file from within the obj directory instead.'); + return loadMtl(shallowPath, options) + .then(function(materialsInMtl) { + materials = materials.concat(materialsInMtl); + }) + .catch(function(error) { + options.logger(error.message); + options.logger('Could not read material file at ' + shallowPath + '. Using default material instead.'); + }); } + return loadMtl(mtlPath, options) + .catch(function(error) { + // Try looking for the .mtl in the same directory as the obj + options.logger(error.message); + options.logger('Could not read material file at ' + mtlPath + '. Attempting to read the material file from within the obj directory instead.'); + return loadMtl(shallowPath, options); + }) .then(function(materialsInMtl) { materials = materials.concat(materialsInMtl); }) - .catch(function() { - options.logger('Could not read mtl file at ' + mtlPath + '. Using default material instead.'); + .catch(function(error) { + options.logger(error.message); + options.logger('Could not read material file at ' + shallowPath + '. Using default material instead.'); }); }, {concurrency : 10}) .then(function() { diff --git a/specs/data/box-external-resources-in-root/box-external-resources-in-root.mtl b/specs/data/box-external-resources-in-root/box-external-resources-in-root.mtl new file mode 100644 index 0000000..2e2d3a5 --- /dev/null +++ b/specs/data/box-external-resources-in-root/box-external-resources-in-root.mtl @@ -0,0 +1,13 @@ +# Blender MTL File: 'box.blend' +# Material Count: 1 + +newmtl MaterialTextured +Ns 96.078431 +Ka 0.000000 0.000000 0.000000 +Kd 0.640000 0.640000 0.640000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 2 +map_Kd ../box-textured/cesium.png diff --git a/specs/data/box-external-resources-in-root/box-external-resources-in-root.obj b/specs/data/box-external-resources-in-root/box-external-resources-in-root.obj new file mode 100644 index 0000000..6b17fc5 --- /dev/null +++ b/specs/data/box-external-resources-in-root/box-external-resources-in-root.obj @@ -0,0 +1,46 @@ +# Blender v2.78 (sub 0) OBJ File: 'box-multiple-materials.blend' +# www.blender.org +mtllib box-external-resources-in-root.mtl +mtllib ../box/box.mtl +v -1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn -1.0000 0.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 0.0000 1.0000 +usemtl MaterialTextured +f 3/1/1 7/2/1 5/3/1 1/4/1 +f 1/9/3 2/10/3 4/11/3 3/12/3 +f 3/1/5 4/6/5 8/17/5 7/18/5 +usemtl Material +f 8/5/2 4/6/2 2/7/2 6/8/2 +f 7/13/4 8/14/4 6/15/4 5/16/4 +f 5/19/6 6/20/6 2/7/6 1/4/6 diff --git a/specs/data/box-external-resources-in-root/box.mtl b/specs/data/box-external-resources-in-root/box.mtl new file mode 100644 index 0000000..4f8d129 --- /dev/null +++ b/specs/data/box-external-resources-in-root/box.mtl @@ -0,0 +1,12 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl Material +Ns 96.078431 +Ka 0.100000 0.000000 0.000000 +Kd 0.640000 0.640000 0.640000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.100000 +Ni 1.000000 +d 1.000000 +illum 2 diff --git a/specs/data/box-external-resources-in-root/cesium.png b/specs/data/box-external-resources-in-root/cesium.png new file mode 100644 index 0000000..3b8baee Binary files /dev/null and b/specs/data/box-external-resources-in-root/cesium.png differ diff --git a/specs/data/box-resources-in-root/box-resources-in-root.mtl b/specs/data/box-resources-in-root/box-resources-in-root.mtl new file mode 100644 index 0000000..7bc1846 --- /dev/null +++ b/specs/data/box-resources-in-root/box-resources-in-root.mtl @@ -0,0 +1,13 @@ +# Blender MTL File: 'box.blend' +# Material Count: 1 + +newmtl Material +Ns 96.078431 +Ka 0.000000 0.000000 0.000000 +Kd 0.640000 0.640000 0.640000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 2 +map_Kd resources/textures/cesium.png diff --git a/specs/data/box-resources-in-root/box-resources-in-root.obj b/specs/data/box-resources-in-root/box-resources-in-root.obj new file mode 100644 index 0000000..1e9d945 --- /dev/null +++ b/specs/data/box-resources-in-root/box-resources-in-root.obj @@ -0,0 +1,46 @@ +# Blender v2.78 (sub 0) OBJ File: 'box.blend' +# www.blender.org +mtllib resources/box-resources-in-root.mtl +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 0.0000 0.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 1.0000 +vt 1.0000 0.0000 +vt 1.0000 1.0000 +vt 0.0000 0.0000 +vt 0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +usemtl Material +s off +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/5/2 4/6/2 8/7/2 7/8/2 +f 7/9/3 8/10/3 6/11/3 5/12/3 +f 5/13/4 6/14/4 2/15/4 1/16/4 +f 3/5/5 7/17/5 5/18/5 1/16/5 +f 8/19/6 4/6/6 2/15/6 6/20/6 diff --git a/specs/data/box-resources-in-root/cesium.png b/specs/data/box-resources-in-root/cesium.png new file mode 100644 index 0000000..3b8baee Binary files /dev/null and b/specs/data/box-resources-in-root/cesium.png differ diff --git a/specs/lib/loadMtlSpec.js b/specs/lib/loadMtlSpec.js index 059dd45..f491e90 100644 --- a/specs/lib/loadMtlSpec.js +++ b/specs/lib/loadMtlSpec.js @@ -14,6 +14,8 @@ var texturedMaterialPath = 'specs/data/box-complex-material/box-complex-material var texturedWithOptionsMaterialPath = 'specs/data/box-texture-options/box-texture-options.mtl'; var multipleMaterialsPath = 'specs/data/box-multiple-materials/box-multiple-materials.mtl'; var externalMaterialPath = 'specs/data/box-external-resources/box-external-resources.mtl'; +var resourcesInRootMaterialPath = 'specs/data/box-resources-in-root/box-resources-in-root.mtl'; +var externalInRootMaterialPath = 'specs/data/box-external-resources-in-root/box-external-resources-in-root.mtl'; var transparentMaterialPath = 'specs/data/box-transparent/box-transparent.mtl'; var diffuseTexturePath = 'specs/data/box-textured/cesium.png'; @@ -207,7 +209,31 @@ describe('loadMtl', function() { var material = materials[0]; var baseColorTexture = material.pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture).toBeUndefined(); - expect(spy.calls.argsFor(0)[0].indexOf('Could not read texture file') >= 0).toBe(true); + expect(spy.calls.argsFor(0)[0].indexOf('Texture file is outside of the mtl directory and the secure flag is true. Attempting to read the texture file from within the obj directory instead') >= 0).toBe(true); + expect(spy.calls.argsFor(1)[0].indexOf('ENOENT') >= 0).toBe(true); + expect(spy.calls.argsFor(2)[0].indexOf('Could not read texture file') >= 0).toBe(true); + }), done).toResolve(); + }); + + it('loads textures from root directory when the texture paths do not exist', function(done) { + expect(loadMtl(resourcesInRootMaterialPath, options) + .then(function(materials) { + var material = materials[0]; + var baseColorTexture = material.pbrMetallicRoughness.baseColorTexture; + expect(baseColorTexture.source).toBeDefined(); + expect(baseColorTexture.name).toBe('cesium'); + }), done).toResolve(); + }); + + it('loads textures from root directory when texture is outside of the mtl directory and secure is true', function(done) { + options.secure = true; + + expect(loadMtl(externalInRootMaterialPath, options) + .then(function(materials) { + var material = materials[0]; + var baseColorTexture = material.pbrMetallicRoughness.baseColorTexture; + expect(baseColorTexture.source).toBeDefined(); + expect(baseColorTexture.name).toBe('cesium'); }), done).toResolve(); }); diff --git a/specs/lib/loadObjSpec.js b/specs/lib/loadObjSpec.js index 9014b6b..ea6004b 100644 --- a/specs/lib/loadObjSpec.js +++ b/specs/lib/loadObjSpec.js @@ -24,6 +24,8 @@ var objMtllibPath = 'specs/data/box-mtllib/box-mtllib.obj'; var objMtllibSpacesPath = 'specs/data/box-mtllib-spaces/box mtllib.obj'; var objMissingMtllibPath = 'specs/data/box-missing-mtllib/box-missing-mtllib.obj'; var objExternalResourcesPath = 'specs/data/box-external-resources/box-external-resources.obj'; +var objResourcesInRootPath = 'specs/data/box-resources-in-root/box-resources-in-root.obj'; +var objExternalResourcesInRootPath = 'specs/data/box-external-resources-in-root/box-external-resources-in-root.obj'; var objTexturedPath = 'specs/data/box-textured/box-textured.obj'; var objMissingTexturePath = 'specs/data/box-missing-texture/box-missing-texture.obj'; var objSubdirectoriesPath = 'specs/data/box-subdirectories/box-textured.obj'; @@ -317,7 +319,10 @@ describe('loadObj', function() { expect(loadObj(objMissingMtllibPath, options) .then(function(data) { expect(data.materials.length).toBe(0); - expect(spy.calls.argsFor(0)[0].indexOf('Could not read mtl file') >= 0).toBe(true); + expect(spy.calls.argsFor(0)[0].indexOf('ENOENT') >= 0).toBe(true); + expect(spy.calls.argsFor(1)[0].indexOf('Attempting to read the material file from within the obj directory instead.') >= 0).toBe(true); + expect(spy.calls.argsFor(2)[0].indexOf('ENOENT') >= 0).toBe(true); + expect(spy.calls.argsFor(3)[0].indexOf('Could not read material file') >= 0).toBe(true); }), done).toResolve(); }); @@ -343,8 +348,34 @@ describe('loadObj', function() { expect(loadObj(objExternalResourcesPath, options) .then(function(data) { expect(data.materials.length).toBe(1); // obj references 2 materials, one of which is outside the input directory - expect(spy.calls.argsFor(0)[0].indexOf('Could not read mtl file') >= 0).toBe(true); - expect(spy.calls.argsFor(1)[0].indexOf('Could not read texture file') >= 0).toBe(true); + expect(spy.calls.argsFor(0)[0].indexOf('The material file is outside of the obj directory and the secure flag is true. Attempting to read the material file from within the obj directory instead.') >= 0).toBe(true); + expect(spy.calls.argsFor(1)[0].indexOf('ENOENT') >= 0).toBe(true); + expect(spy.calls.argsFor(2)[0].indexOf('Could not read material file') >= 0).toBe(true); + }), done).toResolve(); + }); + + it('loads .mtl from root directory when the .mtl path does not exist', function(done) { + expect(loadObj(objResourcesInRootPath, options) + .then(function(data) { + var baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture; + expect(baseColorTexture.name).toBe('cesium'); + expect(baseColorTexture.source).toBeDefined(); + }), done).toResolve(); + }); + + it('loads .mtl from root directory when the .mtl path is outside of the obj directory and secure is true', function(done) { + options.secure = true; + + expect(loadObj(objExternalResourcesInRootPath, options) + .then(function(data) { + var materials = data.materials; + expect(materials.length).toBe(2); + + // .mtl files are loaded in an arbitrary order, so find the "MaterialTextured" material + var materialTextured = materials[0].name === 'MaterialTextured' ? materials[0] : materials[1]; + var baseColorTexture = materialTextured.pbrMetallicRoughness.baseColorTexture; + expect(baseColorTexture.source).toBeDefined(); + expect(baseColorTexture.name).toEqual('cesium'); }), done).toResolve(); }); @@ -365,7 +396,10 @@ describe('loadObj', function() { .then(function(data) { var baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture).toBeUndefined(); - expect(spy.calls.argsFor(0)[0].indexOf('Could not read texture file') >= 0).toBe(true); + expect(spy.calls.argsFor(0)[0].indexOf('ENOENT') >= 0).toBe(true); + expect(spy.calls.argsFor(1)[0].indexOf('Attempting to read the texture file from within the obj directory instead.') >= 0).toBe(true); + expect(spy.calls.argsFor(2)[0].indexOf('ENOENT') >= 0).toBe(true); + expect(spy.calls.argsFor(3)[0].indexOf('Could not read texture file') >= 0).toBe(true); }), done).toResolve(); }); diff --git a/specs/lib/obj2gltfSpec.js b/specs/lib/obj2gltfSpec.js index be16cf2..d54b5bc 100644 --- a/specs/lib/obj2gltfSpec.js +++ b/specs/lib/obj2gltfSpec.js @@ -124,7 +124,7 @@ describe('obj2gltf', function() { }; expect(obj2gltf(missingMtllibObjPath, options) .then(function() { - expect(lastMessage.indexOf('Could not read mtl file') >= 0).toBe(true); + expect(lastMessage.indexOf('Could not read material file') >= 0).toBe(true); }), done).toResolve(); });