Skip to content

Commit

Permalink
Merge ffb347f into 3db3306
Browse files Browse the repository at this point in the history
  • Loading branch information
Joshua Storm Becker committed Jun 2, 2016
2 parents 3db3306 + ffb347f commit 4433a81
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 113 deletions.
136 changes: 38 additions & 98 deletions bin/gltf-pipeline.js
@@ -1,114 +1,54 @@
#!/usr/bin/env node
'use strict';
var fs = require('fs');
var argv = require('yargs').argv;
var path = require('path');
var argv = require('minimist')(process.argv.slice(2));
var addDefaults = require('../').addDefaults;
var removeUnusedImages = require('../').removeUnusedImages;
var removeUnusedSamplers = require('../').removeUnusedSamplers;
var removeUnusedShaders = require('../').removeUnusedShaders;
var removeUnusedTechniques = require('../').removeUnusedTechniques;
var removeUnusedPrograms = require('../').removeUnusedPrograms;
var removeUnusedBuffers = require('../').removeUnusedBuffers;
var removeUnusedBufferViews = require('../').removeUnusedBufferViews;
var removeUnusedMaterials = require('../').removeUnusedMaterials;
var removeUnusedSkins = require('../').removeUnusedSkins;
var removeUnusedCameras = require('../').removeUnusedCameras;
var removeUnusedTextures = require('../').removeUnusedTextures;
var removeUnusedMeshes = require('../').removeUnusedMeshes;
var removeUnusedNodes = require('../').removeUnusedNodes;
var removeUnusedAccessors = require('../').removeUnusedAccessors;
var removeUnused = require('../').removeUnused;
var loadGltfUris = require('../').loadGltfUris;
var writeGltf = require('../').writeGltf;
var parseBinaryGltf = require('../').parseBinaryGltf;
var addPipelineExtras = require('../').addPipelineExtras;
var convertDagToTree = require('../').convertDagToTree;
var combineMeshes = require('../').combineMeshes;
var combinePrimitives = require('../').combinePrimitives;
var removeUnusedVertices = require('../').removeUnusedVertices;
var OptimizationStatistics = require('../').OptimizationStatistics;
var Cesium = require('cesium');
var defaultValue = Cesium.defaultValue;
var defined = Cesium.defined;

if (!defined(argv._[0]) || defined(argv.h) || defined(argv.help)) {
var help =
var writeGltf = require('../lib/writeGltf');
var writeBinaryGltf = require('../lib/writeBinaryGltf');
var gltfPipeline = require('../lib/gltfPipeline');
var addPipelineExtras = require('../lib/addPipelineExtras');
var readGltf = require('../lib/readGltf');

if (process.argv.length < 3 || defined(argv.h) || defined(argv.help)) {
var help =
'Usage: node ' + path.basename(__filename) + ' [path-to.gltf or path-to.bgltf] [OPTIONS]\n' +
' -o=PATH Write optimized glTF to the specified file.\n';
' -i, input=PATH Read unoptimized glTF from the specified file.\n ' +
' -b, write binary glTF file.\n' +
' -s, writes out separate geometry/animation data files, shader files and textures instead of embedding them in the glTF file.\n ' +
' -o, output=PATH write optimized glTF to the specified file.\n';
process.stdout.write(help);
return;
}

var gltfPath = argv._[0];

fs.readFile(gltfPath, function (err, data) {
if (err) {
throw err;
}

var fileExtension = path.extname(gltfPath);
var fileName = path.basename(gltfPath, fileExtension);
var filePath = path.dirname(gltfPath);

var gltf;
if (fileExtension === '.glb') {
gltf = parseBinaryGltf(data);
}
else if (fileExtension === '.gltf') {
gltf = JSON.parse(data);
}
else {
throw new Error('Invalid glTF file.');
}

var stats = new OptimizationStatistics();
var gltfPath = defaultValue(argv._[0], argv.i);
var fileExtension = path.extname(gltfPath);
var fileName = path.basename(gltfPath, fileExtension);
var filePath = path.dirname(gltfPath);

addDefaults(gltf, stats);
var outputPath = defaultValue(argv._[1], argv.o);
var isSeparate = defaultValue(argv.s, false);
var exportBinary = defaultValue(argv.b, false);

// TODO: custom pipeline based on arguments / config
removeUnused(gltf, stats);
printStats(stats);

addPipelineExtras(gltf);
convertDagToTree(gltf);

gltf = loadGltfUris(gltf, filePath, function(err) {
if (err) {
throw err;
}
if (!defined(gltfPath)) {
throw new DeveloperError('Input path is undefined.');
}

combineMeshes(gltf);
combinePrimitives(gltf);
if (fileExtension !== '.glb' && fileExtension !== '.gltf') {
throw new DeveloperError('Invalid glTF file.');
}

removeUnusedVertices(gltf);
if (!defined(outputPath)) {
// Default output. For example, path/asset.gltf becomes path/asset-optimized.gltf
outputPath = path.join(filePath, fileName + '-optimized' + fileExtension);
}

var outputPath = argv.o;
if (!defined(outputPath)) {
// Default output. For example, path/asset.gltf becomes path/asset-optimized.gltf
outputPath = path.join(filePath, fileName + '-optimized' + fileExtension);
readGltf(gltfPath, function(gltf) {
gltfPipeline(gltf, function(gltf) {
if (exportBinary) {
writeBinaryGltf(gltf, outputPath, true);
} else {
writeGltf(gltf, outputPath, !isSeparate, true);
}

//Run removeUnused stage again after all pipeline stages have been run to remove objects that become unused
removeUnused(gltf);

var isEmbedded = true;
writeGltf(gltf, outputPath, isEmbedded, true);
});
});

function printStats(stats) {
process.stdout.write('Nodes removed: ' + stats.numberRemoved.nodes + '\n');
process.stdout.write('Skins removed: ' + stats.numberRemoved.skins + '\n');
process.stdout.write('Cameras removed: ' + stats.numberRemoved.cameras + '\n');
process.stdout.write('Meshes removed: ' + stats.numberRemoved.meshes + '\n');
process.stdout.write('Accessors removed: ' + stats.numberRemoved.accessors + '\n');
process.stdout.write('Materials removed: ' + stats.numberRemoved.materials + '\n');
process.stdout.write('BufferViews removed: ' + stats.numberRemoved.bufferViews + '\n');
process.stdout.write('Techniques removed: ' + stats.numberRemoved.techniques + '\n');
process.stdout.write('Textures removed: ' + stats.numberRemoved.textures + '\n');
process.stdout.write('Buffers removed: ' + stats.numberRemoved.buffers + '\n');
process.stdout.write('Programs removed: ' + stats.numberRemoved.programs + '\n');
process.stdout.write('Images removed: ' + stats.numberRemoved.images + '\n');
process.stdout.write('Samplers removed: ' + stats.numberRemoved.samplers + '\n');
process.stdout.write('Shaders removed: ' + stats.numberRemoved.shaders + '\n');
}
});
3 changes: 2 additions & 1 deletion index.js
Expand Up @@ -26,5 +26,6 @@ module.exports = {
combineMeshes : require('./lib/combineMeshes'),
combinePrimitives : require('./lib/combinePrimitives'),
removeUnusedVertices : require('./lib/removeUnusedVertices'),
OptimizationStatistics : require('./lib/OptimizationStatistics')
OptimizationStatistics : require('./lib/OptimizationStatistics'),
gltfPipeline : require('./lib/gltfPipeline')
};
69 changes: 69 additions & 0 deletions lib/gltfPipeline.js
@@ -0,0 +1,69 @@
'use strict';
var fs = require('fs');
var addDefaults = require('./addDefaults');
var removeUnusedImages = require('./removeUnusedImages');
var removeUnusedSamplers = require('./removeUnusedSamplers');
var removeUnusedShaders = require('./removeUnusedShaders');
var removeUnusedTechniques = require('./removeUnusedTechniques');
var removeUnusedPrograms = require('./removeUnusedPrograms');
var removeUnusedBuffers = require('./removeUnusedBuffers');
var removeUnusedBufferViews = require('./removeUnusedBufferViews');
var removeUnusedMaterials = require('./removeUnusedMaterials');
var removeUnusedSkins = require('./removeUnusedSkins');
var removeUnusedCameras = require('./removeUnusedCameras');
var removeUnusedTextures = require('./removeUnusedTextures');
var removeUnusedMeshes = require('./removeUnusedMeshes');
var removeUnusedNodes = require('./removeUnusedNodes');
var removeUnusedAccessors = require('./removeUnusedAccessors');
var removeUnused = require('./removeUnused');
var parseBinaryGltf = require('./parseBinaryGltf');
var addPipelineExtras = require('./addPipelineExtras');
var convertDagToTree = require('./convertDagToTree');
var combineMeshes = require('./combineMeshes');
var combinePrimitives = require('./combinePrimitives');
var removeUnusedVertices = require('./removeUnusedVertices');
var OptimizationStatistics = require('./OptimizationStatistics');
var Cesium = require('cesium');
var defined = Cesium.defined;
var defaultValue = Cesium.defaultValue;
var DeveloperError = Cesium.DeveloperError;

module.exports = gltfPipeline;

function gltfPipeline(gltfWithExtras, callback) {
var stats = new OptimizationStatistics();

addDefaults(gltfWithExtras, stats);

removeUnused(gltfWithExtras, stats);
printStats(stats);

convertDagToTree(gltfWithExtras);

removeUnusedVertices(gltfWithExtras);

combineMeshes(gltfWithExtras);
combinePrimitives(gltfWithExtras);

//Run removeUnused stage again after all pipeline stages have been run to remove objects that become unused
removeUnused(gltfWithExtras);

callback(gltfWithExtras);
}

function printStats(stats) {
process.stdout.write('Nodes removed: ' + stats.numberRemoved.nodes + '\n');
process.stdout.write('Skins removed: ' + stats.numberRemoved.skins + '\n');
process.stdout.write('Cameras removed: ' + stats.numberRemoved.cameras + '\n');
process.stdout.write('Meshes removed: ' + stats.numberRemoved.meshes + '\n');
process.stdout.write('Accessors removed: ' + stats.numberRemoved.accessors + '\n');
process.stdout.write('Materials removed: ' + stats.numberRemoved.materials + '\n');
process.stdout.write('BufferViews removed: ' + stats.numberRemoved.bufferViews + '\n');
process.stdout.write('Techniques removed: ' + stats.numberRemoved.techniques + '\n');
process.stdout.write('Textures removed: ' + stats.numberRemoved.textures + '\n');
process.stdout.write('Buffers removed: ' + stats.numberRemoved.buffers + '\n');
process.stdout.write('Programs removed: ' + stats.numberRemoved.programs + '\n');
process.stdout.write('Images removed: ' + stats.numberRemoved.images + '\n');
process.stdout.write('Samplers removed: ' + stats.numberRemoved.samplers + '\n');
process.stdout.write('Shaders removed: ' + stats.numberRemoved.shaders + '\n');
}
44 changes: 44 additions & 0 deletions lib/readGltf.js
@@ -0,0 +1,44 @@
'use strict';
var path = require('path');
var fs = require('fs');
var parseBinaryGltf = require('./parseBinaryGltf');
var addPipelineExtras = require('./addPipelineExtras');
var loadGltfUris = require('../lib/loadGltfUris');
var Cesium = require('cesium');
var defined = Cesium.defined;

module.exports = readGltf;


function readGltf(gltfPath, callback) {

var fileExtension = path.extname(gltfPath);
var filePath = path.dirname(gltfPath);


if (!defined(gltfPath)) {
throw new DeveloperError('Input path is undefined.');
}

if (fileExtension !== '.glb' && fileExtension !== '.gltf') {
throw new DeveloperError('Invalid glTF file.');
}

fs.readFile(gltfPath, function(err, data) {
if (err) {
throw err;
}

var gltf;
if (fileExtension === '.glb') {
gltf = parseBinaryGltf(data);
}
else if (fileExtension === '.gltf') {
gltf = JSON.parse(data);
addPipelineExtras(gltf);
}
var gltf = loadGltfUris(gltf, filePath, function() {
callback(gltf);
});
});
}
30 changes: 18 additions & 12 deletions lib/writeBinaryGltf.js
Expand Up @@ -15,13 +15,19 @@ var removePipelineExtras = require('./removePipelineExtras');
module.exports = writeBinaryGltf;

function writeBinaryGltf(gltf, outputPath, createDirectory, callback) {
//Create the output directory if specified
// Correct output path extension if necessary
var outputExtension = path.extname(outputPath);
if (outputExtension !== '.glb') {
outputPath = path.basename(outputPath, outputExtension) + '.glb';
}
// Create the output directory if specified
if (createDirectory) {
outputPath = path.join(path.dirname(outputPath), 'output', path.basename(outputPath));
mkdirp.sync(path.dirname(outputPath));
}

//Create the special binary buffer from the existing buffers

// Create the special binary buffer from the existing buffers
gltf.bufferViews = defaultValue(gltf.bufferViews, {});
gltf.buffers = defaultValue(gltf.buffers, {});
mergeBuffers(gltf, 'binary_glTF');
Expand All @@ -31,21 +37,21 @@ function writeBinaryGltf(gltf, outputPath, createDirectory, callback) {
var currentOffset = buffers.binary_glTF.byteLength;
var body = buffers.binary_glTF.extras._pipeline.source;
var currentBinaryView = 0;
//Update object with KHR_binary_glTF properties and add to body and bufferViews
// Update object with KHR_binary_glTF properties and add to body and bufferViews
function updateBinaryObject(name) {
var objects = gltf[name];
if (defined(objects)) {
for (var objectId in objects) {
if (objects.hasOwnProperty(objectId)) {
var object = objects[objectId];

//Update object with binary format
// Update object with binary format
object.uri = "data:,";
object.extensions = defaultValue(object.extensions, {});
object.extensions.KHR_binary_glTF = defaultValue(object.extensions.KHR_binary_glTF, {});
var KHR_binary_glTF = object.extensions.KHR_binary_glTF;

//Create a bufferView based on the byte length and current offset
// Create a bufferView based on the byte length and current offset
var bufferViewKeys = Object.keys(bufferViews);
while (bufferViewKeys.indexOf('binary_bufferView' + currentBinaryView) != -1) {
currentBinaryView++;
Expand All @@ -61,10 +67,10 @@ function writeBinaryGltf(gltf, outputPath, createDirectory, callback) {
};
currentOffset += objectSource.length;

//Append the object source to the binary body
// Append the object source to the binary body
body = Buffer.concat([body, objectSource]);

//Add additional properties for images
// Add additional properties for images
if (name === 'images') {
KHR_binary_glTF.mimeType = mime.lookup(object.extras._pipeline.extension);

Expand All @@ -82,10 +88,10 @@ function writeBinaryGltf(gltf, outputPath, createDirectory, callback) {

buffers.binary_glTF.byteLength = currentOffset;

//Remove extras objects before writing
// Remove extras objects before writing
removePipelineExtras(gltf);

//Create padded binary scene string and calculate total length
// Create padded binary scene string and calculate total length
var sceneString = JSON.stringify(gltf);
var sceneLength = Buffer.byteLength(sceneString);
sceneLength += 4 - (sceneLength % 4);
Expand All @@ -94,18 +100,18 @@ function writeBinaryGltf(gltf, outputPath, createDirectory, callback) {
var bodyOffset = 20 + sceneLength;
var glbLength = bodyOffset + body.length;

//Write binary glTF header (magic, version, length, sceneLength, sceneFormat)
// Write binary glTF header (magic, version, length, sceneLength, sceneFormat)
var header = new Buffer(20);
header.write('glTF', 0);
header.writeUInt32LE(1, 4);
header.writeUInt32LE(glbLength, 8);
header.writeUInt32LE(sceneLength, 12);
header.writeUInt32LE(0, 16);

//Create scene buffer and overall buffer
// Create scene buffer and overall buffer
var scene = new Buffer(sceneString);
var glb = Buffer.concat([header, scene, body], glbLength);

fs.writeFile(outputPath, glb, function (err) {
if (err) {
if (callback) {
Expand Down
4 changes: 2 additions & 2 deletions package.json 100755 → 100644
Expand Up @@ -40,9 +40,9 @@
"datauri": "^1.0.0-alpha.5",
"image-size": "^0.5.0",
"mime": "^1.3.4",
"minimist": "1.1.0",
"mkdirp": "^0.5.1",
"object-values": "^1.0.0"
"object-values": "^1.0.0",
"yargs": "^4.7.1"
},
"devDependencies": {
"clone": "^1.0.2",
Expand Down

0 comments on commit 4433a81

Please sign in to comment.