var to let/const

This commit is contained in:
Sean Lilley 2019-02-05 20:59:09 -05:00
parent 50f4192afd
commit 075beb60d4
24 changed files with 1414 additions and 1550 deletions

View File

@ -1,6 +1,6 @@
{ {
"extends": "cesium/node", "extends": "cesium/node",
"rules": { "rules": {
"no-var": "off" "no-unused-vars": ["error", {"args": "none"}]
} }
} }

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="JavaScriptSettings"> <component name="JavaScriptSettings">
<option name="languageLevel" value="ES5" /> <option name="languageLevel" value="ES6" />
</component> </component>
</project> </project>

View File

@ -24,11 +24,11 @@ npm install -g obj2gltf
#### Converting an obj model to gltf: #### Converting an obj model to gltf:
```javascript ```javascript
var obj2gltf = require('obj2gltf'); const obj2gltf = require('obj2gltf');
var fs = require('fs'); const fs = require('fs');
obj2gltf('model.obj') obj2gltf('model.obj')
.then(function(gltf) { .then(function(gltf) {
var data = Buffer.from(JSON.stringify(gltf)); const data = Buffer.from(JSON.stringify(gltf));
fs.writeFileSync('model.gltf', data); fs.writeFileSync('model.gltf', data);
}); });
``` ```
@ -36,9 +36,9 @@ obj2gltf('model.obj')
#### Converting an obj model to glb #### Converting an obj model to glb
```javascript ```javascript
var obj2gltf = require('obj2gltf'); const obj2gltf = require('obj2gltf');
var fs = require('fs'); const fs = require('fs');
var options = { const options = {
binary : true binary : true
} }
obj2gltf('model.obj', options) obj2gltf('model.obj', options)

View File

@ -1,19 +1,19 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var fsExtra = require('fs-extra'); const fsExtra = require('fs-extra');
var path = require('path'); const path = require('path');
var yargs = require('yargs'); const yargs = require('yargs');
var obj2gltf = require('../lib/obj2gltf'); const obj2gltf = require('../lib/obj2gltf');
var defaultValue = Cesium.defaultValue; const defaultValue = Cesium.defaultValue;
var defined = Cesium.defined; const defined = Cesium.defined;
var defaults = obj2gltf.defaults; const defaults = obj2gltf.defaults;
var args = process.argv; const args = process.argv;
var argv = yargs const argv = yargs
.usage('Usage: node $0 -i inputPath -o outputPath') .usage('Usage: node $0 -i inputPath -o outputPath')
.example('node $0 -i ./specs/data/box/box.obj -o box.gltf') .example('node $0 -i ./specs/data/box/box.obj -o box.gltf')
.help('h') .help('h')
@ -135,18 +135,18 @@ if (defined(argv.metallicRoughnessOcclusionTexture) && defined(argv.specularGlos
process.exit(1); process.exit(1);
} }
var objPath = argv.input; const objPath = argv.input;
var gltfPath = argv.output; let gltfPath = argv.output;
var filename = defaultValue(gltfPath, objPath); const filename = defaultValue(gltfPath, objPath);
var name = path.basename(filename, path.extname(filename)); const name = path.basename(filename, path.extname(filename));
var outputDirectory = path.dirname(filename); const outputDirectory = path.dirname(filename);
var binary = argv.binary || path.extname(filename).toLowerCase() === '.glb'; const binary = argv.binary || path.extname(filename).toLowerCase() === '.glb';
var extension = binary ? '.glb' : '.gltf'; const extension = binary ? '.glb' : '.gltf';
gltfPath = path.join(outputDirectory, name + extension); gltfPath = path.join(outputDirectory, name + extension);
var overridingTextures = { const overridingTextures = {
metallicRoughnessOcclusionTexture : argv.metallicRoughnessOcclusionTexture, metallicRoughnessOcclusionTexture : argv.metallicRoughnessOcclusionTexture,
specularGlossinessTexture : argv.specularGlossinessTexture, specularGlossinessTexture : argv.specularGlossinessTexture,
occlusionTexture : argv.occlusionTexture, occlusionTexture : argv.occlusionTexture,
@ -156,7 +156,7 @@ var overridingTextures = {
alphaTexture : argv.alphaTexture alphaTexture : argv.alphaTexture
}; };
var options = { const options = {
binary : binary, binary : binary,
separate : argv.separate, separate : argv.separate,
separateTextures : argv.separateTextures, separateTextures : argv.separateTextures,
@ -178,7 +178,7 @@ obj2gltf(objPath, options)
// gltf is a glb buffer // gltf is a glb buffer
return fsExtra.outputFile(gltfPath, gltf); return fsExtra.outputFile(gltfPath, gltf);
} }
var jsonOptions = { const jsonOptions = {
spaces : 2 spaces : 2
}; };
return fsExtra.outputJson(gltfPath, gltf, jsonOptions); return fsExtra.outputJson(gltfPath, gltf, jsonOptions);

View File

@ -1,26 +1,26 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var Promise = require('bluebird'); const Promise = require('bluebird');
var child_process = require('child_process'); const child_process = require('child_process');
var fsExtra = require('fs-extra'); const fsExtra = require('fs-extra');
var gulp = require('gulp'); const gulp = require('gulp');
var Jasmine = require('jasmine'); const Jasmine = require('jasmine');
var JasmineSpecReporter = require('jasmine-spec-reporter').SpecReporter; const JasmineSpecReporter = require('jasmine-spec-reporter').SpecReporter;
var open = require('open'); const open = require('open');
var path = require('path'); const path = require('path');
var yargs = require('yargs'); const yargs = require('yargs');
var defined = Cesium.defined; const defined = Cesium.defined;
var argv = yargs.argv; const argv = yargs.argv;
// Add third-party node module binaries to the system path // Add third-party node module binaries to the system path
// since some tasks need to call them directly. // since some tasks need to call them directly.
var environmentSeparator = process.platform === 'win32' ? ';' : ':'; const environmentSeparator = process.platform === 'win32' ? ';' : ':';
var nodeBinaries = path.join(__dirname, 'node_modules', '.bin'); const nodeBinaries = path.join(__dirname, 'node_modules', '.bin');
process.env.PATH += environmentSeparator + nodeBinaries; process.env.PATH += environmentSeparator + nodeBinaries;
var specFiles = ['**/*.js', '!node_modules/**', '!coverage/**', '!doc/**', '!bin/**']; const specFiles = ['**/*.js', '!node_modules/**', '!coverage/**', '!doc/**', '!bin/**'];
module.exports = { module.exports = {
test: test, test: test,
@ -30,7 +30,7 @@ module.exports = {
}; };
function test(done) { function test(done) {
var jasmine = new Jasmine(); const jasmine = new Jasmine();
jasmine.loadConfigFile('specs/jasmine.json'); jasmine.loadConfigFile('specs/jasmine.json');
jasmine.addReporter(new JasmineSpecReporter({ jasmine.addReporter(new JasmineSpecReporter({
displaySuccessfulSpec: !defined(argv.suppressPassed) || !argv.suppressPassed displaySuccessfulSpec: !defined(argv.suppressPassed) || !argv.suppressPassed
@ -70,11 +70,11 @@ async function coverage() {
} }
function cloc() { function cloc() {
var cmdLine; let cmdLine;
var clocPath = path.join('node_modules', 'cloc', 'lib', 'cloc'); const clocPath = path.join('node_modules', 'cloc', 'lib', 'cloc');
//Run cloc on primary Source files only //Run cloc on primary Source files only
var source = new Promise(function(resolve, reject) { const source = new Promise(function(resolve, reject) {
cmdLine = 'perl ' + clocPath + ' --quiet --progress-rate=0' + cmdLine = 'perl ' + clocPath + ' --quiet --progress-rate=0' +
' lib/ bin/'; ' lib/ bin/';

View File

@ -1,13 +1,13 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var ComponentDatatype = Cesium.ComponentDatatype; const ComponentDatatype = Cesium.ComponentDatatype;
module.exports = ArrayStorage; module.exports = ArrayStorage;
var initialLength = 1024; // 2^10 const initialLength = 1024; // 2^10
var doublingThreshold = 33554432; // 2^25 (~134 MB for a Float32Array) const doublingThreshold = 33554432; // 2^25 (~134 MB for a Float32Array)
var fixedExpansionLength = 33554432; // 2^25 (~134 MB for a Float32Array) const fixedExpansionLength = 33554432; // 2^25 (~134 MB for a Float32Array)
/** /**
* Provides expandable typed array storage for geometry data. This is preferable to JS arrays which are * Provides expandable typed array storage for geometry data. This is preferable to JS arrays which are
@ -24,14 +24,14 @@ function ArrayStorage(componentDatatype) {
} }
function resize(storage, length) { function resize(storage, length) {
var typedArray = ComponentDatatype.createTypedArray(storage.componentDatatype, length); const typedArray = ComponentDatatype.createTypedArray(storage.componentDatatype, length);
typedArray.set(storage.typedArray); typedArray.set(storage.typedArray);
storage.typedArray = typedArray; storage.typedArray = typedArray;
} }
ArrayStorage.prototype.push = function(value) { ArrayStorage.prototype.push = function(value) {
var length = this.length; const length = this.length;
var typedArrayLength = this.typedArray.length; const typedArrayLength = this.typedArray.length;
if (length === 0) { if (length === 0) {
resize(this, initialLength); resize(this, initialLength);
@ -50,51 +50,51 @@ ArrayStorage.prototype.get = function(index) {
return this.typedArray[index]; return this.typedArray[index];
}; };
var sizeOfUint16 = 2; const sizeOfUint16 = 2;
var sizeOfUint32 = 4; const sizeOfUint32 = 4;
var sizeOfFloat = 4; const sizeOfFloat = 4;
ArrayStorage.prototype.toUint16Buffer = function() { ArrayStorage.prototype.toUint16Buffer = function() {
var length = this.length; const length = this.length;
var typedArray = this.typedArray; const typedArray = this.typedArray;
var paddedLength = length + ((length % 2 === 0) ? 0 : 1); // Round to next multiple of 2 const paddedLength = length + ((length % 2 === 0) ? 0 : 1); // Round to next multiple of 2
var buffer = Buffer.alloc(paddedLength * sizeOfUint16); const buffer = Buffer.alloc(paddedLength * sizeOfUint16);
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
buffer.writeUInt16LE(typedArray[i], i * sizeOfUint16); buffer.writeUInt16LE(typedArray[i], i * sizeOfUint16);
} }
return buffer; return buffer;
}; };
ArrayStorage.prototype.toUint32Buffer = function() { ArrayStorage.prototype.toUint32Buffer = function() {
var length = this.length; const length = this.length;
var typedArray = this.typedArray; const typedArray = this.typedArray;
var buffer = Buffer.alloc(length * sizeOfUint32); const buffer = Buffer.alloc(length * sizeOfUint32);
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
buffer.writeUInt32LE(typedArray[i], i * sizeOfUint32); buffer.writeUInt32LE(typedArray[i], i * sizeOfUint32);
} }
return buffer; return buffer;
}; };
ArrayStorage.prototype.toFloatBuffer = function() { ArrayStorage.prototype.toFloatBuffer = function() {
var length = this.length; const length = this.length;
var typedArray = this.typedArray; const typedArray = this.typedArray;
var buffer = Buffer.alloc(length * sizeOfFloat); const buffer = Buffer.alloc(length * sizeOfFloat);
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
buffer.writeFloatLE(typedArray[i], i * sizeOfFloat); buffer.writeFloatLE(typedArray[i], i * sizeOfFloat);
} }
return buffer; return buffer;
}; };
ArrayStorage.prototype.getMinMax = function(components) { ArrayStorage.prototype.getMinMax = function(components) {
var length = this.length; const length = this.length;
var typedArray = this.typedArray; const typedArray = this.typedArray;
var count = length / components; const count = length / components;
var min = new Array(components).fill(Number.POSITIVE_INFINITY); const min = new Array(components).fill(Number.POSITIVE_INFINITY);
var max = new Array(components).fill(Number.NEGATIVE_INFINITY); const max = new Array(components).fill(Number.NEGATIVE_INFINITY);
for (var i = 0; i < count; ++i) { for (let i = 0; i < count; ++i) {
for (var j = 0; j < components; ++j) { for (let j = 0; j < components; ++j) {
var index = i * components + j; const index = i * components + j;
var value = typedArray[index]; const value = typedArray[index];
min[j] = Math.min(min[j], value); min[j] = Math.min(min[j], value);
max[j] = Math.max(max[j], value); max[j] = Math.max(max[j], value);
} }

View File

@ -1,12 +1,12 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var getBufferPadded = require('./getBufferPadded'); const getBufferPadded = require('./getBufferPadded');
var getDefaultMaterial = require('./loadMtl').getDefaultMaterial; const getDefaultMaterial = require('./loadMtl').getDefaultMaterial;
var Texture = require('./Texture'); const Texture = require('./Texture');
var defaultValue = Cesium.defaultValue; const defaultValue = Cesium.defaultValue;
var defined = Cesium.defined; const defined = Cesium.defined;
var WebGLConstants = Cesium.WebGLConstants; const WebGLConstants = Cesium.WebGLConstants;
module.exports = createGltf; module.exports = createGltf;
@ -20,14 +20,14 @@ module.exports = createGltf;
* @private * @private
*/ */
function createGltf(objData, options) { function createGltf(objData, options) {
var nodes = objData.nodes; const nodes = objData.nodes;
var materials = objData.materials; let materials = objData.materials;
var name = objData.name; const name = objData.name;
// Split materials used by primitives with different types of attributes // Split materials used by primitives with different types of attributes
materials = splitIncompatibleMaterials(nodes, materials, options); materials = splitIncompatibleMaterials(nodes, materials, options);
var gltf = { const gltf = {
accessors : [], accessors : [],
asset : {}, asset : {},
buffers : [], buffers : [],
@ -53,7 +53,7 @@ function createGltf(objData, options) {
nodes : [] nodes : []
}); });
var bufferState = { const bufferState = {
positionBuffers : [], positionBuffers : [],
normalBuffers : [], normalBuffers : [],
uvBuffers : [], uvBuffers : [],
@ -64,24 +64,23 @@ function createGltf(objData, options) {
indexAccessors : [] indexAccessors : []
}; };
var uint32Indices = requiresUint32Indices(nodes); const uint32Indices = requiresUint32Indices(nodes);
var nodesLength = nodes.length; const nodesLength = nodes.length;
for (var i = 0; i < nodesLength; ++i) { for (let i = 0; i < nodesLength; ++i) {
var node = nodes[i]; const node = nodes[i];
var meshes = node.meshes; const meshes = node.meshes;
var meshesLength = meshes.length; const meshesLength = meshes.length;
var meshIndex;
if (meshesLength === 1) { if (meshesLength === 1) {
meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, meshes[0], options); const meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, meshes[0], options);
addNode(gltf, node.name, meshIndex, undefined); addNode(gltf, node.name, meshIndex, undefined);
} else { } else {
// Add meshes as child nodes // Add meshes as child nodes
var parentIndex = addNode(gltf, node.name); const parentIndex = addNode(gltf, node.name);
for (var j = 0; j < meshesLength; ++j) { for (let j = 0; j < meshesLength; ++j) {
var mesh = meshes[j]; const mesh = meshes[j];
meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, mesh, options); const meshIndex = addMesh(gltf, materials, bufferState, uint32Indices, mesh, options);
addNode(gltf, mesh.name, meshIndex, parentIndex); addNode(gltf, mesh.name, meshIndex, parentIndex);
} }
} }
@ -112,16 +111,16 @@ function createGltf(objData, options) {
} }
function addBufferView(gltf, buffers, accessors, byteStride, target) { function addBufferView(gltf, buffers, accessors, byteStride, target) {
var length = buffers.length; const length = buffers.length;
if (length === 0) { if (length === 0) {
return; return;
} }
var bufferViewIndex = gltf.bufferViews.length; const bufferViewIndex = gltf.bufferViews.length;
var previousBufferView = gltf.bufferViews[bufferViewIndex - 1]; const previousBufferView = gltf.bufferViews[bufferViewIndex - 1];
var byteOffset = defined(previousBufferView) ? previousBufferView.byteOffset + previousBufferView.byteLength : 0; const byteOffset = defined(previousBufferView) ? previousBufferView.byteOffset + previousBufferView.byteLength : 0;
var byteLength = 0; let byteLength = 0;
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
var accessor = gltf.accessors[accessors[i]]; const accessor = gltf.accessors[accessors[i]];
accessor.bufferView = bufferViewIndex; accessor.bufferView = bufferViewIndex;
accessor.byteOffset = byteLength; accessor.byteOffset = byteLength;
byteLength += buffers[i].length; byteLength += buffers[i].length;
@ -142,9 +141,9 @@ function addBuffers(gltf, bufferState, name) {
addBufferView(gltf, bufferState.uvBuffers, bufferState.uvAccessors, 8, WebGLConstants.ARRAY_BUFFER); addBufferView(gltf, bufferState.uvBuffers, bufferState.uvAccessors, 8, WebGLConstants.ARRAY_BUFFER);
addBufferView(gltf, bufferState.indexBuffers, bufferState.indexAccessors, undefined, WebGLConstants.ELEMENT_ARRAY_BUFFER); addBufferView(gltf, bufferState.indexBuffers, bufferState.indexAccessors, undefined, WebGLConstants.ELEMENT_ARRAY_BUFFER);
var buffers = []; let buffers = [];
buffers = buffers.concat(bufferState.positionBuffers, bufferState.normalBuffers, bufferState.uvBuffers, bufferState.indexBuffers); buffers = buffers.concat(bufferState.positionBuffers, bufferState.normalBuffers, bufferState.uvBuffers, bufferState.indexBuffers);
var buffer = getBufferPadded(Buffer.concat(buffers)); const buffer = getBufferPadded(Buffer.concat(buffers));
gltf.buffers.push({ gltf.buffers.push({
name : name, name : name,
@ -158,10 +157,10 @@ function addBuffers(gltf, bufferState, name) {
} }
function addTexture(gltf, texture) { function addTexture(gltf, texture) {
var imageName = texture.name; const imageName = texture.name;
var textureName = texture.name; const textureName = texture.name;
var imageIndex = gltf.images.length; const imageIndex = gltf.images.length;
var textureIndex = gltf.textures.length; const textureIndex = gltf.textures.length;
gltf.images.push({ gltf.images.push({
name : imageName, name : imageName,
@ -180,11 +179,11 @@ function addTexture(gltf, texture) {
} }
function getTexture(gltf, texture) { function getTexture(gltf, texture) {
var textureIndex; let textureIndex;
var name = texture.name; const name = texture.name;
var textures = gltf.textures; const textures = gltf.textures;
var length = textures.length; const length = textures.length;
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
if (textures[i].name === name) { if (textures[i].name === name) {
textureIndex = i; textureIndex = i;
break; break;
@ -209,15 +208,15 @@ function cloneMaterial(material, removeTextures) {
} }
return material; return material;
} else if (Array.isArray(material)) { } else if (Array.isArray(material)) {
var length = material.length; const length = material.length;
var clonedArray = new Array(length); const clonedArray = new Array(length);
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
clonedArray[i] = cloneMaterial(material[i], removeTextures); clonedArray[i] = cloneMaterial(material[i], removeTextures);
} }
return clonedArray; return clonedArray;
} }
var clonedObject = {}; const clonedObject = {};
for (var name in material) { for (const name in material) {
if (material.hasOwnProperty(name)) { if (material.hasOwnProperty(name)) {
clonedObject[name] = cloneMaterial(material[name], removeTextures); clonedObject[name] = cloneMaterial(material[name], removeTextures);
} }
@ -226,9 +225,9 @@ function cloneMaterial(material, removeTextures) {
} }
function resolveTextures(gltf, material) { function resolveTextures(gltf, material) {
for (var name in material) { for (const name in material) {
if (material.hasOwnProperty(name)) { if (material.hasOwnProperty(name)) {
var property = material[name]; const property = material[name];
if (property instanceof Texture) { if (property instanceof Texture) {
material[name] = getTexture(gltf, property); material[name] = getTexture(gltf, property);
} else if (!Array.isArray(property) && (typeof property === 'object')) { } else if (!Array.isArray(property) && (typeof property === 'object')) {
@ -240,7 +239,7 @@ function resolveTextures(gltf, material) {
function addGltfMaterial(gltf, material, options) { function addGltfMaterial(gltf, material, options) {
resolveTextures(gltf, material); resolveTextures(gltf, material);
var materialIndex = gltf.materials.length; const materialIndex = gltf.materials.length;
if (options.unlit) { if (options.unlit) {
if (!defined(material.extensions)) { if (!defined(material.extensions)) {
material.extensions = {}; material.extensions = {};
@ -252,8 +251,8 @@ function addGltfMaterial(gltf, material, options) {
} }
function getMaterialByName(materials, materialName) { function getMaterialByName(materials, materialName) {
var materialsLength = materials.length; const materialsLength = materials.length;
for (var i = 0; i < materialsLength; ++i) { for (let i = 0; i < materialsLength; ++i) {
if (materials[i].name === materialName) { if (materials[i].name === materialName) {
return materials[i]; return materials[i];
} }
@ -261,8 +260,8 @@ function getMaterialByName(materials, materialName) {
} }
function getMaterialIndex(materials, materialName) { function getMaterialIndex(materials, materialName) {
var materialsLength = materials.length; const materialsLength = materials.length;
for (var i = 0; i < materialsLength; ++i) { for (let i = 0; i < materialsLength; ++i) {
if (materials[i].name === materialName) { if (materials[i].name === materialName) {
return i; return i;
} }
@ -270,8 +269,8 @@ function getMaterialIndex(materials, materialName) {
} }
function getOrCreateGltfMaterial(gltf, materials, materialName, options) { function getOrCreateGltfMaterial(gltf, materials, materialName, options) {
var material = getMaterialByName(materials, materialName); const material = getMaterialByName(materials, materialName);
var materialIndex = getMaterialIndex(gltf.materials, materialName); let materialIndex = getMaterialIndex(gltf.materials, materialName);
if (!defined(materialIndex)) { if (!defined(materialIndex)) {
materialIndex = addGltfMaterial(gltf, material, options); materialIndex = addGltfMaterial(gltf, material, options);
@ -286,8 +285,8 @@ function primitiveInfoMatch(a, b) {
} }
function getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfoByMaterial) { function getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfoByMaterial) {
var splitMaterialName = originalMaterialName; let splitMaterialName = originalMaterialName;
var suffix = 2; let suffix = 2;
while (defined(primitiveInfoByMaterial[splitMaterialName])) { while (defined(primitiveInfoByMaterial[splitMaterialName])) {
if (primitiveInfoMatch(primitiveInfo, primitiveInfoByMaterial[splitMaterialName])) { if (primitiveInfoMatch(primitiveInfo, primitiveInfoByMaterial[splitMaterialName])) {
break; break;
@ -298,34 +297,34 @@ function getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfo
} }
function splitIncompatibleMaterials(nodes, materials, options) { function splitIncompatibleMaterials(nodes, materials, options) {
var splitMaterials = []; const splitMaterials = [];
var primitiveInfoByMaterial = {}; const primitiveInfoByMaterial = {};
var nodesLength = nodes.length; const nodesLength = nodes.length;
for (var i = 0; i < nodesLength; ++i) { for (let i = 0; i < nodesLength; ++i) {
var meshes = nodes[i].meshes; const meshes = nodes[i].meshes;
var meshesLength = meshes.length; const meshesLength = meshes.length;
for (var j = 0; j < meshesLength; ++j) { for (let j = 0; j < meshesLength; ++j) {
var primitives = meshes[j].primitives; const primitives = meshes[j].primitives;
var primitivesLength = primitives.length; const primitivesLength = primitives.length;
for (var k = 0; k < primitivesLength; ++k) { for (let k = 0; k < primitivesLength; ++k) {
var primitive = primitives[k]; const primitive = primitives[k];
var hasUvs = primitive.uvs.length > 0; const hasUvs = primitive.uvs.length > 0;
var hasNormals = primitive.normals.length > 0; const hasNormals = primitive.normals.length > 0;
var primitiveInfo = { const primitiveInfo = {
hasUvs : hasUvs, hasUvs : hasUvs,
hasNormals : hasNormals hasNormals : hasNormals
}; };
var originalMaterialName = defaultValue(primitive.material, 'default'); const originalMaterialName = defaultValue(primitive.material, 'default');
var splitMaterialName = getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfoByMaterial); const splitMaterialName = getSplitMaterialName(originalMaterialName, primitiveInfo, primitiveInfoByMaterial);
primitive.material = splitMaterialName; primitive.material = splitMaterialName;
primitiveInfoByMaterial[splitMaterialName] = primitiveInfo; primitiveInfoByMaterial[splitMaterialName] = primitiveInfo;
var splitMaterial = getMaterialByName(splitMaterials, splitMaterialName); let splitMaterial = getMaterialByName(splitMaterials, splitMaterialName);
if (defined(splitMaterial)) { if (defined(splitMaterial)) {
continue; continue;
} }
var originalMaterial = getMaterialByName(materials, originalMaterialName); const originalMaterial = getMaterialByName(materials, originalMaterialName);
if (defined(originalMaterial)) { if (defined(originalMaterial)) {
splitMaterial = cloneMaterial(originalMaterial, !hasUvs); splitMaterial = cloneMaterial(originalMaterial, !hasUvs);
} else { } else {
@ -340,11 +339,11 @@ function splitIncompatibleMaterials(nodes, materials, options) {
} }
function addVertexAttribute(gltf, array, components, name) { function addVertexAttribute(gltf, array, components, name) {
var count = array.length / components; const count = array.length / components;
var minMax = array.getMinMax(components); const minMax = array.getMinMax(components);
var type = (components === 3 ? 'VEC3' : 'VEC2'); const type = (components === 3 ? 'VEC3' : 'VEC2');
var accessor = { const accessor = {
name : name, name : name,
componentType : WebGLConstants.FLOAT, componentType : WebGLConstants.FLOAT,
count : count, count : count,
@ -353,17 +352,17 @@ function addVertexAttribute(gltf, array, components, name) {
type : type type : type
}; };
var accessorIndex = gltf.accessors.length; const accessorIndex = gltf.accessors.length;
gltf.accessors.push(accessor); gltf.accessors.push(accessor);
return accessorIndex; return accessorIndex;
} }
function addIndexArray(gltf, array, uint32Indices, name) { function addIndexArray(gltf, array, uint32Indices, name) {
var componentType = uint32Indices ? WebGLConstants.UNSIGNED_INT : WebGLConstants.UNSIGNED_SHORT; const componentType = uint32Indices ? WebGLConstants.UNSIGNED_INT : WebGLConstants.UNSIGNED_SHORT;
var count = array.length; const count = array.length;
var minMax = array.getMinMax(1); const minMax = array.getMinMax(1);
var accessor = { const accessor = {
name : name, name : name,
componentType : componentType, componentType : componentType,
count : count, count : count,
@ -372,22 +371,22 @@ function addIndexArray(gltf, array, uint32Indices, name) {
type : 'SCALAR' type : 'SCALAR'
}; };
var accessorIndex = gltf.accessors.length; const accessorIndex = gltf.accessors.length;
gltf.accessors.push(accessor); gltf.accessors.push(accessor);
return accessorIndex; return accessorIndex;
} }
function requiresUint32Indices(nodes) { function requiresUint32Indices(nodes) {
var nodesLength = nodes.length; const nodesLength = nodes.length;
for (var i = 0; i < nodesLength; ++i) { for (let i = 0; i < nodesLength; ++i) {
var meshes = nodes[i].meshes; const meshes = nodes[i].meshes;
var meshesLength = meshes.length; const meshesLength = meshes.length;
for (var j = 0; j < meshesLength; ++j) { for (let j = 0; j < meshesLength; ++j) {
var primitives = meshes[j].primitives; const primitives = meshes[j].primitives;
var primitivesLength = primitives.length; const primitivesLength = primitives.length;
for (var k = 0; k < primitivesLength; ++k) { for (let k = 0; k < primitivesLength; ++k) {
// Reserve the 65535 index for primitive restart // Reserve the 65535 index for primitive restart
var vertexCount = primitives[k].positions.length / 3; const vertexCount = primitives[k].positions.length / 3;
if (vertexCount > 65534) { if (vertexCount > 65534) {
return true; return true;
} }
@ -398,33 +397,32 @@ function requiresUint32Indices(nodes) {
} }
function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitive, index, options) { function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitive, index, options) {
var hasPositions = primitive.positions.length > 0; const hasPositions = primitive.positions.length > 0;
var hasNormals = primitive.normals.length > 0; const hasNormals = primitive.normals.length > 0;
var hasUVs = primitive.uvs.length > 0; const hasUVs = primitive.uvs.length > 0;
var accessorIndex; const attributes = {};
var attributes = {};
if (hasPositions) { if (hasPositions) {
accessorIndex = addVertexAttribute(gltf, primitive.positions, 3, mesh.name + '_' + index + '_positions'); const accessorIndex = addVertexAttribute(gltf, primitive.positions, 3, mesh.name + '_' + index + '_positions');
attributes.POSITION = accessorIndex; attributes.POSITION = accessorIndex;
bufferState.positionBuffers.push(primitive.positions.toFloatBuffer()); bufferState.positionBuffers.push(primitive.positions.toFloatBuffer());
bufferState.positionAccessors.push(accessorIndex); bufferState.positionAccessors.push(accessorIndex);
} }
if (hasNormals) { if (hasNormals) {
accessorIndex = addVertexAttribute(gltf, primitive.normals, 3, mesh.name + '_' + index + '_normals'); const accessorIndex = addVertexAttribute(gltf, primitive.normals, 3, mesh.name + '_' + index + '_normals');
attributes.NORMAL = accessorIndex; attributes.NORMAL = accessorIndex;
bufferState.normalBuffers.push(primitive.normals.toFloatBuffer()); bufferState.normalBuffers.push(primitive.normals.toFloatBuffer());
bufferState.normalAccessors.push(accessorIndex); bufferState.normalAccessors.push(accessorIndex);
} }
if (hasUVs) { if (hasUVs) {
accessorIndex = addVertexAttribute(gltf, primitive.uvs, 2, mesh.name + '_' + index + '_texcoords'); const accessorIndex = addVertexAttribute(gltf, primitive.uvs, 2, mesh.name + '_' + index + '_texcoords');
attributes.TEXCOORD_0 = accessorIndex; attributes.TEXCOORD_0 = accessorIndex;
bufferState.uvBuffers.push(primitive.uvs.toFloatBuffer()); bufferState.uvBuffers.push(primitive.uvs.toFloatBuffer());
bufferState.uvAccessors.push(accessorIndex); bufferState.uvAccessors.push(accessorIndex);
} }
var indexAccessorIndex = addIndexArray(gltf, primitive.indices, uint32Indices, mesh.name + '_' + index + '_indices'); const indexAccessorIndex = addIndexArray(gltf, primitive.indices, uint32Indices, mesh.name + '_' + index + '_indices');
var indexBuffer = uint32Indices ? primitive.indices.toUint32Buffer() : primitive.indices.toUint16Buffer(); const indexBuffer = uint32Indices ? primitive.indices.toUint32Buffer() : primitive.indices.toUint16Buffer();
bufferState.indexBuffers.push(indexBuffer); bufferState.indexBuffers.push(indexBuffer);
bufferState.indexAccessors.push(indexAccessorIndex); bufferState.indexAccessors.push(indexAccessorIndex);
@ -434,7 +432,7 @@ function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primiti
primitive.uvs = undefined; primitive.uvs = undefined;
primitive.indices = undefined; primitive.indices = undefined;
var materialIndex = getOrCreateGltfMaterial(gltf, materials, primitive.material, options); const materialIndex = getOrCreateGltfMaterial(gltf, materials, primitive.material, options);
return { return {
attributes : attributes, attributes : attributes,
@ -445,34 +443,34 @@ function addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primiti
} }
function addMesh(gltf, materials, bufferState, uint32Indices, mesh, options) { function addMesh(gltf, materials, bufferState, uint32Indices, mesh, options) {
var gltfPrimitives = []; const gltfPrimitives = [];
var primitives = mesh.primitives; const primitives = mesh.primitives;
var primitivesLength = primitives.length; const primitivesLength = primitives.length;
for (var i = 0; i < primitivesLength; ++i) { for (let i = 0; i < primitivesLength; ++i) {
gltfPrimitives.push(addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitives[i], i, options)); gltfPrimitives.push(addPrimitive(gltf, materials, bufferState, uint32Indices, mesh, primitives[i], i, options));
} }
var gltfMesh = { const gltfMesh = {
name : mesh.name, name : mesh.name,
primitives : gltfPrimitives primitives : gltfPrimitives
}; };
var meshIndex = gltf.meshes.length; const meshIndex = gltf.meshes.length;
gltf.meshes.push(gltfMesh); gltf.meshes.push(gltfMesh);
return meshIndex; return meshIndex;
} }
function addNode(gltf, name, meshIndex, parentIndex) { function addNode(gltf, name, meshIndex, parentIndex) {
var node = { const node = {
name : name, name : name,
mesh : meshIndex mesh : meshIndex
}; };
var nodeIndex = gltf.nodes.length; const nodeIndex = gltf.nodes.length;
gltf.nodes.push(node); gltf.nodes.push(node);
if (defined(parentIndex)) { if (defined(parentIndex)) {
var parentNode = gltf.nodes[parentIndex]; const parentNode = gltf.nodes[parentIndex];
if (!defined(parentNode.children)) { if (!defined(parentNode.children)) {
parentNode.children = []; parentNode.children = [];
} }

View File

@ -10,13 +10,13 @@ module.exports = getBufferPadded;
* @private * @private
*/ */
function getBufferPadded(buffer) { function getBufferPadded(buffer) {
var boundary = 4; const boundary = 4;
var byteLength = buffer.length; const byteLength = buffer.length;
var remainder = byteLength % boundary; const remainder = byteLength % boundary;
if (remainder === 0) { if (remainder === 0) {
return buffer; return buffer;
} }
var padding = (remainder === 0) ? 0 : boundary - remainder; const padding = (remainder === 0) ? 0 : boundary - remainder;
var emptyBuffer = Buffer.alloc(padding); const emptyBuffer = Buffer.alloc(padding);
return Buffer.concat([buffer, emptyBuffer]); return Buffer.concat([buffer, emptyBuffer]);
} }

View File

@ -13,14 +13,14 @@ module.exports = getJsonBufferPadded;
* @private * @private
*/ */
function getJsonBufferPadded(json) { function getJsonBufferPadded(json) {
var string = JSON.stringify(json); let string = JSON.stringify(json);
var boundary = 4; const boundary = 4;
var byteLength = Buffer.byteLength(string); const byteLength = Buffer.byteLength(string);
var remainder = byteLength % boundary; const remainder = byteLength % boundary;
var padding = (remainder === 0) ? 0 : boundary - remainder; const padding = (remainder === 0) ? 0 : boundary - remainder;
var whitespace = ''; let whitespace = '';
for (var i = 0; i < padding; ++i) { for (let i = 0; i < padding; ++i) {
whitespace += ' '; whitespace += ' ';
} }
string += whitespace; string += whitespace;

View File

@ -1,8 +1,8 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var getJsonBufferPadded = require('./getJsonBufferPadded'); const getJsonBufferPadded = require('./getJsonBufferPadded');
var defined = Cesium.defined; const defined = Cesium.defined;
module.exports = gltfToGlb; module.exports = gltfToGlb;
@ -18,20 +18,20 @@ module.exports = gltfToGlb;
* @private * @private
*/ */
function gltfToGlb(gltf, binaryBuffer) { function gltfToGlb(gltf, binaryBuffer) {
var buffer = gltf.buffers[0]; const buffer = gltf.buffers[0];
if (defined(buffer.uri)) { if (defined(buffer.uri)) {
binaryBuffer = Buffer.alloc(0); binaryBuffer = Buffer.alloc(0);
} }
// Create padded binary scene string // Create padded binary scene string
var jsonBuffer = getJsonBufferPadded(gltf); const jsonBuffer = getJsonBufferPadded(gltf);
// Allocate buffer (Global header) + (JSON chunk header) + (JSON chunk) + (Binary chunk header) + (Binary chunk) // Allocate buffer (Global header) + (JSON chunk header) + (JSON chunk) + (Binary chunk header) + (Binary chunk)
var glbLength = 12 + 8 + jsonBuffer.length + 8 + binaryBuffer.length; const glbLength = 12 + 8 + jsonBuffer.length + 8 + binaryBuffer.length;
var glb = Buffer.alloc(glbLength); const glb = Buffer.alloc(glbLength);
// Write binary glTF header (magic, version, length) // Write binary glTF header (magic, version, length)
var byteOffset = 0; let byteOffset = 0;
glb.writeUInt32LE(0x46546C67, byteOffset); glb.writeUInt32LE(0x46546C67, byteOffset);
byteOffset += 4; byteOffset += 4;
glb.writeUInt32LE(2, byteOffset); glb.writeUInt32LE(2, byteOffset);

View File

@ -1,16 +1,16 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var path = require('path'); const path = require('path');
var Promise = require('bluebird'); const Promise = require('bluebird');
var loadTexture = require('./loadTexture'); const loadTexture = require('./loadTexture');
var outsideDirectory = require('./outsideDirectory'); const outsideDirectory = require('./outsideDirectory');
var readLines = require('./readLines'); const readLines = require('./readLines');
var Texture = require('./Texture'); const Texture = require('./Texture');
var CesiumMath = Cesium.Math; const CesiumMath = Cesium.Math;
var combine = Cesium.combine; const combine = Cesium.combine;
var defaultValue = Cesium.defaultValue; const defaultValue = Cesium.defaultValue;
var defined = Cesium.defined; const defined = Cesium.defined;
module.exports = loadMtl; module.exports = loadMtl;
@ -30,39 +30,39 @@ module.exports = loadMtl;
* @private * @private
*/ */
function loadMtl(mtlPath, options) { function loadMtl(mtlPath, options) {
var material; let material;
var values; let values;
var value; let value;
var mtlDirectory = path.dirname(mtlPath); const mtlDirectory = path.dirname(mtlPath);
var materials = []; const materials = [];
var texturePromiseMap = {}; // Maps texture paths to load promises so that no texture is loaded twice const texturePromiseMap = {}; // Maps texture paths to load promises so that no texture is loaded twice
var texturePromises = []; const texturePromises = [];
var overridingTextures = options.overridingTextures; const overridingTextures = options.overridingTextures;
var overridingSpecularTexture = defaultValue(overridingTextures.metallicRoughnessOcclusionTexture, overridingTextures.specularGlossinessTexture); const overridingSpecularTexture = defaultValue(overridingTextures.metallicRoughnessOcclusionTexture, overridingTextures.specularGlossinessTexture);
var overridingSpecularShininessTexture = defaultValue(overridingTextures.metallicRoughnessOcclusionTexture, overridingTextures.specularGlossinessTexture); const overridingSpecularShininessTexture = defaultValue(overridingTextures.metallicRoughnessOcclusionTexture, overridingTextures.specularGlossinessTexture);
var overridingAmbientTexture = defaultValue(overridingTextures.metallicRoughnessOcclusionTexture, overridingTextures.occlusionTexture); const overridingAmbientTexture = defaultValue(overridingTextures.metallicRoughnessOcclusionTexture, overridingTextures.occlusionTexture);
var overridingNormalTexture = overridingTextures.normalTexture; const overridingNormalTexture = overridingTextures.normalTexture;
var overridingDiffuseTexture = overridingTextures.baseColorTexture; const overridingDiffuseTexture = overridingTextures.baseColorTexture;
var overridingEmissiveTexture = overridingTextures.emissiveTexture; const overridingEmissiveTexture = overridingTextures.emissiveTexture;
var overridingAlphaTexture = overridingTextures.alphaTexture; const overridingAlphaTexture = overridingTextures.alphaTexture;
// Textures that are packed into PBR textures need to be decoded first // Textures that are packed into PBR textures need to be decoded first
var decodeOptions = { const decodeOptions = {
decode : true decode : true
}; };
var diffuseTextureOptions = { const diffuseTextureOptions = {
checkTransparency : options.checkTransparency checkTransparency : options.checkTransparency
}; };
var ambientTextureOptions = defined(overridingAmbientTexture) ? undefined : (options.packOcclusion ? decodeOptions : undefined); const ambientTextureOptions = defined(overridingAmbientTexture) ? undefined : (options.packOcclusion ? decodeOptions : undefined);
var specularTextureOptions = defined(overridingSpecularTexture) ? undefined : decodeOptions; const specularTextureOptions = defined(overridingSpecularTexture) ? undefined : decodeOptions;
var specularShinessTextureOptions = defined(overridingSpecularShininessTexture) ? undefined : decodeOptions; const specularShinessTextureOptions = defined(overridingSpecularShininessTexture) ? undefined : decodeOptions;
var emissiveTextureOptions; const emissiveTextureOptions = undefined;
var normalTextureOptions; const normalTextureOptions = undefined;
var alphaTextureOptions = { const alphaTextureOptions = {
decode : true decode : true
}; };
@ -83,7 +83,7 @@ function loadMtl(mtlPath, options) {
function normalizeTexturePath(texturePath, mtlDirectory) { function normalizeTexturePath(texturePath, mtlDirectory) {
// Removes texture options from texture name // Removes texture options from texture name
// Assumes no spaces in texture name // Assumes no spaces in texture name
var re = /-(bm|t|s|o|blendu|blendv|boost|mm|texres|clamp|imfchan|type)/; const re = /-(bm|t|s|o|blendu|blendv|boost|mm|texres|clamp|imfchan|type)/;
if (re.test(texturePath)) { if (re.test(texturePath)) {
texturePath = texturePath.split(/\s+/).pop(); texturePath = texturePath.split(/\s+/).pop();
} }
@ -94,7 +94,7 @@ function loadMtl(mtlPath, options) {
function parseLine(line) { function parseLine(line) {
line = line.trim(); line = line.trim();
if (/^newmtl /i.test(line)) { if (/^newmtl /i.test(line)) {
var name = line.substring(7).trim(); const name = line.substring(7).trim();
createMaterial(name); createMaterial(name);
} else if (/^Ka /i.test(line)) { } else if (/^Ka /i.test(line)) {
values = line.substring(3).trim().split(' '); values = line.substring(3).trim().split(' ');
@ -170,7 +170,7 @@ function loadMtl(mtlPath, options) {
function loadMaterialTextures(material) { function loadMaterialTextures(material) {
// If an alpha texture is present the diffuse texture needs to be decoded so they can be packed together // If an alpha texture is present the diffuse texture needs to be decoded so they can be packed together
var diffuseAlphaTextureOptions = defined(material.alphaTexture) ? alphaTextureOptions : diffuseTextureOptions; const diffuseAlphaTextureOptions = defined(material.alphaTexture) ? alphaTextureOptions : diffuseTextureOptions;
if (material.diffuseTexture === material.ambientTexture) { if (material.diffuseTexture === material.ambientTexture) {
// OBJ models are often exported with the same texture in the diffuse and ambient slots but this is typically not desirable, particularly // OBJ models are often exported with the same texture in the diffuse and ambient slots but this is typically not desirable, particularly
@ -189,8 +189,8 @@ function loadMtl(mtlPath, options) {
return readLines(mtlPath, parseLine) return readLines(mtlPath, parseLine)
.then(function() { .then(function() {
var length = materials.length; const length = materials.length;
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
loadMaterialTextures(materials[i]); loadMaterialTextures(materials[i]);
} }
return Promise.all(texturePromises); return Promise.all(texturePromises);
@ -232,14 +232,14 @@ loadMtl._createMaterial = function(materialOptions, options) {
}; };
function loadMaterialTexture(material, name, textureOptions, mtlDirectory, texturePromiseMap, texturePromises, options) { function loadMaterialTexture(material, name, textureOptions, mtlDirectory, texturePromiseMap, texturePromises, options) {
var texturePath = material[name]; const texturePath = material[name];
if (!defined(texturePath)) { if (!defined(texturePath)) {
return; return;
} }
var texturePromise = texturePromiseMap[texturePath]; let texturePromise = texturePromiseMap[texturePath];
if (!defined(texturePromise)) { if (!defined(texturePromise)) {
var shallowPath = path.join(mtlDirectory, path.basename(texturePath)); const shallowPath = path.join(mtlDirectory, path.basename(texturePath));
if (options.secure && outsideDirectory(texturePath, mtlDirectory)) { if (options.secure && outsideDirectory(texturePath, mtlDirectory)) {
// Try looking for the texture in the same directory as the obj // 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.'); 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.');
@ -289,33 +289,33 @@ function convertMaterials(materials, options) {
function resizeChannel(sourcePixels, sourceWidth, sourceHeight, targetPixels, targetWidth, targetHeight) { function resizeChannel(sourcePixels, sourceWidth, sourceHeight, targetPixels, targetWidth, targetHeight) {
// Nearest neighbor sampling // Nearest neighbor sampling
var widthRatio = sourceWidth / targetWidth; const widthRatio = sourceWidth / targetWidth;
var heightRatio = sourceHeight / targetHeight; const heightRatio = sourceHeight / targetHeight;
for (var y = 0; y < targetHeight; ++y) { for (let y = 0; y < targetHeight; ++y) {
for (var x = 0; x < targetWidth; ++x) { for (let x = 0; x < targetWidth; ++x) {
var targetIndex = y * targetWidth + x; const targetIndex = y * targetWidth + x;
var sourceY = Math.round(y * heightRatio); const sourceY = Math.round(y * heightRatio);
var sourceX = Math.round(x * widthRatio); const sourceX = Math.round(x * widthRatio);
var sourceIndex = sourceY * sourceWidth + sourceX; const sourceIndex = sourceY * sourceWidth + sourceX;
var sourceValue = sourcePixels.readUInt8(sourceIndex); const sourceValue = sourcePixels.readUInt8(sourceIndex);
targetPixels.writeUInt8(sourceValue, targetIndex); targetPixels.writeUInt8(sourceValue, targetIndex);
} }
} }
return targetPixels; return targetPixels;
} }
var scratchResizeChannel; let scratchResizeChannel;
function getTextureChannel(texture, index, targetWidth, targetHeight, targetChannel) { function getTextureChannel(texture, index, targetWidth, targetHeight, targetChannel) {
var pixels = texture.pixels; // RGBA const pixels = texture.pixels; // RGBA
var sourceWidth = texture.width; const sourceWidth = texture.width;
var sourceHeight = texture.height; const sourceHeight = texture.height;
var sourcePixelsLength = sourceWidth * sourceHeight; const sourcePixelsLength = sourceWidth * sourceHeight;
var targetPixelsLength = targetWidth * targetHeight; const targetPixelsLength = targetWidth * targetHeight;
// Allocate the scratchResizeChannel on demand if the texture needs to be resized // Allocate the scratchResizeChannel on demand if the texture needs to be resized
var sourceChannel = targetChannel; let sourceChannel = targetChannel;
if (sourcePixelsLength > targetPixelsLength) { if (sourcePixelsLength > targetPixelsLength) {
if (!defined(scratchResizeChannel) || (sourcePixelsLength > scratchResizeChannel.length)) { if (!defined(scratchResizeChannel) || (sourcePixelsLength > scratchResizeChannel.length)) {
scratchResizeChannel = Buffer.alloc(sourcePixelsLength); scratchResizeChannel = Buffer.alloc(sourcePixelsLength);
@ -323,8 +323,8 @@ function getTextureChannel(texture, index, targetWidth, targetHeight, targetChan
sourceChannel = scratchResizeChannel; sourceChannel = scratchResizeChannel;
} }
for (var i = 0; i < sourcePixelsLength; ++i) { for (let i = 0; i < sourcePixelsLength; ++i) {
var value = pixels.readUInt8(i * 4 + index); const value = pixels.readUInt8(i * 4 + index);
sourceChannel.writeUInt8(value, i); sourceChannel.writeUInt8(value, i);
} }
@ -336,28 +336,26 @@ function getTextureChannel(texture, index, targetWidth, targetHeight, targetChan
} }
function writeChannel(pixels, channel, index) { function writeChannel(pixels, channel, index) {
var pixelsLength = pixels.length / 4; const pixelsLength = pixels.length / 4;
for (var i = 0; i < pixelsLength; ++i) { for (let i = 0; i < pixelsLength; ++i) {
var value = channel.readUInt8(i); const value = channel.readUInt8(i);
pixels.writeUInt8(value, i * 4 + index); pixels.writeUInt8(value, i * 4 + index);
} }
} }
function getMinimumDimensions(textures, options) { function getMinimumDimensions(textures, options) {
var i; let width = Number.POSITIVE_INFINITY;
var texture; let height = Number.POSITIVE_INFINITY;
var width = Number.POSITIVE_INFINITY;
var height = Number.POSITIVE_INFINITY;
var length = textures.length; const length = textures.length;
for (i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
texture = textures[i]; const texture = textures[i];
width = Math.min(texture.width, width); width = Math.min(texture.width, width);
height = Math.min(texture.height, height); height = Math.min(texture.height, height);
} }
for (i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
texture = textures[i]; const texture = textures[i];
if (texture.width !== width || texture.height !== height) { if (texture.width !== width || texture.height !== height) {
options.logger('Texture ' + texture.path + ' will be scaled from ' + texture.width + 'x' + texture.height + ' to ' + width + 'x' + height + '.'); options.logger('Texture ' + texture.path + ' will be scaled from ' + texture.width + 'x' + texture.height + ' to ' + width + 'x' + height + '.');
} }
@ -367,9 +365,9 @@ function getMinimumDimensions(textures, options) {
} }
function isChannelSingleColor(buffer) { function isChannelSingleColor(buffer) {
var first = buffer.readUInt8(0); const first = buffer.readUInt8(0);
var length = buffer.length; const length = buffer.length;
for (var i = 1; i < length; ++i) { for (let i = 1; i < length; ++i) {
if (buffer[i] !== first) { if (buffer[i] !== first) {
return false; return false;
} }
@ -378,8 +376,8 @@ function isChannelSingleColor(buffer) {
} }
function createDiffuseAlphaTexture(diffuseTexture, alphaTexture, options) { function createDiffuseAlphaTexture(diffuseTexture, alphaTexture, options) {
var packDiffuse = defined(diffuseTexture); const packDiffuse = defined(diffuseTexture);
var packAlpha = defined(alphaTexture); const packAlpha = defined(alphaTexture);
if (!packDiffuse) { if (!packDiffuse) {
return undefined; return undefined;
@ -394,30 +392,30 @@ function createDiffuseAlphaTexture(diffuseTexture, alphaTexture, options) {
return diffuseTexture; return diffuseTexture;
} }
var packedTextures = [diffuseTexture, alphaTexture]; const packedTextures = [diffuseTexture, alphaTexture];
var dimensions = getMinimumDimensions(packedTextures, options); const dimensions = getMinimumDimensions(packedTextures, options);
var width = dimensions[0]; const width = dimensions[0];
var height = dimensions[1]; const height = dimensions[1];
var pixelsLength = width * height; const pixelsLength = width * height;
var pixels = Buffer.alloc(pixelsLength * 4, 0xFF); // Initialize with 4 channels const pixels = Buffer.alloc(pixelsLength * 4, 0xFF); // Initialize with 4 channels
var scratchChannel = Buffer.alloc(pixelsLength); const scratchChannel = Buffer.alloc(pixelsLength);
// Write into the R, G, B channels // Write into the R, G, B channels
var redChannel = getTextureChannel(diffuseTexture, 0, width, height, scratchChannel); const redChannel = getTextureChannel(diffuseTexture, 0, width, height, scratchChannel);
writeChannel(pixels, redChannel, 0); writeChannel(pixels, redChannel, 0);
var greenChannel = getTextureChannel(diffuseTexture, 1, width, height, scratchChannel); const greenChannel = getTextureChannel(diffuseTexture, 1, width, height, scratchChannel);
writeChannel(pixels, greenChannel, 1); writeChannel(pixels, greenChannel, 1);
var blueChannel = getTextureChannel(diffuseTexture, 2, width, height, scratchChannel); const blueChannel = getTextureChannel(diffuseTexture, 2, width, height, scratchChannel);
writeChannel(pixels, blueChannel, 2); writeChannel(pixels, blueChannel, 2);
// First try reading the alpha component from the alpha channel, but if it is a single color read from the red channel instead. // First try reading the alpha component from the alpha channel, but if it is a single color read from the red channel instead.
var alphaChannel = getTextureChannel(alphaTexture, 3, width, height, scratchChannel); let alphaChannel = getTextureChannel(alphaTexture, 3, width, height, scratchChannel);
if (isChannelSingleColor(alphaChannel)) { if (isChannelSingleColor(alphaChannel)) {
alphaChannel = getTextureChannel(alphaTexture, 0, width, height, scratchChannel); alphaChannel = getTextureChannel(alphaTexture, 0, width, height, scratchChannel);
} }
writeChannel(pixels, alphaChannel, 3); writeChannel(pixels, alphaChannel, 3);
var texture = new Texture(); const texture = new Texture();
texture.name = diffuseTexture.name; texture.name = diffuseTexture.name;
texture.extension = '.png'; texture.extension = '.png';
texture.pixels = pixels; texture.pixels = pixels;
@ -433,9 +431,9 @@ function createMetallicRoughnessTexture(metallicTexture, roughnessTexture, occlu
return metallicTexture; return metallicTexture;
} }
var packMetallic = defined(metallicTexture); const packMetallic = defined(metallicTexture);
var packRoughness = defined(roughnessTexture); const packRoughness = defined(roughnessTexture);
var packOcclusion = defined(occlusionTexture) && options.packOcclusion; const packOcclusion = defined(occlusionTexture) && options.packOcclusion;
if (!packMetallic && !packRoughness) { if (!packMetallic && !packRoughness) {
return undefined; return undefined;
@ -456,43 +454,43 @@ function createMetallicRoughnessTexture(metallicTexture, roughnessTexture, occlu
return undefined; return undefined;
} }
var packedTextures = [metallicTexture, roughnessTexture, occlusionTexture].filter(function(texture) { const packedTextures = [metallicTexture, roughnessTexture, occlusionTexture].filter(function(texture) {
return defined(texture) && defined(texture.pixels); return defined(texture) && defined(texture.pixels);
}); });
var dimensions = getMinimumDimensions(packedTextures, options); const dimensions = getMinimumDimensions(packedTextures, options);
var width = dimensions[0]; const width = dimensions[0];
var height = dimensions[1]; const height = dimensions[1];
var pixelsLength = width * height; const pixelsLength = width * height;
var pixels = Buffer.alloc(pixelsLength * 4, 0xFF); // Initialize with 4 channels, unused channels will be white const pixels = Buffer.alloc(pixelsLength * 4, 0xFF); // Initialize with 4 channels, unused channels will be white
var scratchChannel = Buffer.alloc(pixelsLength); const scratchChannel = Buffer.alloc(pixelsLength);
if (packMetallic) { if (packMetallic) {
// Write into the B channel // Write into the B channel
var metallicChannel = getTextureChannel(metallicTexture, 0, width, height, scratchChannel); const metallicChannel = getTextureChannel(metallicTexture, 0, width, height, scratchChannel);
writeChannel(pixels, metallicChannel, 2); writeChannel(pixels, metallicChannel, 2);
} }
if (packRoughness) { if (packRoughness) {
// Write into the G channel // Write into the G channel
var roughnessChannel = getTextureChannel(roughnessTexture, 0, width, height, scratchChannel); const roughnessChannel = getTextureChannel(roughnessTexture, 0, width, height, scratchChannel);
writeChannel(pixels, roughnessChannel, 1); writeChannel(pixels, roughnessChannel, 1);
} }
if (packOcclusion) { if (packOcclusion) {
// Write into the R channel // Write into the R channel
var occlusionChannel = getTextureChannel(occlusionTexture, 0, width, height, scratchChannel); const occlusionChannel = getTextureChannel(occlusionTexture, 0, width, height, scratchChannel);
writeChannel(pixels, occlusionChannel, 0); writeChannel(pixels, occlusionChannel, 0);
} }
var length = packedTextures.length; const length = packedTextures.length;
var names = new Array(length); const names = new Array(length);
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
names[i] = packedTextures[i].name; names[i] = packedTextures[i].name;
} }
var name = names.join('_'); const name = names.join('_');
var texture = new Texture(); const texture = new Texture();
texture.name = name; texture.name = name;
texture.extension = '.png'; texture.extension = '.png';
texture.pixels = pixels; texture.pixels = pixels;
@ -507,8 +505,8 @@ function createSpecularGlossinessTexture(specularTexture, glossinessTexture, opt
return specularTexture; return specularTexture;
} }
var packSpecular = defined(specularTexture); const packSpecular = defined(specularTexture);
var packGlossiness = defined(glossinessTexture); const packGlossiness = defined(glossinessTexture);
if (!packSpecular && !packGlossiness) { if (!packSpecular && !packGlossiness) {
return undefined; return undefined;
@ -524,41 +522,41 @@ function createSpecularGlossinessTexture(specularTexture, glossinessTexture, opt
return undefined; return undefined;
} }
var packedTextures = [specularTexture, glossinessTexture].filter(function(texture) { const packedTextures = [specularTexture, glossinessTexture].filter(function(texture) {
return defined(texture) && defined(texture.pixels); return defined(texture) && defined(texture.pixels);
}); });
var dimensions = getMinimumDimensions(packedTextures, options); const dimensions = getMinimumDimensions(packedTextures, options);
var width = dimensions[0]; const width = dimensions[0];
var height = dimensions[1]; const height = dimensions[1];
var pixelsLength = width * height; const pixelsLength = width * height;
var pixels = Buffer.alloc(pixelsLength * 4, 0xFF); // Initialize with 4 channels, unused channels will be white const pixels = Buffer.alloc(pixelsLength * 4, 0xFF); // Initialize with 4 channels, unused channels will be white
var scratchChannel = Buffer.alloc(pixelsLength); const scratchChannel = Buffer.alloc(pixelsLength);
if (packSpecular) { if (packSpecular) {
// Write into the R, G, B channels // Write into the R, G, B channels
var redChannel = getTextureChannel(specularTexture, 0, width, height, scratchChannel); const redChannel = getTextureChannel(specularTexture, 0, width, height, scratchChannel);
writeChannel(pixels, redChannel, 0); writeChannel(pixels, redChannel, 0);
var greenChannel = getTextureChannel(specularTexture, 1, width, height, scratchChannel); const greenChannel = getTextureChannel(specularTexture, 1, width, height, scratchChannel);
writeChannel(pixels, greenChannel, 1); writeChannel(pixels, greenChannel, 1);
var blueChannel = getTextureChannel(specularTexture, 2, width, height, scratchChannel); const blueChannel = getTextureChannel(specularTexture, 2, width, height, scratchChannel);
writeChannel(pixels, blueChannel, 2); writeChannel(pixels, blueChannel, 2);
} }
if (packGlossiness) { if (packGlossiness) {
// Write into the A channel // Write into the A channel
var glossinessChannel = getTextureChannel(glossinessTexture, 0, width, height, scratchChannel); const glossinessChannel = getTextureChannel(glossinessTexture, 0, width, height, scratchChannel);
writeChannel(pixels, glossinessChannel, 3); writeChannel(pixels, glossinessChannel, 3);
} }
var length = packedTextures.length; const length = packedTextures.length;
var names = new Array(length); const names = new Array(length);
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
names[i] = packedTextures[i].name; names[i] = packedTextures[i].name;
} }
var name = names.join('_'); const name = names.join('_');
var texture = new Texture(); const texture = new Texture();
texture.name = name; texture.name = name;
texture.extension = '.png'; texture.extension = '.png';
texture.pixels = pixels; texture.pixels = pixels;
@ -569,20 +567,20 @@ function createSpecularGlossinessTexture(specularTexture, glossinessTexture, opt
} }
function createSpecularGlossinessMaterial(material, options) { function createSpecularGlossinessMaterial(material, options) {
var emissiveTexture = material.emissiveTexture; const emissiveTexture = material.emissiveTexture;
var normalTexture = material.normalTexture; const normalTexture = material.normalTexture;
var occlusionTexture = material.ambientTexture; const occlusionTexture = material.ambientTexture;
var diffuseTexture = material.diffuseTexture; const diffuseTexture = material.diffuseTexture;
var alphaTexture = material.alphaTexture; const alphaTexture = material.alphaTexture;
var specularTexture = material.specularTexture; const specularTexture = material.specularTexture;
var glossinessTexture = material.specularShininessTexture; const glossinessTexture = material.specularShininessTexture;
var specularGlossinessTexture = createSpecularGlossinessTexture(specularTexture, glossinessTexture, options); const specularGlossinessTexture = createSpecularGlossinessTexture(specularTexture, glossinessTexture, options);
var diffuseAlphaTexture = createDiffuseAlphaTexture(diffuseTexture, alphaTexture, options); const diffuseAlphaTexture = createDiffuseAlphaTexture(diffuseTexture, alphaTexture, options);
var emissiveFactor = material.emissiveColor.slice(0, 3); let emissiveFactor = material.emissiveColor.slice(0, 3);
var diffuseFactor = material.diffuseColor; let diffuseFactor = material.diffuseColor;
var specularFactor = material.specularColor.slice(0, 3); let specularFactor = material.specularColor.slice(0, 3);
var glossinessFactor = material.specularShininess; let glossinessFactor = material.specularShininess;
if (defined(emissiveTexture)) { if (defined(emissiveTexture)) {
emissiveFactor = [1.0, 1.0, 1.0]; emissiveFactor = [1.0, 1.0, 1.0];
@ -600,11 +598,11 @@ function createSpecularGlossinessMaterial(material, options) {
glossinessFactor = 1.0; glossinessFactor = 1.0;
} }
var transparent = false; let transparent = false;
if (defined(alphaTexture)) { if (defined(alphaTexture)) {
transparent = true; transparent = true;
} else { } else {
var alpha = material.alpha; const alpha = material.alpha;
diffuseFactor[3] = alpha; diffuseFactor[3] = alpha;
transparent = alpha < 1.0; transparent = alpha < 1.0;
} }
@ -613,8 +611,8 @@ function createSpecularGlossinessMaterial(material, options) {
transparent = transparent || diffuseTexture.transparent; transparent = transparent || diffuseTexture.transparent;
} }
var doubleSided = transparent; const doubleSided = transparent;
var alphaMode = transparent ? 'BLEND' : 'OPAQUE'; const alphaMode = transparent ? 'BLEND' : 'OPAQUE';
return { return {
name : material.name, name : material.name,
@ -637,24 +635,24 @@ function createSpecularGlossinessMaterial(material, options) {
} }
function createMetallicRoughnessMaterial(material, options) { function createMetallicRoughnessMaterial(material, options) {
var emissiveTexture = material.emissiveTexture; const emissiveTexture = material.emissiveTexture;
var normalTexture = material.normalTexture; const normalTexture = material.normalTexture;
var occlusionTexture = material.ambientTexture; let occlusionTexture = material.ambientTexture;
var baseColorTexture = material.diffuseTexture; const baseColorTexture = material.diffuseTexture;
var alphaTexture = material.alphaTexture; const alphaTexture = material.alphaTexture;
var metallicTexture = material.specularTexture; const metallicTexture = material.specularTexture;
var roughnessTexture = material.specularShininessTexture; const roughnessTexture = material.specularShininessTexture;
var metallicRoughnessTexture = createMetallicRoughnessTexture(metallicTexture, roughnessTexture, occlusionTexture, options); const metallicRoughnessTexture = createMetallicRoughnessTexture(metallicTexture, roughnessTexture, occlusionTexture, options);
var diffuseAlphaTexture = createDiffuseAlphaTexture(baseColorTexture, alphaTexture, options); const diffuseAlphaTexture = createDiffuseAlphaTexture(baseColorTexture, alphaTexture, options);
if (options.packOcclusion) { if (options.packOcclusion) {
occlusionTexture = metallicRoughnessTexture; occlusionTexture = metallicRoughnessTexture;
} }
var emissiveFactor = material.emissiveColor.slice(0, 3); let emissiveFactor = material.emissiveColor.slice(0, 3);
var baseColorFactor = material.diffuseColor; let baseColorFactor = material.diffuseColor;
var metallicFactor = material.specularColor[0]; let metallicFactor = material.specularColor[0];
var roughnessFactor = material.specularShininess; let roughnessFactor = material.specularShininess;
if (defined(emissiveTexture)) { if (defined(emissiveTexture)) {
emissiveFactor = [1.0, 1.0, 1.0]; emissiveFactor = [1.0, 1.0, 1.0];
@ -672,11 +670,11 @@ function createMetallicRoughnessMaterial(material, options) {
roughnessFactor = 1.0; roughnessFactor = 1.0;
} }
var transparent = false; let transparent = false;
if (defined(alphaTexture)) { if (defined(alphaTexture)) {
transparent = true; transparent = true;
} else { } else {
var alpha = material.alpha; const alpha = material.alpha;
baseColorFactor[3] = alpha; baseColorFactor[3] = alpha;
transparent = alpha < 1.0; transparent = alpha < 1.0;
} }
@ -685,8 +683,8 @@ function createMetallicRoughnessMaterial(material, options) {
transparent = transparent || baseColorTexture.transparent; transparent = transparent || baseColorTexture.transparent;
} }
var doubleSided = transparent; const doubleSided = transparent;
var alphaMode = transparent ? 'BLEND' : 'OPAQUE'; const alphaMode = transparent ? 'BLEND' : 'OPAQUE';
return { return {
name : material.name, name : material.name,
@ -715,10 +713,10 @@ function convertTraditionalToMetallicRoughness(material) {
// Roughness factor is a combination of specular intensity and shininess // Roughness factor is a combination of specular intensity and shininess
// Metallic factor is 0.0 // Metallic factor is 0.0
// Textures are not converted for now // Textures are not converted for now
var specularIntensity = luminance(material.specularColor); const specularIntensity = luminance(material.specularColor);
// Transform from 0-1000 range to 0-1 range. Then invert. // Transform from 0-1000 range to 0-1 range. Then invert.
var roughnessFactor = material.specularShininess; let roughnessFactor = material.specularShininess;
roughnessFactor = roughnessFactor / 1000.0; roughnessFactor = roughnessFactor / 1000.0;
roughnessFactor = 1.0 - roughnessFactor; roughnessFactor = 1.0 - roughnessFactor;
roughnessFactor = CesiumMath.clamp(roughnessFactor, 0.0, 1.0); roughnessFactor = CesiumMath.clamp(roughnessFactor, 0.0, 1.0);
@ -728,7 +726,7 @@ function convertTraditionalToMetallicRoughness(material) {
roughnessFactor *= (1.0 - specularIntensity); roughnessFactor *= (1.0 - specularIntensity);
} }
var metallicFactor = 0.0; const metallicFactor = 0.0;
material.specularColor = [metallicFactor, metallicFactor, metallicFactor, 1.0]; material.specularColor = [metallicFactor, metallicFactor, metallicFactor, 1.0];
material.specularShininess = roughnessFactor; material.specularShininess = roughnessFactor;

View File

@ -1,21 +1,21 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var path = require('path'); const path = require('path');
var Promise = require('bluebird'); const Promise = require('bluebird');
var ArrayStorage = require('./ArrayStorage'); const ArrayStorage = require('./ArrayStorage');
var loadMtl = require('./loadMtl'); const loadMtl = require('./loadMtl');
var outsideDirectory = require('./outsideDirectory'); const outsideDirectory = require('./outsideDirectory');
var readLines = require('./readLines'); const readLines = require('./readLines');
var Cartesian3 = Cesium.Cartesian3; const Cartesian3 = Cesium.Cartesian3;
var ComponentDatatype = Cesium.ComponentDatatype; const ComponentDatatype = Cesium.ComponentDatatype;
var CoplanarPolygonGeometryLibrary = Cesium.CoplanarPolygonGeometryLibrary; const CoplanarPolygonGeometryLibrary = Cesium.CoplanarPolygonGeometryLibrary;
var defaultValue = Cesium.defaultValue; const defaultValue = Cesium.defaultValue;
var defined = Cesium.defined; const defined = Cesium.defined;
var PolygonPipeline = Cesium.PolygonPipeline; const PolygonPipeline = Cesium.PolygonPipeline;
var RuntimeError = Cesium.RuntimeError; const RuntimeError = Cesium.RuntimeError;
var WindingOrder = Cesium.WindingOrder; const WindingOrder = Cesium.WindingOrder;
module.exports = loadObj; module.exports = loadObj;
@ -42,10 +42,10 @@ function Primitive() {
} }
// OBJ regex patterns are modified from ThreeJS (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js) // OBJ regex patterns are modified from ThreeJS (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js)
var vertexPattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // v float float float const vertexPattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // v float float float
var normalPattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vn float float float const normalPattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vn float float float
var uvPattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vt float float const uvPattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vt float float
var facePattern = /(-?\d+)\/?(-?\d*)\/?(-?\d*)/g; // for any face format "f v", "f v/v", "f v//v", "f v/v/v" const facePattern = /(-?\d+)\/?(-?\d*)\/?(-?\d*)/g; // for any face format "f v", "f v/v", "f v//v", "f v/v/v"
/** /**
* Parse an obj file. * Parse an obj file.
@ -58,36 +58,36 @@ var facePattern = /(-?\d+)\/?(-?\d*)\/?(-?\d*)/g;
*/ */
function loadObj(objPath, options) { function loadObj(objPath, options) {
// Global store of vertex attributes listed in the obj file // Global store of vertex attributes listed in the obj file
var positions = new ArrayStorage(ComponentDatatype.FLOAT); let positions = new ArrayStorage(ComponentDatatype.FLOAT);
var normals = new ArrayStorage(ComponentDatatype.FLOAT); let normals = new ArrayStorage(ComponentDatatype.FLOAT);
var uvs = new ArrayStorage(ComponentDatatype.FLOAT); let uvs = new ArrayStorage(ComponentDatatype.FLOAT);
// The current node, mesh, and primitive // The current node, mesh, and primitive
var node; let node;
var mesh; let mesh;
var primitive; let primitive;
var activeMaterial; let activeMaterial;
// All nodes seen in the obj // All nodes seen in the obj
var nodes = []; const nodes = [];
// Used to build the indices. The vertex cache is unique to each primitive. // Used to build the indices. The vertex cache is unique to each primitive.
var vertexCache = {}; let vertexCache = {};
var vertexCacheLimit = 1000000; const vertexCacheLimit = 1000000;
var vertexCacheCount = 0; let vertexCacheCount = 0;
var vertexCount = 0; let vertexCount = 0;
// All mtl paths seen in the obj // All mtl paths seen in the obj
var mtlPaths = []; let mtlPaths = [];
// Buffers for face data that spans multiple lines // Buffers for face data that spans multiple lines
var lineBuffer = ''; let lineBuffer = '';
// Used for parsing face data // Used for parsing face data
var faceVertices = []; const faceVertices = [];
var facePositions = []; const facePositions = [];
var faceUvs = []; const faceUvs = [];
var faceNormals = []; const faceNormals = [];
function clearVertexCache() { function clearVertexCache() {
vertexCache = {}; vertexCache = {};
@ -123,9 +123,9 @@ function loadObj(objPath, options) {
} }
function reusePrimitive(callback) { function reusePrimitive(callback) {
var primitives = mesh.primitives; const primitives = mesh.primitives;
var primitivesLength = primitives.length; const primitivesLength = primitives.length;
for (var i = 0; i < primitivesLength; ++i) { for (let i = 0; i < primitivesLength; ++i) {
if (primitives[i].material === activeMaterial) { if (primitives[i].material === activeMaterial) {
if (!defined(callback) || callback(primitives[i])) { if (!defined(callback) || callback(primitives[i])) {
primitive = primitives[i]; primitive = primitives[i];
@ -144,15 +144,15 @@ function loadObj(objPath, options) {
} }
function faceAndPrimitiveMatch(uvs, normals, primitive) { function faceAndPrimitiveMatch(uvs, normals, primitive) {
var faceHasUvs = uvs[0].length > 0; const faceHasUvs = uvs[0].length > 0;
var faceHasNormals = normals[0].length > 0; const faceHasNormals = normals[0].length > 0;
var primitiveHasUvs = primitive.uvs.length > 0; const primitiveHasUvs = primitive.uvs.length > 0;
var primitiveHasNormals = primitive.normals.length > 0; const primitiveHasNormals = primitive.normals.length > 0;
return primitiveHasUvs === faceHasUvs && primitiveHasNormals === faceHasNormals; return primitiveHasUvs === faceHasUvs && primitiveHasNormals === faceHasNormals;
} }
function checkPrimitive(uvs, normals) { function checkPrimitive(uvs, normals) {
var firstFace = primitive.indices.length === 0; const firstFace = primitive.indices.length === 0;
if (!firstFace && !faceAndPrimitiveMatch(uvs, normals, primitive)) { if (!firstFace && !faceAndPrimitiveMatch(uvs, normals, primitive)) {
reusePrimitive(function(primitive) { reusePrimitive(function(primitive) {
return faceAndPrimitiveMatch(uvs, normals, primitive); return faceAndPrimitiveMatch(uvs, normals, primitive);
@ -161,7 +161,7 @@ function loadObj(objPath, options) {
} }
function getOffset(a, attributeData, components) { function getOffset(a, attributeData, components) {
var i = parseInt(a); const i = parseInt(a);
if (i < 0) { if (i < 0) {
// Negative vertex indexes reference the vertices immediately above it // Negative vertex indexes reference the vertices immediately above it
return (attributeData.length / components + i) * components; return (attributeData.length / components + i) * components;
@ -172,10 +172,10 @@ function loadObj(objPath, options) {
function createVertex(p, u, n) { function createVertex(p, u, n) {
// Positions // Positions
if (p.length > 0) { if (p.length > 0) {
var pi = getOffset(p, positions, 3); const pi = getOffset(p, positions, 3);
var px = positions.get(pi + 0); const px = positions.get(pi + 0);
var py = positions.get(pi + 1); const py = positions.get(pi + 1);
var pz = positions.get(pi + 2); const pz = positions.get(pi + 2);
primitive.positions.push(px); primitive.positions.push(px);
primitive.positions.push(py); primitive.positions.push(py);
primitive.positions.push(pz); primitive.positions.push(pz);
@ -183,10 +183,10 @@ function loadObj(objPath, options) {
// Normals // Normals
if (n.length > 0) { if (n.length > 0) {
var ni = getOffset(n, normals, 3); const ni = getOffset(n, normals, 3);
var nx = normals.get(ni + 0); const nx = normals.get(ni + 0);
var ny = normals.get(ni + 1); const ny = normals.get(ni + 1);
var nz = normals.get(ni + 2); const nz = normals.get(ni + 2);
primitive.normals.push(nx); primitive.normals.push(nx);
primitive.normals.push(ny); primitive.normals.push(ny);
primitive.normals.push(nz); primitive.normals.push(nz);
@ -194,16 +194,16 @@ function loadObj(objPath, options) {
// UVs // UVs
if (u.length > 0) { if (u.length > 0) {
var ui = getOffset(u, uvs, 2); const ui = getOffset(u, uvs, 2);
var ux = uvs.get(ui + 0); const ux = uvs.get(ui + 0);
var uy = uvs.get(ui + 1); const uy = uvs.get(ui + 1);
primitive.uvs.push(ux); primitive.uvs.push(ux);
primitive.uvs.push(uy); primitive.uvs.push(uy);
} }
} }
function addVertex(v, p, u, n) { function addVertex(v, p, u, n) {
var index = vertexCache[v]; let index = vertexCache[v];
if (!defined(index)) { if (!defined(index)) {
index = vertexCount++; index = vertexCount++;
vertexCache[v] = index; vertexCache[v] = index;
@ -220,47 +220,47 @@ function loadObj(objPath, options) {
} }
function getPosition(index, result) { function getPosition(index, result) {
var pi = getOffset(index, positions, 3); const pi = getOffset(index, positions, 3);
var px = positions.get(pi + 0); const px = positions.get(pi + 0);
var py = positions.get(pi + 1); const py = positions.get(pi + 1);
var pz = positions.get(pi + 2); const pz = positions.get(pi + 2);
return Cartesian3.fromElements(px, py, pz, result); return Cartesian3.fromElements(px, py, pz, result);
} }
function getNormal(index, result) { function getNormal(index, result) {
var ni = getOffset(index, normals, 3); const ni = getOffset(index, normals, 3);
var nx = normals.get(ni + 0); const nx = normals.get(ni + 0);
var ny = normals.get(ni + 1); const ny = normals.get(ni + 1);
var nz = normals.get(ni + 2); const nz = normals.get(ni + 2);
return Cartesian3.fromElements(nx, ny, nz, result); return Cartesian3.fromElements(nx, ny, nz, result);
} }
var scratch1 = new Cartesian3(); const scratch1 = new Cartesian3();
var scratch2 = new Cartesian3(); const scratch2 = new Cartesian3();
var scratch3 = new Cartesian3(); const scratch3 = new Cartesian3();
var scratch4 = new Cartesian3(); const scratch4 = new Cartesian3();
var scratch5 = new Cartesian3(); const scratch5 = new Cartesian3();
var scratchCenter = new Cartesian3(); const scratchCenter = new Cartesian3();
var scratchAxis1 = new Cartesian3(); const scratchAxis1 = new Cartesian3();
var scratchAxis2 = new Cartesian3(); const scratchAxis2 = new Cartesian3();
var scratchNormal = new Cartesian3(); const scratchNormal = new Cartesian3();
var scratchPositions = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()]; const scratchPositions = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
var scratchVertexIndices = []; const scratchVertexIndices = [];
var scratchPoints = []; const scratchPoints = [];
function checkWindingCorrect(positionIndex1, positionIndex2, positionIndex3, normalIndex) { function checkWindingCorrect(positionIndex1, positionIndex2, positionIndex3, normalIndex) {
if (normalIndex.length === 0) { if (normalIndex.length === 0) {
// If no face normal, we have to assume the winding is correct. // If no face normal, we have to assume the winding is correct.
return true; return true;
} }
var normal = getNormal(normalIndex, scratchNormal); const normal = getNormal(normalIndex, scratchNormal);
var A = getPosition(positionIndex1, scratch1); const A = getPosition(positionIndex1, scratch1);
var B = getPosition(positionIndex2, scratch2); const B = getPosition(positionIndex2, scratch2);
var C = getPosition(positionIndex3, scratch3); const C = getPosition(positionIndex3, scratch3);
var BA = Cartesian3.subtract(B, A, scratch4); const BA = Cartesian3.subtract(B, A, scratch4);
var CA = Cartesian3.subtract(C, A, scratch5); const CA = Cartesian3.subtract(C, A, scratch5);
var cross = Cartesian3.cross(BA, CA, scratch3); const cross = Cartesian3.cross(BA, CA, scratch3);
return (Cartesian3.dot(normal, cross) >= 0); return (Cartesian3.dot(normal, cross) >= 0);
} }
@ -278,26 +278,23 @@ function loadObj(objPath, options) {
} }
function addFace(vertices, positions, uvs, normals) { function addFace(vertices, positions, uvs, normals) {
var i;
var isWindingCorrect;
checkPrimitive(uvs, normals); checkPrimitive(uvs, normals);
if (vertices.length === 3) { if (vertices.length === 3) {
isWindingCorrect = checkWindingCorrect(positions[0], positions[1], positions[2], normals[0]); const isWindingCorrect = checkWindingCorrect(positions[0], positions[1], positions[2], normals[0]);
var index1 = addVertex(vertices[0], positions[0], uvs[0], normals[0]); const index1 = addVertex(vertices[0], positions[0], uvs[0], normals[0]);
var index2 = addVertex(vertices[1], positions[1], uvs[1], normals[1]); const index2 = addVertex(vertices[1], positions[1], uvs[1], normals[1]);
var index3 = addVertex(vertices[2], positions[2], uvs[2], normals[2]); const index3 = addVertex(vertices[2], positions[2], uvs[2], normals[2]);
addTriangle(index1, index2, index3, isWindingCorrect); addTriangle(index1, index2, index3, isWindingCorrect);
} else { // Triangulate if the face is not a triangle } else { // Triangulate if the face is not a triangle
var points = scratchPoints; const points = scratchPoints;
var vertexIndices = scratchVertexIndices; const vertexIndices = scratchVertexIndices;
points.length = 0; points.length = 0;
vertexIndices.length = 0; vertexIndices.length = 0;
for (i = 0; i < vertices.length; ++i) { for (let i = 0; i < vertices.length; ++i) {
var index = addVertex(vertices[i], positions[i], uvs[i], normals[i]); const index = addVertex(vertices[i], positions[i], uvs[i], normals[i]);
vertexIndices.push(index); vertexIndices.push(index);
if (i === scratchPositions.length) { if (i === scratchPositions.length) {
scratchPositions.push(new Cartesian3()); scratchPositions.push(new Cartesian3());
@ -305,16 +302,16 @@ function loadObj(objPath, options) {
points.push(getPosition(positions[i], scratchPositions[i])); points.push(getPosition(positions[i], scratchPositions[i]));
} }
var validGeometry = CoplanarPolygonGeometryLibrary.computeProjectTo2DArguments(points, scratchCenter, scratchAxis1, scratchAxis2); const validGeometry = CoplanarPolygonGeometryLibrary.computeProjectTo2DArguments(points, scratchCenter, scratchAxis1, scratchAxis2);
if (!validGeometry) { if (!validGeometry) {
return; return;
} }
var projectPoints = CoplanarPolygonGeometryLibrary.createProjectPointsTo2DFunction(scratchCenter, scratchAxis1, scratchAxis2); const projectPoints = CoplanarPolygonGeometryLibrary.createProjectPointsTo2DFunction(scratchCenter, scratchAxis1, scratchAxis2);
var points2D = projectPoints(points); const points2D = projectPoints(points);
var indices = PolygonPipeline.triangulate(points2D); const indices = PolygonPipeline.triangulate(points2D);
isWindingCorrect = PolygonPipeline.computeWindingOrder2D(points2D) !== WindingOrder.CLOCKWISE; const isWindingCorrect = PolygonPipeline.computeWindingOrder2D(points2D) !== WindingOrder.CLOCKWISE;
for (i = 0; i < indices.length - 2; i += 3) { for (let i = 0; i < indices.length - 2; i += 3) {
addTriangle(vertexIndices[indices[i]], vertexIndices[indices[i+1]], vertexIndices[indices[i+2]], isWindingCorrect); addTriangle(vertexIndices[indices[i]], vertexIndices[indices[i+1]], vertexIndices[indices[i+2]], isWindingCorrect);
} }
} }
@ -322,28 +319,28 @@ function loadObj(objPath, options) {
function parseLine(line) { function parseLine(line) {
line = line.trim(); line = line.trim();
var result; let 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 (/^o\s/i.test(line)) { } else if (/^o\s/i.test(line)) {
var objectName = line.substring(2).trim(); const objectName = line.substring(2).trim();
addNode(objectName); addNode(objectName);
} else if (/^g\s/i.test(line)) { } else if (/^g\s/i.test(line)) {
var groupName = line.substring(2).trim(); const groupName = line.substring(2).trim();
addMesh(groupName); addMesh(groupName);
} else if (/^usemtl\s/i.test(line)) { } else if (/^usemtl\s/i.test(line)) {
var materialName = line.substring(7).trim(); const materialName = line.substring(7).trim();
useMaterial(materialName); useMaterial(materialName);
} else if (/^mtllib/i.test(line)) { } else if (/^mtllib/i.test(line)) {
var mtllibLine = line.substring(7).trim(); const mtllibLine = line.substring(7).trim();
mtlPaths = mtlPaths.concat(getMtlPaths(mtllibLine)); mtlPaths = mtlPaths.concat(getMtlPaths(mtllibLine));
} else if ((result = vertexPattern.exec(line)) !== null) { } else if ((result = vertexPattern.exec(line)) !== null) {
positions.push(parseFloat(result[1])); positions.push(parseFloat(result[1]));
positions.push(parseFloat(result[2])); positions.push(parseFloat(result[2]));
positions.push(parseFloat(result[3])); positions.push(parseFloat(result[3]));
} else if ((result = normalPattern.exec(line) ) !== null) { } else if ((result = normalPattern.exec(line) ) !== null) {
var normal = Cartesian3.fromElements(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]), scratchNormal); const normal = Cartesian3.fromElements(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]), scratchNormal);
if (Cartesian3.equals(normal, Cartesian3.ZERO)) { if (Cartesian3.equals(normal, Cartesian3.ZERO)) {
Cartesian3.clone(Cartesian3.UNIT_Z, normal); Cartesian3.clone(Cartesian3.UNIT_Z, normal);
} else { } else {
@ -404,15 +401,15 @@ function loadObj(objPath, options) {
function getMtlPaths(mtllibLine) { function getMtlPaths(mtllibLine) {
// Handle paths with spaces. E.g. mtllib my material file.mtl // Handle paths with spaces. E.g. mtllib my material file.mtl
var mtlPaths = []; const mtlPaths = [];
var splits = mtllibLine.split(' '); const splits = mtllibLine.split(' ');
var length = splits.length; const length = splits.length;
var startIndex = 0; let startIndex = 0;
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
if (path.extname(splits[i]) !== '.mtl') { if (path.extname(splits[i]) !== '.mtl') {
continue; continue;
} }
var mtlPath = splits.slice(startIndex, i + 1).join(' '); const mtlPath = splits.slice(startIndex, i + 1).join(' ');
mtlPaths.push(mtlPath); mtlPaths.push(mtlPath);
startIndex = i + 1; startIndex = i + 1;
} }
@ -424,7 +421,7 @@ function finishLoading(nodes, mtlPaths, objPath, usesMaterials, options) {
if (nodes.length === 0) { if (nodes.length === 0) {
throw new RuntimeError(objPath + ' does not have any geometry data'); throw new RuntimeError(objPath + ' does not have any geometry data');
} }
var name = path.basename(objPath, path.extname(objPath)); const name = path.basename(objPath, path.extname(objPath));
return loadMtls(mtlPaths, objPath, options) return loadMtls(mtlPaths, objPath, options)
.then(function(materials) { .then(function(materials) {
if (materials.length > 0 && !usesMaterials) { if (materials.length > 0 && !usesMaterials) {
@ -444,8 +441,8 @@ function normalizeMtlPath(mtlPath, objDirectory) {
} }
function loadMtls(mtlPaths, objPath, options) { function loadMtls(mtlPaths, objPath, options) {
var objDirectory = path.dirname(objPath); const objDirectory = path.dirname(objPath);
var materials = []; let materials = [];
// Remove duplicates // Remove duplicates
mtlPaths = mtlPaths.filter(function(value, index, self) { mtlPaths = mtlPaths.filter(function(value, index, self) {
@ -454,7 +451,7 @@ function loadMtls(mtlPaths, objPath, options) {
return Promise.map(mtlPaths, function(mtlPath) { return Promise.map(mtlPaths, function(mtlPath) {
mtlPath = normalizeMtlPath(mtlPath, objDirectory); mtlPath = normalizeMtlPath(mtlPath, objDirectory);
var shallowPath = path.join(objDirectory, path.basename(mtlPath)); const shallowPath = path.join(objDirectory, path.basename(mtlPath));
if (options.secure && outsideDirectory(mtlPath, objDirectory)) { if (options.secure && outsideDirectory(mtlPath, objDirectory)) {
// Try looking for the .mtl in the same directory as the obj // 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.'); 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.');
@ -489,16 +486,16 @@ function loadMtls(mtlPaths, objPath, options) {
} }
function assignDefaultMaterial(nodes, materials) { function assignDefaultMaterial(nodes, materials) {
var defaultMaterial = materials[0].name; const defaultMaterial = materials[0].name;
var nodesLength = nodes.length; const nodesLength = nodes.length;
for (var i = 0; i < nodesLength; ++i) { for (let i = 0; i < nodesLength; ++i) {
var meshes = nodes[i].meshes; const meshes = nodes[i].meshes;
var meshesLength = meshes.length; const meshesLength = meshes.length;
for (var j = 0; j < meshesLength; ++j) { for (let j = 0; j < meshesLength; ++j) {
var primitives = meshes[j].primitives; const primitives = meshes[j].primitives;
var primitivesLength = primitives.length; const primitivesLength = primitives.length;
for (var k = 0; k < primitivesLength; ++k) { for (let k = 0; k < primitivesLength; ++k) {
var primitive = primitives[k]; const primitive = primitives[k];
primitive.material = defaultValue(primitive.material, defaultMaterial); primitive.material = defaultValue(primitive.material, defaultMaterial);
} }
} }
@ -517,8 +514,8 @@ function removeEmptyMeshes(meshes) {
} }
function meshesHaveNames(meshes) { function meshesHaveNames(meshes) {
var meshesLength = meshes.length; const meshesLength = meshes.length;
for (var i = 0; i < meshesLength; ++i) { for (let i = 0; i < meshesLength; ++i) {
if (defined(meshes[i].name)) { if (defined(meshes[i].name)) {
return true; return true;
} }
@ -527,21 +524,21 @@ function meshesHaveNames(meshes) {
} }
function removeEmptyNodes(nodes) { function removeEmptyNodes(nodes) {
var final = []; const final = [];
var nodesLength = nodes.length; const nodesLength = nodes.length;
for (var i = 0; i < nodesLength; ++i) { for (let i = 0; i < nodesLength; ++i) {
var node = nodes[i]; const node = nodes[i];
var meshes = removeEmptyMeshes(node.meshes); const meshes = removeEmptyMeshes(node.meshes);
if (meshes.length === 0) { if (meshes.length === 0) {
continue; continue;
} }
node.meshes = meshes; node.meshes = meshes;
if (!defined(node.name) && meshesHaveNames(meshes)) { if (!defined(node.name) && meshesHaveNames(meshes)) {
// If the obj has groups (g) but not object groups (o) then convert meshes to nodes // If the obj has groups (g) but not object groups (o) then convert meshes to nodes
var meshesLength = meshes.length; const meshesLength = meshes.length;
for (var j = 0; j < meshesLength; ++j) { for (let j = 0; j < meshesLength; ++j) {
var mesh = meshes[j]; const mesh = meshes[j];
var convertedNode = new Node(); const convertedNode = new Node();
convertedNode.name = mesh.name; convertedNode.name = mesh.name;
convertedNode.meshes = [mesh]; convertedNode.meshes = [mesh];
final.push(convertedNode); final.push(convertedNode);
@ -554,11 +551,11 @@ function removeEmptyNodes(nodes) {
} }
function setDefaultNames(items, defaultName, usedNames) { function setDefaultNames(items, defaultName, usedNames) {
var itemsLength = items.length; const itemsLength = items.length;
for (var i = 0; i < itemsLength; ++i) { for (let i = 0; i < itemsLength; ++i) {
var item = items[i]; const item = items[i];
var name = defaultValue(item.name, defaultName); let name = defaultValue(item.name, defaultName);
var occurrences = usedNames[name]; const occurrences = usedNames[name];
if (defined(occurrences)) { if (defined(occurrences)) {
usedNames[name]++; usedNames[name]++;
name = name + '_' + occurrences; name = name + '_' + occurrences;
@ -570,11 +567,11 @@ function setDefaultNames(items, defaultName, usedNames) {
} }
function setDefaults(nodes) { function setDefaults(nodes) {
var usedNames = {}; const usedNames = {};
setDefaultNames(nodes, 'Node', usedNames); setDefaultNames(nodes, 'Node', usedNames);
var nodesLength = nodes.length; const nodesLength = nodes.length;
for (var i = 0; i < nodesLength; ++i) { for (let i = 0; i < nodesLength; ++i) {
var node = nodes[i]; const node = nodes[i];
setDefaultNames(node.meshes, node.name + '-Mesh', usedNames); setDefaultNames(node.meshes, node.name + '-Mesh', usedNames);
} }
} }

View File

@ -1,14 +1,14 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var fsExtra = require('fs-extra'); const fsExtra = require('fs-extra');
var jpeg = require('jpeg-js'); const jpeg = require('jpeg-js');
var path = require('path'); const path = require('path');
var PNG = require('pngjs').PNG; const PNG = require('pngjs').PNG;
var Promise = require('bluebird'); const Promise = require('bluebird');
var Texture = require('./Texture'); const Texture = require('./Texture');
var defaultValue = Cesium.defaultValue; const defaultValue = Cesium.defaultValue;
var defined = Cesium.defined; const defined = Cesium.defined;
module.exports = loadTexture; module.exports = loadTexture;
@ -30,15 +30,15 @@ function loadTexture(texturePath, options) {
return fsExtra.readFile(texturePath) return fsExtra.readFile(texturePath)
.then(function(source) { .then(function(source) {
var name = path.basename(texturePath, path.extname(texturePath)); const name = path.basename(texturePath, path.extname(texturePath));
var extension = path.extname(texturePath).toLowerCase(); const extension = path.extname(texturePath).toLowerCase();
var texture = new Texture(); const texture = new Texture();
texture.source = source; texture.source = source;
texture.name = name; texture.name = name;
texture.extension = extension; texture.extension = extension;
texture.path = texturePath; texture.path = texturePath;
var decodePromise; let decodePromise;
if (extension === '.png') { if (extension === '.png') {
decodePromise = decodePng(texture, options); decodePromise = decodePng(texture, options);
} else if (extension === '.jpg' || extension === '.jpeg') { } else if (extension === '.jpg' || extension === '.jpeg') {
@ -54,8 +54,8 @@ function loadTexture(texturePath, options) {
} }
function hasTransparency(pixels) { function hasTransparency(pixels) {
var pixelsLength = pixels.length / 4; const pixelsLength = pixels.length / 4;
for (var i = 0; i < pixelsLength; ++i) { for (let i = 0; i < pixelsLength; ++i) {
if (pixels[i * 4 + 3] < 255) { if (pixels[i * 4 + 3] < 255) {
return true; return true;
} }
@ -92,12 +92,12 @@ function parsePng(data) {
function decodePng(texture, options) { function decodePng(texture, options) {
// Color type is encoded in the 25th bit of the png // Color type is encoded in the 25th bit of the png
var source = texture.source; const source = texture.source;
var colorType = source[25]; const colorType = source[25];
var channels = getChannels(colorType); const channels = getChannels(colorType);
var checkTransparency = (channels === 4 && options.checkTransparency); const checkTransparency = (channels === 4 && options.checkTransparency);
var decode = options.decode || checkTransparency; const decode = options.decode || checkTransparency;
if (decode) { if (decode) {
return parsePng(source) return parsePng(source)
@ -117,8 +117,8 @@ function decodePng(texture, options) {
function decodeJpeg(texture, options) { function decodeJpeg(texture, options) {
if (options.decode) { if (options.decode) {
var source = texture.source; const source = texture.source;
var decodedResults = jpeg.decode(source); const decodedResults = jpeg.decode(source);
texture.pixels = decodedResults.data; texture.pixels = decodedResults.data;
texture.width = decodedResults.width; texture.width = decodedResults.width;
texture.height = decodedResults.height; texture.height = decodedResults.height;

View File

@ -1,14 +1,14 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var fsExtra = require('fs-extra'); const fsExtra = require('fs-extra');
var path = require('path'); const path = require('path');
var createGltf = require('./createGltf'); const createGltf = require('./createGltf');
var loadObj = require('./loadObj'); const loadObj = require('./loadObj');
var writeGltf = require('./writeGltf'); const writeGltf = require('./writeGltf');
var defaultValue = Cesium.defaultValue; const defaultValue = Cesium.defaultValue;
var defined = Cesium.defined; const defined = Cesium.defined;
var DeveloperError = Cesium.DeveloperError; const DeveloperError = Cesium.DeveloperError;
module.exports = obj2gltf; module.exports = obj2gltf;
@ -40,7 +40,7 @@ module.exports = obj2gltf;
* @return {Promise} A promise that resolves to the glTF JSON or glb buffer. * @return {Promise} A promise that resolves to the glTF JSON or glb buffer.
*/ */
function obj2gltf(objPath, options) { function obj2gltf(objPath, options) {
var defaults = obj2gltf.defaults; const defaults = obj2gltf.defaults;
options = defaultValue(options, {}); options = defaultValue(options, {});
options.binary = defaultValue(options.binary, defaults.binary); options.binary = defaultValue(options.binary, defaults.binary);
options.separate = defaultValue(options.separate, defaults.separate); options.separate = defaultValue(options.separate, defaults.separate);
@ -100,7 +100,7 @@ function getDefaultLogger() {
function getDefaultWriter(outputDirectory) { function getDefaultWriter(outputDirectory) {
if (defined(outputDirectory)) { if (defined(outputDirectory)) {
return function(file, data) { return function(file, data) {
var outputFile = path.join(outputDirectory, file); const outputFile = path.join(outputDirectory, file);
return fsExtra.outputFile(outputFile, data); return fsExtra.outputFile(outputFile, data);
}; };
} }

View File

@ -1,5 +1,5 @@
'use strict'; 'use strict';
var path = require('path'); const path = require('path');
module.exports = outsideDirectory; module.exports = outsideDirectory;

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var fsExtra = require('fs-extra'); const fsExtra = require('fs-extra');
var Promise = require('bluebird'); const Promise = require('bluebird');
var readline = require('readline'); const readline = require('readline');
module.exports = readLines; module.exports = readLines;
@ -16,11 +16,11 @@ module.exports = readLines;
*/ */
function readLines(path, callback) { function readLines(path, callback) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var stream = fsExtra.createReadStream(path); const stream = fsExtra.createReadStream(path);
stream.on('error', reject); stream.on('error', reject);
stream.on('end', resolve); stream.on('end', resolve);
var lineReader = readline.createInterface({ const lineReader = readline.createInterface({
input : stream input : stream
}); });
lineReader.on('line', callback); lineReader.on('line', callback);

View File

@ -1,13 +1,13 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var mime = require('mime'); const mime = require('mime');
var PNG = require('pngjs').PNG; const PNG = require('pngjs').PNG;
var Promise = require('bluebird'); const Promise = require('bluebird');
var getBufferPadded = require('./getBufferPadded'); const getBufferPadded = require('./getBufferPadded');
var gltfToGlb = require('./gltfToGlb'); const gltfToGlb = require('./gltfToGlb');
var defined = Cesium.defined; const defined = Cesium.defined;
var RuntimeError = Cesium.RuntimeError; const RuntimeError = Cesium.RuntimeError;
module.exports = writeGltf; module.exports = writeGltf;
@ -23,11 +23,11 @@ module.exports = writeGltf;
function writeGltf(gltf, options) { function writeGltf(gltf, options) {
return encodeTextures(gltf) return encodeTextures(gltf)
.then(function() { .then(function() {
var binary = options.binary; const binary = options.binary;
var separate = options.separate; const separate = options.separate;
var separateTextures = options.separateTextures; const separateTextures = options.separateTextures;
var promises = []; const promises = [];
if (separateTextures) { if (separateTextures) {
promises.push(writeSeparateTextures(gltf, options)); promises.push(writeSeparateTextures(gltf, options));
} else { } else {
@ -40,7 +40,7 @@ function writeGltf(gltf, options) {
writeEmbeddedBuffer(gltf); writeEmbeddedBuffer(gltf);
} }
var binaryBuffer = gltf.buffers[0].extras._obj2gltf.source; const binaryBuffer = gltf.buffers[0].extras._obj2gltf.source;
return Promise.all(promises) return Promise.all(promises)
.then(function() { .then(function() {
@ -56,10 +56,10 @@ function writeGltf(gltf, options) {
function encodePng(texture) { function encodePng(texture) {
// Constants defined by pngjs // Constants defined by pngjs
var rgbColorType = 2; const rgbColorType = 2;
var rgbaColorType = 6; const rgbaColorType = 6;
var png = new PNG({ const png = new PNG({
width : texture.width, width : texture.width,
height : texture.height, height : texture.height,
colorType : texture.transparent ? rgbaColorType : rgbColorType, colorType : texture.transparent ? rgbaColorType : rgbColorType,
@ -70,8 +70,8 @@ function encodePng(texture) {
png.data = texture.pixels; png.data = texture.pixels;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var chunks = []; const chunks = [];
var stream = png.pack(); const stream = png.pack();
stream.on('data', function(chunk) { stream.on('data', function(chunk) {
chunks.push(chunk); chunks.push(chunk);
}); });
@ -93,22 +93,22 @@ function encodeTexture(texture) {
function encodeTextures(gltf) { function encodeTextures(gltf) {
// Dynamically generated PBR textures need to be encoded to png prior to being saved // Dynamically generated PBR textures need to be encoded to png prior to being saved
var encodePromises = []; const encodePromises = [];
var images = gltf.images; const images = gltf.images;
var length = images.length; const length = images.length;
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
encodePromises.push(encodeTexture(images[i].extras._obj2gltf)); encodePromises.push(encodeTexture(images[i].extras._obj2gltf));
} }
return Promise.all(encodePromises); return Promise.all(encodePromises);
} }
function deleteExtras(gltf) { function deleteExtras(gltf) {
var buffer = gltf.buffers[0]; const buffer = gltf.buffers[0];
delete buffer.extras; delete buffer.extras;
var images = gltf.images; const images = gltf.images;
var imagesLength = images.length; const imagesLength = images.length;
for (var i = 0; i < imagesLength; ++i) { for (let i = 0; i < imagesLength; ++i) {
delete images[i].extras; delete images[i].extras;
} }
} }
@ -124,26 +124,26 @@ function removeEmpty(json) {
} }
function writeSeparateBuffer(gltf, options) { function writeSeparateBuffer(gltf, options) {
var buffer = gltf.buffers[0]; const buffer = gltf.buffers[0];
var source = buffer.extras._obj2gltf.source; const source = buffer.extras._obj2gltf.source;
var bufferUri = buffer.name + '.bin'; const bufferUri = buffer.name + '.bin';
buffer.uri = bufferUri; buffer.uri = bufferUri;
return options.writer(bufferUri, source); return options.writer(bufferUri, source);
} }
function writeSeparateTextures(gltf, options) { function writeSeparateTextures(gltf, options) {
var images = gltf.images; const images = gltf.images;
return Promise.map(images, function(image) { return Promise.map(images, function(image) {
var texture = image.extras._obj2gltf; const texture = image.extras._obj2gltf;
var imageUri = image.name + texture.extension; const imageUri = image.name + texture.extension;
image.uri = imageUri; image.uri = imageUri;
return options.writer(imageUri, texture.source); return options.writer(imageUri, texture.source);
}, {concurrency : 10}); }, {concurrency : 10});
} }
function writeEmbeddedBuffer(gltf) { function writeEmbeddedBuffer(gltf) {
var buffer = gltf.buffers[0]; const buffer = gltf.buffers[0];
var source = buffer.extras._obj2gltf.source; const source = buffer.extras._obj2gltf.source;
// Buffers larger than ~192MB cannot be base64 encoded due to a NodeJS limitation. Source: https://github.com/nodejs/node/issues/4266 // Buffers larger than ~192MB cannot be base64 encoded due to a NodeJS limitation. Source: https://github.com/nodejs/node/issues/4266
if (source.length > 201326580) { if (source.length > 201326580) {
@ -154,19 +154,19 @@ function writeEmbeddedBuffer(gltf) {
} }
function writeEmbeddedTextures(gltf) { function writeEmbeddedTextures(gltf) {
var buffer = gltf.buffers[0]; const buffer = gltf.buffers[0];
var bufferExtras = buffer.extras._obj2gltf; const bufferExtras = buffer.extras._obj2gltf;
var bufferSource = bufferExtras.source; const bufferSource = bufferExtras.source;
var images = gltf.images; const images = gltf.images;
var imagesLength = images.length; const imagesLength = images.length;
var sources = [bufferSource]; const sources = [bufferSource];
var byteOffset = bufferSource.length; let byteOffset = bufferSource.length;
for (var i = 0; i < imagesLength; ++i) { for (let i = 0; i < imagesLength; ++i) {
var image = images[i]; const image = images[i];
var texture = image.extras._obj2gltf; const texture = image.extras._obj2gltf;
var textureSource = texture.source; const textureSource = texture.source;
var textureByteLength = textureSource.length; const textureByteLength = textureSource.length;
image.mimeType = mime.getType(texture.extension); image.mimeType = mime.getType(texture.extension);
image.bufferView = gltf.bufferViews.length; image.bufferView = gltf.bufferViews.length;
@ -179,7 +179,7 @@ function writeEmbeddedTextures(gltf) {
sources.push(textureSource); sources.push(textureSource);
} }
var source = getBufferPadded(Buffer.concat(sources)); const source = getBufferPadded(Buffer.concat(sources));
bufferExtras.source = source; bufferExtras.source = source;
buffer.byteLength = source.length; buffer.byteLength = source.length;
} }

View File

@ -2,5 +2,8 @@
"extends": "../.eslintrc.json", "extends": "../.eslintrc.json",
"env": { "env": {
"jasmine": true "jasmine": true
},
"rules": {
"no-restricted-globals": ["error", "fdescribe", "fit"]
} }
} }

View File

@ -2,8 +2,5 @@
"spec_dir": "specs", "spec_dir": "specs",
"spec_files": [ "spec_files": [
"**/*Spec.js" "**/*Spec.js"
],
"helpers": [
"matchers/nodeHelper.js"
] ]
} }

View File

@ -1,61 +1,43 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var Promise = require('bluebird'); const obj2gltf = require('../../lib/obj2gltf');
var obj2gltf = require('../../lib/obj2gltf'); const createGltf = require('../../lib/createGltf');
var createGltf = require('../../lib/createGltf'); const loadObj = require('../../lib/loadObj');
var loadObj = require('../../lib/loadObj'); const { getDefaultMaterial } = require('../../lib/loadMtl');
var getDefaultMaterial = require('../../lib/loadMtl').getDefaultMaterial;
var clone = Cesium.clone; const clone = Cesium.clone;
var defined = Cesium.defined; const defined = Cesium.defined;
var WebGLConstants = Cesium.WebGLConstants; const WebGLConstants = Cesium.WebGLConstants;
var boxObjPath = 'specs/data/box/box.obj'; const boxObjPath = 'specs/data/box/box.obj';
var groupObjPath = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.obj'; const groupObjPath = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.obj';
var complexObjPath = 'specs/data/box-complex-material/box-complex-material.obj'; const complexObjPath = 'specs/data/box-complex-material/box-complex-material.obj';
var noMaterialsObjPath = 'specs/data/box-no-materials/box-no-materials.obj'; const noMaterialsObjPath = 'specs/data/box-no-materials/box-no-materials.obj';
var mixedAttributesObjPath = 'specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj'; const mixedAttributesObjPath = 'specs/data/box-mixed-attributes-2/box-mixed-attributes-2.obj';
var options; let options;
describe('createGltf', function() { describe('createGltf', () => {
var boxObjData; let boxObjData;
var groupObjData; let groupObjData;
var complexObjData; let complexObjData;
var noMaterialsObjData; let noMaterialsObjData;
var mixedAttributesObjData; let mixedAttributesObjData;
beforeEach(function(done) { beforeEach(async () => {
options = clone(obj2gltf.defaults); options = clone(obj2gltf.defaults);
options.overridingTextures = {}; options.overridingTextures = {};
options.logger = function() {}; options.logger = () => {};
return Promise.all([ boxObjData = await loadObj(boxObjPath, options);
loadObj(boxObjPath, options) groupObjData = await loadObj(groupObjPath, options);
.then(function(data) { complexObjData = await loadObj(complexObjPath, options);
boxObjData = data; noMaterialsObjData = await loadObj(noMaterialsObjPath, options);
}), mixedAttributesObjData = await loadObj(mixedAttributesObjPath, options);
loadObj(groupObjPath, options)
.then(function(data) {
groupObjData = data;
}),
loadObj(complexObjPath, options)
.then(function(data) {
complexObjData = data;
}),
loadObj(noMaterialsObjPath, options)
.then(function(data) {
noMaterialsObjData = data;
}),
loadObj(mixedAttributesObjPath, options)
.then(function(data) {
mixedAttributesObjData = data;
})
]).then(done);
}); });
it('simple gltf', function() { it('simple gltf', () => {
var gltf = createGltf(boxObjData, options); const gltf = createGltf(boxObjData, options);
expect(gltf.materials.length).toBe(1); expect(gltf.materials.length).toBe(1);
expect(gltf.scene).toBe(0); expect(gltf.scene).toBe(0);
@ -63,13 +45,13 @@ describe('createGltf', function() {
expect(gltf.nodes.length).toBe(1); expect(gltf.nodes.length).toBe(1);
expect(gltf.meshes.length).toBe(1); expect(gltf.meshes.length).toBe(1);
var primitives = gltf.meshes[0].primitives; const primitives = gltf.meshes[0].primitives;
var primitive = primitives[0]; const primitive = primitives[0];
var attributes = primitive.attributes; const attributes = primitive.attributes;
var positionAccessor = gltf.accessors[attributes.POSITION]; const positionAccessor = gltf.accessors[attributes.POSITION];
var normalAccessor = gltf.accessors[attributes.NORMAL]; const normalAccessor = gltf.accessors[attributes.NORMAL];
var uvAccessor = gltf.accessors[attributes.TEXCOORD_0]; const uvAccessor = gltf.accessors[attributes.TEXCOORD_0];
var indexAccessor = gltf.accessors[primitive.indices]; const indexAccessor = gltf.accessors[primitive.indices];
expect(primitives.length).toBe(1); expect(primitives.length).toBe(1);
expect(positionAccessor.count).toBe(24); expect(positionAccessor.count).toBe(24);
@ -78,8 +60,8 @@ describe('createGltf', function() {
expect(indexAccessor.count).toBe(36); expect(indexAccessor.count).toBe(36);
}); });
it('multiple nodes, meshes, and primitives', function() { it('multiple nodes, meshes, and primitives', () => {
var gltf = createGltf(groupObjData, options); const gltf = createGltf(groupObjData, options);
expect(gltf.materials.length).toBe(3); expect(gltf.materials.length).toBe(3);
expect(gltf.scene).toBe(0); expect(gltf.scene).toBe(0);
@ -90,28 +72,28 @@ describe('createGltf', function() {
expect(gltf.meshes.length).toBe(3); expect(gltf.meshes.length).toBe(3);
// Check for two primitives in each mesh // Check for two primitives in each mesh
var length = gltf.meshes.length; const length = gltf.meshes.length;
for (var i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
var mesh = gltf.meshes[i]; const mesh = gltf.meshes[i];
expect(mesh.primitives.length).toBe(2); expect(mesh.primitives.length).toBe(2);
} }
}); });
it('multiple textures', function() { it('multiple textures', () => {
var gltf = createGltf(complexObjData, options); const gltf = createGltf(complexObjData, options);
var material = gltf.materials[0]; const material = gltf.materials[0];
var pbr = material.pbrMetallicRoughness; const pbr = material.pbrMetallicRoughness;
var textures = [pbr.metallicRoughnessTexture, pbr.baseColorTexture, material.emissiveTexture, material.normalTexture, material.occlusionTexture]; const textures = [pbr.metallicRoughnessTexture, pbr.baseColorTexture, material.emissiveTexture, material.normalTexture, material.occlusionTexture];
expect(textures.map(function(texture) { expect(textures.map((texture) => {
return texture.index; return texture.index;
}).sort()).toEqual([0, 1, 2, 3, 4]); }).sort()).toEqual([0, 1, 2, 3, 4]);
expect(gltf.samplers[0]).toBeDefined(); expect(gltf.samplers[0]).toBeDefined();
}); });
it('creates default material', function() { it('creates default material', () => {
var gltf = createGltf(noMaterialsObjData, options); const gltf = createGltf(noMaterialsObjData, options);
var material = gltf.materials[0]; const material = gltf.materials[0];
var pbr = material.pbrMetallicRoughness; const pbr = material.pbrMetallicRoughness;
expect(material.name).toBe('default'); expect(material.name).toBe('default');
expect(pbr.baseColorTexture).toBeUndefined(); expect(pbr.baseColorTexture).toBeUndefined();
expect(pbr.metallicRoughnessTexture).toBeUndefined(); expect(pbr.metallicRoughnessTexture).toBeUndefined();
@ -126,70 +108,70 @@ describe('createGltf', function() {
expect(material.doubleSided).toBe(false); expect(material.doubleSided).toBe(false);
}); });
it('adds KHR_materials_pbrSpecularGlossiness extension when specularGlossiness is set', function() { it('adds KHR_materials_pbrSpecularGlossiness extension when specularGlossiness is set', () => {
options.specularGlossiness = true; options.specularGlossiness = true;
var gltf = createGltf(noMaterialsObjData, options); const gltf = createGltf(noMaterialsObjData, options);
expect(gltf.extensionsUsed).toEqual(['KHR_materials_pbrSpecularGlossiness']); expect(gltf.extensionsUsed).toEqual(['KHR_materials_pbrSpecularGlossiness']);
expect(gltf.extensionsRequired).toEqual(['KHR_materials_pbrSpecularGlossiness']); expect(gltf.extensionsRequired).toEqual(['KHR_materials_pbrSpecularGlossiness']);
}); });
it('adds KHR_materials_unlit extension when unlit is set', function() { it('adds KHR_materials_unlit extension when unlit is set', () => {
options.unlit = true; options.unlit = true;
var gltf = createGltf(noMaterialsObjData, options); const gltf = createGltf(noMaterialsObjData, options);
expect(gltf.extensionsUsed).toEqual(['KHR_materials_unlit']); expect(gltf.extensionsUsed).toEqual(['KHR_materials_unlit']);
expect(gltf.extensionsRequired).toEqual(['KHR_materials_unlit']); expect(gltf.extensionsRequired).toEqual(['KHR_materials_unlit']);
}); });
it('runs without normals', function() { it('runs without normals', () => {
boxObjData.nodes[0].meshes[0].primitives[0].normals.length = 0; boxObjData.nodes[0].meshes[0].primitives[0].normals.length = 0;
var gltf = createGltf(boxObjData, options); const gltf = createGltf(boxObjData, options);
var attributes = gltf.meshes[0].primitives[0].attributes; const attributes = gltf.meshes[0].primitives[0].attributes;
expect(attributes.POSITION).toBeDefined(); expect(attributes.POSITION).toBeDefined();
expect(attributes.NORMAL).toBeUndefined(); expect(attributes.NORMAL).toBeUndefined();
expect(attributes.TEXCOORD_0).toBeDefined(); expect(attributes.TEXCOORD_0).toBeDefined();
}); });
it('runs without uvs', function() { it('runs without uvs', () => {
boxObjData.nodes[0].meshes[0].primitives[0].uvs.length = 0; boxObjData.nodes[0].meshes[0].primitives[0].uvs.length = 0;
var gltf = createGltf(boxObjData, options); const gltf = createGltf(boxObjData, options);
var attributes = gltf.meshes[0].primitives[0].attributes; const attributes = gltf.meshes[0].primitives[0].attributes;
expect(attributes.POSITION).toBeDefined(); expect(attributes.POSITION).toBeDefined();
expect(attributes.NORMAL).toBeDefined(); expect(attributes.NORMAL).toBeDefined();
expect(attributes.TEXCOORD_0).toBeUndefined(); expect(attributes.TEXCOORD_0).toBeUndefined();
}); });
it('runs without uvs and normals', function() { it('runs without uvs and normals', () => {
boxObjData.nodes[0].meshes[0].primitives[0].normals.length = 0; boxObjData.nodes[0].meshes[0].primitives[0].normals.length = 0;
boxObjData.nodes[0].meshes[0].primitives[0].uvs.length = 0; boxObjData.nodes[0].meshes[0].primitives[0].uvs.length = 0;
var gltf = createGltf(boxObjData, options); const gltf = createGltf(boxObjData, options);
var attributes = gltf.meshes[0].primitives[0].attributes; const attributes = gltf.meshes[0].primitives[0].attributes;
expect(attributes.POSITION).toBeDefined(); expect(attributes.POSITION).toBeDefined();
expect(attributes.NORMAL).toBeUndefined(); expect(attributes.NORMAL).toBeUndefined();
expect(attributes.TEXCOORD_0).toBeUndefined(); expect(attributes.TEXCOORD_0).toBeUndefined();
}); });
it('splits incompatible materials', function() { it('splits incompatible materials', () => {
var gltf = createGltf(mixedAttributesObjData, options); const gltf = createGltf(mixedAttributesObjData, options);
var materials = gltf.materials; const materials = gltf.materials;
var meshes = gltf.meshes; const meshes = gltf.meshes;
var referenceMaterial = mixedAttributesObjData.materials[0]; const referenceMaterial = mixedAttributesObjData.materials[0];
delete referenceMaterial.name; delete referenceMaterial.name;
referenceMaterial.pbrMetallicRoughness.baseColorTexture = { referenceMaterial.pbrMetallicRoughness.baseColorTexture = {
index : 0 index : 0
}; };
var referenceMaterialNoTextures = clone(referenceMaterial, true); const referenceMaterialNoTextures = clone(referenceMaterial, true);
referenceMaterialNoTextures.pbrMetallicRoughness.baseColorTexture = undefined; referenceMaterialNoTextures.pbrMetallicRoughness.baseColorTexture = undefined;
var defaultMaterial = getDefaultMaterial(options); const defaultMaterial = getDefaultMaterial(options);
delete defaultMaterial.name; delete defaultMaterial.name;
var materialNames = materials.map(function(material) { const materialNames = materials.map((material) => {
var name = material.name; const name = material.name;
delete material.name; delete material.name;
return name; return name;
}); });
@ -222,14 +204,14 @@ describe('createGltf', function() {
expect(materials[8]).toEqual(defaultMaterial); expect(materials[8]).toEqual(defaultMaterial);
// Test that primitives without uvs reference materials without textures // Test that primitives without uvs reference materials without textures
var meshesLength = meshes.length; const meshesLength = meshes.length;
for (var i = 0; i < meshesLength; ++i) { for (let i = 0; i < meshesLength; ++i) {
var mesh = meshes[i]; const mesh = meshes[i];
var primitives = mesh.primitives; const primitives = mesh.primitives;
var primitivesLength = primitives.length; const primitivesLength = primitives.length;
for (var j = 0; j < primitivesLength; ++j) { for (let j = 0; j < primitivesLength; ++j) {
var primitive = primitives[j]; const primitive = primitives[j];
var material = materials[primitive.material]; const material = materials[primitive.material];
if (!defined(primitive.attributes.TEXCOORD_0)) { if (!defined(primitive.attributes.TEXCOORD_0)) {
expect(material.pbrMetallicRoughness.baseColorTexture).toBeUndefined(); expect(material.pbrMetallicRoughness.baseColorTexture).toBeUndefined();
} }
@ -238,17 +220,17 @@ describe('createGltf', function() {
}); });
function expandObjData(objData, duplicatesLength) { function expandObjData(objData, duplicatesLength) {
var primitive = objData.nodes[0].meshes[0].primitives[0]; const primitive = objData.nodes[0].meshes[0].primitives[0];
var indices = primitive.indices; const indices = primitive.indices;
var positions = primitive.positions; const positions = primitive.positions;
var normals = primitive.normals; const normals = primitive.normals;
var uvs = primitive.uvs; const uvs = primitive.uvs;
var indicesLength = indices.length; const indicesLength = indices.length;
var vertexCount = positions.length / 3; const vertexCount = positions.length / 3;
for (var i = 1; i < duplicatesLength; ++i) { for (let i = 1; i < duplicatesLength; ++i) {
for (var j = 0; j < vertexCount; ++j) { for (let j = 0; j < vertexCount; ++j) {
positions.push(0.0); positions.push(0.0);
positions.push(0.0); positions.push(0.0);
positions.push(0.0); positions.push(0.0);
@ -258,26 +240,26 @@ describe('createGltf', function() {
uvs.push(0.0); uvs.push(0.0);
uvs.push(0.0); uvs.push(0.0);
} }
for (var k = 0; k < indicesLength; ++k) { for (let k = 0; k < indicesLength; ++k) {
indices.push(indices.get(k) + vertexCount * i); indices.push(indices.get(k) + vertexCount * i);
} }
} }
} }
it('detects need to use uint32 indices', function() { it('detects need to use uint32 indices', () => {
expandObjData(boxObjData, 2731); // Right above 65536 limit expandObjData(boxObjData, 2731); // Right above 65536 limit
var primitive = boxObjData.nodes[0].meshes[0].primitives[0]; let primitive = boxObjData.nodes[0].meshes[0].primitives[0];
var indicesLength = primitive.indices.length; const indicesLength = primitive.indices.length;
var vertexCount = primitive.positions.length / 3; const vertexCount = primitive.positions.length / 3;
var gltf = createGltf(boxObjData, options); const gltf = createGltf(boxObjData, options);
primitive = gltf.meshes[0].primitives[0]; primitive = gltf.meshes[0].primitives[0];
var indicesAccessor = gltf.accessors[primitive.indices]; const indicesAccessor = gltf.accessors[primitive.indices];
expect(indicesAccessor.count).toBe(indicesLength); expect(indicesAccessor.count).toBe(indicesLength);
expect(indicesAccessor.max[0]).toBe(vertexCount - 1); expect(indicesAccessor.max[0]).toBe(vertexCount - 1);
expect(indicesAccessor.componentType).toBe(WebGLConstants.UNSIGNED_INT); expect(indicesAccessor.componentType).toBe(WebGLConstants.UNSIGNED_INT);
var positionAccessor = gltf.accessors[primitive.attributes.POSITION]; const positionAccessor = gltf.accessors[primitive.attributes.POSITION];
expect(positionAccessor.count).toBe(vertexCount); expect(positionAccessor.count).toBe(vertexCount);
}); });
}); });

View File

@ -1,271 +1,222 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var Promise = require('bluebird'); const fsExtra = require('fs-extra');
var fsExtra = require('fs-extra'); const loadMtl = require('../../lib/loadMtl');
var loadMtl = require('../../lib/loadMtl'); const loadTexture = require('../../lib/loadTexture');
var loadTexture = require('../../lib/loadTexture'); const obj2gltf = require('../../lib/obj2gltf');
var obj2gltf = require('../../lib/obj2gltf');
var clone = Cesium.clone; const clone = Cesium.clone;
var coloredMaterialPath = 'specs/data/box/box.mtl'; const coloredMaterialPath = 'specs/data/box/box.mtl';
var texturedMaterialPath = 'specs/data/box-complex-material/box-complex-material.mtl'; const texturedMaterialPath = 'specs/data/box-complex-material/box-complex-material.mtl';
var texturedWithOptionsMaterialPath = 'specs/data/box-texture-options/box-texture-options.mtl'; const texturedWithOptionsMaterialPath = 'specs/data/box-texture-options/box-texture-options.mtl';
var multipleMaterialsPath = 'specs/data/box-multiple-materials/box-multiple-materials.mtl'; const multipleMaterialsPath = 'specs/data/box-multiple-materials/box-multiple-materials.mtl';
var externalMaterialPath = 'specs/data/box-external-resources/box-external-resources.mtl'; const externalMaterialPath = 'specs/data/box-external-resources/box-external-resources.mtl';
var resourcesInRootMaterialPath = 'specs/data/box-resources-in-root/box-resources-in-root.mtl'; const 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'; const externalInRootMaterialPath = 'specs/data/box-external-resources-in-root/box-external-resources-in-root.mtl';
var transparentMaterialPath = 'specs/data/box-transparent/box-transparent.mtl'; const transparentMaterialPath = 'specs/data/box-transparent/box-transparent.mtl';
var diffuseAmbientSameMaterialPath = 'specs/data/box-diffuse-ambient-same/box-diffuse-ambient-same.mtl'; const diffuseAmbientSameMaterialPath = 'specs/data/box-diffuse-ambient-same/box-diffuse-ambient-same.mtl';
var diffuseTexturePath = 'specs/data/box-textured/cesium.png'; const diffuseTexturePath = 'specs/data/box-textured/cesium.png';
var transparentDiffuseTexturePath = 'specs/data/box-complex-material/diffuse.png'; const transparentDiffuseTexturePath = 'specs/data/box-complex-material/diffuse.png';
var alphaTexturePath = 'specs/data/box-complex-material-alpha/alpha.png'; const alphaTexturePath = 'specs/data/box-complex-material-alpha/alpha.png';
var ambientTexturePath = 'specs/data/box-complex-material/ambient.gif'; const ambientTexturePath = 'specs/data/box-complex-material/ambient.gif';
var normalTexturePath = 'specs/data/box-complex-material/bump.png'; const normalTexturePath = 'specs/data/box-complex-material/bump.png';
var emissiveTexturePath = 'specs/data/box-complex-material/emission.jpg'; const emissiveTexturePath = 'specs/data/box-complex-material/emission.jpg';
var specularTexturePath = 'specs/data/box-complex-material/specular.jpeg'; const specularTexturePath = 'specs/data/box-complex-material/specular.jpeg';
var specularShininessTexturePath = 'specs/data/box-complex-material/shininess.png'; const specularShininessTexturePath = 'specs/data/box-complex-material/shininess.png';
var diffuseTexture; let diffuseTexture;
var transparentDiffuseTexture; let transparentDiffuseTexture;
var alphaTexture; let alphaTexture;
var ambientTexture; let ambientTexture;
var normalTexture; let normalTexture;
var emissiveTexture; let emissiveTexture;
var specularTexture; let specularTexture;
var specularShininessTexture; let specularShininessTexture;
var checkTransparencyOptions = { const checkTransparencyOptions = {
checkTransparency : true checkTransparency : true
}; };
var decodeOptions = { const decodeOptions = {
decode : true decode : true
}; };
var options; let options;
describe('loadMtl', function() { describe('loadMtl', () => {
beforeAll(function(done) { beforeAll(async () => {
return Promise.all([ diffuseTexture = await loadTexture(diffuseTexturePath, decodeOptions);
loadTexture(diffuseTexturePath, decodeOptions) transparentDiffuseTexture = await loadTexture(transparentDiffuseTexturePath, checkTransparencyOptions);
.then(function(texture) { alphaTexture = await loadTexture(alphaTexturePath, decodeOptions);
diffuseTexture = texture; ambientTexture = await loadTexture(ambientTexturePath);
}), normalTexture = await loadTexture(normalTexturePath);
loadTexture(transparentDiffuseTexturePath, checkTransparencyOptions) emissiveTexture = await loadTexture(emissiveTexturePath);
.then(function(texture) { specularTexture = await loadTexture(specularTexturePath, decodeOptions);
transparentDiffuseTexture = texture; specularShininessTexture = await loadTexture(specularShininessTexturePath, decodeOptions);
}),
loadTexture(alphaTexturePath, decodeOptions)
.then(function(texture) {
alphaTexture = texture;
}),
loadTexture(ambientTexturePath)
.then(function(texture) {
ambientTexture = texture;
}),
loadTexture(normalTexturePath)
.then(function(texture) {
normalTexture = texture;
}),
loadTexture(emissiveTexturePath)
.then(function(texture) {
emissiveTexture = texture;
}),
loadTexture(specularTexturePath, decodeOptions)
.then(function(texture) {
specularTexture = texture;
}),
loadTexture(specularShininessTexturePath, decodeOptions)
.then(function(texture) {
specularShininessTexture = texture;
})
]).then(done);
}); });
beforeEach(function() { beforeEach(() => {
options = clone(obj2gltf.defaults); options = clone(obj2gltf.defaults);
options.overridingTextures = {}; options.overridingTextures = {};
options.logger = function() {}; options.logger = () => {};
options.hasNormals = true; options.hasNormals = true;
}); });
it('loads mtl', function(done) { it('loads mtl', async () => {
options.metallicRoughness = true; options.metallicRoughness = true;
expect(loadMtl(coloredMaterialPath, options) const materials = await loadMtl(coloredMaterialPath, options);
.then(function(materials) { expect(materials.length).toBe(1);
expect(materials.length).toBe(1); const material = materials[0];
var material = materials[0]; const pbr = material.pbrMetallicRoughness;
var pbr = material.pbrMetallicRoughness; expect(pbr.baseColorTexture).toBeUndefined();
expect(pbr.baseColorTexture).toBeUndefined(); expect(pbr.metallicRoughnessTexture).toBeUndefined();
expect(pbr.metallicRoughnessTexture).toBeUndefined(); expect(pbr.baseColorFactor).toEqual([0.64, 0.64, 0.64, 1.0]);
expect(pbr.baseColorFactor).toEqual([0.64, 0.64, 0.64, 1.0]); expect(pbr.metallicFactor).toBe(0.5);
expect(pbr.metallicFactor).toBe(0.5); expect(pbr.roughnessFactor).toBe(96.078431);
expect(pbr.roughnessFactor).toBe(96.078431); expect(material.name).toBe('Material');
expect(material.name).toBe('Material'); expect(material.emissiveTexture).toBeUndefined();
expect(material.emissiveTexture).toBeUndefined(); expect(material.normalTexture).toBeUndefined();
expect(material.normalTexture).toBeUndefined(); expect(material.ambientTexture).toBeUndefined();
expect(material.ambientTexture).toBeUndefined(); expect(material.emissiveFactor).toEqual([0.0, 0.0, 0.1]);
expect(material.emissiveFactor).toEqual([0.0, 0.0, 0.1]); expect(material.alphaMode).toBe('OPAQUE');
expect(material.alphaMode).toBe('OPAQUE'); expect(material.doubleSided).toBe(false);
expect(material.doubleSided).toBe(false);
}), done).toResolve();
}); });
it('loads mtl with textures', function(done) { it('loads mtl with textures', async () => {
options.metallicRoughness = true; options.metallicRoughness = true;
expect(loadMtl(texturedMaterialPath, options) const materials = await loadMtl(texturedMaterialPath, options);
.then(function(materials) { expect(materials.length).toBe(1);
expect(materials.length).toBe(1); const material = materials[0];
var material = materials[0]; const pbr = material.pbrMetallicRoughness;
var pbr = material.pbrMetallicRoughness; expect(pbr.baseColorTexture).toBeDefined();
expect(pbr.baseColorTexture).toBeDefined(); expect(pbr.metallicRoughnessTexture).toBeDefined();
expect(pbr.metallicRoughnessTexture).toBeDefined(); expect(pbr.baseColorFactor).toEqual([1.0, 1.0, 1.0, 0.9]);
expect(pbr.baseColorFactor).toEqual([1.0, 1.0, 1.0, 0.9]); expect(pbr.metallicFactor).toBe(1.0);
expect(pbr.metallicFactor).toBe(1.0); expect(pbr.roughnessFactor).toBe(1.0);
expect(pbr.roughnessFactor).toBe(1.0); expect(material.name).toBe('Material');
expect(material.name).toBe('Material'); expect(material.emissiveTexture).toBeDefined();
expect(material.emissiveTexture).toBeDefined(); expect(material.normalTexture).toBeDefined();
expect(material.normalTexture).toBeDefined(); expect(material.occlusionTexture).toBeDefined();
expect(material.occlusionTexture).toBeDefined(); expect(material.emissiveFactor).toEqual([1.0, 1.0, 1.0]);
expect(material.emissiveFactor).toEqual([1.0, 1.0, 1.0]); expect(material.alphaMode).toBe('BLEND');
expect(material.alphaMode).toBe('BLEND'); expect(material.doubleSided).toBe(true);
expect(material.doubleSided).toBe(true);
}), done).toResolve();
}); });
it('loads mtl with textures having options', function(done) { it('loads mtl with textures having options', async () => {
options.metallicRoughness = true; options.metallicRoughness = true;
expect(loadMtl(texturedWithOptionsMaterialPath, options) const materials = await loadMtl(texturedWithOptionsMaterialPath, options);
.then(function(materials) { expect(materials.length).toBe(1);
expect(materials.length).toBe(1); const material = materials[0];
var material = materials[0]; const pbr = material.pbrMetallicRoughness;
var pbr = material.pbrMetallicRoughness; expect(pbr.baseColorTexture).toBeDefined();
expect(pbr.baseColorTexture).toBeDefined(); expect(pbr.metallicRoughnessTexture).toBeDefined();
expect(pbr.metallicRoughnessTexture).toBeDefined(); expect(pbr.baseColorFactor).toEqual([1.0, 1.0, 1.0, 0.9]);
expect(pbr.baseColorFactor).toEqual([1.0, 1.0, 1.0, 0.9]); expect(pbr.metallicFactor).toBe(1.0);
expect(pbr.metallicFactor).toBe(1.0); expect(pbr.roughnessFactor).toBe(1.0);
expect(pbr.roughnessFactor).toBe(1.0); expect(material.name).toBe('Material');
expect(material.name).toBe('Material'); expect(material.emissiveTexture).toBeDefined();
expect(material.emissiveTexture).toBeDefined(); expect(material.normalTexture).toBeDefined();
expect(material.normalTexture).toBeDefined(); expect(material.occlusionTexture).toBeDefined();
expect(material.occlusionTexture).toBeDefined(); expect(material.emissiveFactor).toEqual([1.0, 1.0, 1.0]);
expect(material.emissiveFactor).toEqual([1.0, 1.0, 1.0]); expect(material.alphaMode).toBe('BLEND');
expect(material.alphaMode).toBe('BLEND'); expect(material.doubleSided).toBe(true);
expect(material.doubleSided).toBe(true);
}), done).toResolve();
}); });
it('loads mtl with multiple materials', function(done) { it('loads mtl with multiple materials', async () => {
options.metallicRoughness = true; options.metallicRoughness = true;
expect(loadMtl(multipleMaterialsPath, options) const materials = await loadMtl(multipleMaterialsPath, options);
.then(function(materials) { expect(materials.length).toBe(3);
expect(materials.length).toBe(3); expect(materials[0].name).toBe('Blue');
expect(materials[0].name).toBe('Blue'); expect(materials[0].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.0, 0.64, 1.0]);
expect(materials[0].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.0, 0.64, 1.0]); expect(materials[1].name).toBe('Green');
expect(materials[1].name).toBe('Green'); expect(materials[1].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.64, 0.0, 1.0]);
expect(materials[1].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.64, 0.0, 1.0]); expect(materials[2].name).toBe('Red');
expect(materials[2].name).toBe('Red'); expect(materials[2].pbrMetallicRoughness.baseColorFactor).toEqual([0.64, 0.0, 0.0, 1.0]);
expect(materials[2].pbrMetallicRoughness.baseColorFactor).toEqual([0.64, 0.0, 0.0, 1.0]);
}), done).toResolve();
}); });
it('sets overriding textures', function(done) { it('sets overriding textures', async () => {
spyOn(fsExtra, 'readFile').and.callThrough(); spyOn(fsExtra, 'readFile').and.callThrough();
options.overridingTextures = { options.overridingTextures = {
metallicRoughnessOcclusionTexture : alphaTexturePath, metallicRoughnessOcclusionTexture : alphaTexturePath,
baseColorTexture : alphaTexturePath, baseColorTexture : alphaTexturePath,
emissiveTexture : emissiveTexturePath emissiveTexture : emissiveTexturePath
}; };
expect(loadMtl(texturedMaterialPath, options) const materials = await loadMtl(texturedMaterialPath, options);
.then(function(materials) { const material = materials[0];
var material = materials[0]; const pbr = material.pbrMetallicRoughness;
var pbr = material.pbrMetallicRoughness; expect(pbr.baseColorTexture.name).toBe('alpha');
expect(pbr.baseColorTexture.name).toBe('alpha'); expect(pbr.metallicRoughnessTexture.name).toBe('alpha');
expect(pbr.metallicRoughnessTexture.name).toBe('alpha'); expect(material.emissiveTexture.name).toBe('emission');
expect(material.emissiveTexture.name).toBe('emission'); expect(material.normalTexture.name).toBe('bump');
expect(material.normalTexture.name).toBe('bump'); expect(fsExtra.readFile.calls.count()).toBe(3);
expect(fsExtra.readFile.calls.count()).toBe(3);
}), done).toResolve();
}); });
it('loads texture outside of the mtl directory', function(done) { it('loads texture outside of the mtl directory', async () => {
expect(loadMtl(externalMaterialPath, options) const materials = await loadMtl(externalMaterialPath, options);
.then(function(materials) { const material = materials[0];
var material = materials[0]; const baseColorTexture = material.pbrMetallicRoughness.baseColorTexture;
var baseColorTexture = material.pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture.source).toBeDefined();
expect(baseColorTexture.source).toBeDefined(); expect(baseColorTexture.name).toBe('cesium');
expect(baseColorTexture.name).toBe('cesium');
}), done).toResolve();
}); });
it('does not load texture outside of the mtl directory when secure is true', function(done) { it('does not load texture outside of the mtl directory when secure is true', async () => {
var spy = jasmine.createSpy('logger'); const spy = jasmine.createSpy('logger');
options.logger = spy; options.logger = spy;
options.secure = true; options.secure = true;
expect(loadMtl(externalMaterialPath, options) const materials = await loadMtl(externalMaterialPath, options);
.then(function(materials) { const material = materials[0];
var material = materials[0]; const baseColorTexture = material.pbrMetallicRoughness.baseColorTexture;
var baseColorTexture = material.pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture).toBeUndefined();
expect(baseColorTexture).toBeUndefined(); 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(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(1)[0].indexOf('ENOENT') >= 0).toBe(true); expect(spy.calls.argsFor(2)[0].indexOf('Could not read texture file') >= 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) { it('loads textures from root directory when the texture paths do not exist', async () => {
expect(loadMtl(resourcesInRootMaterialPath, options) const materials = await loadMtl(resourcesInRootMaterialPath, options);
.then(function(materials) { const material = materials[0];
var material = materials[0]; const baseColorTexture = material.pbrMetallicRoughness.baseColorTexture;
var baseColorTexture = material.pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture.source).toBeDefined();
expect(baseColorTexture.source).toBeDefined(); expect(baseColorTexture.name).toBe('cesium');
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) { it('loads textures from root directory when texture is outside of the mtl directory and secure is true', async () => {
options.secure = true; options.secure = true;
expect(loadMtl(externalInRootMaterialPath, options) const materials = await loadMtl(externalInRootMaterialPath, options);
.then(function(materials) { const material = materials[0];
var material = materials[0]; const baseColorTexture = material.pbrMetallicRoughness.baseColorTexture;
var baseColorTexture = material.pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture.source).toBeDefined();
expect(baseColorTexture.source).toBeDefined(); expect(baseColorTexture.name).toBe('cesium');
expect(baseColorTexture.name).toBe('cesium');
}), done).toResolve();
}); });
it('alpha of 0.0 is treated as 1.0', function(done) { it('alpha of 0.0 is treated as 1.0', async () => {
expect(loadMtl(transparentMaterialPath, options) const materials = await loadMtl(transparentMaterialPath, options);
.then(function(materials) { expect(materials.length).toBe(1);
expect(materials.length).toBe(1); const material = materials[0];
var material = materials[0]; const pbr = material.pbrMetallicRoughness;
var pbr = material.pbrMetallicRoughness; expect(pbr.baseColorTexture).toBeUndefined();
expect(pbr.baseColorTexture).toBeUndefined(); expect(pbr.metallicRoughnessTexture).toBeUndefined();
expect(pbr.metallicRoughnessTexture).toBeUndefined(); expect(pbr.baseColorFactor[3]).toEqual(1.0);
expect(pbr.baseColorFactor[3]).toEqual(1.0); expect(material.alphaMode).toBe('OPAQUE');
expect(material.alphaMode).toBe('OPAQUE'); expect(material.doubleSided).toBe(false);
expect(material.doubleSided).toBe(false);
}), done).toResolve();
}); });
it('ambient texture is ignored if it is the same as the diffuse texture', function(done) { it('ambient texture is ignored if it is the same as the diffuse texture', async () => {
expect(loadMtl(diffuseAmbientSameMaterialPath, options) const materials = await loadMtl(diffuseAmbientSameMaterialPath, options);
.then(function(materials) { expect(materials.length).toBe(1);
expect(materials.length).toBe(1); const material = materials[0];
var material = materials[0]; const pbr = material.pbrMetallicRoughness;
var pbr = material.pbrMetallicRoughness; expect(pbr.baseColorTexture).toBeDefined();
expect(pbr.baseColorTexture).toBeDefined(); expect(pbr.occlusionTexture).toBeUndefined();
expect(pbr.occlusionTexture).toBeUndefined();
}), done).toResolve();
}); });
describe('metallicRoughness', function() { describe('metallicRoughness', () => {
it('creates default material', function() { it('creates default material', () => {
var material = loadMtl._createMaterial(undefined, options); const material = loadMtl._createMaterial(undefined, options);
var pbr = material.pbrMetallicRoughness; const pbr = material.pbrMetallicRoughness;
expect(pbr.baseColorTexture).toBeUndefined(); expect(pbr.baseColorTexture).toBeUndefined();
expect(pbr.metallicRoughnessTexture).toBeUndefined(); expect(pbr.metallicRoughnessTexture).toBeUndefined();
expect(pbr.baseColorFactor).toEqual([0.5, 0.5, 0.5, 1.0]); expect(pbr.baseColorFactor).toEqual([0.5, 0.5, 0.5, 1.0]);
@ -279,10 +230,10 @@ describe('loadMtl', function() {
expect(material.doubleSided).toBe(false); expect(material.doubleSided).toBe(false);
}); });
it('creates material with textures', function() { it('creates material with textures', () => {
options.metallicRoughness = true; options.metallicRoughness = true;
var material = loadMtl._createMaterial({ const material = loadMtl._createMaterial({
diffuseTexture : diffuseTexture, diffuseTexture : diffuseTexture,
ambientTexture : ambientTexture, ambientTexture : ambientTexture,
normalTexture : normalTexture, normalTexture : normalTexture,
@ -291,7 +242,7 @@ describe('loadMtl', function() {
specularShininessTexture : specularShininessTexture specularShininessTexture : specularShininessTexture
}, options); }, options);
var pbr = material.pbrMetallicRoughness; const pbr = material.pbrMetallicRoughness;
expect(pbr.baseColorTexture).toBeDefined(); expect(pbr.baseColorTexture).toBeDefined();
expect(pbr.metallicRoughnessTexture).toBeDefined(); expect(pbr.metallicRoughnessTexture).toBeDefined();
expect(pbr.baseColorFactor).toEqual([1.0, 1.0, 1.0, 1.0]); expect(pbr.baseColorFactor).toEqual([1.0, 1.0, 1.0, 1.0]);
@ -305,63 +256,63 @@ describe('loadMtl', function() {
expect(material.doubleSided).toBe(false); expect(material.doubleSided).toBe(false);
}); });
it('packs occlusion in metallic roughness texture', function() { it('packs occlusion in metallic roughness texture', () => {
options.metallicRoughness = true; options.metallicRoughness = true;
options.packOcclusion = true; options.packOcclusion = true;
var material = loadMtl._createMaterial({ const material = loadMtl._createMaterial({
ambientTexture : alphaTexture, ambientTexture : alphaTexture,
specularTexture : specularTexture, specularTexture : specularTexture,
specularShininessTexture : specularShininessTexture specularShininessTexture : specularShininessTexture
}, options); }, options);
var pbr = material.pbrMetallicRoughness; const pbr = material.pbrMetallicRoughness;
expect(pbr.metallicRoughnessTexture).toBeDefined(); expect(pbr.metallicRoughnessTexture).toBeDefined();
expect(pbr.metallicRoughnessTexture).toBe(material.occlusionTexture); expect(pbr.metallicRoughnessTexture).toBe(material.occlusionTexture);
}); });
it('does not create metallic roughness texture if decoded texture data is not available', function() { it('does not create metallic roughness texture if decoded texture data is not available', () => {
options.metallicRoughness = true; options.metallicRoughness = true;
options.packOcclusion = true; options.packOcclusion = true;
var material = loadMtl._createMaterial({ const material = loadMtl._createMaterial({
ambientTexture : ambientTexture, // Is a .gif which can't be decoded ambientTexture : ambientTexture, // Is a .gif which can't be decoded
specularTexture : specularTexture, specularTexture : specularTexture,
specularShininessTexture : specularShininessTexture specularShininessTexture : specularShininessTexture
}, options); }, options);
var pbr = material.pbrMetallicRoughness; const pbr = material.pbrMetallicRoughness;
expect(pbr.metallicRoughnessTexture).toBeUndefined(); expect(pbr.metallicRoughnessTexture).toBeUndefined();
expect(material.occlusionTexture).toBeUndefined(); expect(material.occlusionTexture).toBeUndefined();
}); });
it('sets material for transparent diffuse texture', function() { it('sets material for transparent diffuse texture', () => {
options.metallicRoughness = true; options.metallicRoughness = true;
var material = loadMtl._createMaterial({ const material = loadMtl._createMaterial({
diffuseTexture : transparentDiffuseTexture diffuseTexture : transparentDiffuseTexture
}, options); }, options);
expect(material.alphaMode).toBe('BLEND'); expect(material.alphaMode).toBe('BLEND');
expect(material.doubleSided).toBe(true); expect(material.doubleSided).toBe(true);
}); });
it('packs alpha texture in base color texture', function() { it('packs alpha texture in base color texture', () => {
options.metallicRoughness = true; options.metallicRoughness = true;
var material = loadMtl._createMaterial({ const material = loadMtl._createMaterial({
diffuseTexture : diffuseTexture, diffuseTexture : diffuseTexture,
alphaTexture : alphaTexture alphaTexture : alphaTexture
}, options); }, options);
var pbr = material.pbrMetallicRoughness; const pbr = material.pbrMetallicRoughness;
expect(pbr.baseColorTexture).toBeDefined(); expect(pbr.baseColorTexture).toBeDefined();
var hasBlack = false; let hasBlack = false;
var hasWhite = false; let hasWhite = false;
var pixels = pbr.baseColorTexture.pixels; const pixels = pbr.baseColorTexture.pixels;
var pixelsLength = pixels.length / 4; const pixelsLength = pixels.length / 4;
for (var i = 0; i < pixelsLength; ++i) { for (let i = 0; i < pixelsLength; ++i) {
var alpha = pixels[i * 4 + 3]; const alpha = pixels[i * 4 + 3];
hasBlack = hasBlack || (alpha === 0); hasBlack = hasBlack || (alpha === 0);
hasWhite = hasWhite || (alpha === 255); hasWhite = hasWhite || (alpha === 255);
} }
@ -373,11 +324,11 @@ describe('loadMtl', function() {
}); });
}); });
describe('specularGlossiness', function() { describe('specularGlossiness', () => {
it('creates default material', function() { it('creates default material', () => {
options.specularGlossiness = true; options.specularGlossiness = true;
var material = loadMtl._createMaterial(undefined, options); const material = loadMtl._createMaterial(undefined, options);
var pbr = material.extensions.KHR_materials_pbrSpecularGlossiness; const pbr = material.extensions.KHR_materials_pbrSpecularGlossiness;
expect(pbr.diffuseTexture).toBeUndefined(); expect(pbr.diffuseTexture).toBeUndefined();
expect(pbr.specularGlossinessTexture).toBeUndefined(); expect(pbr.specularGlossinessTexture).toBeUndefined();
expect(pbr.diffuseFactor).toEqual([0.5, 0.5, 0.5, 1.0]); expect(pbr.diffuseFactor).toEqual([0.5, 0.5, 0.5, 1.0]);
@ -391,10 +342,10 @@ describe('loadMtl', function() {
expect(material.doubleSided).toBe(false); expect(material.doubleSided).toBe(false);
}); });
it('creates material with textures', function() { it('creates material with textures', () => {
options.specularGlossiness = true; options.specularGlossiness = true;
var material = loadMtl._createMaterial({ const material = loadMtl._createMaterial({
diffuseTexture : diffuseTexture, diffuseTexture : diffuseTexture,
ambientTexture : ambientTexture, ambientTexture : ambientTexture,
normalTexture : normalTexture, normalTexture : normalTexture,
@ -403,7 +354,7 @@ describe('loadMtl', function() {
specularShininessTexture : specularShininessTexture specularShininessTexture : specularShininessTexture
}, options); }, options);
var pbr = material.extensions.KHR_materials_pbrSpecularGlossiness; const pbr = material.extensions.KHR_materials_pbrSpecularGlossiness;
expect(pbr.diffuseTexture).toBeDefined(); expect(pbr.diffuseTexture).toBeDefined();
expect(pbr.specularGlossinessTexture).toBeDefined(); expect(pbr.specularGlossinessTexture).toBeDefined();
expect(pbr.diffuseFactor).toEqual([1.0, 1.0, 1.0, 1.0]); expect(pbr.diffuseFactor).toEqual([1.0, 1.0, 1.0, 1.0]);
@ -417,22 +368,22 @@ describe('loadMtl', function() {
expect(material.doubleSided).toBe(false); expect(material.doubleSided).toBe(false);
}); });
it('does not create specular glossiness texture if decoded texture data is not available', function() { it('does not create specular glossiness texture if decoded texture data is not available', () => {
options.specularGlossiness = true; options.specularGlossiness = true;
var material = loadMtl._createMaterial({ const material = loadMtl._createMaterial({
specularTexture : ambientTexture, // Is a .gif which can't be decoded specularTexture : ambientTexture, // Is a .gif which can't be decoded
specularShininessTexture : specularShininessTexture specularShininessTexture : specularShininessTexture
}, options); }, options);
var pbr = material.extensions.KHR_materials_pbrSpecularGlossiness; const pbr = material.extensions.KHR_materials_pbrSpecularGlossiness;
expect(pbr.specularGlossinessTexture).toBeUndefined(); expect(pbr.specularGlossinessTexture).toBeUndefined();
}); });
it('sets material for transparent diffuse texture', function() { it('sets material for transparent diffuse texture', () => {
options.specularGlossiness = true; options.specularGlossiness = true;
var material = loadMtl._createMaterial({ const material = loadMtl._createMaterial({
diffuseTexture : transparentDiffuseTexture diffuseTexture : transparentDiffuseTexture
}, options); }, options);
@ -440,23 +391,23 @@ describe('loadMtl', function() {
expect(material.doubleSided).toBe(true); expect(material.doubleSided).toBe(true);
}); });
it('packs alpha texture in diffuse texture', function() { it('packs alpha texture in diffuse texture', () => {
options.specularGlossiness = true; options.specularGlossiness = true;
var material = loadMtl._createMaterial({ const material = loadMtl._createMaterial({
diffuseTexture : diffuseTexture, diffuseTexture : diffuseTexture,
alphaTexture : alphaTexture alphaTexture : alphaTexture
}, options); }, options);
var pbr = material.extensions.KHR_materials_pbrSpecularGlossiness; const pbr = material.extensions.KHR_materials_pbrSpecularGlossiness;
expect(pbr.diffuseTexture).toBeDefined(); expect(pbr.diffuseTexture).toBeDefined();
var hasBlack = false; let hasBlack = false;
var hasWhite = false; let hasWhite = false;
var pixels = pbr.diffuseTexture.pixels; const pixels = pbr.diffuseTexture.pixels;
var pixelsLength = pixels.length / 4; const pixelsLength = pixels.length / 4;
for (var i = 0; i < pixelsLength; ++i) { for (let i = 0; i < pixelsLength; ++i) {
var alpha = pixels[i * 4 + 3]; const alpha = pixels[i * 4 + 3];
hasBlack = hasBlack || (alpha === 0); hasBlack = hasBlack || (alpha === 0);
hasWhite = hasWhite || (alpha === 255); hasWhite = hasWhite || (alpha === 255);
} }

View File

@ -1,233 +1,215 @@
'use strict'; 'use strict';
var Cesium = require('cesium'); const Cesium = require('cesium');
var Promise = require('bluebird');
var loadObj = require('../../lib/loadObj');
var obj2gltf = require('../../lib/obj2gltf');
var Cartesian3 = Cesium.Cartesian3; const loadObj = require('../../lib/loadObj');
var CesiumMath = Cesium.Math; const obj2gltf = require('../../lib/obj2gltf');
var clone = Cesium.clone;
var RuntimeError = Cesium.RuntimeError;
var objPath = 'specs/data/box/box.obj'; const Cartesian3 = Cesium.Cartesian3;
var objNormalsPath = 'specs/data/box-normals/box-normals.obj'; const CesiumMath = Cesium.Math;
var objUvsPath = 'specs/data/box-uvs/box-uvs.obj'; const clone = Cesium.clone;
var objPositionsOnlyPath = 'specs/data/box-positions-only/box-positions-only.obj'; const RuntimeError = Cesium.RuntimeError;
var objNegativeIndicesPath = 'specs/data/box-negative-indices/box-negative-indices.obj';
var objTrianglesPath = 'specs/data/box-triangles/box-triangles.obj'; const objPath = 'specs/data/box/box.obj';
var objObjectsPath = 'specs/data/box-objects/box-objects.obj'; const objNormalsPath = 'specs/data/box-normals/box-normals.obj';
var objGroupsPath = 'specs/data/box-groups/box-groups.obj'; const objUvsPath = 'specs/data/box-uvs/box-uvs.obj';
var objObjectsGroupsPath = 'specs/data/box-objects-groups/box-objects-groups.obj'; const objPositionsOnlyPath = 'specs/data/box-positions-only/box-positions-only.obj';
var objObjectsGroupsMaterialsPath = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.obj'; const objNegativeIndicesPath = 'specs/data/box-negative-indices/box-negative-indices.obj';
var objObjectsGroupsMaterialsPath2 = 'specs/data/box-objects-groups-materials-2/box-objects-groups-materials-2.obj'; const objTrianglesPath = 'specs/data/box-triangles/box-triangles.obj';
var objUsemtlPath = 'specs/data/box-usemtl/box-usemtl.obj'; const objObjectsPath = 'specs/data/box-objects/box-objects.obj';
var objNoMaterialsPath = 'specs/data/box-no-materials/box-no-materials.obj'; const objGroupsPath = 'specs/data/box-groups/box-groups.obj';
var objMultipleMaterialsPath = 'specs/data/box-multiple-materials/box-multiple-materials.obj'; const objObjectsGroupsPath = 'specs/data/box-objects-groups/box-objects-groups.obj';
var objUncleanedPath = 'specs/data/box-uncleaned/box-uncleaned.obj'; const objObjectsGroupsMaterialsPath = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.obj';
var objMtllibPath = 'specs/data/box-mtllib/box-mtllib.obj'; const objObjectsGroupsMaterialsPath2 = 'specs/data/box-objects-groups-materials-2/box-objects-groups-materials-2.obj';
var objMtllibSpacesPath = 'specs/data/box-mtllib-spaces/box mtllib.obj'; const objUsemtlPath = 'specs/data/box-usemtl/box-usemtl.obj';
var objMissingMtllibPath = 'specs/data/box-missing-mtllib/box-missing-mtllib.obj'; const objNoMaterialsPath = 'specs/data/box-no-materials/box-no-materials.obj';
var objMissingUsemtlPath = 'specs/data/box-missing-usemtl/box-missing-usemtl.obj'; const objMultipleMaterialsPath = 'specs/data/box-multiple-materials/box-multiple-materials.obj';
var objExternalResourcesPath = 'specs/data/box-external-resources/box-external-resources.obj'; const objUncleanedPath = 'specs/data/box-uncleaned/box-uncleaned.obj';
var objResourcesInRootPath = 'specs/data/box-resources-in-root/box-resources-in-root.obj'; const objMtllibPath = 'specs/data/box-mtllib/box-mtllib.obj';
var objExternalResourcesInRootPath = 'specs/data/box-external-resources-in-root/box-external-resources-in-root.obj'; const objMtllibSpacesPath = 'specs/data/box-mtllib-spaces/box mtllib.obj';
var objTexturedPath = 'specs/data/box-textured/box-textured.obj'; const objMissingMtllibPath = 'specs/data/box-missing-mtllib/box-missing-mtllib.obj';
var objMissingTexturePath = 'specs/data/box-missing-texture/box-missing-texture.obj'; const objMissingUsemtlPath = 'specs/data/box-missing-usemtl/box-missing-usemtl.obj';
var objSubdirectoriesPath = 'specs/data/box-subdirectories/box-textured.obj'; const objExternalResourcesPath = 'specs/data/box-external-resources/box-external-resources.obj';
var objWindowsPaths = 'specs/data/box-windows-paths/box-windows-paths.obj'; const objResourcesInRootPath = 'specs/data/box-resources-in-root/box-resources-in-root.obj';
var objInvalidContentsPath = 'specs/data/box/box.mtl'; const objExternalResourcesInRootPath = 'specs/data/box-external-resources-in-root/box-external-resources-in-root.obj';
var objConcavePath = 'specs/data/concave/concave.obj'; const objTexturedPath = 'specs/data/box-textured/box-textured.obj';
var objUnnormalizedPath = 'specs/data/box-unnormalized/box-unnormalized.obj'; const objMissingTexturePath = 'specs/data/box-missing-texture/box-missing-texture.obj';
var objMixedAttributesPath = 'specs/data/box-mixed-attributes/box-mixed-attributes.obj'; const objSubdirectoriesPath = 'specs/data/box-subdirectories/box-textured.obj';
var objInvalidPath = 'invalid.obj'; const objWindowsPaths = 'specs/data/box-windows-paths/box-windows-paths.obj';
const objInvalidContentsPath = 'specs/data/box/box.mtl';
const objConcavePath = 'specs/data/concave/concave.obj';
const objUnnormalizedPath = 'specs/data/box-unnormalized/box-unnormalized.obj';
const objMixedAttributesPath = 'specs/data/box-mixed-attributes/box-mixed-attributes.obj';
const objInvalidPath = 'invalid.obj';
function getMeshes(data) { function getMeshes(data) {
var meshes = []; let meshes = [];
var nodes = data.nodes; const nodes = data.nodes;
var nodesLength = nodes.length; const nodesLength = nodes.length;
for (var i = 0; i < nodesLength; ++i) { for (let i = 0; i < nodesLength; ++i) {
meshes = meshes.concat(nodes[i].meshes); meshes = meshes.concat(nodes[i].meshes);
} }
return meshes; return meshes;
} }
function getPrimitives(data) { function getPrimitives(data) {
var primitives = []; let primitives = [];
var nodes = data.nodes; const nodes = data.nodes;
var nodesLength = nodes.length; const nodesLength = nodes.length;
for (var i = 0; i < nodesLength; ++i) { for (let i = 0; i < nodesLength; ++i) {
var meshes = nodes[i].meshes; const meshes = nodes[i].meshes;
var meshesLength = meshes.length; const meshesLength = meshes.length;
for (var j = 0; j < meshesLength; ++j) { for (let j = 0; j < meshesLength; ++j) {
primitives = primitives.concat(meshes[j].primitives); primitives = primitives.concat(meshes[j].primitives);
} }
} }
return primitives; return primitives;
} }
var options; let options;
describe('loadObj', function() { describe('loadObj', () => {
beforeEach(function() { beforeEach(() => {
options = clone(obj2gltf.defaults); options = clone(obj2gltf.defaults);
options.overridingTextures = {}; options.overridingTextures = {};
options.logger = function() {}; options.logger = () => {};
}); });
it('loads obj with positions, normals, and uvs', function(done) { it('loads obj with positions, normals, and uvs', async () => {
expect(loadObj(objPath, options) const data = await loadObj(objPath, options);
.then(function(data) { const materials = data.materials;
var materials = data.materials; const nodes = data.nodes;
var nodes = data.nodes; const name = data.name;
var name = data.name; const meshes = getMeshes(data);
var meshes = getMeshes(data); const primitives = getPrimitives(data);
var primitives = getPrimitives(data);
expect(name).toBe('box'); expect(name).toBe('box');
expect(materials.length).toBe(1); expect(materials.length).toBe(1);
expect(nodes.length).toBe(1); expect(nodes.length).toBe(1);
expect(meshes.length).toBe(1); expect(meshes.length).toBe(1);
expect(primitives.length).toBe(1); expect(primitives.length).toBe(1);
var node = nodes[0]; const node = nodes[0];
var mesh = meshes[0]; const mesh = meshes[0];
var primitive = primitives[0]; const primitive = primitives[0];
expect(node.name).toBe('Cube'); expect(node.name).toBe('Cube');
expect(mesh.name).toBe('Cube-Mesh'); expect(mesh.name).toBe('Cube-Mesh');
expect(primitive.positions.length / 3).toBe(24); expect(primitive.positions.length / 3).toBe(24);
expect(primitive.normals.length / 3).toBe(24); expect(primitive.normals.length / 3).toBe(24);
expect(primitive.uvs.length / 2).toBe(24); expect(primitive.uvs.length / 2).toBe(24);
expect(primitive.indices.length).toBe(36); expect(primitive.indices.length).toBe(36);
expect(primitive.material).toBe('Material'); expect(primitive.material).toBe('Material');
}), done).toResolve();
}); });
it('loads obj with normals', function(done) { it('loads obj with normals', async () => {
expect(loadObj(objNormalsPath, options) const data = await loadObj(objNormalsPath, options);
.then(function(data) { const primitive = getPrimitives(data)[0];
var primitive = getPrimitives(data)[0]; expect(primitive.positions.length / 3).toBe(24);
expect(primitive.positions.length / 3).toBe(24); expect(primitive.normals.length / 3).toBe(24);
expect(primitive.normals.length / 3).toBe(24); expect(primitive.uvs.length / 2).toBe(0);
expect(primitive.uvs.length / 2).toBe(0);
}), done).toResolve();
}); });
it('normalizes normals', function(done) { it('normalizes normals', async () => {
expect(loadObj(objUnnormalizedPath, options) const data = await loadObj(objUnnormalizedPath, options);
.then(function(data) { const scratchNormal = new Cesium.Cartesian3();
var scratchNormal = new Cesium.Cartesian3(); const primitive = getPrimitives(data)[0];
var primitive = getPrimitives(data)[0]; const normals = primitive.normals;
var normals = primitive.normals; const normalsLength = normals.length / 3;
var normalsLength = normals.length / 3; for (let i = 0; i < normalsLength; ++i) {
for (var i = 0; i < normalsLength; ++i) { const normalX = normals.get(i * 3);
var normalX = normals.get(i * 3); const normalY = normals.get(i * 3 + 1);
var normalY = normals.get(i * 3 + 1); const normalZ = normals.get(i * 3 + 2);
var normalZ = normals.get(i * 3 + 2); const normal = Cartesian3.fromElements(normalX, normalY, normalZ, scratchNormal);
var normal = Cartesian3.fromElements(normalX, normalY, normalZ, scratchNormal); expect(CesiumMath.equalsEpsilon(Cartesian3.magnitude(normal), 1.0, CesiumMath.EPSILON5)).toBe(true);
expect(Cartesian3.magnitude(normal)).toEqualEpsilon(1.0, CesiumMath.EPSILON5); }
}
}), done).toResolve();
}); });
it('loads obj with uvs', function(done) { it('loads obj with uvs', async () => {
expect(loadObj(objUvsPath, options) const data = await loadObj(objUvsPath, options);
.then(function(data) { const primitive = getPrimitives(data)[0];
var primitive = getPrimitives(data)[0]; expect(primitive.positions.length / 3).toBe(20);
expect(primitive.positions.length / 3).toBe(20); expect(primitive.normals.length / 3).toBe(0);
expect(primitive.normals.length / 3).toBe(0); expect(primitive.uvs.length / 2).toBe(20);
expect(primitive.uvs.length / 2).toBe(20);
}), done).toResolve();
}); });
it('loads obj with negative indices', function(done) { it('loads obj with negative indices', async () => {
expect(Promise.all([ const results = [
loadObj(objPositionsOnlyPath, options), await loadObj(objPositionsOnlyPath, options),
loadObj(objNegativeIndicesPath, options) await loadObj(objNegativeIndicesPath, options)
]) ];
.then(function(results) { const positionsReference = getPrimitives(results[0])[0].positions.toFloatBuffer();
var positionsReference = getPrimitives(results[0])[0].positions.toFloatBuffer(); const positions = getPrimitives(results[1])[0].positions.toFloatBuffer();
var positions = getPrimitives(results[1])[0].positions.toFloatBuffer(); expect(positions).toEqual(positionsReference);
expect(positions).toEqual(positionsReference);
}), done).toResolve();
}); });
it('loads obj with triangle faces', function(done) { it('loads obj with triangle faces', async () => {
expect(loadObj(objTrianglesPath, options) const data = await loadObj(objTrianglesPath, options);
.then(function(data) { const primitive = getPrimitives(data)[0];
var primitive = getPrimitives(data)[0]; expect(primitive.positions.length / 3).toBe(24);
expect(primitive.positions.length / 3).toBe(24); expect(primitive.indices.length).toBe(36);
expect(primitive.indices.length).toBe(36);
}), done).toResolve();
}); });
it('loads obj with objects', function(done) { it('loads obj with objects', async () => {
expect(loadObj(objObjectsPath, options) const data = await loadObj(objObjectsPath, options);
.then(function(data) { const nodes = data.nodes;
var nodes = data.nodes; expect(nodes.length).toBe(3);
expect(nodes.length).toBe(3); expect(nodes[0].name).toBe('CubeBlue');
expect(nodes[0].name).toBe('CubeBlue'); expect(nodes[1].name).toBe('CubeGreen');
expect(nodes[1].name).toBe('CubeGreen'); expect(nodes[2].name).toBe('CubeRed');
expect(nodes[2].name).toBe('CubeRed');
var primitives = getPrimitives(data); const primitives = getPrimitives(data);
expect(primitives.length).toBe(3); expect(primitives.length).toBe(3);
expect(primitives[0].material).toBe('Blue'); expect(primitives[0].material).toBe('Blue');
expect(primitives[1].material).toBe('Green'); expect(primitives[1].material).toBe('Green');
expect(primitives[2].material).toBe('Red'); expect(primitives[2].material).toBe('Red');
}), done).toResolve();
}); });
it('loads obj with groups', function(done) { it('loads obj with groups', async () => {
expect(loadObj(objGroupsPath, options) const data = await loadObj(objGroupsPath, options);
.then(function(data) { const nodes = data.nodes;
var nodes = data.nodes; expect(nodes.length).toBe(3);
expect(nodes.length).toBe(3); expect(nodes[0].name).toBe('CubeBlue');
expect(nodes[0].name).toBe('CubeBlue'); expect(nodes[1].name).toBe('CubeGreen');
expect(nodes[1].name).toBe('CubeGreen'); expect(nodes[2].name).toBe('CubeRed');
expect(nodes[2].name).toBe('CubeRed');
var primitives = getPrimitives(data); const primitives = getPrimitives(data);
expect(primitives.length).toBe(3); expect(primitives.length).toBe(3);
expect(primitives[0].material).toBe('Blue'); expect(primitives[0].material).toBe('Blue');
expect(primitives[1].material).toBe('Green'); expect(primitives[1].material).toBe('Green');
expect(primitives[2].material).toBe('Red'); expect(primitives[2].material).toBe('Red');
}), done).toResolve();
}); });
it('loads obj with objects and groups', function(done) { it('loads obj with objects and groups', async () => {
expect(loadObj(objObjectsGroupsPath, options) const data = await loadObj(objObjectsGroupsPath, options);
.then(function(data) { const nodes = data.nodes;
var nodes = data.nodes; expect(nodes.length).toBe(3);
expect(nodes.length).toBe(3); expect(nodes[0].name).toBe('CubeBlue');
expect(nodes[0].name).toBe('CubeBlue'); expect(nodes[1].name).toBe('CubeGreen');
expect(nodes[1].name).toBe('CubeGreen'); expect(nodes[2].name).toBe('CubeRed');
expect(nodes[2].name).toBe('CubeRed');
var meshes = getMeshes(data); const meshes = getMeshes(data);
expect(meshes.length).toBe(3); expect(meshes.length).toBe(3);
expect(meshes[0].name).toBe('CubeBlue_CubeBlue_Blue'); expect(meshes[0].name).toBe('CubeBlue_CubeBlue_Blue');
expect(meshes[1].name).toBe('CubeGreen_CubeGreen_Green'); expect(meshes[1].name).toBe('CubeGreen_CubeGreen_Green');
expect(meshes[2].name).toBe('CubeRed_CubeRed_Red'); expect(meshes[2].name).toBe('CubeRed_CubeRed_Red');
var primitives = getPrimitives(data); const primitives = getPrimitives(data);
expect(primitives.length).toBe(3); expect(primitives.length).toBe(3);
expect(primitives[0].material).toBe('Blue'); expect(primitives[0].material).toBe('Blue');
expect(primitives[1].material).toBe('Green'); expect(primitives[1].material).toBe('Green');
expect(primitives[2].material).toBe('Red'); expect(primitives[2].material).toBe('Red');
}), done).toResolve();
}); });
function loadsObjWithObjectsGroupsAndMaterials(data) { function loadsObjWithObjectsGroupsAndMaterials(data) {
var nodes = data.nodes; const nodes = data.nodes;
expect(nodes.length).toBe(1); expect(nodes.length).toBe(1);
expect(nodes[0].name).toBe('Cube'); expect(nodes[0].name).toBe('Cube');
var meshes = getMeshes(data); const meshes = getMeshes(data);
expect(meshes.length).toBe(3); expect(meshes.length).toBe(3);
expect(meshes[0].name).toBe('Blue'); expect(meshes[0].name).toBe('Blue');
expect(meshes[1].name).toBe('Green'); expect(meshes[1].name).toBe('Green');
expect(meshes[2].name).toBe('Red'); expect(meshes[2].name).toBe('Red');
var primitives = getPrimitives(data); const primitives = getPrimitives(data);
expect(primitives.length).toBe(6); expect(primitives.length).toBe(6);
expect(primitives[0].material).toBe('Blue'); expect(primitives[0].material).toBe('Blue');
expect(primitives[1].material).toBe('Green'); expect(primitives[1].material).toBe('Green');
@ -237,280 +219,252 @@ describe('loadObj', function() {
expect(primitives[5].material).toBe('Blue'); expect(primitives[5].material).toBe('Blue');
} }
it('loads obj with objects, groups, and materials', function(done) { it('loads obj with objects, groups, and materials', async () => {
expect(loadObj(objObjectsGroupsMaterialsPath, options) const data = await loadObj(objObjectsGroupsMaterialsPath, options);
.then(function(data) { loadsObjWithObjectsGroupsAndMaterials(data);
loadsObjWithObjectsGroupsAndMaterials(data);
}), done).toResolve();
}); });
it('loads obj with objects, groups, and materials (2)', function(done) { it('loads obj with objects, groups, and materials (2)', async () => {
// The usemtl lines are placed in an unordered fashion but // The usemtl lines are placed in an unordered fashion but
// should produce the same result as the previous test // should produce the same result as the previous test
expect(loadObj(objObjectsGroupsMaterialsPath2, options) const data = await loadObj(objObjectsGroupsMaterialsPath2, options);
.then(function(data) { loadsObjWithObjectsGroupsAndMaterials(data);
loadsObjWithObjectsGroupsAndMaterials(data);
}), done).toResolve();
}); });
it('loads obj with concave face containing 5 vertices', function(done) { it('loads obj with concave face containing 5 vertices', async () => {
expect(loadObj(objConcavePath, options) const data = await loadObj(objConcavePath, options);
.then(function(data) { const primitive = getPrimitives(data)[0];
var primitive = getPrimitives(data)[0]; expect(primitive.positions.length / 3).toBe(30);
expect(primitive.positions.length / 3).toBe(30); expect(primitive.indices.length).toBe(48);
expect(primitive.indices.length).toBe(48);
}), done).toResolve();
}); });
it('loads obj with usemtl only', function(done) { it('loads obj with usemtl only', async () => {
expect(loadObj(objUsemtlPath, options) const data = await loadObj(objUsemtlPath, options);
.then(function(data) { const nodes = data.nodes;
var nodes = data.nodes; expect(nodes.length).toBe(1);
expect(nodes.length).toBe(1); expect(nodes[0].name).toBe('Node'); // default name
expect(nodes[0].name).toBe('Node'); // default name
var meshes = getMeshes(data); const meshes = getMeshes(data);
expect(meshes.length).toBe(1); expect(meshes.length).toBe(1);
expect(meshes[0].name).toBe('Node-Mesh'); expect(meshes[0].name).toBe('Node-Mesh');
var primitives = getPrimitives(data); const primitives = getPrimitives(data);
expect(primitives.length).toBe(3); expect(primitives.length).toBe(3);
expect(primitives[0].material).toBe('Blue'); expect(primitives[0].material).toBe('Blue');
expect(primitives[1].material).toBe('Green'); expect(primitives[1].material).toBe('Green');
expect(primitives[2].material).toBe('Red'); expect(primitives[2].material).toBe('Red');
}), done).toResolve();
}); });
it('loads obj with no materials', function(done) { it('loads obj with no materials', async () => {
expect(loadObj(objNoMaterialsPath, options) const data = await loadObj(objNoMaterialsPath, options);
.then(function(data) { const nodes = data.nodes;
var nodes = data.nodes; expect(nodes.length).toBe(1);
expect(nodes.length).toBe(1); expect(nodes[0].name).toBe('Node'); // default name
expect(nodes[0].name).toBe('Node'); // default name
var primitives = getPrimitives(data); const primitives = getPrimitives(data);
expect(primitives.length).toBe(1); expect(primitives.length).toBe(1);
}), done).toResolve();
}); });
it('loads obj with multiple materials', function(done) { it('loads obj with multiple materials', async () => {
// The usemtl markers are interleaved, but should condense to just three primitives // The usemtl markers are interleaved, but should condense to just three primitives
expect(loadObj(objMultipleMaterialsPath, options) const data = await loadObj(objMultipleMaterialsPath, options);
.then(function(data) { const nodes = data.nodes;
var nodes = data.nodes; expect(nodes.length).toBe(1);
expect(nodes.length).toBe(1);
var primitives = getPrimitives(data); const primitives = getPrimitives(data);
expect(primitives.length).toBe(3); expect(primitives.length).toBe(3);
expect(primitives[0].indices.length).toBe(12); expect(primitives[0].indices.length).toBe(12);
expect(primitives[1].indices.length).toBe(12); expect(primitives[1].indices.length).toBe(12);
expect(primitives[2].indices.length).toBe(12); expect(primitives[2].indices.length).toBe(12);
expect(primitives[0].material).toBe('Red'); expect(primitives[0].material).toBe('Red');
expect(primitives[1].material).toBe('Green'); expect(primitives[1].material).toBe('Green');
expect(primitives[2].material).toBe('Blue'); expect(primitives[2].material).toBe('Blue');
for (var i = 0; i < 3; ++i) { for (let i = 0; i < 3; ++i) {
var indices = primitives[i].indices; const indices = primitives[i].indices;
for (var j = 0; j < indices.length; ++j) { for (let j = 0; j < indices.length; ++j) {
expect(indices.get(j)).toBeLessThan(8); expect(indices.get(j)).toBeLessThan(8);
} }
} }
}), done).toResolve();
}); });
it('loads obj uncleaned', function(done) { it('loads obj uncleaned', async () => {
// Obj with extraneous o, g, and usemtl lines // Obj with extraneous o, g, and usemtl lines
// Also tests handling of o and g lines with the same names // Also tests handling of o and g lines with the same names
expect(loadObj(objUncleanedPath, options) const data = await loadObj(objUncleanedPath, options);
.then(function(data) { const nodes = data.nodes;
var nodes = data.nodes; const meshes = getMeshes(data);
var meshes = getMeshes(data); const primitives = getPrimitives(data);
var primitives = getPrimitives(data);
expect(nodes.length).toBe(1); expect(nodes.length).toBe(1);
expect(meshes.length).toBe(1); expect(meshes.length).toBe(1);
expect(primitives.length).toBe(1); expect(primitives.length).toBe(1);
expect(nodes[0].name).toBe('Cube'); expect(nodes[0].name).toBe('Cube');
expect(meshes[0].name).toBe('Cube_1'); expect(meshes[0].name).toBe('Cube_1');
}), done).toResolve();
}); });
it('loads obj with multiple mtllibs', function(done) { it('loads obj with multiple mtllibs', async () => {
expect(loadObj(objMtllibPath, options) const data = await loadObj(objMtllibPath, options);
.then(function(data) { const materials = data.materials;
var materials = data.materials; expect(materials.length).toBe(3);
expect(materials.length).toBe(3);
// .mtl files are loaded in an arbitrary order, so sort for testing purposes // .mtl files are loaded in an arbitrary order, so sort for testing purposes
materials.sort(function(a, b){ materials.sort((a, b) => {
return a.name.localeCompare(b.name); return a.name.localeCompare(b.name);
}); });
expect(materials[0].name).toBe('Blue'); expect(materials[0].name).toBe('Blue');
expect(materials[0].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.0, 0.64, 1.0]); expect(materials[0].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.0, 0.64, 1.0]);
expect(materials[1].name).toBe('Green'); expect(materials[1].name).toBe('Green');
expect(materials[1].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.64, 0.0, 1.0]); expect(materials[1].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.64, 0.0, 1.0]);
expect(materials[2].name).toBe('Red'); expect(materials[2].name).toBe('Red');
expect(materials[2].pbrMetallicRoughness.baseColorFactor).toEqual([0.64, 0.0, 0.0, 1.0]); expect(materials[2].pbrMetallicRoughness.baseColorFactor).toEqual([0.64, 0.0, 0.0, 1.0]);
}), done).toResolve();
}); });
it('loads obj with mtllib paths with spaces', function(done) { it('loads obj with mtllib paths with spaces', async () => {
expect(loadObj(objMtllibSpacesPath, options) const data = await loadObj(objMtllibSpacesPath, options);
.then(function(data) { const materials = data.materials;
var materials = data.materials; expect(materials.length).toBe(3);
expect(materials.length).toBe(3);
// .mtl files are loaded in an arbitrary order, so sort for testing purposes // .mtl files are loaded in an arbitrary order, so sort for testing purposes
materials.sort(function(a, b){ materials.sort((a, b) => {
return a.name.localeCompare(b.name); return a.name.localeCompare(b.name);
}); });
expect(materials[0].name).toBe('Blue'); expect(materials[0].name).toBe('Blue');
expect(materials[0].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.0, 0.64, 1.0]); expect(materials[0].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.0, 0.64, 1.0]);
expect(materials[1].name).toBe('Green'); expect(materials[1].name).toBe('Green');
expect(materials[1].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.64, 0.0, 1.0]); expect(materials[1].pbrMetallicRoughness.baseColorFactor).toEqual([0.0, 0.64, 0.0, 1.0]);
expect(materials[2].name).toBe('Red'); expect(materials[2].name).toBe('Red');
expect(materials[2].pbrMetallicRoughness.baseColorFactor).toEqual([0.64, 0.0, 0.0, 1.0]); expect(materials[2].pbrMetallicRoughness.baseColorFactor).toEqual([0.64, 0.0, 0.0, 1.0]);
}), done).toResolve();
}); });
it('loads obj with missing mtllib', function(done) { it('loads obj with missing mtllib', async () => {
var spy = jasmine.createSpy('logger'); const spy = jasmine.createSpy('logger');
options.logger = spy; options.logger = spy;
expect(loadObj(objMissingMtllibPath, options) const data = await loadObj(objMissingMtllibPath, options);
.then(function(data) { expect(data.materials.length).toBe(0);
expect(data.materials.length).toBe(0); expect(spy.calls.argsFor(0)[0].indexOf('ENOENT') >= 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(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(2)[0].indexOf('ENOENT') >= 0).toBe(true); expect(spy.calls.argsFor(3)[0].indexOf('Could not read material file') >= 0).toBe(true);
expect(spy.calls.argsFor(3)[0].indexOf('Could not read material file') >= 0).toBe(true);
}), done).toResolve();
}); });
it('loads obj with missing usemtl', function(done) { it('loads obj with missing usemtl', async () => {
expect(loadObj(objMissingUsemtlPath, options) const data = await loadObj(objMissingUsemtlPath, options);
.then(function(data) { expect(data.materials.length).toBe(1);
expect(data.materials.length).toBe(1); expect(data.nodes[0].meshes[0].primitives[0].material).toBe('Material');
expect(data.nodes[0].meshes[0].primitives[0].material).toBe('Material');
}), done).toResolve();
}); });
it('loads .mtl outside of the obj directory', function(done) { it('loads .mtl outside of the obj directory', async () => {
expect(loadObj(objExternalResourcesPath, options) const data = await loadObj(objExternalResourcesPath, options);
.then(function(data) { const materials = data.materials;
var materials = data.materials; expect(materials.length).toBe(2);
expect(materials.length).toBe(2);
// .mtl files are loaded in an arbitrary order, so find the "MaterialTextured" material // .mtl files are loaded in an arbitrary order, so find the "MaterialTextured" material
var materialTextured = materials[0].name === 'MaterialTextured' ? materials[0] : materials[1]; const materialTextured = materials[0].name === 'MaterialTextured' ? materials[0] : materials[1];
var baseColorTexture = materialTextured.pbrMetallicRoughness.baseColorTexture; const baseColorTexture = materialTextured.pbrMetallicRoughness.baseColorTexture;
expect(baseColorTexture.source).toBeDefined(); expect(baseColorTexture.source).toBeDefined();
expect(baseColorTexture.name).toEqual('cesium'); expect(baseColorTexture.name).toEqual('cesium');
}), done).toResolve();
}); });
it('does not load .mtl outside of the obj directory when secure is true', function(done) { it('does not load .mtl outside of the obj directory when secure is true', async () => {
var spy = jasmine.createSpy('logger'); const spy = jasmine.createSpy('logger');
options.logger = spy; options.logger = spy;
options.secure = true; options.secure = true;
expect(loadObj(objExternalResourcesPath, options) const data = await 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(data.materials.length).toBe(1); // obj references 2 materials, one of which is outside the input directory 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(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(1)[0].indexOf('ENOENT') >= 0).toBe(true); expect(spy.calls.argsFor(2)[0].indexOf('Could not read material file') >= 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) { it('loads .mtl from root directory when the .mtl path does not exist', async () => {
expect(loadObj(objResourcesInRootPath, options) const data = await loadObj(objResourcesInRootPath, options);
.then(function(data) { const baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture;
var baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture.name).toBe('cesium');
expect(baseColorTexture.name).toBe('cesium'); expect(baseColorTexture.source).toBeDefined();
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) { it('loads .mtl from root directory when the .mtl path is outside of the obj directory and secure is true', async () => {
options.secure = true; options.secure = true;
expect(loadObj(objExternalResourcesInRootPath, options) const data = await loadObj(objExternalResourcesInRootPath, options);
.then(function(data) { const materials = data.materials;
var materials = data.materials; expect(materials.length).toBe(2);
expect(materials.length).toBe(2);
// .mtl files are loaded in an arbitrary order, so find the "MaterialTextured" material // .mtl files are loaded in an arbitrary order, so find the "MaterialTextured" material
var materialTextured = materials[0].name === 'MaterialTextured' ? materials[0] : materials[1]; const materialTextured = materials[0].name === 'MaterialTextured' ? materials[0] : materials[1];
var baseColorTexture = materialTextured.pbrMetallicRoughness.baseColorTexture; const baseColorTexture = materialTextured.pbrMetallicRoughness.baseColorTexture;
expect(baseColorTexture.source).toBeDefined(); expect(baseColorTexture.source).toBeDefined();
expect(baseColorTexture.name).toEqual('cesium'); expect(baseColorTexture.name).toEqual('cesium');
}), done).toResolve();
}); });
it('loads obj with texture', function(done) { it('loads obj with texture', async () => {
expect(loadObj(objTexturedPath, options) const data = await loadObj(objTexturedPath, options);
.then(function(data) { const baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture;
var baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture.name).toBe('cesium');
expect(baseColorTexture.name).toBe('cesium'); expect(baseColorTexture.source).toBeDefined();
expect(baseColorTexture.source).toBeDefined();
}), done).toResolve();
}); });
it('loads obj with missing texture', function(done) { it('loads obj with missing texture', async () => {
var spy = jasmine.createSpy('logger'); const spy = jasmine.createSpy('logger');
options.logger = spy; options.logger = spy;
expect(loadObj(objMissingTexturePath, options) const data = await loadObj(objMissingTexturePath, options);
.then(function(data) { const baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture;
var baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture).toBeUndefined();
expect(baseColorTexture).toBeUndefined(); expect(spy.calls.argsFor(0)[0].indexOf('ENOENT') >= 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(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(2)[0].indexOf('ENOENT') >= 0).toBe(true); expect(spy.calls.argsFor(3)[0].indexOf('Could not read texture file') >= 0).toBe(true);
expect(spy.calls.argsFor(3)[0].indexOf('Could not read texture file') >= 0).toBe(true);
}), done).toResolve();
}); });
it('loads obj with subdirectories', function(done) { it('loads obj with subdirectories', async () => {
expect(loadObj(objSubdirectoriesPath, options) const data = await loadObj(objSubdirectoriesPath, options);
.then(function(data) { const baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture;
var baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture.name).toBe('cesium');
expect(baseColorTexture.name).toBe('cesium'); expect(baseColorTexture.source).toBeDefined();
expect(baseColorTexture.source).toBeDefined();
}), done).toResolve();
}); });
it('loads obj with windows paths', function(done) { it('loads obj with windows paths', async () => {
expect(loadObj(objWindowsPaths, options) const data = await loadObj(objWindowsPaths, options);
.then(function(data) { const baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture;
var baseColorTexture = data.materials[0].pbrMetallicRoughness.baseColorTexture; expect(baseColorTexture.name).toBe('cesium');
expect(baseColorTexture.name).toBe('cesium'); expect(baseColorTexture.source).toBeDefined();
expect(baseColorTexture.source).toBeDefined();
}), done).toResolve();
}); });
it('separates faces that don\'t use the same attributes as other faces in the primitive', function(done) { it('separates faces that don\'t use the same attributes as other faces in the primitive', async () => {
expect(loadObj(objMixedAttributesPath, options) const data = await loadObj(objMixedAttributesPath, options);
.then(function(data) { const primitives = getPrimitives(data);
var primitives = getPrimitives(data); expect(primitives.length).toBe(4);
expect(primitives.length).toBe(4); expect(primitives[0].indices.length).toBe(18); // 6 faces
expect(primitives[0].indices.length).toBe(18); // 6 faces expect(primitives[1].indices.length).toBe(6); // 2 faces
expect(primitives[1].indices.length).toBe(6); // 2 faces expect(primitives[2].indices.length).toBe(6); // 2 faces
expect(primitives[2].indices.length).toBe(6); // 2 faces expect(primitives[3].indices.length).toBe(6); // 2 faces
expect(primitives[3].indices.length).toBe(6); // 2 faces
}), done).toResolve();
}); });
it('throws when file has invalid contents', function(done) { it('throws when file has invalid contents', async () => {
expect(loadObj(objInvalidContentsPath, options), done).toRejectWith(RuntimeError); let thrownError;
try {
await loadObj(objInvalidContentsPath, options);
} catch (e) {
thrownError = e;
}
expect(thrownError).toEqual(new RuntimeError(objInvalidContentsPath + ' does not have any geometry data'));
}); });
it('throw when reading invalid file', function(done) { it('throw when reading invalid file', async () => {
expect(loadObj(objInvalidPath, options), done).toRejectWith(Error); let thrownError;
try {
await loadObj(objInvalidPath, options);
} catch (e) {
thrownError = e;
}
expect(thrownError.message.startsWith('ENOENT: no such file or directory')).toBe(true);
}); });
}); });

View File

@ -1,117 +1,99 @@
'use strict'; 'use strict';
var loadTexture = require('../../lib/loadTexture'); const loadTexture = require('../../lib/loadTexture');
var pngTexturePath = 'specs/data/box-complex-material/shininess.png'; const pngTexturePath = 'specs/data/box-complex-material/shininess.png';
var jpgTexturePath = 'specs/data/box-complex-material/emission.jpg'; const jpgTexturePath = 'specs/data/box-complex-material/emission.jpg';
var jpegTexturePath = 'specs/data/box-complex-material/specular.jpeg'; const jpegTexturePath = 'specs/data/box-complex-material/specular.jpeg';
var gifTexturePath = 'specs/data/box-complex-material/ambient.gif'; const gifTexturePath = 'specs/data/box-complex-material/ambient.gif';
var grayscaleTexturePath = 'specs/data/box-complex-material-alpha/alpha.png'; const grayscaleTexturePath = 'specs/data/box-complex-material-alpha/alpha.png';
var transparentTexturePath = 'specs/data/box-complex-material/diffuse.png'; const transparentTexturePath = 'specs/data/box-complex-material/diffuse.png';
describe('loadTexture', function() { describe('loadTexture', () => {
it('loads png texture', function(done) { it('loads png texture', async () => {
expect(loadTexture(pngTexturePath) const texture = await loadTexture(pngTexturePath);
.then(function(texture) { expect(texture.transparent).toBe(false);
expect(texture.transparent).toBe(false); expect(texture.source).toBeDefined();
expect(texture.source).toBeDefined(); expect(texture.name).toBe('shininess');
expect(texture.name).toBe('shininess'); expect(texture.extension).toBe('.png');
expect(texture.extension).toBe('.png'); expect(texture.path).toBe(pngTexturePath);
expect(texture.path).toBe(pngTexturePath); expect(texture.pixels).toBeUndefined();
expect(texture.pixels).toBeUndefined(); expect(texture.width).toBeUndefined();
expect(texture.width).toBeUndefined(); expect(texture.height).toBeUndefined();
expect(texture.height).toBeUndefined();
}), done).toResolve();
}); });
it('loads jpg texture', function(done) { it('loads jpg texture', async () => {
expect(loadTexture(jpgTexturePath) const texture = await loadTexture(jpgTexturePath);
.then(function(texture) { expect(texture.transparent).toBe(false);
expect(texture.transparent).toBe(false); expect(texture.source).toBeDefined();
expect(texture.source).toBeDefined(); expect(texture.name).toBe('emission');
expect(texture.name).toBe('emission'); expect(texture.extension).toBe('.jpg');
expect(texture.extension).toBe('.jpg'); expect(texture.path).toBe(jpgTexturePath);
expect(texture.path).toBe(jpgTexturePath); expect(texture.pixels).toBeUndefined();
expect(texture.pixels).toBeUndefined(); expect(texture.width).toBeUndefined();
expect(texture.width).toBeUndefined(); expect(texture.height).toBeUndefined();
expect(texture.height).toBeUndefined();
}), done).toResolve();
}); });
it('loads jpeg texture', function(done) { it('loads jpeg texture', async () => {
expect(loadTexture(jpegTexturePath) const texture = await loadTexture(jpegTexturePath);
.then(function(texture) { expect(texture.transparent).toBe(false);
expect(texture.transparent).toBe(false); expect(texture.source).toBeDefined();
expect(texture.source).toBeDefined(); expect(texture.name).toBe('specular');
expect(texture.name).toBe('specular'); expect(texture.extension).toBe('.jpeg');
expect(texture.extension).toBe('.jpeg'); expect(texture.path).toBe(jpegTexturePath);
expect(texture.path).toBe(jpegTexturePath); expect(texture.pixels).toBeUndefined();
expect(texture.pixels).toBeUndefined(); expect(texture.width).toBeUndefined();
expect(texture.width).toBeUndefined(); expect(texture.height).toBeUndefined();
expect(texture.height).toBeUndefined();
}), done).toResolve();
}); });
it('loads gif texture', function(done) { it('loads gif texture', async () => {
expect(loadTexture(gifTexturePath) const texture = await loadTexture(gifTexturePath);
.then(function(texture) { expect(texture.transparent).toBe(false);
expect(texture.transparent).toBe(false); expect(texture.source).toBeDefined();
expect(texture.source).toBeDefined(); expect(texture.name).toBe('ambient');
expect(texture.name).toBe('ambient'); expect(texture.extension).toBe('.gif');
expect(texture.extension).toBe('.gif'); expect(texture.path).toBe(gifTexturePath);
expect(texture.path).toBe(gifTexturePath); expect(texture.pixels).toBeUndefined();
expect(texture.pixels).toBeUndefined(); expect(texture.width).toBeUndefined();
expect(texture.width).toBeUndefined(); expect(texture.height).toBeUndefined();
expect(texture.height).toBeUndefined();
}), done).toResolve();
}); });
it('loads grayscale texture', function(done) { it('loads grayscale texture', async () => {
expect(loadTexture(grayscaleTexturePath) const texture = await loadTexture(grayscaleTexturePath);
.then(function(texture) { expect(texture.transparent).toBe(false);
expect(texture.transparent).toBe(false); expect(texture.source).toBeDefined();
expect(texture.source).toBeDefined(); expect(texture.extension).toBe('.png');
expect(texture.extension).toBe('.png');
}), done).toResolve();
}); });
it('loads texture with alpha channel', function(done) { it('loads texture with alpha channel', async () => {
expect(loadTexture(transparentTexturePath) const texture = await loadTexture(transparentTexturePath);
.then(function(texture) { expect(texture.transparent).toBe(false);
expect(texture.transparent).toBe(false);
}), done).toResolve();
}); });
it('loads texture with checkTransparency flag', function(done) { it('loads texture with checkTransparency flag', async () => {
var options = { const options = {
checkTransparency : true checkTransparency : true
}; };
expect(loadTexture(transparentTexturePath, options) const texture = await loadTexture(transparentTexturePath, options);
.then(function(texture) { expect(texture.transparent).toBe(true);
expect(texture.transparent).toBe(true);
}), done).toResolve();
}); });
it('loads and decodes png', function(done) { it('loads and decodes png', async () => {
var options = { const options = {
decode : true decode : true
}; };
expect(loadTexture(pngTexturePath, options) const texture = await loadTexture(pngTexturePath, options);
.then(function(texture) { expect(texture.pixels).toBeDefined();
expect(texture.pixels).toBeDefined(); expect(texture.width).toBe(211);
expect(texture.width).toBe(211); expect(texture.height).toBe(211);
expect(texture.height).toBe(211);
}), done).toResolve();
}); });
it('loads and decodes jpeg', function(done) { it('loads and decodes jpeg', async () => {
var options = { const options = {
decode : true decode : true
}; };
expect(loadTexture(jpegTexturePath, options) const texture = await loadTexture(jpegTexturePath, options);
.then(function(texture) { expect(texture.pixels).toBeDefined();
expect(texture.pixels).toBeDefined(); expect(texture.width).toBe(211);
expect(texture.width).toBe(211); expect(texture.height).toBe(211);
expect(texture.height).toBe(211);
}), done).toResolve();
}); });
}); });

View File

@ -1,79 +1,70 @@
'use strict'; 'use strict';
var fsExtra = require('fs-extra'); const { DeveloperError } = require('cesium');
var path = require('path'); const fsExtra = require('fs-extra');
var Promise = require('bluebird'); const path = require('path');
var obj2gltf = require('../../lib/obj2gltf'); const Promise = require('bluebird');
const obj2gltf = require('../../lib/obj2gltf');
var texturedObjPath = 'specs/data/box-textured/box-textured.obj'; const texturedObjPath = 'specs/data/box-textured/box-textured.obj';
var complexObjPath = 'specs/data/box-complex-material/box-complex-material.obj'; const complexObjPath = 'specs/data/box-complex-material/box-complex-material.obj';
var missingMtllibObjPath = 'specs/data/box-missing-mtllib/box-missing-mtllib.obj'; const missingMtllibObjPath = 'specs/data/box-missing-mtllib/box-missing-mtllib.obj';
var outputDirectory = 'output'; const outputDirectory = 'output';
var textureUrl = 'specs/data/box-textured/cesium.png'; const textureUrl = 'specs/data/box-textured/cesium.png';
describe('obj2gltf', function() { describe('obj2gltf', () => {
beforeEach(function() { beforeEach(() => {
spyOn(fsExtra, 'outputFile').and.returnValue(Promise.resolve()); spyOn(fsExtra, 'outputFile').and.returnValue(Promise.resolve());
}); });
it('converts obj to gltf', function(done) { it('converts obj to gltf', async () => {
expect(obj2gltf(texturedObjPath) const gltf = await obj2gltf(texturedObjPath);
.then(function(gltf) { expect(gltf).toBeDefined();
expect(gltf).toBeDefined(); expect(gltf.images.length).toBe(1);
expect(gltf.images.length).toBe(1);
}), done).toResolve();
}); });
it('converts obj to glb', function(done) { it('converts obj to glb', async () => {
var options = { const options = {
binary : true binary : true
}; };
expect(obj2gltf(texturedObjPath, options) const glb = await obj2gltf(texturedObjPath, options);
.then(function(glb) { const magic = glb.toString('utf8', 0, 4);
var magic = glb.toString('utf8', 0, 4); expect(magic).toBe('glTF');
expect(magic).toBe('glTF');
}), done).toResolve();
}); });
it('convert obj to gltf with separate resources', function(done) { it('convert obj to gltf with separate resources', async () => {
var options = { const options = {
separate : true, separate : true,
separateTextures : true, separateTextures : true,
outputDirectory : outputDirectory outputDirectory : outputDirectory
}; };
expect(obj2gltf(texturedObjPath, options) await obj2gltf(texturedObjPath, options);
.then(function() { expect(fsExtra.outputFile.calls.count()).toBe(2); // Saves out .png and .bin
expect(fsExtra.outputFile.calls.count()).toBe(2); // Saves out .png and .bin
}), done).toResolve();
}); });
it('converts obj to glb with separate resources', function(done) { it('converts obj to glb with separate resources', async () => {
var options = { const options = {
separate : true, separate : true,
separateTextures : true, separateTextures : true,
outputDirectory : outputDirectory, outputDirectory : outputDirectory,
binary : true binary : true
}; };
expect(obj2gltf(texturedObjPath, options) await obj2gltf(texturedObjPath, options);
.then(function() { expect(fsExtra.outputFile.calls.count()).toBe(2); // Saves out .png and .bin
expect(fsExtra.outputFile.calls.count()).toBe(2); // Saves out .png and .bin
}), done).toResolve();
}); });
it('converts obj with multiple textures', function(done) { it('converts obj with multiple textures', async () => {
var options = { const options = {
separateTextures : true, separateTextures : true,
outputDirectory : outputDirectory outputDirectory : outputDirectory
}; };
expect(obj2gltf(complexObjPath, options) await obj2gltf(complexObjPath, options);
.then(function() { expect(fsExtra.outputFile.calls.count()).toBe(5); // baseColor, metallicRoughness, occlusion, emission, normal
expect(fsExtra.outputFile.calls.count()).toBe(5); // baseColor, metallicRoughness, occlusion, emission, normal
}), done).toResolve();
}); });
it('sets overriding textures (1)', function(done) { it('sets overriding textures (1)', async () => {
var options = { const options = {
overridingTextures : { overridingTextures : {
metallicRoughnessOcclusionTexture : textureUrl, metallicRoughnessOcclusionTexture : textureUrl,
normalTexture : textureUrl, normalTexture : textureUrl,
@ -84,18 +75,16 @@ describe('obj2gltf', function() {
separateTextures : true, separateTextures : true,
outputDirectory : outputDirectory outputDirectory : outputDirectory
}; };
expect(obj2gltf(complexObjPath, options) await obj2gltf(complexObjPath, options);
.then(function() { const args = fsExtra.outputFile.calls.allArgs();
var args = fsExtra.outputFile.calls.allArgs(); const length = args.length;
var length = args.length; for (let i = 0; i < length; ++i) {
for (var i = 0; i < length; ++i) { expect(path.basename(args[i][0])).toBe(path.basename(textureUrl));
expect(path.basename(args[i][0])).toBe(path.basename(textureUrl)); }
}
}), done).toResolve();
}); });
it('sets overriding textures (2)', function(done) { it('sets overriding textures (2)', async () => {
var options = { const options = {
overridingTextures : { overridingTextures : {
specularGlossinessTexture : textureUrl, specularGlossinessTexture : textureUrl,
occlusionTexture : textureUrl, occlusionTexture : textureUrl,
@ -107,81 +96,94 @@ describe('obj2gltf', function() {
separateTextures : true, separateTextures : true,
outputDirectory : outputDirectory outputDirectory : outputDirectory
}; };
expect(obj2gltf(complexObjPath, options) await obj2gltf(complexObjPath, options);
.then(function() { const args = fsExtra.outputFile.calls.allArgs();
var args = fsExtra.outputFile.calls.allArgs(); const length = args.length;
var length = args.length; for (let i = 0; i < length; ++i) {
for (var i = 0; i < length; ++i) { expect(path.basename(args[i][0])).toBe(path.basename(textureUrl));
expect(path.basename(args[i][0])).toBe(path.basename(textureUrl)); }
}
}), done).toResolve();
}); });
it('uses a custom logger', function(done) { it('uses a custom logger', async () => {
var lastMessage; let lastMessage;
var options = { const options = {
logger : function(message) { logger : (message) => {
lastMessage = message; lastMessage = message;
} }
}; };
expect(obj2gltf(missingMtllibObjPath, options) await obj2gltf(missingMtllibObjPath, options);
.then(function() { expect(lastMessage.indexOf('Could not read material file') >= 0).toBe(true);
expect(lastMessage.indexOf('Could not read material file') >= 0).toBe(true);
}), done).toResolve();
}); });
it('uses a custom writer', function(done) { it('uses a custom writer', async () => {
var filePaths = []; const filePaths = [];
var fileContents = []; const fileContents = [];
var options = { const options = {
separate : true, separate : true,
writer : function(relativePath, contents) { writer : (relativePath, contents) => {
filePaths.push(relativePath); filePaths.push(relativePath);
fileContents.push(contents); fileContents.push(contents);
} }
}; };
expect(obj2gltf(texturedObjPath, options) await obj2gltf(texturedObjPath, options);
.then(function() { expect(filePaths).toEqual(['box-textured.bin', 'cesium.png']);
expect(filePaths).toEqual(['box-textured.bin', 'cesium.png']); expect(fileContents[0]).toBeDefined();
expect(fileContents[0]).toBeDefined(); expect(fileContents[1]).toBeDefined();
expect(fileContents[1]).toBeDefined();
}), done).toResolve();
}); });
it('throws if objPath is undefined', function() { it('throws if objPath is undefined', () => {
expect(function() { let thrownError;
try {
obj2gltf(undefined); obj2gltf(undefined);
}).toThrowDeveloperError(); } catch (e) {
thrownError = e;
}
expect(thrownError).toEqual(new DeveloperError('objPath is required'));
}); });
it('throws if both options.writer and options.outputDirectory are undefined when writing separate resources', function() { it('throws if both options.writer and options.outputDirectory are undefined when writing separate resources', () => {
var options = { const options = {
separateTextures : true separateTextures : true
}; };
expect(function() {
let thrownError;
try {
obj2gltf(texturedObjPath, options); obj2gltf(texturedObjPath, options);
}).toThrowDeveloperError(); } catch (e) {
thrownError = e;
}
expect(thrownError).toEqual(new DeveloperError('Either options.writer or options.outputDirectory must be defined when writing separate resources.'));
}); });
it('throws if more than one material type is set', function() { it('throws if more than one material type is set', () => {
var options = { const options = {
metallicRoughness : true, metallicRoughness : true,
specularGlossiness : true specularGlossiness : true
}; };
expect(function() {
let thrownError;
try {
obj2gltf(texturedObjPath, options); obj2gltf(texturedObjPath, options);
}).toThrowDeveloperError(); } catch (e) {
thrownError = e;
}
expect(thrownError).toEqual(new DeveloperError('Only one material type may be set from [metallicRoughness, specularGlossiness, unlit].'));
}); });
it('throws if metallicRoughnessOcclusionTexture and specularGlossinessTexture are both defined', function() { it('throws if metallicRoughnessOcclusionTexture and specularGlossinessTexture are both defined', () => {
var options = { const options = {
overridingTextures : { overridingTextures : {
metallicRoughnessOcclusionTexture : textureUrl, metallicRoughnessOcclusionTexture : textureUrl,
specularGlossinessTexture : textureUrl specularGlossinessTexture : textureUrl
} }
}; };
expect(function() {
let thrownError;
try {
obj2gltf(texturedObjPath, options); obj2gltf(texturedObjPath, options);
}).toThrowDeveloperError(); } catch (e) {
thrownError = e;
}
expect(thrownError).toEqual(new DeveloperError('metallicRoughnessOcclusionTexture and specularGlossinessTexture cannot both be defined.'));
}); });
}); });