@needle-tools/gltf-build-pipeline 1.6.0-alpha.7 → 2.1.0-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/README.md +18 -0
- package/dist/___config.json +3 -0
- package/dist/package.json +31 -25
- package/dist/src/cache/cache.d.ts +1 -0
- package/dist/src/cache/cache.js +1 -0
- package/dist/src/cli/index.js +44 -32
- package/dist/src/config/index.d.ts +6 -2
- package/dist/src/config/index.js +35 -37
- package/dist/src/extensions/NEEDLE_opaque/NEEDLE_opaque.d.ts +1 -1
- package/dist/src/extensions/NEEDLE_opaque/NEEDLE_opaque.js +74 -24
- package/dist/src/extensions/NEEDLE_progressive/NEEDLE_progressive.d.ts +5 -1
- package/dist/src/scripts/pack-gltf.js +15 -18
- package/dist/src/transforms/needle_mesh_transform.js +11 -12
- package/dist/src/transforms/needle_progressive.js +176 -66
- package/dist/src/transforms/needle_toktx.js +57 -23
- package/dist/src/transforms/toktx.d.ts +9 -35
- package/dist/src/transforms/toktx.js +73 -92
- package/dist/src/utils/fileutils.d.ts +1 -0
- package/dist/src/utils/fileutils.js +10 -1
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.js +1 -0
- package/dist/src/utils/stats.d.ts +12 -6
- package/dist/src/utils/stats.js +12 -6
- package/dist/src/utils/texture.d.ts +2 -0
- package/dist/src/utils/texture.js +8 -0
- package/package.json +32 -26
- package/scripts/pack-gltf.mjs +1 -1
- package/tsconfig.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,45 @@ All notable changes to this package will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [2.1.0-alpha] - 2023-06-03
|
|
8
|
+
- add: compression config support for high-level usecases that can be passed via commandline arguments or via config. Available options are currently `default`, `world` and `product`.
|
|
9
|
+
- add: texture LODs can now be generated by passing in the path to a compression config. `--config <path/to/config.json>`
|
|
10
|
+
- change: VRMs now use draco mesh compression by default
|
|
11
|
+
|
|
12
|
+
### Config Examples
|
|
13
|
+
- `default` - use default compression. When not explictly configured textures will be compressed with ETC1S
|
|
14
|
+
- `product` - when not explictly configured textures will use UASTC for `metallicRoughnessTexture` and `normalTexture`
|
|
15
|
+
- `world` - generate texture LODs when enabled (and not explictly disabled by `textures: { lods: false }`)
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"usecase": "default" // optional
|
|
19
|
+
"textures" : {
|
|
20
|
+
"lods": true
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
The config can also be part of a `needle.config.json`:
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
... regular needle.config
|
|
28
|
+
"gltf": {
|
|
29
|
+
"usecase": "default" // optional
|
|
30
|
+
"textures": {
|
|
31
|
+
"lods": true
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## [2.0.0-alpha] - 2023-06-01
|
|
38
|
+
- update gltf-transform dependency to 4.x
|
|
39
|
+
- change: ensure ETC1S and UASTC textures are power of 2
|
|
40
|
+
|
|
41
|
+
- CLI: commands can be run with `needle-gltf <command>`
|
|
42
|
+
- CLI: add `--cache` to allow disabling cache with `--cache False` (default true)
|
|
43
|
+
- CLI: add `--stats` to produce `.needle.stats.json` (default false)
|
|
44
|
+
- CLI: change `--output` to be the optional second argument
|
|
45
|
+
|
|
7
46
|
## [1.6.0-alpha.7] - 2023-05-30
|
|
8
47
|
- fix: npx cli command return wrong error due to `packGLTF` not returning a booelan
|
|
9
48
|
- fix: mjs script import paths
|
package/README.md
CHANGED
|
@@ -8,6 +8,24 @@ Includes support for generating LOD quality level for textures and meshes that c
|
|
|
8
8
|
- [Example on Github](https://github.com/needle-engine/progressive-meshes-sample)
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
In general all files that have been processed by this package are valid glTF/GLB files.
|
|
14
|
+
The glTF Build Pipeline package is meant to be used as a last step before delivery.
|
|
15
|
+
That means:
|
|
16
|
+
- files are meant to be loaded e.g. in a web runtime like three.js
|
|
17
|
+
- files are not to be opened in Blender again to be further edited
|
|
18
|
+
|
|
19
|
+
To load progressively enhanced glTF files in any three.js based engine see examples at [@needle-tools/gltf-progressive](https://www.npmjs.com/package/@needle-tools/gltf-progressive)
|
|
20
|
+
|
|
21
|
+
### Installation
|
|
22
|
+
|
|
23
|
+
`npx @needle-tools/gltf-build-pipeline@latest`
|
|
24
|
+
|
|
25
|
+
### Commands
|
|
26
|
+
- `gltf-build-pipeline help` - use help to see options for each command
|
|
27
|
+
- `gltf-build-pipeline compress <input>`
|
|
28
|
+
- `gltf-build-pipeline transform <input>`
|
|
11
29
|
|
|
12
30
|
# Contact ✒️
|
|
13
31
|
<b>[🌵 needle — tools for creators](https://needle.tools)</b> •
|
package/dist/package.json
CHANGED
|
@@ -1,30 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/gltf-build-pipeline",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0-alpha",
|
|
4
4
|
"description": "Pipeline and tools for optimizing gltf files using gltf-transform and compression settings within glTF extensions",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"readme": "README.md",
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "Needle",
|
|
10
|
+
"email": "help@needle.tools",
|
|
11
|
+
"url": "https://needle.tools/"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/needle-tools/needle-gltf-extensions.git"
|
|
16
|
+
},
|
|
8
17
|
"bin": {
|
|
9
|
-
"gltf-build-pipeline": "./dist/src/cli/index.js"
|
|
18
|
+
"gltf-build-pipeline": "./dist/src/cli/index.js",
|
|
19
|
+
"needle-gltf": "./dist/src/cli/index.js"
|
|
10
20
|
},
|
|
11
21
|
"scripts": {
|
|
12
22
|
"start": "node scripts/index.mjs",
|
|
13
23
|
"dev": "npm-watch compile",
|
|
24
|
+
"compile": "tsc || exit 1",
|
|
25
|
+
"clear-caches": "node scripts/clear-caches.mjs",
|
|
26
|
+
"limit-caches": "node scripts/limit-caches.mjs",
|
|
14
27
|
"transform": "node scripts/index.mjs",
|
|
15
28
|
"transform:make-progressive": "node scripts/make-progressive.mjs",
|
|
16
29
|
"transform:pack-gltf": "node --no-experimental-fetch scripts/pack-gltf.mjs",
|
|
17
30
|
"pack-gltf": "node --no-experimental-fetch scripts/pack-gltf.mjs",
|
|
18
|
-
"dev:pack-gltf": "npm run compile && node scripts/pack-gltf.mjs"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
31
|
+
"dev:pack-gltf": "npm run compile && node scripts/pack-gltf.mjs"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@img/sharp-win32-x64": "^0.33.4",
|
|
35
|
+
"@types/node": "^18.7.23",
|
|
36
|
+
"npm-watch": "^0.13.0",
|
|
37
|
+
"typescript": "^4.9.5"
|
|
38
|
+
},
|
|
39
|
+
"optionalDependencies": {
|
|
40
|
+
"@img/sharp-linux-arm": "^0.33.4",
|
|
41
|
+
"@img/sharp-win32-x64": "^0.33.4"
|
|
22
42
|
},
|
|
23
43
|
"dependencies": {
|
|
24
44
|
"@donmccurdy/caporal": "~0.0.10",
|
|
25
|
-
"@gltf-transform/
|
|
26
|
-
"@gltf-transform/
|
|
27
|
-
"@gltf-transform/
|
|
45
|
+
"@gltf-transform/cli": "^4.0.1",
|
|
46
|
+
"@gltf-transform/core": "^4.0.1",
|
|
47
|
+
"@gltf-transform/extensions": "^4.0.1",
|
|
48
|
+
"@gltf-transform/functions": "^4.0.1",
|
|
28
49
|
"command-exists": "^1.2.9",
|
|
29
50
|
"command-line-args": "^5.2.1",
|
|
30
51
|
"draco3dgltf": "^1.5.3",
|
|
@@ -36,7 +57,7 @@
|
|
|
36
57
|
"ndarray-pixels": "^2.0.1",
|
|
37
58
|
"p-limit": "3.1.0",
|
|
38
59
|
"semver": "^7.3.7",
|
|
39
|
-
"sharp": "^0.
|
|
60
|
+
"sharp": "^0.33.4",
|
|
40
61
|
"tmp": "^0.2.1",
|
|
41
62
|
"uuid": "^9.0.1"
|
|
42
63
|
},
|
|
@@ -48,20 +69,5 @@
|
|
|
48
69
|
"extensions": "ts",
|
|
49
70
|
"quiet": false
|
|
50
71
|
}
|
|
51
|
-
},
|
|
52
|
-
"devDependencies": {
|
|
53
|
-
"@types/node": "^18.7.23",
|
|
54
|
-
"nodemon": "^3.1.2",
|
|
55
|
-
"npm-watch": "^0.13.0",
|
|
56
|
-
"typescript": "^4.9.5"
|
|
57
|
-
},
|
|
58
|
-
"author": {
|
|
59
|
-
"name": "Needle",
|
|
60
|
-
"email": "help@needle.tools",
|
|
61
|
-
"url": "https://needle.tools/"
|
|
62
|
-
},
|
|
63
|
-
"repository": {
|
|
64
|
-
"type": "git",
|
|
65
|
-
"url": "git+https://github.com/needle-tools/needle-gltf-extensions.git"
|
|
66
72
|
}
|
|
67
73
|
}
|
|
@@ -48,6 +48,7 @@ export declare function getKeyWithHash(property: ExtensibleProperty): {
|
|
|
48
48
|
/**
|
|
49
49
|
* Get the hash for a property or an object.
|
|
50
50
|
* @param property The property to get the hash for.
|
|
51
|
+
* @param level The current level of recursion.
|
|
51
52
|
* @returns The hash as a number.
|
|
52
53
|
*/
|
|
53
54
|
export declare function getHash(property: ExtensibleProperty | object, level?: number): number;
|
package/dist/src/cache/cache.js
CHANGED
|
@@ -167,6 +167,7 @@ export function getKeyWithHash(property) {
|
|
|
167
167
|
/**
|
|
168
168
|
* Get the hash for a property or an object.
|
|
169
169
|
* @param property The property to get the hash for.
|
|
170
|
+
* @param level The current level of recursion.
|
|
170
171
|
* @returns The hash as a number.
|
|
171
172
|
*/
|
|
172
173
|
export function getHash(property, level = 0) {
|
package/dist/src/cli/index.js
CHANGED
|
@@ -7,8 +7,8 @@ import { UsecaseOptions, createConfig, getConfig } from '../config/index.js';
|
|
|
7
7
|
import { make_progressive } from '../transforms/needle_progressive.js';
|
|
8
8
|
import { cacheSizeLimit, clearCache } from '../cache/cache.js';
|
|
9
9
|
import { existsSync, statSync } from 'fs';
|
|
10
|
-
import { foreachGLTF } from '../utils/fileutils.js';
|
|
11
|
-
import { dirname } from 'path';
|
|
10
|
+
import { foreachGLTF, getDirName } from '../utils/fileutils.js';
|
|
11
|
+
import path, { dirname } from 'path';
|
|
12
12
|
import { ERROR_CODES } from '../constants.js';
|
|
13
13
|
// For testing / dev you can run `npm link` in the package directory
|
|
14
14
|
// For removing the link run `npm rm --global @needle-tools/gltf-build-pipeline`
|
|
@@ -30,10 +30,12 @@ Caches are limited to ${cacheSizeLimit} MB disc space by default.
|
|
|
30
30
|
Compress a single glTF file. The input file is compressed and written to the output file.
|
|
31
31
|
`)
|
|
32
32
|
.argument('<input>', "The input glTF, GLB or VRM file that should be compressed OR a directory that contains files to be compressed")
|
|
33
|
-
.
|
|
33
|
+
.argument('<output>', "The output file. If not provided, the input file will be overwritten.", { default: "" })
|
|
34
|
+
.option("--usecase <usecase>", `The usecase for the compression allows you to determine how your asset is supposed to be used:\nThis will set compression and transform settings on a high level if no other settings are found.\nPossible options: [${UsecaseOptions.join(", ")}] e.g. \"--usecase ${UsecaseOptions[0]}\"`, { validator: program.STRING })
|
|
34
35
|
.option("--config <config>", "The path to a JSON file containing the compression settings. This can also be a needle.config.json file with a \"compression\" object or usecase string.", { validator: program.STRING })
|
|
35
|
-
.option("--
|
|
36
|
-
.option("--
|
|
36
|
+
.option("--stats", "Output a stats file next to input file (or inside the input directory). It will be named as the input file/directory \"<input>.needle.stats.json\"", { validator: program.BOOLEAN, default: false })
|
|
37
|
+
.option("--cache", "Use \"--cache False\" to disable caching.\nWhen caching is enabled then previously processed files will be detected and loaded from disc cache instead of being processed again if settings or the file contents have not changed.", { validator: program.BOOLEAN, default: true })
|
|
38
|
+
.option("--debug", "Enable for more verbose outout with \"--debug True\"", { validator: program.BOOLEAN, default: false })
|
|
37
39
|
.action(async ({ logger, args, options }) => {
|
|
38
40
|
logger.info("Transforming glTF file: " + args.input);
|
|
39
41
|
const stats = {
|
|
@@ -43,19 +45,21 @@ Compress a single glTF file. The input file is compressed and written to the out
|
|
|
43
45
|
totalFileSizeInMB: 0,
|
|
44
46
|
totalFileSizeInMBBefore: 0,
|
|
45
47
|
};
|
|
46
|
-
|
|
48
|
+
const file = args.input.toString();
|
|
49
|
+
let config = getConfig(options.config?.toString(), file);
|
|
47
50
|
if (options.usecase) {
|
|
48
51
|
logger.info("Using usecase: " + options.usecase);
|
|
49
52
|
config = { ...createConfig(options.usecase.toString()), ...config, };
|
|
50
|
-
if (config.usecase != "
|
|
53
|
+
if (config.usecase != "default" && config.usecase != options.usecase.toString()) {
|
|
51
54
|
logger.warn(`Conflicting usecase. Your specific config at \"${options.config}\" has a different usecase than the one provided by the CLI: \"${options.usecase}\". Using the usecase from the config file.`);
|
|
52
55
|
}
|
|
53
56
|
else {
|
|
54
57
|
config.usecase = options.usecase.toString();
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
|
-
const
|
|
58
|
-
const
|
|
60
|
+
const debug = options.debug === true;
|
|
61
|
+
const isDirectory = statSync(file).isDirectory();
|
|
62
|
+
const outDir = isDirectory ? file : dirname(file);
|
|
59
63
|
let outputIsDirectory = false;
|
|
60
64
|
if (statSync(file).isDirectory() && options.output) {
|
|
61
65
|
if (statSync(options.output.toString()).isDirectory()) {
|
|
@@ -73,17 +77,20 @@ Compress a single glTF file. The input file is compressed and written to the out
|
|
|
73
77
|
const file_stats = [];
|
|
74
78
|
const set = new Set();
|
|
75
79
|
await foreachGLTF(file, async (file) => {
|
|
76
|
-
let outputFile =
|
|
80
|
+
let outputFile = args.output?.toString();
|
|
81
|
+
if (!outputFile?.length) {
|
|
82
|
+
outputFile = file;
|
|
83
|
+
}
|
|
77
84
|
if (outputIsDirectory) {
|
|
78
85
|
const filename = file.replaceAll("\\", "/").split("/").pop();
|
|
79
|
-
outputFile =
|
|
86
|
+
outputFile = args.output?.toString() + "/" + filename;
|
|
80
87
|
}
|
|
81
88
|
const res = await packGLTF(file, outputFile, {
|
|
82
89
|
config,
|
|
83
90
|
packedFiles: set,
|
|
84
91
|
stats,
|
|
85
|
-
debug
|
|
86
|
-
useCache:
|
|
92
|
+
debug,
|
|
93
|
+
useCache: options.cache !== false,
|
|
87
94
|
logger: logger,
|
|
88
95
|
file_stats: file_stats,
|
|
89
96
|
});
|
|
@@ -91,10 +98,11 @@ Compress a single glTF file. The input file is compressed and written to the out
|
|
|
91
98
|
process.exit(ERROR_CODES.PACKING_FAILED);
|
|
92
99
|
}
|
|
93
100
|
});
|
|
94
|
-
printStats(stats);
|
|
101
|
+
printStats(stats, logger, config);
|
|
95
102
|
console.log("Stats: ", options);
|
|
96
|
-
if (options.
|
|
97
|
-
|
|
103
|
+
if (options.stats) {
|
|
104
|
+
const statsFile = (isDirectory ? (path.join(file, getDirName(file))) : file) + ".needle.stats.json";
|
|
105
|
+
writeFileStatsToFile(config, file_stats, statsFile);
|
|
98
106
|
}
|
|
99
107
|
})
|
|
100
108
|
.command("transform", "Transform (progressive loading) and compress glTF, GLB or VRM files")
|
|
@@ -103,10 +111,12 @@ This will produce multiple versions of the input file, each with a different lev
|
|
|
103
111
|
Each version will be compressed and written to the output directory.
|
|
104
112
|
`)
|
|
105
113
|
.argument('<input>', "The input glTF, GLB or VRM file that should be compressed OR a directory that contains files to be compressed")
|
|
114
|
+
// .argument('<output>', "The output file. If not provided, the input file will be overwritten.", { default: "" })
|
|
106
115
|
.option("--usecase <usecase>", `The usecase for the compression. This will set the compression settings. Possible options: [${UsecaseOptions.join(", ")}]`, { validator: program.STRING })
|
|
107
116
|
.option("--config <config>", "The path to a JSON file containing the compression settings. This can also be a needle.config.json file with a \"compression\" object or usecase string.", { validator: program.STRING })
|
|
108
|
-
|
|
109
|
-
.option("--
|
|
117
|
+
.option("--stats", "Output a stats file next to input file (or inside the input directory). It will be named as the input file/directory \"<input>.needle.stats.json\"", { validator: program.BOOLEAN, default: false })
|
|
118
|
+
.option("--cache", "Use \"--cache False\" to disable caching.\nWhen caching is enabled then previously processed files will be detected and loaded from disc cache instead of being processed again if settings or the file contents have not changed.", { validator: program.BOOLEAN, default: true })
|
|
119
|
+
.option("--debug", "Enable for more verbose outout with \"--debug True\"", { validator: program.BOOLEAN, default: false })
|
|
110
120
|
.action(async ({ logger, args, options }) => {
|
|
111
121
|
logger.info("Transforming glTF file: " + args.input);
|
|
112
122
|
const stats = {
|
|
@@ -116,30 +126,33 @@ Each version will be compressed and written to the output directory.
|
|
|
116
126
|
totalFileSizeInMB: 0,
|
|
117
127
|
totalFileSizeInMBBefore: 0,
|
|
118
128
|
};
|
|
119
|
-
|
|
129
|
+
const file = args.input.toString();
|
|
130
|
+
let config = getConfig(options.config?.toString(), file);
|
|
120
131
|
if (options.usecase) {
|
|
121
132
|
logger.info("Using usecase: " + options.usecase);
|
|
122
133
|
config = { ...createConfig(options.usecase.toString()), ...config, };
|
|
123
|
-
if (config.usecase != "
|
|
134
|
+
if (config.usecase != "default" && config.usecase != options.usecase.toString()) {
|
|
124
135
|
logger.warn(`Conflicting usecase. Your specific config at \"${options.config}\" has a different usecase than the one provided by the CLI: \"${options.usecase}\". Using the usecase from the config file.`);
|
|
125
136
|
}
|
|
126
137
|
else {
|
|
127
138
|
config.usecase = options.usecase.toString();
|
|
128
139
|
}
|
|
129
140
|
}
|
|
130
|
-
const
|
|
131
|
-
const outDir =
|
|
141
|
+
const isDirectory = statSync(file).isDirectory();
|
|
142
|
+
const outDir = isDirectory ? file : dirname(file);
|
|
132
143
|
const file_stats = [];
|
|
133
144
|
const set = new Set();
|
|
145
|
+
const useCache = options.cache !== false;
|
|
146
|
+
const debug = options.debug === true;
|
|
134
147
|
await foreachGLTF(file, async (file) => {
|
|
135
|
-
logger.info("
|
|
148
|
+
logger.info("→ Transform " + file);
|
|
136
149
|
const progressive_results = new Array();
|
|
137
150
|
await make_progressive({
|
|
138
151
|
path: file,
|
|
139
152
|
results: progressive_results,
|
|
140
153
|
config,
|
|
141
|
-
debug
|
|
142
|
-
useCache
|
|
154
|
+
debug,
|
|
155
|
+
useCache,
|
|
143
156
|
}).catch(err => {
|
|
144
157
|
logger.error(err);
|
|
145
158
|
process.exit(ERROR_CODES.PROGRESSIVE_FAILED);
|
|
@@ -148,25 +161,24 @@ Each version will be compressed and written to the output directory.
|
|
|
148
161
|
config,
|
|
149
162
|
stats,
|
|
150
163
|
packedFiles: set,
|
|
151
|
-
debug
|
|
152
|
-
useCache
|
|
164
|
+
debug,
|
|
165
|
+
useCache,
|
|
153
166
|
logger: logger,
|
|
154
167
|
file_stats,
|
|
155
168
|
};
|
|
156
169
|
for (const res of progressive_results) {
|
|
157
|
-
logger.info("> Compress " + res);
|
|
158
170
|
if (await packGLTF(res, res, opts) === false) {
|
|
159
171
|
process.exit(ERROR_CODES.PACKING_FAILED);
|
|
160
172
|
}
|
|
161
173
|
}
|
|
162
|
-
logger.info("> Compress " + file);
|
|
163
174
|
if (await packGLTF(file, file, opts) === false) {
|
|
164
175
|
process.exit(ERROR_CODES.PACKING_FAILED);
|
|
165
176
|
}
|
|
166
177
|
});
|
|
167
|
-
printStats(stats);
|
|
168
|
-
if (options.
|
|
169
|
-
|
|
178
|
+
printStats(stats, logger, config);
|
|
179
|
+
if (options.stats) {
|
|
180
|
+
const statsFile = (isDirectory ? (path.join(file, getDirName(file))) : file) + ".needle.stats.json";
|
|
181
|
+
writeFileStatsToFile(config, file_stats, statsFile);
|
|
170
182
|
}
|
|
171
183
|
});
|
|
172
184
|
program.run();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare type Usecase = "
|
|
1
|
+
declare type Usecase = "default" | "product" | "world";
|
|
2
2
|
export declare const UsecaseOptions: string[];
|
|
3
3
|
/**
|
|
4
4
|
* The config object contains information about how a file should be processed.
|
|
@@ -6,6 +6,9 @@ export declare const UsecaseOptions: string[];
|
|
|
6
6
|
export type Config = {
|
|
7
7
|
/** High-level configuration */
|
|
8
8
|
usecase: Usecase;
|
|
9
|
+
textures?: {
|
|
10
|
+
lods: boolean;
|
|
11
|
+
};
|
|
9
12
|
};
|
|
10
13
|
/**
|
|
11
14
|
* Create a config object with the given usecase.
|
|
@@ -39,5 +42,6 @@ export declare function createConfig(usecase: string): {
|
|
|
39
42
|
*
|
|
40
43
|
*
|
|
41
44
|
*/
|
|
42
|
-
export declare function getConfig(
|
|
45
|
+
export declare function getConfig(configPath?: string, fallbackSearchDirectory?: string): Config;
|
|
46
|
+
export declare function searchConfig(directory: string): Config | null;
|
|
43
47
|
export {};
|
package/dist/src/config/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "fs";
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
2
|
+
import path, { dirname } from "path";
|
|
2
3
|
export const UsecaseOptions = ["product"];
|
|
3
4
|
const defaultConfig = {
|
|
4
|
-
usecase: "
|
|
5
|
+
usecase: "default",
|
|
5
6
|
};
|
|
6
7
|
/**
|
|
7
8
|
* Create a config object with the given usecase.
|
|
@@ -40,49 +41,46 @@ export function createConfig(usecase) {
|
|
|
40
41
|
*
|
|
41
42
|
*
|
|
42
43
|
*/
|
|
43
|
-
export function getConfig(
|
|
44
|
-
if (
|
|
45
|
-
if (!existsSync(
|
|
46
|
-
throw new Error(`No config found at \"${
|
|
44
|
+
export function getConfig(configPath, fallbackSearchDirectory) {
|
|
45
|
+
if (configPath != null) {
|
|
46
|
+
if (!existsSync(configPath)) {
|
|
47
|
+
throw new Error(`No config found at \"${configPath}\"`);
|
|
48
|
+
}
|
|
49
|
+
const res = resolveConfig(configPath, readFileSync(configPath, "utf8"));
|
|
50
|
+
if (res) {
|
|
51
|
+
return res;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
throw new Error(`Failed parsing config at \"${configPath}\"`);
|
|
47
55
|
}
|
|
48
|
-
return resolveConfig(path, readFileSync(path, "utf8"));
|
|
49
56
|
}
|
|
50
57
|
if (_cachedConfig !== undefined) {
|
|
51
58
|
return _cachedConfig;
|
|
52
59
|
}
|
|
53
60
|
// Resolve the config once and cache it
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
// Check if a needle.config.json exists in the directory from which the script is run (or any parent directory)
|
|
62
|
+
if (fallbackSearchDirectory) {
|
|
63
|
+
const result = searchConfig(fallbackSearchDirectory);
|
|
64
|
+
if (result) {
|
|
65
|
+
_cachedConfig = { ...defaultConfig, ...result };
|
|
66
|
+
console.log("INFO: Using config with usecase: " + _cachedConfig.usecase);
|
|
67
|
+
}
|
|
58
68
|
}
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
// If no config was found, use the default config
|
|
70
|
+
if (!_cachedConfig) {
|
|
71
|
+
console.log("INFO: No config found. Using default config.");
|
|
61
72
|
_cachedConfig = defaultConfig;
|
|
62
73
|
}
|
|
63
74
|
return _cachedConfig;
|
|
64
75
|
}
|
|
65
76
|
let _cachedConfig = undefined;
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
for (let i = 0; i < args.length; i++) {
|
|
70
|
-
if (args[i] === "--config") {
|
|
71
|
-
if (i + 1 < args.length) {
|
|
72
|
-
const configPath = args[i + 1];
|
|
73
|
-
if (existsSync(configPath)) {
|
|
74
|
-
const content = readFileSync(configPath, "utf8");
|
|
75
|
-
return resolveConfig(configPath, content);
|
|
76
|
-
}
|
|
77
|
-
throw new Error(`Config file not found at path configured by CLI --config argument: \"${configPath}\"`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
77
|
+
export function searchConfig(directory) {
|
|
78
|
+
if (statSync(directory).isFile()) {
|
|
79
|
+
directory = dirname(directory);
|
|
80
80
|
}
|
|
81
|
-
|
|
82
|
-
const workingDir = process.cwd();
|
|
83
|
-
let directory = workingDir.replaceAll("\\", "/");
|
|
81
|
+
directory = directory.replaceAll("\\", "/");
|
|
84
82
|
while (directory.length > 0) {
|
|
85
|
-
const configPath =
|
|
83
|
+
const configPath = path.join(directory, "needle.config.json");
|
|
86
84
|
if (existsSync(configPath)) {
|
|
87
85
|
const content = readFileSync(configPath, "utf8");
|
|
88
86
|
const config = resolveConfig(configPath, content);
|
|
@@ -103,16 +101,16 @@ function resolveConfig(filename, content) {
|
|
|
103
101
|
if (filename.endsWith("needle.config.json")) {
|
|
104
102
|
try {
|
|
105
103
|
const config = JSON.parse(content);
|
|
106
|
-
if (config.
|
|
107
|
-
console.log("INFO: Found
|
|
104
|
+
if (config.gltf) {
|
|
105
|
+
console.log("INFO: Found \"gltf\" config at \"" + filename + "\".");
|
|
108
106
|
// If the optimization config is a string, it's the usecase
|
|
109
|
-
if (typeof config.
|
|
110
|
-
return createConfig(config.
|
|
107
|
+
if (typeof config.gltf === "string") {
|
|
108
|
+
return createConfig(config.gltf);
|
|
111
109
|
}
|
|
112
|
-
return config.
|
|
110
|
+
return config.gltf;
|
|
113
111
|
}
|
|
114
112
|
else {
|
|
115
|
-
console.log("INFO: No
|
|
113
|
+
console.log("INFO: No \"gltf\" config found in needle.config.json. Using default config.");
|
|
116
114
|
return null;
|
|
117
115
|
}
|
|
118
116
|
}
|
|
@@ -15,7 +15,7 @@ export interface IOpaqueProperty {
|
|
|
15
15
|
/** register a reference so gltf-transform will not remove it in e.g. dedup
|
|
16
16
|
* https://github.com/donmccurdy/glTF-Transform/issues/980#issuecomment-1585748202
|
|
17
17
|
*/
|
|
18
|
-
setReference(name: string, value: any):
|
|
18
|
+
setReference(name: string, value: any, attributes?: Record<string, any>): void;
|
|
19
19
|
}
|
|
20
20
|
export interface IExtensionWriter {
|
|
21
21
|
/** used by progressive texture extension to pass an extension between documents */
|