Merge pull request #21 from AnalyticalGraphicsInc/promises-everywhere

Convert callbacks to promises
This commit is contained in:
Sean Lilley 2016-07-25 18:57:27 -07:00 committed by GitHub
commit 60ba99d4ec
9 changed files with 427 additions and 401 deletions

View File

@ -15,9 +15,10 @@ var convert = obj2gltf.convert;
var options = { var options = {
embedImage : false // Don't embed image in the converted glTF embedImage : false // Don't embed image in the converted glTF
} }
convert('model.obj', 'model.gltf', options, function() { convert('model.obj', 'model.gltf', options)
console.log('Converted model'); .then(function() {
}); console.log('Converted model');
});
``` ```
Using obj2gltf as a command-line tool: Using obj2gltf as a command-line tool:

View File

@ -40,6 +40,10 @@ var options = {
ao : ao ao : ao
}; };
convert(objFile, outputPath, options, function() { convert(objFile, outputPath, options)
console.timeEnd('Total'); .then(function() {
}); console.timeEnd('Total');
})
.catch(function(err) {
console.log(err);
});

View File

@ -9,7 +9,7 @@ var defaultValue = Cesium.defaultValue;
module.exports = convert; module.exports = convert;
function convert(objFile, outputPath, options, done) { function convert(objFile, outputPath, options) {
options = defaultValue(options, {}); options = defaultValue(options, {});
var binary = defaultValue(options.binary, false); var binary = defaultValue(options.binary, false);
var embed = defaultValue(options.embed, true); var embed = defaultValue(options.embed, true);
@ -37,24 +37,21 @@ function convert(objFile, outputPath, options, done) {
extension = binary ? '.glb' : '.gltf'; extension = binary ? '.glb' : '.gltf';
var gltfFile = path.join(outputPath, modelName + extension); var gltfFile = path.join(outputPath, modelName + extension);
parseObj(objFile, inputPath, function(data) { return parseObj(objFile, inputPath)
createGltf(data, inputPath, modelName, function(gltf) { .then(function(data) {
return createGltf(data, inputPath, modelName);
})
.then(function(gltf) {
var aoOptions = ao ? {} : undefined; var aoOptions = ao ? {} : undefined;
var options = { var options = {
binary : binary, binary: binary,
embed : embed, embed: embed,
embedImage : embedImage, embedImage: embedImage,
quantize : quantize, quantize: quantize,
aoOptions : aoOptions, aoOptions: aoOptions,
createDirectory : false, createDirectory: false,
basePath : inputPath basePath: inputPath
}; };
gltfPipeline.processJSONToDisk(gltf, gltfFile, options, function(error) { return gltfPipeline.processJSONToDisk(gltf, gltfFile, options);
if (error) {
throw error;
}
done();
});
}); });
});
} }

View File

@ -1,14 +1,18 @@
"use strict"; "use strict";
var Cesium = require('cesium');
var Promise = require('bluebird');
var fs = require('fs-extra'); var fs = require('fs-extra');
var path = require('path'); var path = require('path');
var Cesium = require('cesium');
var defined = Cesium.defined; var defined = Cesium.defined;
var defaultValue = Cesium.defaultValue; var defaultValue = Cesium.defaultValue;
var WebGLConstants = Cesium.WebGLConstants; var WebGLConstants = Cesium.WebGLConstants;
var fsWriteFile = Promise.promisify(fs.writeFile);
module.exports = createGltf; module.exports = createGltf;
function createGltf(data, inputPath, modelName, done) { function createGltf(data, inputPath, modelName) {
var vertexCount = data.vertexCount; var vertexCount = data.vertexCount;
var vertexArray = data.vertexArray; var vertexArray = data.vertexArray;
var positionMin = data.positionMin; var positionMin = data.positionMin;
@ -328,13 +332,7 @@ function createGltf(data, inputPath, modelName, done) {
if (bufferSeparate) { if (bufferSeparate) {
var bufferPath = path.join(inputPath, modelName + '.bin'); var bufferPath = path.join(inputPath, modelName + '.bin');
fs.writeFile(bufferPath, buffer, function(err) { return fsWriteFile(bufferPath, buffer);
if (err) {
throw err;
}
done(gltf);
});
} else {
done(gltf);
} }
return gltf;
} }

View File

@ -1,7 +1,10 @@
"use strict"; "use strict";
var Promise = require('bluebird');
var fs = require('fs-extra'); var fs = require('fs-extra');
var path = require('path'); var path = require('path');
var fsReadFile = Promise.promisify(fs.readFile);
module.exports = loadImage; module.exports = loadImage;
function getChannels(colorType) { function getChannels(colorType) {
@ -34,31 +37,27 @@ function getUriType(extension) {
} }
} }
function loadImage(imagePath, done) { function loadImage(imagePath) {
fs.readFile(imagePath, function(error, data) { return fsReadFile(imagePath)
if (error) { .then(function(data) {
throw(error); var extension = path.extname(imagePath).slice(1);
} var uriType = getUriType(extension);
var uri = uriType + ';base64,' + data.toString('base64');
var extension = path.extname(imagePath).slice(1); var info = {
var uriType = getUriType(extension); transparent: false,
var uri = uriType + ';base64,' + data.toString('base64'); channels: 3,
data: data,
uri: uri
};
var info = { if (path.extname(imagePath) === 'png') {
transparent: false, // Color type is encoded in the 25th bit of the png
channels: 3, var colorType = data[25];
data: data, var channels = getChannels(colorType);
uri: uri info.channels = channels;
}; info.transparent = (channels === 4);
}
if (path.extname(imagePath) === 'png') { return info;
// Color type is encoded in the 25th bit of the png
var colorType = data[25];
var channels = getChannels(colorType);
info.channels = channels;
info.transparent = (channels === 4);
}
done(info);
}); });
} }

View File

@ -1,7 +1,10 @@
"use strict"; "use strict";
var Promise = require('bluebird');
var fs = require('fs-extra'); var fs = require('fs-extra');
var defined = require('cesium').defined; var defined = require('cesium').defined;
var fsReadFile = Promise.promisify(fs.readFile);
module.exports = { module.exports = {
getDefault : getDefault, getDefault : getDefault,
parse : parse parse : parse
@ -31,89 +34,85 @@ function getDefault() {
return material; return material;
} }
function parse(mtlPath, done) { function parse(mtlPath) {
fs.readFile(mtlPath, 'utf8', function (error, contents) { return fsReadFile(mtlPath, 'utf8')
if (error) { .then(function (contents) {
console.log('Could not read material file at ' + mtlPath + '. Using default material instead.'); var materials = {};
done({}); var material;
return; var values;
} var value;
var lines = contents.split('\n');
var materials = {}; var length = lines.length;
var material; for (var i = 0; i < length; ++i) {
var line = lines[i].trim();
var values; if (/^newmtl /i.test(line)) {
var value; var name = line.substring(7).trim();
var lines = contents.split('\n'); material = createMaterial();
var length = lines.length; materials[name] = material;
for (var i = 0; i < length; ++i) { } else if (/^Ka /i.test(line)) {
var line = lines[i].trim(); values = line.substring(3).trim().split(' ');
if (/^newmtl /i.test(line)) { material.ambientColor = [
var name = line.substring(7).trim(); parseFloat(values[0]),
material = createMaterial(); parseFloat(values[1]),
materials[name] = material; parseFloat(values[2]),
} else if (/^Ka /i.test(line)) { 1.0
values = line.substring(3).trim().split(' '); ];
material.ambientColor = [ } else if (/^Ke /i.test(line)) {
parseFloat(values[0]), values = line.substring(3).trim().split(' ');
parseFloat(values[1]), material.emissionColor = [
parseFloat(values[2]), parseFloat(values[0]),
1.0 parseFloat(values[1]),
]; parseFloat(values[2]),
} else if (/^Ke /i.test(line)) { 1.0
values = line.substring(3).trim().split(' '); ];
material.emissionColor = [ } else if (/^Kd /i.test(line)) {
parseFloat(values[0]), values = line.substring(3).trim().split(' ');
parseFloat(values[1]), material.diffuseColor = [
parseFloat(values[2]), parseFloat(values[0]),
1.0 parseFloat(values[1]),
]; parseFloat(values[2]),
} else if (/^Kd /i.test(line)) { 1.0
values = line.substring(3).trim().split(' '); ];
material.diffuseColor = [ } else if (/^Ks /i.test(line)) {
parseFloat(values[0]), values = line.substring(3).trim().split(' ');
parseFloat(values[1]), material.specularColor = [
parseFloat(values[2]), parseFloat(values[0]),
1.0 parseFloat(values[1]),
]; parseFloat(values[2]),
} else if (/^Ks /i.test(line)) { 1.0
values = line.substring(3).trim().split(' '); ];
material.specularColor = [ } else if (/^Ns /i.test(line)) {
parseFloat(values[0]), value = line.substring(3).trim();
parseFloat(values[1]), material.specularShininess = parseFloat(value);
parseFloat(values[2]), } else if (/^d /i.test(line)) {
1.0 value = line.substring(2).trim();
]; material.alpha = parseFloat(value);
} else if (/^Ns /i.test(line)) { } else if (/^Tr /i.test(line)) {
value = line.substring(3).trim(); value = line.substring(3).trim();
material.specularShininess = parseFloat(value); material.alpha = parseFloat(value);
} else if (/^d /i.test(line)) { } else if (/^map_Ka /i.test(line)) {
value = line.substring(2).trim(); material.ambientColorMap = line.substring(7).trim();
material.alpha = parseFloat(value); } else if (/^map_Ke /i.test(line)) {
} else if (/^Tr /i.test(line)) { material.emissionColorMap = line.substring(7).trim();
value = line.substring(3).trim(); } else if (/^map_Kd /i.test(line)) {
material.alpha = parseFloat(value); material.diffuseColorMap = line.substring(7).trim();
} else if (/^map_Ka /i.test(line)) { } else if (/^map_Ks /i.test(line)) {
material.ambientColorMap = line.substring(7).trim(); material.specularColorMap = line.substring(7).trim();
} else if (/^map_Ke /i.test(line)) { } else if (/^map_Ns /i.test(line)) {
material.emissionColorMap = line.substring(7).trim(); material.specularShininessMap = line.substring(7).trim();
} else if (/^map_Kd /i.test(line)) { } else if (/^map_Bump /i.test(line)) {
material.diffuseColorMap = line.substring(7).trim(); material.normalMap = line.substring(9).trim();
} else if (/^map_Ks /i.test(line)) { } else if (/^map_d /i.test(line)) {
material.specularColorMap = line.substring(7).trim(); material.alphaMap = line.substring(6).trim();
} else if (/^map_Ns /i.test(line)) { }
material.specularShininessMap = line.substring(7).trim();
} else if (/^map_Bump /i.test(line)) {
material.normalMap = line.substring(9).trim();
} else if (/^map_d /i.test(line)) {
material.alphaMap = line.substring(6).trim();
} }
} if (defined(material.alpha)) {
material.diffuseColor[3] = material.alpha;
if (defined(material.alpha)) { }
material.diffuseColor[3] = material.alpha; return materials;
} })
.catch(function() {
done(materials); console.log('Could not read material file at ' + mtlPath + '. Using default material instead.');
}); return {};
});
} }

View File

@ -1,11 +1,14 @@
"use strict"; "use strict";
var async = require('async');
var Cesium = require('cesium');
var Promise = require('bluebird');
var byline = require('byline'); var byline = require('byline');
var fs = require('fs-extra'); var fs = require('fs-extra');
var path = require('path'); var path = require('path');
var loadImage = require('./image'); var loadImage = require('./image');
var Material = require('./mtl'); var Material = require('./mtl');
var Cesium = require('cesium');
var Cartesian3 = Cesium.Cartesian3; var Cartesian3 = Cesium.Cartesian3;
var defined = Cesium.defined; var defined = Cesium.defined;
@ -13,231 +16,237 @@ module.exports = parseObj;
// OBJ regex patterns are from ThreeJS (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js) // OBJ regex patterns are from ThreeJS (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js)
function parseObj(objFile, inputPath, done) { function parseObj(objFile, inputPath) {
getObjInfo(objFile, inputPath, function(info, materials, images) { return getObjInfo(objFile, inputPath)
processObj(objFile, info, materials, images, done); .then(function(result) {
}); var info = result.info;
var materials = result.materials;
var images = result.images;
return processObj(objFile, info, materials, images);
});
} }
function processObj(objFile, info, materials, images, done) { function processObj(objFile, info, materials, images) {
// A vertex is specified by indexes into each of the attribute arrays, return new Promise(function(resolve) {
// but these indexes may be different. This maps the separate indexes to a single index. // A vertex is specified by indexes into each of the attribute arrays,
var vertexCache = {}; // but these indexes may be different. This maps the separate indexes to a single index.
var vertexCount = 0; var vertexCache = {};
var vertexCount = 0;
var vertexArray = []; var vertexArray = [];
var positions = [];
var normals = [];
var uvs = [];
var positionMin = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE]; var positions = [];
var positionMax = [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE]; var normals = [];
var uvs = [];
var hasNormals = info.hasNormals; var positionMin = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE];
var hasUVs = info.hasUVs; var positionMax = [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE];
var materialGroups = {}; // Map material to index array var hasNormals = info.hasNormals;
var currentIndexArray; var hasUVs = info.hasUVs;
// Switch to the material-specific index array, or create it if it doesn't exist var materialGroups = {}; // Map material to index array
function useMaterial(material) { var currentIndexArray;
if (!defined(materials[material])) {
useDefaultMaterial();
} else {
currentIndexArray = materialGroups[material];
if (!defined(currentIndexArray)) {
currentIndexArray = [];
materialGroups[material] = currentIndexArray;
}
}
}
function useDefaultMaterial() { // Switch to the material-specific index array, or create it if it doesn't exist
var defaultMaterial = 'czmDefaultMat'; function useMaterial(material) {
if (!defined(materials[defaultMaterial])) { if (!defined(materials[material])) {
materials[defaultMaterial] = Material.getDefault(); useDefaultMaterial();
}
useMaterial(defaultMaterial);
}
var materialsLength = Object.keys(materials).length;
if (materialsLength === 0) {
useDefaultMaterial();
}
function getOffset(a, data, components) {
var i = parseInt(a);
if (i < 0) {
// Negative vertex indexes reference the vertices immediately above it
return (data.length / components + i) * components;
}
return (i - 1) * components;
}
function createVertex(p, u, n) {
// Positions
var pi = getOffset(p, positions, 3);
var px = positions[pi + 0];
var py = positions[pi + 1];
var pz = positions[pi + 2];
positionMin[0] = Math.min(px, positionMin[0]);
positionMin[1] = Math.min(py, positionMin[1]);
positionMin[2] = Math.min(pz, positionMin[2]);
positionMax[0] = Math.max(px, positionMax[0]);
positionMax[1] = Math.max(py, positionMax[1]);
positionMax[2] = Math.max(pz, positionMax[2]);
vertexArray.push(px, py, pz);
// Normals
if (hasNormals) {
var ni = getOffset(n, normals, 3);
var nx = normals[ni + 0];
var ny = normals[ni + 1];
var nz = normals[ni + 2];
vertexArray.push(nx, ny, nz);
}
// UVs
if (hasUVs) {
if (defined(u)) {
var ui = getOffset(u, uvs, 2);
var ux = uvs[ui + 0];
var uy = uvs[ui + 1];
// Flip y so 0.0 is the bottom of the image
uy = 1.0 - uy;
vertexArray.push(ux, uy);
} else { } else {
// Some objects in the model may not have uvs, fill with 0's for consistency currentIndexArray = materialGroups[material];
vertexArray.push(0.0, 0.0); if (!defined(currentIndexArray)) {
currentIndexArray = [];
materialGroups[material] = currentIndexArray;
}
} }
} }
}
function addVertex(v, p, u, n) { function useDefaultMaterial() {
var index = vertexCache[v]; var defaultMaterial = 'czmDefaultMat';
if (!defined(index)) { if (!defined(materials[defaultMaterial])) {
index = vertexCount++; materials[defaultMaterial] = Material.getDefault();
vertexCache[v] = index; }
createVertex(p, u, n); useMaterial(defaultMaterial);
} }
return index; var materialsLength = Object.keys(materials).length;
} if (materialsLength === 0) {
useDefaultMaterial();
}
function addFace(v1, p1, u1, n1, v2, p2, u2, n2, v3, p3, u3, n3, v4, p4, u4, n4) { function getOffset(a, data, components) {
var index1 = addVertex(v1, p1, u1, n1); var i = parseInt(a);
var index2 = addVertex(v2, p2, u2, n2); if (i < 0) {
var index3 = addVertex(v3, p3, u3, n3); // Negative vertex indexes reference the vertices immediately above it
return (data.length / components + i) * components;
}
return (i - 1) * components;
}
currentIndexArray.push(index1); function createVertex(p, u, n) {
currentIndexArray.push(index2); // Positions
currentIndexArray.push(index3); var pi = getOffset(p, positions, 3);
var px = positions[pi + 0];
var py = positions[pi + 1];
var pz = positions[pi + 2];
positionMin[0] = Math.min(px, positionMin[0]);
positionMin[1] = Math.min(py, positionMin[1]);
positionMin[2] = Math.min(pz, positionMin[2]);
positionMax[0] = Math.max(px, positionMax[0]);
positionMax[1] = Math.max(py, positionMax[1]);
positionMax[2] = Math.max(pz, positionMax[2]);
vertexArray.push(px, py, pz);
// Normals
if (hasNormals) {
var ni = getOffset(n, normals, 3);
var nx = normals[ni + 0];
var ny = normals[ni + 1];
var nz = normals[ni + 2];
vertexArray.push(nx, ny, nz);
}
// UVs
if (hasUVs) {
if (defined(u)) {
var ui = getOffset(u, uvs, 2);
var ux = uvs[ui + 0];
var uy = uvs[ui + 1];
// Flip y so 0.0 is the bottom of the image
uy = 1.0 - uy;
vertexArray.push(ux, uy);
} else {
// Some objects in the model may not have uvs, fill with 0's for consistency
vertexArray.push(0.0, 0.0);
}
}
}
function addVertex(v, p, u, n) {
var index = vertexCache[v];
if (!defined(index)) {
index = vertexCount++;
vertexCache[v] = index;
createVertex(p, u, n);
}
return index;
}
function addFace(v1, p1, u1, n1, v2, p2, u2, n2, v3, p3, u3, n3, v4, p4, u4, n4) {
var index1 = addVertex(v1, p1, u1, n1);
var index2 = addVertex(v2, p2, u2, n2);
var index3 = addVertex(v3, p3, u3, n3);
// Triangulate if the face is a quad
if (defined(v4)) {
var index4 = addVertex(v4, p4, u4, n4);
currentIndexArray.push(index1); currentIndexArray.push(index1);
currentIndexArray.push(index2);
currentIndexArray.push(index3); currentIndexArray.push(index3);
currentIndexArray.push(index4);
// Triangulate if the face is a quad
if (defined(v4)) {
var index4 = addVertex(v4, p4, u4, n4);
currentIndexArray.push(index1);
currentIndexArray.push(index3);
currentIndexArray.push(index4);
}
} }
}
// v float float float // v float float float
var vertexPattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; var vertexPattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
// vn float float float // vn float float float
var normalPattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; var normalPattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
// vt float float // vt float float
var uvPattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; var uvPattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
// f vertex vertex vertex ... // f vertex vertex vertex ...
var facePattern1 = /f( +-?\d+)\/?( +-?\d+)\/?( +-?\d+)\/?( +-?\d+)?\/?/; var facePattern1 = /f( +-?\d+)\/?( +-?\d+)\/?( +-?\d+)\/?( +-?\d+)?\/?/;
// f vertex/uv vertex/uv vertex/uv ... // f vertex/uv vertex/uv vertex/uv ...
var facePattern2 = /f( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)?/; var facePattern2 = /f( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)?/;
// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var facePattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/; var facePattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/;
// f vertex//normal vertex//normal vertex//normal ... // f vertex//normal vertex//normal vertex//normal ...
var facePattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/; var facePattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/;
var stream = byline(fs.createReadStream(objFile, {encoding: 'utf8'})); var stream = byline(fs.createReadStream(objFile, {encoding: 'utf8'}));
stream.on('data', function(line) { stream.on('data', function (line) {
line = line.trim(); line = line.trim();
var result; var result;
if ((line.length === 0) || (line.charAt(0) === '#')) { if ((line.length === 0) || (line.charAt(0) === '#')) {
// Don't process empty lines or comments // Don't process empty lines or comments
} else if ((result = vertexPattern.exec(line)) !== null) { } else if ((result = vertexPattern.exec(line)) !== null) {
positions.push( positions.push(
parseFloat(result[1]), parseFloat(result[1]),
parseFloat(result[2]), parseFloat(result[2]),
parseFloat(result[3]) parseFloat(result[3])
); );
} else if ((result = normalPattern.exec(line) ) !== null) { } else if ((result = normalPattern.exec(line) ) !== null) {
var nx = parseFloat(result[1]); var nx = parseFloat(result[1]);
var ny = parseFloat(result[2]); var ny = parseFloat(result[2]);
var nz = parseFloat(result[3]); var nz = parseFloat(result[3]);
var normal = Cartesian3.normalize(new Cartesian3(nx, ny, nz), new Cartesian3()); var normal = Cartesian3.normalize(new Cartesian3(nx, ny, nz), new Cartesian3());
normals.push(normal.x, normal.y, normal.z); normals.push(normal.x, normal.y, normal.z);
} else if ((result = uvPattern.exec(line)) !== null) { } else if ((result = uvPattern.exec(line)) !== null) {
uvs.push( uvs.push(
parseFloat(result[1]), parseFloat(result[1]),
parseFloat(result[2]) parseFloat(result[2])
); );
} else if ((result = facePattern1.exec(line)) !== null) { } else if ((result = facePattern1.exec(line)) !== null) {
addFace( addFace(
result[1], result[1], undefined, undefined, result[1], result[1], undefined, undefined,
result[2], result[2], undefined, undefined, result[2], result[2], undefined, undefined,
result[3], result[3], undefined, undefined, result[3], result[3], undefined, undefined,
result[4], result[4], undefined, undefined result[4], result[4], undefined, undefined
); );
} else if ((result = facePattern2.exec(line)) !== null) { } else if ((result = facePattern2.exec(line)) !== null) {
addFace( addFace(
result[1], result[2], result[3], undefined, result[1], result[2], result[3], undefined,
result[4], result[5], result[6], undefined, result[4], result[5], result[6], undefined,
result[7], result[8], result[9], undefined, result[7], result[8], result[9], undefined,
result[10], result[11], result[12], undefined result[10], result[11], result[12], undefined
); );
} else if ((result = facePattern3.exec(line)) !== null) { } else if ((result = facePattern3.exec(line)) !== null) {
addFace( addFace(
result[1], result[2], result[3], result[4], result[1], result[2], result[3], result[4],
result[5], result[6], result[7], result[8], result[5], result[6], result[7], result[8],
result[9], result[10], result[11], result[12], result[9], result[10], result[11], result[12],
result[13], result[14], result[15], result[16] result[13], result[14], result[15], result[16]
); );
} else if ((result = facePattern4.exec(line)) !== null) { } else if ((result = facePattern4.exec(line)) !== null) {
addFace( addFace(
result[1], result[2], undefined, result[3], result[1], result[2], undefined, result[3],
result[4], result[5], undefined, result[6], result[4], result[5], undefined, result[6],
result[7], result[8], undefined, result[9], result[7], result[8], undefined, result[9],
result[10], result[11], undefined, result[12] result[10], result[11], undefined, result[12]
); );
} else if (/^usemtl /.test(line)) { } else if (/^usemtl /.test(line)) {
var materialName = line.substring(7).trim(); var materialName = line.substring(7).trim();
useMaterial(materialName); useMaterial(materialName);
} }
}); });
stream.on('end', function() { stream.on('end', function () {
done({ resolve({
vertexCount : vertexCount, vertexCount: vertexCount,
vertexArray : vertexArray, vertexArray: vertexArray,
positionMin : positionMin, positionMin: positionMin,
positionMax : positionMax, positionMax: positionMax,
hasUVs : hasUVs, hasUVs: hasUVs,
hasNormals : hasNormals, hasNormals: hasNormals,
materialGroups : materialGroups, materialGroups: materialGroups,
materials : materials, materials: materials,
images : images images: images
});
}); });
}); });
} }
function getImages(inputPath, materials, done) { function getImages(inputPath, materials) {
// Collect all the image files from the materials // Collect all the image files from the materials
var images = []; var images = [];
for (var name in materials) { for (var name in materials) {
@ -259,84 +268,100 @@ function getImages(inputPath, materials, done) {
} }
// Load the image files // Load the image files
var promises = [];
var imagesInfo = {}; var imagesInfo = {};
async.each(images, function (image, callback) { var imagesLength = images.length;
var imagePath = image; for (var i = 0; i < imagesLength; i++) {
var imagePath = images[i];
if (!path.isAbsolute(imagePath)) { if (!path.isAbsolute(imagePath)) {
imagePath = path.join(inputPath, image); imagePath = path.join(inputPath, imagePath);
} }
loadImage(imagePath, function(info) { promises.push(loadImage(imagePath));
imagesInfo[image] = info; }
callback(); return Promise.all(promises)
.then(function(imageInfoArray) {
var imageInfoArrayLength = imageInfoArray.length;
for (var j = 0; j < imageInfoArrayLength; j++) {
var image = images[j];
var imageInfo = imageInfoArray[j];
imagesInfo[image] = imageInfo;
}
return imagesInfo;
}); });
}, function (error) {
if (error) {
throw error;
}
done(imagesInfo);
});
} }
function getMaterials(mtlPath, hasMaterialGroups, done) { function getMaterials(mtlPath, hasMaterialGroups) {
if (!hasMaterialGroups) { if (!hasMaterialGroups) {
done({});
return; return;
} }
if (defined(mtlPath)) { if (defined(mtlPath)) {
Material.parse(mtlPath, function(materials) { return Material.parse(mtlPath);
done(materials);
});
} else {
done({});
} }
} }
function getObjInfo(objFile, inputPath, done) { function getObjInfo(objFile, inputPath) {
var mtlPath; var mtlPath;
var materials;
var info;
var hasMaterialGroups = false; var hasMaterialGroups = false;
var hasPositions = false; var hasPositions = false;
var hasNormals = false; var hasNormals = false;
var hasUVs = false; var hasUVs = false;
return new Promise(function(resolve, reject) {
var stream = byline(fs.createReadStream(objFile, {encoding: 'utf8'})); var stream = byline(fs.createReadStream(objFile, {encoding: 'utf8'}));
stream.on('data', function(line) { stream.on('data', function (line) {
if (!defined(mtlPath)) { if (!defined(mtlPath)) {
var mtllibMatches = line.match(/^mtllib.*/gm); var mtllibMatches = line.match(/^mtllib.*/gm);
if (mtllibMatches !== null) { if (mtllibMatches !== null) {
var mtlFile = mtllibMatches[0].substring(7).trim(); var mtlFile = mtllibMatches[0].substring(7).trim();
mtlPath = mtlFile; mtlPath = mtlFile;
if (!path.isAbsolute(mtlPath)) { if (!path.isAbsolute(mtlPath)) {
mtlPath = path.join(inputPath, mtlFile); mtlPath = path.join(inputPath, mtlFile);
}
} }
} }
} if (!hasMaterialGroups) {
if (!hasMaterialGroups) { hasMaterialGroups = /^usemtl/gm.test(line);
hasMaterialGroups = /^usemtl/gm.test(line); }
} if (!hasPositions) {
if (!hasPositions) { hasPositions = /^v\s/gm.test(line);
hasPositions = /^v\s/gm.test(line); }
} if (!hasNormals) {
if (!hasNormals) { hasNormals = /^vn/gm.test(line);
hasNormals = /^vn/gm.test(line); }
} if (!hasUVs) {
if (!hasUVs) { hasUVs = /^vt/gm.test(line);
hasUVs = /^vt/gm.test(line); }
} });
});
stream.on('error', function(err) {
stream.on('end', function() { reject(err);
if (!hasPositions) { });
throw new Error('Could not process OBJ file, no positions.');
} stream.on('end', function () {
var info = { if (!hasPositions) {
hasNormals : hasNormals, reject(new Error('Could not process OBJ file, no positions.'));
hasUVs : hasUVs }
}; info = {
getMaterials(mtlPath, hasMaterialGroups, function(materials) { hasNormals: hasNormals,
getImages(inputPath, materials, function(images) { hasUVs: hasUVs
done(info, materials, images); };
}); resolve();
});
})
.then(function() {
return getMaterials(mtlPath, hasMaterialGroups);
})
.then(function(returnedMaterials) {
materials = returnedMaterials;
return getImages(inputPath, materials);
})
.then(function(images) {
return {
info : info,
materials : materials,
images : images
};
}); });
});
} }

View File

@ -27,6 +27,7 @@
}, },
"dependencies": { "dependencies": {
"async": "2.0.0-rc.6", "async": "2.0.0-rc.6",
"bluebird": "^3.4.1",
"byline": "4.2.1", "byline": "4.2.1",
"cesium": "1.23.0", "cesium": "1.23.0",
"fs-extra": "0.30.0", "fs-extra": "0.30.0",

View File

@ -1,4 +1,6 @@
'use strict'; 'use strict';
var Promise = require('bluebird');
var gltfPipeline = require('gltf-pipeline').gltfPipeline; var gltfPipeline = require('gltf-pipeline').gltfPipeline;
var path = require('path'); var path = require('path');
var convert = require('../../lib/convert'); var convert = require('../../lib/convert');
@ -8,14 +10,14 @@ var gltfFile = './specs/data/BoxTextured/BoxTextured.gltf';
describe('convert', function() { describe('convert', function() {
it('converts an obj to gltf', function(done) { it('converts an obj to gltf', function(done) {
var spy = spyOn(gltfPipeline, 'processJSONToDisk').and.callFake(function(gltf, gltfFile, options, callback) { var spy = spyOn(gltfPipeline, 'processJSONToDisk').and.callFake(function(gltf, outputPath, options, callback) {
callback(); return;
});
convert(objFile, gltfFile, {}, function() {
var args = spy.calls.first().args;
expect(args[0]).toBeDefined();
expect(path.normalize(args[1])).toEqual(path.normalize(gltfFile));
done();
}); });
expect(convert(objFile, gltfFile, {})
.then(function() {
var args = spy.calls.first().args;
expect(args[0]).toBeDefined();
expect(path.normalize(args[1])).toEqual(path.normalize(gltfFile));
}), done).toResolve();
}); });
}); });