From f2ded23d3a5be1f1033b0a1ec9f60b44a90040b5 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Thu, 19 Oct 2017 10:14:13 -0700 Subject: [PATCH] Numerous improvements to Node API. - Removed the shell scripts. We now invoke everything straight from Node. - Allow passing command line arguments to the tool via the Node API. - Require .glb or .gltf extension because the tool is automatically going to add that extension anyway, so we strip it off and add it back to shield the user from this weirdness. The tool may eventually stop adding an extension (and perhaps just validate it) and we can simplify our code. - Automatically add --binary option if the requested target file is a .glb. This also renames the bin/Windows directory to bin/Windows_NT, which is unfortunate but that matches os.type(). This ultimately comes from uname and that's what Windows chose to return. Let's just live with this historical accident rather than try to paper over it. --- npm/README.md | 2 +- npm/bin/{Windows => Windows_NT}/.keep | 0 npm/bin/fbx2glb.bat | 1 - npm/bin/fbx2glb.sh | 43 -------------- npm/index.js | 86 +++++++++++++++++++-------- npm/package.json | 7 ++- npm/yarn.lock | 70 ++++++++++++++++++++++ 7 files changed, 137 insertions(+), 72 deletions(-) rename npm/bin/{Windows => Windows_NT}/.keep (100%) delete mode 100644 npm/bin/fbx2glb.bat delete mode 100755 npm/bin/fbx2glb.sh create mode 100644 npm/yarn.lock diff --git a/npm/README.md b/npm/README.md index e738940..02a51b1 100644 --- a/npm/README.md +++ b/npm/README.md @@ -11,7 +11,7 @@ This package contains three versions of `FBX2glTF`, compiled for three platforms and located in three eponymous directories: - bin/Darwin/FBX2glTF - bin/Linux/FBX2glTF - - bin/Windows/FBX2glTF.exe + - bin/Windows_NT/FBX2glTF.exe # Further Reading diff --git a/npm/bin/Windows/.keep b/npm/bin/Windows_NT/.keep similarity index 100% rename from npm/bin/Windows/.keep rename to npm/bin/Windows_NT/.keep diff --git a/npm/bin/fbx2glb.bat b/npm/bin/fbx2glb.bat deleted file mode 100644 index 827b6cb..0000000 --- a/npm/bin/fbx2glb.bat +++ /dev/null @@ -1 +0,0 @@ -%~dp0\Windows\FBX2glTF --binary %1 %2 diff --git a/npm/bin/fbx2glb.sh b/npm/bin/fbx2glb.sh deleted file mode 100755 index 9d2bbe4..0000000 --- a/npm/bin/fbx2glb.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# -# fbx2glb.sh -# -# TODO: Pass command line switches through to binary. - -set -e - -BINDIR=`dirname $0` -BINDIR=`cd ${BINDIR} ; pwd` - -SYSTEM=`uname -s` -FBX2GLTF="${BINDIR}/${SYSTEM}/FBX2glTF" - -if [ ! -f "${FBX2GLTF}" ]; then - echo "Unable to find 'FBX2glTF' binary: ${FBX2GLTF}" - exit 1 -fi - -if [ "$#" != 2 ]; then - echo "Usage: " - exit 1 -fi - -fullpath() { - OLDPWD=$PWD - cd "$(dirname "$1")" - FULLPATH="$PWD/$(basename "$1")" - cd "$OLDPWD" - echo "$FULLPATH" -} - -INFILE=$(fullpath $1) -OUTFILE=$(fullpath $(basename $2 ".glb")) - -# construct a safe work dir -SCRIPT_BASE=`basename $0` -TEMP_DIR=`mktemp -d "/tmp/${SCRIPT_BASE}.XXXX"` -trap "rm -rf ${TEMP_DIR}" EXIT -cd ${TEMP_DIR} - -# some hard-coded defaults for now -"${FBX2GLTF}" --binary --flip-v --input "${INFILE}" --output "${OUTFILE}" diff --git a/npm/index.js b/npm/index.js index fa8fc73..96d17f8 100644 --- a/npm/index.js +++ b/npm/index.js @@ -1,6 +1,8 @@ const childProcess = require('child_process'); +const fs = require('fs'); const os = require('os'); const path = require('path'); +const rimraf = require('rimraf'); const binaries = { 'darwin': `bin/darwin/Fbx2Gtlf`, @@ -8,36 +10,70 @@ const binaries = { 'win32': `bin\windows\Fbx2Gtlf.exe`, }; -function fbx2glb(srcFile, destFile, cwd) { +/** + * Converts an FBX to a GTLF or GLB file. + * @param string srcFile path to the source file. + * @param string destFile path to the destination file. + * This must end in `.glb` or `.gltf` (case matters). + * @param string[] [opts] options to pass to the converter tool. + * @return Promise a promise that yields the full path to the converted + * file, an error on conversion failure. + */ +function convert(srcFile, destFile, opts) { return new Promise((resolve, reject) => { - let script = os.type() === 'Windows_NT' ? 'fbx2glb.bat' : 'fbx2glb.sh'; - let child; try { - let opts = {}; - cwd && (opts.cwd = cwd); - child = childProcess.spawn( - path.join(__dirname, 'bin', script), - [ srcFile, destFile ], - opts - ); + let tool = path.join(__dirname, 'bin', os.type(), 'FBX2glTF'); + if (!fs.existsSync(tool)) { + throw new Error(`Unsupported OS: ${os.type()}`); + } + + let destExt; + if (destFile.endsWith('.glb')) { + destExt = '.glb'; + opts.includes('--binary') || opts.push('--binary'); + } else if (destFile.endsWith('.gltf')) { + destExt = '.gltf'; + } else { + throw new Error(`Unsupported file extension: ${destFile}`); + } + + let srcPath = fs.realpathSync(srcFile); + let destDir = fs.realpathSync(path.dirname(destFile)); + let destPath = path.join(destDir, path.basename(destFile, destExt)); + + let args = opts.slice(0); + args.push('--input', srcPath, '--output', destPath); + let child = childProcess.spawn(tool, args); + + let output = ''; + child.stdout.on('data', (data) => output += data); + child.stderr.on('data', (data) => output += data); + child.on('error', reject); + child.on('close', code => { + // the FBX SDK may create an .fbm dir during conversion; delete! + let fbmCruft = srcPath.replace(/.fbx$/i, '.fbm'); + // don't stick a fork in things if this fails, just log a warning + const onError = error => + error && console.warn(`Failed to delete ${fbmCruft}: ${error}`); + try { + fs.existsSync(fbmCruft) && rimraf(fbmCruft, {}, onError); + } catch (error) { + onError(error); + } + + // non-zero exit code is failure + if (code != 0) { + reject(new Error(`Script ${script} output:\n` + + (output.length ? output : ""))); + } else { + resolve(destPath + destExt); + } + }); + } catch (error) { reject(error); - return; } - let output = ''; - child.stdout.on('data', (data) => output += data); - child.stderr.on('data', (data) => output += data); - child.on('error', reject); - child.on('close', code => { - // non-zero exit code is failure - if (code != 0) { - reject(new Error(`Script ${script} output:\n` + - (output.length ? output : ""))); - } else { - resolve(destFile); - } - }); }); } -module.exports = fbx2glb; +module.exports = convert; diff --git a/npm/package.json b/npm/package.json index 4166690..b0ca66d 100644 --- a/npm/package.json +++ b/npm/package.json @@ -16,12 +16,15 @@ "bugs": { "url": "https://github.com/facebookincubator/FBX2glTF/issues" }, - "homepage": "https://github.com/facebookincubator/FBX2glTF" + "homepage": "https://github.com/facebookincubator/FBX2glTF", "files": [ "LICENSE", "PATENTS", "README.md", "bin", "index.js" - ] + ], + "dependencies": { + "rimraf": "^2.6.2" + } } diff --git a/npm/yarn.lock b/npm/yarn.lock new file mode 100644 index 0000000..c30aedc --- /dev/null +++ b/npm/yarn.lock @@ -0,0 +1,70 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +glob@^7.0.5: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +rimraf@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"