@needle-tools/gltf-build-pipeline 2.15.6 → 2.15.7
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/dist/extensions/NEEDLE_lightmaps/index.d.ts +0 -2
- package/dist/extensions/NEEDLE_lightmaps/index.js +2 -3
- package/dist/extensions/NEEDLE_opaque/NEEDLE_opaque.d.ts +0 -1
- package/dist/extensions/NEEDLE_opaque/NEEDLE_opaque.js +2 -4
- package/dist/extensions/index.d.ts +6 -0
- package/dist/extensions/index.js +11 -0
- package/dist/scripts/pack-gltf.js +2 -3
- package/dist/transforms/needle_pmrem.js +3 -5
- package/dist/transforms/needle_progressive.js +2 -1
- package/dist/transforms/needle_toktx.js +4 -3
- package/dist/utils/fileutils.d.ts +3 -0
- package/dist/utils/fileutils.js +19 -1
- package/dist/utils/version.gen.d.ts +1 -1
- package/dist/utils/version.gen.js +1 -1
- package/package.json +1 -1
|
@@ -17,8 +17,6 @@ export declare class NEEDLE_lightmaps_ext extends Extension {
|
|
|
17
17
|
readonly extensionName = "NEEDLE_lightmaps";
|
|
18
18
|
readonly prereadTypes: PropertyType[];
|
|
19
19
|
readonly prewriteTypes: PropertyType[];
|
|
20
|
-
/** Set before io.read() to allow resolving external file paths in preread */
|
|
21
|
-
static inputFile: string;
|
|
22
20
|
/** The raw extension JSON from the input (mutated in-place during write) */
|
|
23
21
|
private extensionData;
|
|
24
22
|
/** Entries with resolved Texture references */
|
|
@@ -2,6 +2,7 @@ import { Extension, ExtensionProperty, PropertyType } from '@gltf-transform/core
|
|
|
2
2
|
import { existsSync, readFileSync } from 'fs';
|
|
3
3
|
import { join, dirname } from 'path';
|
|
4
4
|
import { isLightmap } from '../../utils/texture.js';
|
|
5
|
+
import { getExtensionInputFile } from '../index.js';
|
|
5
6
|
const EXTENSION_NAME = 'NEEDLE_lightmaps';
|
|
6
7
|
/**
|
|
7
8
|
* Opaque-like ExtensionProperty that holds NEEDLE_lightmaps data on the Root.
|
|
@@ -40,8 +41,6 @@ export class NEEDLE_lightmaps_ext extends Extension {
|
|
|
40
41
|
extensionName = EXTENSION_NAME;
|
|
41
42
|
prereadTypes = [PropertyType.TEXTURE];
|
|
42
43
|
prewriteTypes = [PropertyType.MATERIAL];
|
|
43
|
-
/** Set before io.read() to allow resolving external file paths in preread */
|
|
44
|
-
static inputFile = '';
|
|
45
44
|
/** The raw extension JSON from the input (mutated in-place during write) */
|
|
46
45
|
extensionData = null;
|
|
47
46
|
/** Entries with resolved Texture references */
|
|
@@ -56,7 +55,7 @@ export class NEEDLE_lightmaps_ext extends Extension {
|
|
|
56
55
|
const ext = json.extensions?.[EXTENSION_NAME];
|
|
57
56
|
if (!ext?.textures)
|
|
58
57
|
return this;
|
|
59
|
-
const inputFile =
|
|
58
|
+
const inputFile = getExtensionInputFile();
|
|
60
59
|
const inputDir = inputFile ? dirname(inputFile) : '';
|
|
61
60
|
for (const entry of ext.textures) {
|
|
62
61
|
// Skip embedded pointers — handled in read()
|
|
@@ -23,6 +23,5 @@ export interface IExtensionWriter {
|
|
|
23
23
|
write(context: WriterContext, prop: IExtensibleProperty): void;
|
|
24
24
|
}
|
|
25
25
|
export declare let currentGenerator: string;
|
|
26
|
-
export declare function setOpaqueInputFile(path: string): void;
|
|
27
26
|
export declare function createOpaqueExtension(name: string, types: PropertyType | PropertyType[], opts?: Options): IOpaqueExtension;
|
|
28
27
|
export {};
|
|
@@ -10,9 +10,7 @@ for (const key in PropertyType) {
|
|
|
10
10
|
ALL_PROPERTY_TYPES.push(PropertyType[key]);
|
|
11
11
|
}
|
|
12
12
|
export let currentGenerator = "";
|
|
13
|
-
|
|
14
|
-
let _opaqueInputFile = "";
|
|
15
|
-
export function setOpaqueInputFile(path) { _opaqueInputFile = path; }
|
|
13
|
+
import { getExtensionInputFile } from '../index.js';
|
|
16
14
|
// an opaque extension can be used to pass data through the gltf transform process
|
|
17
15
|
// it should also be able to re-write/fix json pointers after the transformation which might have shuffled them around
|
|
18
16
|
export function createOpaqueExtension(name, types, opts) {
|
|
@@ -632,7 +630,7 @@ class JsonPointerHandler {
|
|
|
632
630
|
// External EXR file reference (e.g. "StudioHDRI_ferndale_studio_04_1k.exr" in a ReflectionProbe)
|
|
633
631
|
// Inject the file into the document as a Texture so PMREM can process it
|
|
634
632
|
if (!isTexturePointer && value.match(/\.exr$/i)) {
|
|
635
|
-
const inputDir =
|
|
633
|
+
const inputDir = getExtensionInputFile() ? dirname(getExtensionInputFile()) : '';
|
|
636
634
|
const exrPath = inputDir ? join(inputDir, value) : '';
|
|
637
635
|
if (exrPath && existsSync(exrPath)) {
|
|
638
636
|
// Check if we already injected this file
|
|
@@ -6,4 +6,10 @@ export * from "./NEEDLE_progressive_texture_settings/index.js";
|
|
|
6
6
|
export * from "./NEEDLE_progressive_mesh_settings/index.js";
|
|
7
7
|
export * from "./NEEDLE_pmrem/index.js";
|
|
8
8
|
export * from "./NEEDLE_lightmaps/index.js";
|
|
9
|
+
/** Central place to set the input file path for all extensions that need to resolve
|
|
10
|
+
* external assets (e.g. .exr files) relative to the source GLB.
|
|
11
|
+
* Call this before io.read(). */
|
|
12
|
+
export declare function setExtensionInputFile(filePath: string): void;
|
|
13
|
+
/** Returns the current input file path set via {@link setExtensionInputFile}. */
|
|
14
|
+
export declare function getExtensionInputFile(): string;
|
|
9
15
|
export declare function registerExtensions(node: any): void;
|
package/dist/extensions/index.js
CHANGED
|
@@ -12,6 +12,17 @@ import { ALL_EXTENSIONS as NEEDLE_EXTENSIONS } from "./NEEDLE_opaque/index.js";
|
|
|
12
12
|
import { NEEDLE_progressive } from './NEEDLE_progressive/index.js';
|
|
13
13
|
import { NEEDLE_pmrem } from './NEEDLE_pmrem/index.js';
|
|
14
14
|
import { NEEDLE_lightmaps_ext } from './NEEDLE_lightmaps/index.js';
|
|
15
|
+
let _extensionInputFile = '';
|
|
16
|
+
/** Central place to set the input file path for all extensions that need to resolve
|
|
17
|
+
* external assets (e.g. .exr files) relative to the source GLB.
|
|
18
|
+
* Call this before io.read(). */
|
|
19
|
+
export function setExtensionInputFile(filePath) {
|
|
20
|
+
_extensionInputFile = filePath;
|
|
21
|
+
}
|
|
22
|
+
/** Returns the current input file path set via {@link setExtensionInputFile}. */
|
|
23
|
+
export function getExtensionInputFile() {
|
|
24
|
+
return _extensionInputFile;
|
|
25
|
+
}
|
|
15
26
|
export function registerExtensions(node) {
|
|
16
27
|
node.registerExtensions(ALL_EXTENSIONS);
|
|
17
28
|
node.registerExtensions(NEEDLE_EXTENSIONS);
|
|
@@ -5,7 +5,7 @@ import draco3d from 'draco3dgltf';
|
|
|
5
5
|
import { existsSync, readFileSync, statSync, writeFileSync } from 'fs';
|
|
6
6
|
import { MeshoptDecoder, MeshoptEncoder } from 'meshoptimizer';
|
|
7
7
|
import { dedup, metalRough, prune, resample } from '@gltf-transform/functions';
|
|
8
|
-
import { ALL_EXTENSIONS as NEEDLE_EXTENSIONS, NEEDLE_compression_texture, NEEDLE_mesh_compression, NEEDLE_pmrem, NEEDLE_lightmaps_ext,
|
|
8
|
+
import { ALL_EXTENSIONS as NEEDLE_EXTENSIONS, NEEDLE_compression_texture, NEEDLE_mesh_compression, NEEDLE_pmrem, NEEDLE_lightmaps_ext, setExtensionInputFile } from '../extensions/index.js';
|
|
9
9
|
import { isLOD, isMeshLOD, needle_animation_transform, needle_asset, needle_mesh_transform, needle_texture_transform, } from '../transforms/index.js';
|
|
10
10
|
import { getOutputPath, getVersion, ioTryReadWithMissingResources, writeNodeIO } from "../utils/index.js";
|
|
11
11
|
import { addToCache, getHash, tryGetFromCache, } from "../cache/index.js";
|
|
@@ -69,8 +69,7 @@ export async function packGLTF(inputFile, outputFile, options) {
|
|
|
69
69
|
// Set input file path so extensions can resolve external EXR files
|
|
70
70
|
// Use sourceFile when available (e.g. when inputFile is a progressive output copy)
|
|
71
71
|
const assetSourceFile = options.sourceFile ?? inputFile;
|
|
72
|
-
|
|
73
|
-
setOpaqueInputFile(assetSourceFile);
|
|
72
|
+
setExtensionInputFile(assetSourceFile);
|
|
74
73
|
const document = await ioTryReadWithMissingResources(io, inputFile);
|
|
75
74
|
if (options.logger) {
|
|
76
75
|
document.setLogger(options.logger);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NEEDLE_pmrem } from '../extensions/index.js';
|
|
2
2
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, chmodSync } from 'fs';
|
|
3
|
+
import { safeRmDir } from '../utils/fileutils.js';
|
|
3
4
|
import { join, dirname } from 'path';
|
|
4
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
5
6
|
import { execFile } from 'child_process';
|
|
@@ -212,11 +213,8 @@ export class NeedlePmremContext {
|
|
|
212
213
|
}
|
|
213
214
|
}
|
|
214
215
|
// Clean up temp directory
|
|
215
|
-
if (this.tmpDir
|
|
216
|
-
|
|
217
|
-
rmSync(this.tmpDir, { recursive: true });
|
|
218
|
-
}
|
|
219
|
-
catch { /* ignore */ }
|
|
216
|
+
if (this.tmpDir) {
|
|
217
|
+
await safeRmDir(this.tmpDir);
|
|
220
218
|
}
|
|
221
219
|
}
|
|
222
220
|
}
|
|
@@ -3,7 +3,7 @@ import { SIMPLIFY_DEFAULTS, WELD_DEFAULTS, listTextureChannels, listTextureSlots
|
|
|
3
3
|
import { KHRMaterialsSpecular } from '@gltf-transform/extensions';
|
|
4
4
|
import draco3d from 'draco3dgltf';
|
|
5
5
|
import { NEEDLE_PROGRESSIVE_EXTENSION_NAME, NEEDLE_progressive } from "../extensions/NEEDLE_progressive/index.js";
|
|
6
|
-
import { createOpaqueExtension, currentGenerator, NEEDLE_compression_texture, NEEDLE_mesh_compression, NEEDLE_progressive_mesh_settings, NEEDLE_progressive_texture_settings, registerExtensions as registerDefaultExtensions } from '../extensions/index.js';
|
|
6
|
+
import { createOpaqueExtension, currentGenerator, NEEDLE_compression_texture, NEEDLE_mesh_compression, NEEDLE_progressive_mesh_settings, NEEDLE_progressive_texture_settings, registerExtensions as registerDefaultExtensions, setExtensionInputFile } from '../extensions/index.js';
|
|
7
7
|
import path, { basename, resolve } from 'path';
|
|
8
8
|
import { existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'fs';
|
|
9
9
|
import { addMetaToCache, addToCache, getHash, getKey, tryGetFromCache, tryGetMetaFromCache } from '../cache/index.js';
|
|
@@ -77,6 +77,7 @@ async function onProcess(file, opts) {
|
|
|
77
77
|
'draco3d.decoder': await draco3d.createDecoderModule(),
|
|
78
78
|
'draco3d.encoder': await draco3d.createEncoderModule(),
|
|
79
79
|
});
|
|
80
|
+
setExtensionInputFile(file);
|
|
80
81
|
let document = await ioTryReadWithMissingResources(io, file); // await io.read(file);
|
|
81
82
|
if (document) {
|
|
82
83
|
if (opts.logger) {
|
|
@@ -2,7 +2,8 @@ import { BufferUtils, FileUtils, ImageUtils, uuid } from "@gltf-transform/core";
|
|
|
2
2
|
import { listTextureSlots, getTextureChannelMask, fitPowerOfTwo, TextureResizeFilter } from "@gltf-transform/functions";
|
|
3
3
|
import { KHRTextureBasisu } from "@gltf-transform/extensions";
|
|
4
4
|
import { checkKTXSoftware, createParams, KTX_SOFTWARE_VERSION_MIN, Mode } from "./toktx.js";
|
|
5
|
-
import { existsSync, mkdirSync
|
|
5
|
+
import { existsSync, mkdirSync } from "fs";
|
|
6
|
+
import { safeRmDir } from "../utils/fileutils.js";
|
|
6
7
|
import { formatBytes, spawn, waitExit } from './util.js';
|
|
7
8
|
import { ETC1S_DEFAULTS, UASTC_DEFAULTS } from "./toktx_types.js";
|
|
8
9
|
import fs from 'fs/promises';
|
|
@@ -235,8 +236,8 @@ export class NeedleToktxContext {
|
|
|
235
236
|
if (!usesKTX2) {
|
|
236
237
|
this.basisuExtension?.dispose();
|
|
237
238
|
}
|
|
238
|
-
if (this.cacheDirectory
|
|
239
|
-
|
|
239
|
+
if (this.cacheDirectory) {
|
|
240
|
+
await safeRmDir(this.cacheDirectory);
|
|
240
241
|
}
|
|
241
242
|
}
|
|
242
243
|
}
|
|
@@ -17,3 +17,6 @@ export declare function isDirectory(path: string): boolean;
|
|
|
17
17
|
* If the directory does not exist, it will be created.
|
|
18
18
|
*/
|
|
19
19
|
export declare function ensureIsDirectory(path: string): string;
|
|
20
|
+
/** Recursively delete a directory, retrying on EBUSY/EPERM (Windows file handle delays).
|
|
21
|
+
* Silently gives up after all retries fail — temp dirs will be cleaned up by the OS. */
|
|
22
|
+
export declare function safeRmDir(dirPath: string, retries?: number, delayMs?: number): Promise<void>;
|
package/dist/utils/fileutils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { existsSync, statSync, readdirSync, readFileSync, mkdirSync } from 'fs';
|
|
1
|
+
import { existsSync, statSync, readdirSync, readFileSync, mkdirSync, rmSync } from 'fs';
|
|
2
|
+
import { setTimeout } from 'timers/promises';
|
|
2
3
|
import { dirname, isAbsolute, join } from 'path';
|
|
3
4
|
/**
|
|
4
5
|
* Get the output path for a file based on the output directory or file.
|
|
@@ -175,3 +176,20 @@ export function ensureIsDirectory(path) {
|
|
|
175
176
|
}
|
|
176
177
|
return path;
|
|
177
178
|
}
|
|
179
|
+
/** Recursively delete a directory, retrying on EBUSY/EPERM (Windows file handle delays).
|
|
180
|
+
* Silently gives up after all retries fail — temp dirs will be cleaned up by the OS. */
|
|
181
|
+
export async function safeRmDir(dirPath, retries = 3, delayMs = 150) {
|
|
182
|
+
for (let i = 0; i <= retries; i++) {
|
|
183
|
+
try {
|
|
184
|
+
if (existsSync(dirPath))
|
|
185
|
+
rmSync(dirPath, { recursive: true });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
const retryable = err?.code === 'EBUSY' || err?.code === 'EPERM';
|
|
190
|
+
if (!retryable || i === retries)
|
|
191
|
+
return;
|
|
192
|
+
await setTimeout(delayMs);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.15.
|
|
1
|
+
export declare const version = "2.15.7";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "2.15.
|
|
1
|
+
export const version = "2.15.7";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/gltf-build-pipeline",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.7",
|
|
4
4
|
"description": "Pipeline and tools for optimizing gltf files using gltf-transform and compression settings within glTF extensions",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|