🚀 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-alpha.3
to
0.4.0
+9
-10
package.json
{
"name": "@gltf-transform/cli",
"version": "0.4.0-alpha.3",
"version": "0.4.0",
"repository": "github:donmccurdy/glTF-Transform",

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

"dependencies": {
"@gltf-transform/ao": "^0.4.0-alpha.3",
"@gltf-transform/colorspace": "^0.4.0-alpha.3",
"@gltf-transform/core": "^0.4.0-alpha.3",
"@gltf-transform/extensions": "^0.4.0-alpha.3",
"@gltf-transform/prune": "^0.4.0-alpha.3",
"@gltf-transform/split": "^0.4.0-alpha.3",
"@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",
"caporal": "^1.3.0",
"gl": "^4.5.0",
"minimatch": "^3.0.4"
"gl": "^4.5.0"
},

@@ -34,3 +33,3 @@ "files": [

],
"gitHead": "6ab967a22de4bfb41845d8d0cfb9ca743f324adb"
"gitHead": "9a2c30c6dd0f0222e86e5f65a8c13f07b9765b1c"
}

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

const { prune } = require('@gltf-transform/prune');
const { toktx, Mode, TOKTX_DEFAULTS } = require('./toktx');

@@ -104,34 +103,2 @@ const io = new NodeIO(fs, path).registerExtensions(KHRONOS_EXTENSIONS);

// KTX
program
.command('ktx', 'Compresses textures with KTX + Basis Universal')
.argument('<input>', 'Path to read glTF 2.0 (.glb, .gltf) input')
.argument('<output>', 'Path to write output')
.option(
'--mode <mode>',
'Basis Universal compression mode ["etc1s" = low quality, "uastc" = high quality]',
[Mode.ETC1S, Mode.UASTC], Mode.ETC1S
)
.option(
'--quality <quality>',
'Quality level, where higher levels mean larger files [0 – 1]',
program.FLOAT, TOKTX_DEFAULTS.quality
)
.option(
'--zstd <zstd>',
'ZSTD compression level (UASTC only) [1 – 20, 0 = Off]',
program.FLOAT, 0
)
.option(
'--slots <slots>',
'Texture slots to compress (glob expression)',
program.STRING, "*"
)
.action(({input, output}, options, logger) => {
const doc = io.read(input)
.setLogger(logger)
.transform(toktx(options));
io.write(output, doc);
});
// UNLIT

@@ -138,0 +105,0 @@ program

const fs = require('fs');
const tmp = require('tmp');
const minimatch = require('minimatch');
const { spawnSync } = require('child_process');
const { BufferUtils, ImageUtils, FileUtils, PropertyType } = require('@gltf-transform/core');
const { TextureBasisu } = require('@gltf-transform/extensions');
const Mode = {
ETC1S: 'etc1s',
UASTC: 'uastc',
};
const TOKTX_DEFAULTS = {
mode: Mode.ETC1S,
quality: 0.5,
zstd: 0,
slots: '*',
};
tmp.setGracefulCleanup();
const toktx = function (options) {
options = {...TOKTX_DEFAULTS, ...options};
return (doc) => {
const logger = doc.getLogger();
doc.createExtension(TextureBasisu);
doc.getRoot()
.listTextures()
.forEach((texture, textureIndex) => {
const slots = getTextureSlots(doc, texture);
const textureLabel = texture.getURI()
|| texture.getName()
|| `${textureIndex + 1}/${doc.getRoot().listTextures().length}`;
logger.debug(`Texture ${textureLabel} (${slots.join(', ')})`);
// Exclude textures that don't match the 'slots' glob, or are already KTX.
if (texture.getMimeType() === 'image/ktx2') {
logger.debug('• Skipping, already KTX.');
return;
} else if (options.slots !== '*' && !slots.find((slot) => minimatch(slot, options.slots, {nocase: true}))) {
logger.debug(`• Skipping, excluded by pattern "${options.slots}".`)
return;
}
const inExtension = texture.getURI()
? FileUtils.extension(texture.getURI())
: ImageUtils.mimeTypeToExtension(texture.getMimeType());
const inPath = tmp.tmpNameSync({postfix: '.' + inExtension});
const outPath = tmp.tmpNameSync({postfix: '.ktx2'});
const inBytes = texture.getImage().byteLength;
fs.writeFileSync(inPath, Buffer.from(texture.getImage()));
const params = [...createParams(slots, options), outPath, inPath];
logger.debug(`• toktx ${params.join(' ')}`);
// Run `toktx` CLI tool.
const {status, error} = spawnSync('toktx', params, {stdio: [process.stderr]});
if (status !== 0) {
logger.error('• Texture compression failed.');
throw error || new Error('Texture compression failed');
}
texture
.setImage(BufferUtils.trim(fs.readFileSync(outPath)))
.setMimeType('image/ktx2');
logger.debug(`• ${inBytes} → ${texture.getImage().byteLength} bytes.`);
});
};
}
function getTextureSlots (doc, texture) {
return doc.getGraph().getLinks()
.filter((link) => link.getChild() === texture)
.map((link) => link.getName())
.filter((slot) => slot !== 'texture')
}
function createParams (slots, options) {
const params = ['--genmipmap'];
if (options.mode === Mode.UASTC) {
params.push('--uastc', Math.round(lerp(0, 4, options.quality)));
if (options.zstd > 0) params.push('--zcmp', options.zstd);
} else {
params.push('--bcmp');
params.push('--clevel', Math.round(mlerp(0, 1, 5, options.quality)));
params.push('--qlevel', Math.round(lerp(1, 255, options.quality)));
if (slots.find((slot) => minimatch(slot, '*normal*', {nocase: true}))) {
params.push('--linear', '--normal_map');
}
}
return params;
}
function lerp(v0, v1, t) {
return v0 * (1 - t) + v1 * t;
}
/** lerp given a specified midpoint to use for 0.5. */
function mlerp(v0, v1, v2, t) {
if (t > 0.5) {
return lerp(v1, v2, (t - 0.5) * 2);
}
return lerp(v0, v1, t * 2);
}
module.exports = {toktx, Mode, TOKTX_DEFAULTS};