@needle-tools/gltf-build-pipeline 1.5.0-alpha.8 → 1.6.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cache/cache.d.ts +2 -1
  3. package/dist/cache/cache.js +8 -2
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.js +102 -0
  6. package/dist/config/index.d.ts +43 -0
  7. package/dist/config/index.js +125 -0
  8. package/dist/extensions/NEEDLE_opaque/NEEDLE_opaque.d.ts +2 -1
  9. package/dist/extensions/NEEDLE_opaque/NEEDLE_opaque.js +32 -14
  10. package/dist/extensions/NEEDLE_opaque/index.d.ts +2 -2
  11. package/dist/extensions/NEEDLE_opaque/index.js +7 -0
  12. package/dist/extensions/NEEDLE_progressive_mesh_settings/index.d.ts +4 -1
  13. package/dist/extensions/NEEDLE_progressive_texture_settings/index.d.ts +4 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.js +3 -0
  16. package/dist/scripts/index.d.ts +1 -0
  17. package/dist/scripts/index.js +1 -0
  18. package/dist/scripts/pack-gltf.d.ts +12 -0
  19. package/dist/scripts/pack-gltf.js +119 -0
  20. package/dist/transforms/needle_common.d.ts +3 -1
  21. package/dist/transforms/needle_mesh_transform.d.ts +3 -1
  22. package/dist/transforms/needle_progressive.d.ts +3 -0
  23. package/dist/transforms/needle_progressive.js +9 -2
  24. package/dist/transforms/needle_texture_transform.d.ts +9 -1
  25. package/dist/transforms/needle_texture_transform.js +17 -11
  26. package/dist/transforms/needle_toktx.d.ts +2 -2
  27. package/dist/transforms/needle_toktx.js +15 -3
  28. package/dist/transforms/needle_webp.d.ts +2 -2
  29. package/dist/transforms/needle_webp.js +1 -1
  30. package/dist/utils/compression_utils.d.ts +1 -1
  31. package/dist/utils/index.d.ts +1 -0
  32. package/dist/utils/index.js +1 -0
  33. package/dist/utils/stats.d.ts +8 -0
  34. package/dist/utils/stats.js +6 -0
  35. package/package.json +13 -9
  36. package/scripts/clear-caches.mjs +4 -0
  37. package/scripts/defaults.mjs +12 -0
  38. package/{fileutils.mjs → scripts/fileutils.mjs} +1 -1
  39. package/{index.mjs → scripts/index.mjs} +3 -3
  40. package/scripts/limit-caches.mjs +4 -0
  41. package/{make-progressive.mjs → scripts/make-progressive.mjs} +4 -2
  42. package/scripts/pack-gltf.mjs +101 -0
  43. package/clear-caches.mjs +0 -4
  44. package/defaults.mjs +0 -12
  45. package/limit-caches.mjs +0 -4
  46. package/pack-gltf.mjs +0 -189
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ 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
+ ## [1.6.0-alpha] - 2023-05-27
8
+ - add: `gltf-build-pipeline` commandline support with `transform` and `compress` (pack-gltf) options.
9
+
10
+ ## [1.5.0-alpha.12] - 2023-05-20
11
+ - add: pack-gltf now also runs `resample` for animations
12
+ - fix: nullreference error in accessing opaque debug options
13
+
14
+ ## [1.5.0-alpha.10] - 2023-05-17
15
+ - add: `generateLods` option to progressive texture settings
16
+
17
+ ## [1.5.0-alpha.9] - 2023-05-16
18
+ - add: start of VRM 1.0 support. Not implemented is the `VRMC_materials_mtoon` extension
19
+
7
20
  ## [1.5.0-alpha.8] - 2023-05-16
8
21
  - fix: issue where updating ktx compressed texture extension also flattened the path
9
22
 
@@ -1,9 +1,10 @@
1
1
  import { ExtensibleProperty } from "@gltf-transform/core";
2
+ import { Logger } from "@donmccurdy/caporal";
2
3
  /**
3
4
  * Clear the cache.
4
5
  * This will remove all files in the cache directory.
5
6
  */
6
- export declare function clearCache(): void;
7
+ export declare function clearCache(logger?: Logger): void;
7
8
  /**
8
9
  * Ensure that the cache size does not exceed the given maximum size in MB.
9
10
  * @param maxSizeMB The maximum size in MB.
@@ -23,10 +23,13 @@ const buildPipelineVersion = getVersion(false);
23
23
  * Clear the cache.
24
24
  * This will remove all files in the cache directory.
25
25
  */
26
- export function clearCache() {
26
+ export function clearCache(logger) {
27
27
  const dir = getCacheDirectory(true);
28
28
  fs.rmSync(dir, { recursive: true });
29
- console.log(`Cleared cache at ${dir}`);
29
+ if (!logger)
30
+ console.log(`Cleared cache at ${dir}`);
31
+ else
32
+ logger.info(`Cleared cache at ${dir}`);
30
33
  }
31
34
  /**
32
35
  * Ensure that the cache size does not exceed the given maximum size in MB.
@@ -223,6 +226,9 @@ function hashObject(obj) {
223
226
  const buffer = obj.getArray();
224
227
  return hashBuffer(buffer);
225
228
  }
229
+ else if (obj == null) {
230
+ return 0;
231
+ }
226
232
  const str = JSON.stringify(obj);
227
233
  return hashString(str);
228
234
  }
@@ -0,0 +1,2 @@
1
+ #! /usr/bin/env node
2
+ export {};
@@ -0,0 +1,102 @@
1
+ #! /usr/bin/env node
2
+ import { program } from '@donmccurdy/caporal';
3
+ import { packGLTF } from "../scripts/index.js";
4
+ import { printStats } from '../utils/stats.js';
5
+ import { getVersion } from '../utils/version.js';
6
+ import { UsecaseOptions, createConfig, getConfig } from '../config/index.js';
7
+ import { make_progressive } from '../transforms/needle_progressive.js';
8
+ import { clearCache } from '../cache/cache.js';
9
+ // For testing / dev you can run `npm link` in the package directory
10
+ // For removing the link run `npm rm --global @needle-tools/gltf-build-pipeline`
11
+ program
12
+ .command("version", "Print current verison")
13
+ .action(async ({ logger }) => {
14
+ logger.info(getVersion());
15
+ })
16
+ .command("clear-caches", "Clear all caches")
17
+ .help(`
18
+ Clear all caches.
19
+ `)
20
+ .action(async ({ logger }) => {
21
+ logger.info("Clearing caches");
22
+ clearCache(logger);
23
+ })
24
+ .command("compress", "Compress a glTF file")
25
+ .help(`
26
+ Compress a single glTF file. The input file is compressed and written to the output file.
27
+ `)
28
+ .argument('<input>', "The input glTF, GLB or VRM file that should be compressed")
29
+ .option("--usecase <usecase>", `The usecase for the compression. This will set the compression settings. Options are ${UsecaseOptions.join(", ")}`, { validator: program.STRING })
30
+ .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 })
31
+ .option("--output <output>", "The output file. If not provided, the input file will be overwritten.", { validator: program.STRING })
32
+ .action(async ({ logger, args, options }) => {
33
+ logger.info("Transforming glTF file: " + args.input);
34
+ const stats = {
35
+ startTime: Date.now(),
36
+ totalGPUMemoryInMB: 0,
37
+ totalFilesProcessed: 0,
38
+ totalFileSizeInMB: 0,
39
+ totalFileSizeInMBBefore: 0,
40
+ };
41
+ let config = getConfig(options.config?.toString());
42
+ if (options.usecase) {
43
+ logger.info("Using usecase: " + options.usecase);
44
+ config = { ...config, ...createConfig(options.usecase.toString()) };
45
+ }
46
+ const file = args.input.toString();
47
+ const set = new Set();
48
+ await packGLTF(file, options.output?.toString() || file, {
49
+ config,
50
+ packedFiles: set,
51
+ stats,
52
+ debug: false,
53
+ useCache: true,
54
+ });
55
+ printStats(stats);
56
+ })
57
+ .command("transform", "Transform a glTF file")
58
+ .help(`
59
+ This will produce multiple versions of the input file, each with a different level of optimization.
60
+ Each version will be compressed and written to the output directory.
61
+ `)
62
+ .argument('<input>', "The input glTF, GLB or VRM file that should be compressed")
63
+ .option("--usecase <usecase>", `The usecase for the compression. This will set the compression settings. Options are ${UsecaseOptions.join(", ")}`, { validator: program.STRING })
64
+ .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 })
65
+ // .option("--output <output>", "The output file. If not provided, the input file will be overwritten.", { validator: program.STRING })
66
+ .action(async ({ logger, args, options }) => {
67
+ logger.info("Transforming glTF file: " + args.input);
68
+ const stats = {
69
+ startTime: Date.now(),
70
+ totalGPUMemoryInMB: 0,
71
+ totalFilesProcessed: 0,
72
+ totalFileSizeInMB: 0,
73
+ totalFileSizeInMBBefore: 0,
74
+ };
75
+ let config = getConfig(options.config?.toString());
76
+ if (options.usecase) {
77
+ logger.info("Using usecase: " + options.usecase);
78
+ config = { ...config, ...createConfig(options.usecase.toString()) };
79
+ }
80
+ const file = args.input.toString();
81
+ const progressive_results = new Array();
82
+ await make_progressive({
83
+ path: file,
84
+ results: progressive_results,
85
+ config,
86
+ debug: false,
87
+ useCache: true,
88
+ });
89
+ console.log("Progressive results: ", progressive_results);
90
+ const opts = {
91
+ config,
92
+ stats,
93
+ debug: false,
94
+ useCache: true,
95
+ };
96
+ for (const prog of progressive_results) {
97
+ await packGLTF(prog, prog, opts);
98
+ }
99
+ await packGLTF(file, file, opts);
100
+ printStats(stats);
101
+ });
102
+ program.run();
@@ -0,0 +1,43 @@
1
+ declare type Usecase = "unknown" | "product" | "game" | "metaverse";
2
+ export declare const UsecaseOptions: string[];
3
+ /**
4
+ * The config object contains information about how a file should be processed.
5
+ */
6
+ export type Config = {
7
+ /** High-level configuration */
8
+ usecase: Usecase;
9
+ };
10
+ /**
11
+ * Create a config object with the given usecase.
12
+ */
13
+ export declare function createConfig(usecase: string): {
14
+ usecase: Usecase;
15
+ };
16
+ /**
17
+ * Get the config object either provided by a CLI path or a needle.config.json file in the parent directory.
18
+ *
19
+ * @example CLI argument where the path points to a json file containing the config as `Config`
20
+ * ```sh
21
+ * node script.js --config path/to/my-optimization-config.json
22
+ * ```
23
+ *
24
+ * @example needle.config.json - the usecase can be provided as a string
25
+ * ```json
26
+ * {
27
+ * "optimization": "product"
28
+ * }
29
+ * ```
30
+ *
31
+ * @example needle.config.json - the whole config object can be provided
32
+ * ```json
33
+ * {
34
+ * "optimization": {
35
+ * "usecase": "product"
36
+ * }
37
+ * }
38
+ * ```
39
+ *
40
+ *
41
+ */
42
+ export declare function getConfig(path?: string): Config;
43
+ export {};
@@ -0,0 +1,125 @@
1
+ import { existsSync, readFileSync } from "fs";
2
+ export const UsecaseOptions = ["product", "game", "metaverse"];
3
+ const defaultConfig = {
4
+ usecase: "unknown",
5
+ };
6
+ /**
7
+ * Create a config object with the given usecase.
8
+ */
9
+ export function createConfig(usecase) {
10
+ if (!UsecaseOptions.includes(usecase)) {
11
+ throw new Error(`Invalid usecase: \"${usecase}\". Valid usecases: ${UsecaseOptions.join(", ")}`);
12
+ }
13
+ return {
14
+ usecase: usecase
15
+ };
16
+ }
17
+ /**
18
+ * Get the config object either provided by a CLI path or a needle.config.json file in the parent directory.
19
+ *
20
+ * @example CLI argument where the path points to a json file containing the config as `Config`
21
+ * ```sh
22
+ * node script.js --config path/to/my-optimization-config.json
23
+ * ```
24
+ *
25
+ * @example needle.config.json - the usecase can be provided as a string
26
+ * ```json
27
+ * {
28
+ * "optimization": "product"
29
+ * }
30
+ * ```
31
+ *
32
+ * @example needle.config.json - the whole config object can be provided
33
+ * ```json
34
+ * {
35
+ * "optimization": {
36
+ * "usecase": "product"
37
+ * }
38
+ * }
39
+ * ```
40
+ *
41
+ *
42
+ */
43
+ export function getConfig(path) {
44
+ if (path != null) {
45
+ if (!existsSync(path)) {
46
+ throw new Error(`No config found at \"${path}\"`);
47
+ }
48
+ return resolveConfig(path, readFileSync(path, "utf8"));
49
+ }
50
+ if (_cachedConfig !== undefined) {
51
+ return _cachedConfig;
52
+ }
53
+ // Resolve the config once and cache it
54
+ const result = internalResolveConfig();
55
+ if (result) {
56
+ console.log("INFO: Using optimization config with usecase: " + result.usecase);
57
+ _cachedConfig = result;
58
+ }
59
+ else {
60
+ console.log("INFO: No optimization config found. Using default config.");
61
+ _cachedConfig = defaultConfig;
62
+ }
63
+ return _cachedConfig;
64
+ }
65
+ let _cachedConfig = undefined;
66
+ function internalResolveConfig() {
67
+ // Check if a config path is passed as an argument
68
+ const args = process.argv.slice(2);
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
+ }
80
+ }
81
+ // Check if a needle.config.json exists in the directory from which the script is run (or any parent directory)
82
+ const workingDir = process.cwd();
83
+ let directory = workingDir.replaceAll("\\", "/");
84
+ while (directory.length > 0) {
85
+ const configPath = `${directory}/needle.config.json`;
86
+ if (existsSync(configPath)) {
87
+ const content = readFileSync(configPath, "utf8");
88
+ const config = resolveConfig(configPath, content);
89
+ if (config) {
90
+ return config;
91
+ }
92
+ }
93
+ const lastSlash = directory.lastIndexOf("/");
94
+ if (lastSlash < 0) {
95
+ break;
96
+ }
97
+ directory = directory.slice(0, lastSlash);
98
+ }
99
+ return null;
100
+ }
101
+ function resolveConfig(filename, content) {
102
+ // Handle config being part of `needle.config.json`
103
+ if (filename.endsWith("needle.config.json")) {
104
+ const config = JSON.parse(content);
105
+ if (config.optimization) {
106
+ console.log("INFO: Found optimization config at \"" + filename + "\".");
107
+ // If the optimization config is a string, it's the usecase
108
+ if (typeof config.optimization === "string") {
109
+ return createConfig(config.optimization);
110
+ }
111
+ return config.optimization;
112
+ }
113
+ else {
114
+ console.log("INFO: No optimization config found in needle.config.json. Using default config.");
115
+ return null;
116
+ }
117
+ }
118
+ // Handle config being the content of the file
119
+ else if (content.trimStart().startsWith("{")) {
120
+ return JSON.parse(content);
121
+ }
122
+ else {
123
+ throw new Error("Invalid config file format. Expected JSON object.");
124
+ }
125
+ }
@@ -1,9 +1,10 @@
1
1
  import { WriterContext, PropertyType } from '@gltf-transform/core';
2
2
  declare interface IExtensibleProperty {
3
3
  }
4
+ type DebugBreakPoint = boolean | "pointer:read";
4
5
  export type Options = {
5
6
  debug?: boolean;
6
- breakpoint?: boolean;
7
+ breakpoint?: DebugBreakPoint;
7
8
  write?: boolean;
8
9
  };
9
10
  export interface IOpaqueExtension {
@@ -19,13 +19,14 @@ export function createOpaqueExtension(name, types, opts) {
19
19
  // private roots: Array<OpaqueProperty> = [];
20
20
  jsonPointerHandler;
21
21
  read(context) {
22
- if (opts.breakpoint === true)
22
+ if (opts?.breakpoint === true)
23
23
  debugger;
24
24
  currentGenerator = context.jsonDoc.json.asset?.generator;
25
25
  if (debugLog)
26
26
  console.log("READ " + EXTENSION_NAME);
27
27
  this.jsonPointerHandler = new JsonPointerHandler(this.document, EXTENSION_NAME);
28
28
  this.jsonPointerHandler.debug = debugLog;
29
+ this.jsonPointerHandler.breakPoint = opts?.breakpoint;
29
30
  for (const type of types) {
30
31
  switch (type) {
31
32
  case PropertyType.ACCESSOR:
@@ -224,7 +225,7 @@ export function createOpaqueExtension(name, types, opts) {
224
225
  }
225
226
  }
226
227
  write(context) {
227
- if (opts.breakpoint === true)
228
+ if (opts?.breakpoint === true)
228
229
  debugger;
229
230
  if (opts?.write === false) {
230
231
  return this;
@@ -514,6 +515,7 @@ class JsonPointerHandler {
514
515
  document;
515
516
  map = new Map();
516
517
  debug = false;
518
+ breakPoint = false;
517
519
  constructor(document, id) {
518
520
  this.document = document;
519
521
  this.id = id;
@@ -524,7 +526,11 @@ class JsonPointerHandler {
524
526
  if (key !== undefined) {
525
527
  fullPath ??= "";
526
528
  fullPath += "/" + key;
529
+ if (this.breakPoint === "pointer:read") {
530
+ debugger;
531
+ }
527
532
  }
533
+ // if(this.debug && key === "colliders") debugger;
528
534
  switch (typeof value) {
529
535
  case 'object':
530
536
  if (value !== null && value !== undefined) {
@@ -570,7 +576,7 @@ class JsonPointerHandler {
570
576
  if (pointer) {
571
577
  if (this.debug)
572
578
  console.log("> Register pointer", this.id + "/" + fullPath + " : " + value);
573
- pointer?.register(obj, key);
579
+ pointer?.register(obj, key, fullPath);
574
580
  }
575
581
  else
576
582
  console.warn("WARN: failed registering pointer", fullPath, value);
@@ -597,13 +603,15 @@ class JsonPointerHandler {
597
603
  pointer.debug = this.debug;
598
604
  this.map.set(value, pointer);
599
605
  }
600
- pointer?.register(obj, key);
606
+ pointer?.register(obj, key, fullPath);
601
607
  }
602
608
  }
603
609
  }
604
610
  break;
605
611
  case 'number':
606
- if (key === "node" || key === "mesh") {
612
+ if (key === "node" || key === "mesh"
613
+ // VRM 1.0 spring bone center https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_springBone-1.0/schema/VRMC_springBone.spring.schema.json
614
+ || fullPath.match(/springs\/\d+\/center/g)) {
607
615
  const object = context.nodes[value];
608
616
  if (object) {
609
617
  const res = new NodeIndexResolver(this.document, object, context.jsonDoc.json.nodes[value]);
@@ -615,12 +623,17 @@ class JsonPointerHandler {
615
623
  pointer = new JsonPointer(null, res, value);
616
624
  }
617
625
  pointer.debug = this.debug;
618
- pointer.register(obj, key);
626
+ pointer.register(obj, key, fullPath);
619
627
  this.map.set(dictKey, pointer);
620
628
  }
621
629
  }
622
- // key texture is matching for example for VRM meta/texture (AvatarSample_A) and the regex is also for handling VRM material properties
623
- else if (key === "texture" || fullPath.match(/materialProperties\/\d+?\/textureProperties/g)) {
630
+ else if (
631
+ // key texture is matching for example for VRM meta/texture (AvatarSample_A)
632
+ key === "texture"
633
+ // VRM 0.0 material properties
634
+ || fullPath.match(/materialProperties\/\d+\/textureProperties/g)
635
+ // VRM 1.0 meta
636
+ || fullPath.match(/meta\/thumbnailImage/g)) {
624
637
  const index = value;
625
638
  // e.g. in meta.texture for VRM avatars it seems like we can have negative values
626
639
  if (index < 0) {
@@ -648,7 +661,7 @@ class JsonPointerHandler {
648
661
  pointer = new JsonPointer(null, res, value);
649
662
  }
650
663
  pointer.debug = this.debug;
651
- pointer.register(obj, key);
664
+ pointer.register(obj, key, fullPath);
652
665
  this.map.set(dictKey, pointer);
653
666
  if (ext) {
654
667
  ext.setReference(dictKey, object);
@@ -656,6 +669,8 @@ class JsonPointerHandler {
656
669
  }
657
670
  }
658
671
  break;
672
+ default:
673
+ break;
659
674
  }
660
675
  }
661
676
  resolveAndWrite(context) {
@@ -677,9 +692,11 @@ class JsonPointer {
677
692
  }
678
693
  _objects = [];
679
694
  _props = [];
680
- register(obj, prop) {
695
+ _debugInfo = [];
696
+ register(obj, prop, fullpath) {
681
697
  this._objects.push(obj);
682
698
  this._props.push(prop);
699
+ this._debugInfo.push(fullpath);
683
700
  }
684
701
  newPointer;
685
702
  resolve(context) {
@@ -694,18 +711,19 @@ class JsonPointer {
694
711
  this.newPointer = index;
695
712
  }
696
713
  if (this.debug)
697
- console.log(`RESOLVED ${this.oldPointer} to → ${this.newPointer}`);
714
+ console.log(`RESOLVED pointer ${this.oldPointer} to → ${this.newPointer}`);
698
715
  }
699
716
  else {
700
- console.log("ERR: failed to resolve pointer", this.pointerBase);
717
+ console.log("ERR: 🧨 FAILED to resolve pointer", this.pointerBase, ` used by ${this._debugInfo.join(", ")}`);
701
718
  }
702
719
  }
703
720
  write() {
704
721
  for (let i = 0; i < this._objects.length; i++) {
705
722
  const obj = this._objects[i];
706
723
  const prop = this._props[i];
707
- if (this.debug)
708
- console.log("< Resolved pointer", this.newPointer, "in", prop);
724
+ if (this.debug) {
725
+ console.log(`< Resolved pointer ${this._debugInfo[i]}: ${this.newPointer}`);
726
+ }
709
727
  obj[prop] = this.newPointer;
710
728
  }
711
729
  }
@@ -1,3 +1,3 @@
1
- import { IOpaqueExtension } from "./NEEDLE_opaque.js";
1
+ import { Extension } from "@gltf-transform/core";
2
2
  export * from "./NEEDLE_opaque.js";
3
- export declare const ALL_EXTENSIONS: IOpaqueExtension[];
3
+ export declare const ALL_EXTENSIONS: (typeof Extension)[];
@@ -17,5 +17,12 @@ export const ALL_EXTENSIONS = [
17
17
  createOpaqueExtension("EXT_texture_exr", [PropertyType.TEXTURE], { ...opaqueOptions }),
18
18
  createOpaqueExtension("NEEDLE_editor", [PropertyType.NODE, PropertyType.MATERIAL], { ...opaqueOptions }),
19
19
  createOpaqueExtension("NEEDLE_gltf_dependencies", [PropertyType.ROOT], { ...opaqueOptions }),
20
+ // VRM 0.0
20
21
  createOpaqueExtension("VRM", [PropertyType.ROOT], { ...opaqueOptions }),
22
+ // VRM 1.0 https://vrm.dev/en/vrm1/changed/
23
+ createOpaqueExtension("VRMC_vrm", [PropertyType.ROOT], { ...opaqueOptions }),
24
+ createOpaqueExtension("VRMC_springBone", [PropertyType.ROOT], { ...opaqueOptions }),
25
+ createOpaqueExtension("VRMC_node_constraint", [PropertyType.NODE], { ...opaqueOptions }),
26
+ // TODO: mtoon materials don't work yet
27
+ // createOpaqueExtension("VRMC_materials_mtoon", [PropertyType.MATERIAL], { ...opaqueOptions, debug: true, breakpoint: "pointer:read" },),
21
28
  ];
@@ -1,7 +1,10 @@
1
1
  import { Extension, ExtensionProperty, PropertyType, ReaderContext, WriterContext } from "@gltf-transform/core";
2
2
  export declare interface IProgressiveMeshSettings {
3
- guid: string;
3
+ /**
4
+ * When false no LODs will be generated for this mesh
5
+ */
4
6
  generateLods: boolean;
7
+ guid: string;
5
8
  }
6
9
  export declare class NEEDLE_progressive_mesh_settings extends Extension {
7
10
  static EXTENSION_NAME: string;
@@ -1,5 +1,9 @@
1
1
  import { Extension, ExtensionProperty, PropertyType, ReaderContext, WriterContext } from "@gltf-transform/core";
2
2
  export declare interface IProgressiveTextureSettings {
3
+ /**
4
+ * When false the texture no progressive texture will be generated
5
+ */
6
+ generateLods?: boolean;
3
7
  maxSize: number;
4
8
  guid: string;
5
9
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
+ export * from "./config/index.js";
2
+ export * from "./cli/index.js";
1
3
  export * from "./utils/index.js";
2
4
  export * from "./transforms/index.js";
3
5
  export * from "./extensions/index.js";
4
6
  export * from "./cache/index.js";
7
+ export * from "./scripts/index.js";
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
+ export * from "./config/index.js";
2
+ export * from "./cli/index.js";
1
3
  export * from "./utils/index.js";
2
4
  export * from "./transforms/index.js";
3
5
  export * from "./extensions/index.js";
4
6
  export * from "./cache/index.js";
7
+ export * from "./scripts/index.js";
@@ -0,0 +1 @@
1
+ export * from "./pack-gltf.js";
@@ -0,0 +1 @@
1
+ export * from "./pack-gltf.js";
@@ -0,0 +1,12 @@
1
+ import { Stats } from "../utils/index.js";
2
+ import { Config } from '../config/index.js';
3
+ export type PackGLTFOptions = {
4
+ debug: boolean;
5
+ useCache: boolean;
6
+ packedFiles?: Set<string>;
7
+ stats?: Stats;
8
+ config?: Config;
9
+ };
10
+ /** Compress a glTF file
11
+ */
12
+ export declare function packGLTF(inputFile: string, outputFile: string, options: PackGLTFOptions): Promise<boolean>;