diff --git a/bin/obj2gltf.js b/bin/obj2gltf.js index 478664c..2c76c20 100644 --- a/bin/obj2gltf.js +++ b/bin/obj2gltf.js @@ -21,14 +21,23 @@ var argv = yargs alias: 'i', describe: 'Path to the obj file.', type: 'string', - normalize: true, - demandOption: true + coerce : function (p) { + if (p.length === 0) { + throw new Error('Input path must be a file name'); + } + return path.resolve(p); + } }, output : { alias: 'o', describe: 'Path of the converted glTF file.', type: 'string', - normalize: true + coerce : function (p) { + if (p.length === 0) { + throw new Error('Output path must be a file name'); + } + return path.resolve(p); + } }, binary : { alias: 'b', diff --git a/lib/loadMtl.js b/lib/loadMtl.js index 5b5c72b..8a7aa96 100644 --- a/lib/loadMtl.js +++ b/lib/loadMtl.js @@ -68,19 +68,19 @@ function loadMtl(mtlPath) { value = line.substring(3).trim(); material.alpha = 1.0 - parseFloat(value); } else if (/^map_Ka /i.test(line)) { - material.ambientTexture = path.resolve(mtlDirectory, line.substring(7).trim()); + material.ambientTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory); } else if (/^map_Ke /i.test(line)) { - material.emissionTexture = path.resolve(mtlDirectory, line.substring(7).trim()); + material.emissionTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory); } else if (/^map_Kd /i.test(line)) { - material.diffuseTexture = path.resolve(mtlDirectory, line.substring(7).trim()); + material.diffuseTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory); } else if (/^map_Ks /i.test(line)) { - material.specularTexture = path.resolve(mtlDirectory, line.substring(7).trim()); + material.specularTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory); } else if (/^map_Ns /i.test(line)) { - material.specularShininessMap = path.resolve(mtlDirectory, line.substring(7).trim()); + material.specularShininessMap = normalizeTexturePath(line.substring(7).trim(), mtlDirectory); } else if (/^map_Bump /i.test(line)) { - material.normalMap = path.resolve(mtlDirectory, line.substring(9).trim()); + material.normalMap = normalizeTexturePath(line.substring(9).trim(), mtlDirectory); } else if (/^map_d /i.test(line)) { - material.alphaMap = path.resolve(mtlDirectory, line.substring(6).trim()); + material.alphaMap = normalizeTexturePath(line.substring(6).trim(), mtlDirectory); } } @@ -89,3 +89,14 @@ function loadMtl(mtlPath) { return materials; }); } + +function normalizeTexturePath(texturePath, mtlDirectory) { + // Removes texture options from texture name + // Assumes no spaces in texture name + var re = /-(bm|t|s|o|blendu|blendv|boost|mm|texres|clamp|imfchan|type)/; + if (re.test(texturePath)) { + texturePath = texturePath.split(/\s+/).pop(); + } + texturePath = texturePath.replace(/\\/g, '/'); + return path.normalize(path.join(mtlDirectory, texturePath)); +} diff --git a/lib/loadObj.js b/lib/loadObj.js index eb5131b..efe97a9 100644 --- a/lib/loadObj.js +++ b/lib/loadObj.js @@ -537,6 +537,11 @@ function finishLoading(nodes, mtlPaths, objPath, options) { }); } +function normalizeMtlPath(mtlPath, objDirectory) { + mtlPath = mtlPath.replace(/\\/g, '/'); + return path.normalize(path.join(objDirectory, mtlPath)); +} + function outsideDirectory(filePath, objPath) { return (path.relative(path.dirname(objPath), filePath).indexOf('..') === 0); } @@ -547,7 +552,7 @@ function loadMaterials(mtlPaths, objPath, options) { var objDirectory = path.dirname(objPath); var materials = {}; return Promise.map(mtlPaths, function(mtlPath) { - mtlPath = path.resolve(objDirectory, mtlPath); + mtlPath = normalizeMtlPath(mtlPath, objDirectory); if (secure && outsideDirectory(mtlPath, objPath)) { 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; diff --git a/specs/data/box-windows-paths/box-windows-paths.obj b/specs/data/box-windows-paths/box-windows-paths.obj new file mode 100644 index 0000000..1c37d5b --- /dev/null +++ b/specs/data/box-windows-paths/box-windows-paths.obj @@ -0,0 +1,46 @@ +# Blender v2.78 (sub 0) OBJ File: 'box.blend' +# www.blender.org +mtllib materials\\box-windows-paths.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-windows-paths/materials/box-windows-paths.mtl b/specs/data/box-windows-paths/materials/box-windows-paths.mtl new file mode 100644 index 0000000..22bca2d --- /dev/null +++ b/specs/data/box-windows-paths/materials/box-windows-paths.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 .\images\cesium.png diff --git a/specs/data/box-windows-paths/materials/images/cesium.png b/specs/data/box-windows-paths/materials/images/cesium.png new file mode 100644 index 0000000..3b8baee Binary files /dev/null and b/specs/data/box-windows-paths/materials/images/cesium.png differ diff --git a/specs/lib/loadMtlSpec.js b/specs/lib/loadMtlSpec.js index 976b322..9d13473 100644 --- a/specs/lib/loadMtlSpec.js +++ b/specs/lib/loadMtlSpec.js @@ -6,7 +6,7 @@ var complexMaterialUrl = 'specs/data/box-complex-material/box-complex-material.m var multipleMaterialsUrl = 'specs/data/box-multiple-materials/box-multiple-materials.mtl'; function getImagePath(objPath, relativePath) { - return path.resolve(path.dirname(objPath), relativePath); + return path.normalize(path.join(path.dirname(objPath), relativePath)); } describe('loadMtl', function() { diff --git a/specs/lib/loadObjSpec.js b/specs/lib/loadObjSpec.js index a43930d..bfe4c44 100644 --- a/specs/lib/loadObjSpec.js +++ b/specs/lib/loadObjSpec.js @@ -30,6 +30,7 @@ var objExternalResourcesUrl = 'specs/data/box-external-resources/box-external-re var objTexturedUrl = 'specs/data/box-textured/box-textured.obj'; var objMissingTextureUrl = 'specs/data/box-missing-texture/box-missing-texture.obj'; var objSubdirectoriesUrl = 'specs/data/box-subdirectories/box-textured.obj'; +var objWindowsPathsUrl = 'specs/data/box-windows-paths/box-windows-paths.obj'; var objComplexMaterialUrl = 'specs/data/box-complex-material/box-complex-material.obj'; var objInvalidContentsUrl = 'specs/data/box/box.mtl'; var objInvalidUrl = 'invalid.obj'; @@ -59,7 +60,7 @@ function getPrimitives(data) { } function getImagePath(objPath, relativePath) { - return path.resolve(path.dirname(objPath), relativePath); + return path.normalize(path.join(path.dirname(objPath), relativePath)); } var defaultOptions = obj2gltf.defaults; @@ -346,6 +347,15 @@ describe('loadObj', function() { }), done).toResolve(); }); + it('loads obj with windows paths', function(done) { + expect(loadObj(objWindowsPathsUrl, defaultOptions) + .then(function(data) { + var imagePath = getImagePath(objWindowsPathsUrl, path.join('materials', 'images', 'cesium.png')); + expect(data.images[imagePath]).toBeDefined(); + expect(data.materials.Material.diffuseTexture).toEqual(imagePath); + }), done).toResolve(); + }); + it('loads obj with complex material', function(done) { expect(loadObj(objComplexMaterialUrl, defaultOptions) .then(function(data) {