🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@gltf-transform/cli

Package Overview
Dependencies
Maintainers
1
Versions
214
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@gltf-transform/cli - npm Package Compare versions

Comparing version
0.4.0
to
0.4.1
+175
src/list.js
const Table = require('cli-table');
const { ImageUtils } = require('@gltf-transform/core');
function list (type, doc) {
const logger = doc.getLogger();
let result;
switch (type) {
case 'meshes': result = listMeshes(doc); break;
case 'textures': result = listTextures(doc); break;
case 'extensions': result = listExtensions(doc); break;
case 'animations': result = listAnimations(doc); break;
default:
throw new Error('Not implemented.');
}
const {head, rows, warnings} = result;
if (rows.length === 0) {
logger.warn(`No ${type} found.`);
return;
}
const table = new Table({head});
table.push(...rows);
logger.info(table.toString());
warnings.forEach((warning) => logger.warn(formatParagraph(warning)));
}
/** List meshes. */
function listMeshes (doc) {
const rows = doc.getRoot().listMeshes().map((mesh, index) => {
const references = mesh.listParents()
.filter((parent) => parent.propertyType !== 'Root')
.length;
let size = 0;
mesh.listPrimitives().forEach((prim) => {
for (const attr of prim.listAttributes()) {
size += attr.getArray().byteLength;
}
if (prim.getIndices()) size += prim.getIndices().getArray().byteLength;
});
return [
index,
mesh.getName(),
references,
formatBytes(size)
];
});
return {
rows,
head: ['index', 'name', 'references', 'size'],
warnings: [
'NOTICE: Estimated mesh sizes do not include morph targets, and may overestimate'
+ ' total sizes if multiple meshes are sharing the same accessors.'
],
};
}
/** List textures. */
function listTextures (doc) {
const rows = doc.getRoot().listTextures().map((texture, index) => {
const references = texture.listParents()
.filter((parent) => parent.propertyType !== 'Root')
.length;
const slots = doc.getGraph().getLinks()
.filter((link) => link.getChild() === texture)
.map((link) => link.getName())
.filter((name) => name !== 'texture');
// TODO: This requires a Buffer, currently?
// const dims = '';
// if (texture.getMimeType() === 'image/png') {
// dims = ImageUtils.getSizePNG(texture.getImage()).join('x');
// } else if (texture.getMimeType() === 'image/jpeg') {
// dims = ImageUtils.getSizeJPEG(texture.getImage()).join('x');
// }
return [
index,
texture.getName(),
texture.getURI(),
Array.from(new Set(slots)).join(', '),
references,
texture.getMimeType(),
formatBytes(texture.getImage().byteLength)
]
});
return {
rows,
head: ['index', 'name', 'uri', 'slots', 'references', 'mimeType', 'size'],
warnings: [],
};
}
/** List animations. */
function listAnimations (doc) {
const rows = doc.getRoot().listAnimations().map((anim, index) => {
let minTime = Infinity;
let maxTime = -Infinity;
anim.listSamplers().forEach((sampler) => {
minTime = Math.min(minTime, sampler.getInput().getMin([])[0]);
maxTime = Math.max(maxTime, sampler.getInput().getMax([])[0]);
});
let size = 0;
const accessors = new Set();
anim.listSamplers().forEach((sampler) => {
accessors.add(sampler.getInput());
accessors.add(sampler.getOutput());
});
Array.from(accessors)
.map((accessor) => accessor.getArray().byteLength)
.forEach((byteLength) => (size += byteLength));
return [
index,
anim.getName(),
anim.listChannels().length,
anim.listSamplers().length,
(maxTime - minTime).toFixed(3) + 's',
formatBytes(size),
]
});
return {
rows,
head: ['index', 'name', 'channels', 'samplers', 'duration', 'size'],
warnings: [
'NOTICE: Estimated animation sizes may overestimate total sizes if multiple animations'
+ ' are sharing the same accessors.'
],
}
}
/** List extensions. */
function listExtensions (doc) {
const required = new Set(doc.getRoot().listExtensionsRequired().map((e) => e.extensionName));
const rows = doc.getRoot().listExtensionsUsed().map((extension) => {
return [
extension.extensionName,
required.has(extension) ? 'x' : ''
];
});
return {
rows,
head: ['name', 'required'],
warnings: [],
};
}
// Utilities.
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
function formatParagraph(str) {
return str.match(/.{1,80}(\s|$)/g).join('\n');
}
module.exports = {list};
+9
-8
{
"name": "@gltf-transform/cli",
"version": "0.4.0",
"version": "0.4.1",
"repository": "github:donmccurdy/glTF-Transform",

@@ -17,9 +17,10 @@ "description": "CLI interface to glTF Transform",

"dependencies": {
"@gltf-transform/ao": "^0.4.0",
"@gltf-transform/colorspace": "^0.4.0",
"@gltf-transform/core": "^0.4.0",
"@gltf-transform/extensions": "^0.4.0",
"@gltf-transform/prune": "^0.4.0",
"@gltf-transform/split": "^0.4.0",
"@gltf-transform/ao": "^0.4.1",
"@gltf-transform/colorspace": "^0.4.1",
"@gltf-transform/core": "^0.4.1",
"@gltf-transform/extensions": "^0.4.1",
"@gltf-transform/prune": "^0.4.1",
"@gltf-transform/split": "^0.4.1",
"caporal": "^1.3.0",
"cli-table": "^0.3.1",
"gl": "^4.5.0"

@@ -33,3 +34,3 @@ },

],
"gitHead": "9a2c30c6dd0f0222e86e5f65a8c13f07b9765b1c"
"gitHead": "fa72e862b943db559d398918e3091216f54a6592"
}

@@ -5,3 +5,2 @@ #!/usr/bin/env node

const path = require('path');
const util = require('util');
const gl = require('gl');

@@ -16,2 +15,3 @@ const program = require('caporal');

const { prune } = require('@gltf-transform/prune');
const { list } = require('./list');

@@ -21,21 +21,5 @@ const io = new NodeIO(fs, path).registerExtensions(KHRONOS_EXTENSIONS);

program
.version(version);
.version(version)
.description('Commandline interface for the glTF-Transform SDK.');
// ANALYZE
program
.command('analyze', 'Analyzes a model\'s contents')
.argument('<input>', 'Path to glTF 2.0 (.glb, .gltf) model')
.action(({input}, options, logger) => {
const root = io.read(input).getRoot();
const analysis = {
accessors: root.listAccessors().length,
buffers: root.listBuffers().length,
materials: root.listMaterials().length,
meshes: root.listMeshes().length,
nodes: root.listNodes().length,
textures: root.listTextures().length,
};
console.log(util.inspect(analysis, {colors: true, sorted: true}));
});
// REPACK

@@ -51,2 +35,14 @@ program

// LIST
program
.command('list', 'List a model\'s resources of a given type')
.argument(
'<type>', 'Property type ("animations", "extensions", "meshes", "textures")',
['animations', 'extensions', 'meshes', 'textures']
)
.argument('<input>', 'Path to glTF 2.0 (.glb, .gltf) model')
.action(({type, input}, _, logger) => {
list(type, io.read(input).setLogger(logger));
});
// AMBIENT OCCLUSION

@@ -95,3 +91,3 @@ program

program
.command('split', 'Splits buffers so that separate meshes can be stored in separate .bin files')
.command('split', 'Splits mesh data into separate .bin files')
.argument('<input>', 'Path to read glTF 2.0 (.glb, .gltf) input')

@@ -98,0 +94,0 @@ .argument('<output>', 'Path to write output')