@needle-tools/gltf-build-pipeline 2.13.0 → 2.13.1
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 +520 -517
- package/README.md +38 -38
- package/dist/cache/cache.d.ts +55 -55
- package/dist/cache/cache.js +326 -326
- package/dist/cache/index.d.ts +1 -1
- package/dist/cache/index.js +1 -1
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.js +198 -198
- package/dist/config/index.d.ts +53 -53
- package/dist/config/index.js +152 -152
- package/dist/constants.d.ts +7 -7
- package/dist/constants.js +7 -7
- package/dist/extensions/NEEDLE_compression_texture/NEEDLE_compression_texture.d.ts +24 -24
- package/dist/extensions/NEEDLE_compression_texture/NEEDLE_compression_texture.js +54 -54
- package/dist/extensions/NEEDLE_compression_texture/index.d.ts +1 -1
- package/dist/extensions/NEEDLE_compression_texture/index.js +1 -1
- package/dist/extensions/NEEDLE_mesh_compression/NEEDLE_mesh_compression.d.ts +27 -27
- package/dist/extensions/NEEDLE_mesh_compression/NEEDLE_mesh_compression.js +88 -88
- package/dist/extensions/NEEDLE_mesh_compression/index.d.ts +1 -1
- package/dist/extensions/NEEDLE_mesh_compression/index.js +1 -1
- package/dist/extensions/NEEDLE_opaque/NEEDLE_opaque.d.ts +27 -27
- package/dist/extensions/NEEDLE_opaque/NEEDLE_opaque.js +980 -980
- package/dist/extensions/NEEDLE_opaque/index.d.ts +3 -3
- package/dist/extensions/NEEDLE_opaque/index.js +30 -30
- package/dist/extensions/NEEDLE_progressive/NEEDLE_progressive.d.ts +48 -48
- package/dist/extensions/NEEDLE_progressive/NEEDLE_progressive.js +69 -69
- package/dist/extensions/NEEDLE_progressive/index.d.ts +1 -1
- package/dist/extensions/NEEDLE_progressive/index.js +1 -1
- package/dist/extensions/NEEDLE_progressive_mesh_settings/index.d.ts +23 -23
- package/dist/extensions/NEEDLE_progressive_mesh_settings/index.js +41 -41
- package/dist/extensions/NEEDLE_progressive_texture_settings/index.d.ts +25 -25
- package/dist/extensions/NEEDLE_progressive_texture_settings/index.js +38 -38
- package/dist/extensions/index.d.ts +7 -7
- package/dist/extensions/index.js +17 -17
- package/dist/extensions/utils.d.ts +6 -6
- package/dist/extensions/utils.js +72 -72
- package/dist/functions/weld.3.d.ts +76 -76
- package/dist/functions/weld.3.js +414 -414
- package/dist/index.d.ts +8 -8
- package/dist/index.js +8 -8
- package/dist/scripts/index.d.ts +2 -2
- package/dist/scripts/index.js +2 -2
- package/dist/scripts/pack-gltf.d.ts +15 -15
- package/dist/scripts/pack-gltf.js +135 -133
- package/dist/scripts/stats.d.ts +2 -2
- package/dist/scripts/stats.js +19 -19
- package/dist/transforms/index.d.ts +9 -9
- package/dist/transforms/index.js +9 -9
- package/dist/transforms/needle_animation_transform.d.ts +2 -2
- package/dist/transforms/needle_animation_transform.js +5 -5
- package/dist/transforms/needle_asset.d.ts +3 -3
- package/dist/transforms/needle_asset.js +50 -50
- package/dist/transforms/needle_common.d.ts +17 -17
- package/dist/transforms/needle_common.js +1 -1
- package/dist/transforms/needle_mesh_transform.d.ts +15 -15
- package/dist/transforms/needle_mesh_transform.js +223 -223
- package/dist/transforms/needle_progressive.d.ts +45 -45
- package/dist/transforms/needle_progressive.js +1043 -1043
- package/dist/transforms/needle_texture_transform.d.ts +13 -13
- package/dist/transforms/needle_texture_transform.js +257 -257
- package/dist/transforms/needle_toktx.d.ts +26 -26
- package/dist/transforms/needle_toktx.js +243 -243
- package/dist/transforms/needle_webp.d.ts +15 -15
- package/dist/transforms/needle_webp.js +53 -53
- package/dist/transforms/toktx.d.ts +52 -52
- package/dist/transforms/toktx.js +221 -221
- package/dist/transforms/toktx_types.d.ts +78 -78
- package/dist/transforms/toktx_types.js +62 -62
- package/dist/transforms/util.d.ts +21 -21
- package/dist/transforms/util.js +90 -90
- package/dist/utils/compression_utils.d.ts +2 -2
- package/dist/utils/compression_utils.js +6 -6
- package/dist/utils/fileutils.d.ts +19 -19
- package/dist/utils/fileutils.js +177 -177
- package/dist/utils/guid.d.ts +1 -1
- package/dist/utils/guid.js +5 -5
- package/dist/utils/index.d.ts +10 -10
- package/dist/utils/index.js +10 -10
- package/dist/utils/merge.d.ts +12 -12
- package/dist/utils/merge.js +31 -31
- package/dist/utils/mesh.d.ts +13 -13
- package/dist/utils/mesh.js +124 -124
- package/dist/utils/nodeio.d.ts +6 -6
- package/dist/utils/nodeio.js +86 -86
- package/dist/utils/stats.d.ts +70 -70
- package/dist/utils/stats.js +258 -258
- package/dist/utils/texture.d.ts +5 -5
- package/dist/utils/texture.js +14 -14
- package/dist/utils/validate.d.ts +5 -5
- package/dist/utils/validate.js +17 -17
- package/dist/utils/version.d.ts +1 -1
- package/dist/utils/version.gen.d.ts +1 -1
- package/dist/utils/version.gen.js +1 -1
- package/dist/utils/version.js +4 -4
- package/package.json +79 -79
- package/scripts/clear-caches.mjs +3 -3
- package/scripts/defaults.mjs +11 -11
- package/scripts/fileutils.mjs +5 -5
- package/scripts/index.mjs +41 -41
- package/scripts/limit-caches.mjs +3 -3
- package/scripts/make-progressive.mjs +16 -16
- package/scripts/pack-gltf.mjs +106 -106
- package/tsconfig.json +19 -19
package/dist/utils/mesh.js
CHANGED
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
import { Mesh } from "@gltf-transform/core";
|
|
2
|
-
export function getMeshInformation(mesh) {
|
|
3
|
-
let maxVertexCount = 0;
|
|
4
|
-
let totalIndexCount = 0;
|
|
5
|
-
let totalVertexCount = 0;
|
|
6
|
-
if (mesh instanceof Mesh) {
|
|
7
|
-
totalVertexCount = mesh.listPrimitives().reduce((acc, prim) => {
|
|
8
|
-
const indices = prim.getIndices()?.getCount() || 0;
|
|
9
|
-
totalIndexCount += indices;
|
|
10
|
-
const vertices = prim.getAttribute('POSITION')?.getCount() || 0;
|
|
11
|
-
maxVertexCount = Math.max(maxVertexCount, vertices);
|
|
12
|
-
return acc + vertices;
|
|
13
|
-
}, 0);
|
|
14
|
-
return {
|
|
15
|
-
maxVertexCount,
|
|
16
|
-
totalVertexCount,
|
|
17
|
-
totalIndexCount,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
mesh.getRoot().listMeshes().forEach(mesh => {
|
|
22
|
-
const info = getMeshInformation(mesh);
|
|
23
|
-
maxVertexCount = Math.max(maxVertexCount, info.maxVertexCount);
|
|
24
|
-
totalVertexCount += info.totalVertexCount;
|
|
25
|
-
totalIndexCount += info.totalIndexCount;
|
|
26
|
-
});
|
|
27
|
-
return {
|
|
28
|
-
maxVertexCount,
|
|
29
|
-
totalVertexCount,
|
|
30
|
-
totalIndexCount,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Calculate the density of a mesh.
|
|
36
|
-
* @param prim - The primitive to calculate the density for.
|
|
37
|
-
* @returns The density of the mesh or -1 if the mesh is not indexed.
|
|
38
|
-
*/
|
|
39
|
-
export function calculateMeshDensity(prim) {
|
|
40
|
-
const bounds = {
|
|
41
|
-
min: [Infinity, Infinity, Infinity],
|
|
42
|
-
max: [-Infinity, -Infinity, -Infinity],
|
|
43
|
-
};
|
|
44
|
-
const position = prim.getAttribute('POSITION');
|
|
45
|
-
if (!position)
|
|
46
|
-
return -1;
|
|
47
|
-
let tempVec3 = [0, 0, 0];
|
|
48
|
-
for (let i = 0; i < position.getCount(); i++) {
|
|
49
|
-
tempVec3 = position.getElement(i, tempVec3);
|
|
50
|
-
expandBounds(tempVec3, bounds);
|
|
51
|
-
}
|
|
52
|
-
const indices = prim.getIndices();
|
|
53
|
-
let area = 0;
|
|
54
|
-
if (indices) {
|
|
55
|
-
// calculate surface area
|
|
56
|
-
const numIndices = indices.getCount();
|
|
57
|
-
const indexArray = indices.getArray();
|
|
58
|
-
const v0 = [0, 0, 0];
|
|
59
|
-
const v1 = [0, 0, 0];
|
|
60
|
-
const v2 = [0, 0, 0];
|
|
61
|
-
const e1 = [0, 0, 0];
|
|
62
|
-
const e2 = [0, 0, 0];
|
|
63
|
-
const boundSizeX = bounds.max[0] - bounds.min[0];
|
|
64
|
-
const boundSizeY = bounds.max[1] - bounds.min[1];
|
|
65
|
-
const boundSizeZ = bounds.max[2] - bounds.min[2];
|
|
66
|
-
const maxBounds = Math.max(boundSizeX, boundSizeY, boundSizeZ);
|
|
67
|
-
for (let i = 0; i < numIndices; i += 3) {
|
|
68
|
-
const i0 = indexArray[i + 0];
|
|
69
|
-
const i1 = indexArray[i + 1];
|
|
70
|
-
const i2 = indexArray[i + 2];
|
|
71
|
-
position.getElement(i0, v0);
|
|
72
|
-
position.getElement(i1, v1);
|
|
73
|
-
position.getElement(i2, v2);
|
|
74
|
-
e1[0] = v1[0] - v0[0];
|
|
75
|
-
e1[1] = v1[1] - v0[1];
|
|
76
|
-
e1[2] = v1[2] - v0[2];
|
|
77
|
-
e2[0] = v2[0] - v0[0];
|
|
78
|
-
e2[1] = v2[1] - v0[1];
|
|
79
|
-
e2[2] = v2[2] - v0[2];
|
|
80
|
-
// Normalize vertex distance in mesh bounds
|
|
81
|
-
e1[0] /= maxBounds;
|
|
82
|
-
e1[1] /= maxBounds;
|
|
83
|
-
e1[2] /= maxBounds;
|
|
84
|
-
e2[0] /= maxBounds;
|
|
85
|
-
e2[1] /= maxBounds;
|
|
86
|
-
e2[2] /= maxBounds;
|
|
87
|
-
// Cross product to get the area of the triangle
|
|
88
|
-
const cross = [
|
|
89
|
-
e1[1] * e2[2] - e1[2] * e2[1],
|
|
90
|
-
e1[2] * e2[0] - e1[0] * e2[2],
|
|
91
|
-
e1[0] * e2[1] - e1[1] * e2[0]
|
|
92
|
-
];
|
|
93
|
-
// Add the area (half the magnitude of the cross product) to the total
|
|
94
|
-
area += Math.sqrt(cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]) / 2;
|
|
95
|
-
}
|
|
96
|
-
const count = indices.getCount() / 3;
|
|
97
|
-
const density = count / area;
|
|
98
|
-
// const size = [0, 0, 0] as vec3;
|
|
99
|
-
// size[0] = bounds.max[0] - bounds.min[0];
|
|
100
|
-
// size[1] = bounds.max[1] - bounds.min[1];
|
|
101
|
-
// size[2] = bounds.max[2] - bounds.min[2];
|
|
102
|
-
// const volume = size[0] * size[1] * size[2];
|
|
103
|
-
// const density = count / volume;
|
|
104
|
-
return density;
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
// calculate density if the mesh is not indexed
|
|
108
|
-
const count = position.getCount();
|
|
109
|
-
const size = [0, 0, 0];
|
|
110
|
-
size[0] = bounds.max[0] - bounds.min[0];
|
|
111
|
-
size[1] = bounds.max[1] - bounds.min[1];
|
|
112
|
-
size[2] = bounds.max[2] - bounds.min[2];
|
|
113
|
-
const volume = size[0] * size[1] * size[2];
|
|
114
|
-
const density = count / volume;
|
|
115
|
-
return density;
|
|
116
|
-
}
|
|
117
|
-
return -1;
|
|
118
|
-
function expandBounds(point, target) {
|
|
119
|
-
for (let i = 0; i < 3; i++) {
|
|
120
|
-
target.min[i] = Math.min(point[i], target.min[i]);
|
|
121
|
-
target.max[i] = Math.max(point[i], target.max[i]);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
1
|
+
import { Mesh } from "@gltf-transform/core";
|
|
2
|
+
export function getMeshInformation(mesh) {
|
|
3
|
+
let maxVertexCount = 0;
|
|
4
|
+
let totalIndexCount = 0;
|
|
5
|
+
let totalVertexCount = 0;
|
|
6
|
+
if (mesh instanceof Mesh) {
|
|
7
|
+
totalVertexCount = mesh.listPrimitives().reduce((acc, prim) => {
|
|
8
|
+
const indices = prim.getIndices()?.getCount() || 0;
|
|
9
|
+
totalIndexCount += indices;
|
|
10
|
+
const vertices = prim.getAttribute('POSITION')?.getCount() || 0;
|
|
11
|
+
maxVertexCount = Math.max(maxVertexCount, vertices);
|
|
12
|
+
return acc + vertices;
|
|
13
|
+
}, 0);
|
|
14
|
+
return {
|
|
15
|
+
maxVertexCount,
|
|
16
|
+
totalVertexCount,
|
|
17
|
+
totalIndexCount,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
mesh.getRoot().listMeshes().forEach(mesh => {
|
|
22
|
+
const info = getMeshInformation(mesh);
|
|
23
|
+
maxVertexCount = Math.max(maxVertexCount, info.maxVertexCount);
|
|
24
|
+
totalVertexCount += info.totalVertexCount;
|
|
25
|
+
totalIndexCount += info.totalIndexCount;
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
maxVertexCount,
|
|
29
|
+
totalVertexCount,
|
|
30
|
+
totalIndexCount,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Calculate the density of a mesh.
|
|
36
|
+
* @param prim - The primitive to calculate the density for.
|
|
37
|
+
* @returns The density of the mesh or -1 if the mesh is not indexed.
|
|
38
|
+
*/
|
|
39
|
+
export function calculateMeshDensity(prim) {
|
|
40
|
+
const bounds = {
|
|
41
|
+
min: [Infinity, Infinity, Infinity],
|
|
42
|
+
max: [-Infinity, -Infinity, -Infinity],
|
|
43
|
+
};
|
|
44
|
+
const position = prim.getAttribute('POSITION');
|
|
45
|
+
if (!position)
|
|
46
|
+
return -1;
|
|
47
|
+
let tempVec3 = [0, 0, 0];
|
|
48
|
+
for (let i = 0; i < position.getCount(); i++) {
|
|
49
|
+
tempVec3 = position.getElement(i, tempVec3);
|
|
50
|
+
expandBounds(tempVec3, bounds);
|
|
51
|
+
}
|
|
52
|
+
const indices = prim.getIndices();
|
|
53
|
+
let area = 0;
|
|
54
|
+
if (indices) {
|
|
55
|
+
// calculate surface area
|
|
56
|
+
const numIndices = indices.getCount();
|
|
57
|
+
const indexArray = indices.getArray();
|
|
58
|
+
const v0 = [0, 0, 0];
|
|
59
|
+
const v1 = [0, 0, 0];
|
|
60
|
+
const v2 = [0, 0, 0];
|
|
61
|
+
const e1 = [0, 0, 0];
|
|
62
|
+
const e2 = [0, 0, 0];
|
|
63
|
+
const boundSizeX = bounds.max[0] - bounds.min[0];
|
|
64
|
+
const boundSizeY = bounds.max[1] - bounds.min[1];
|
|
65
|
+
const boundSizeZ = bounds.max[2] - bounds.min[2];
|
|
66
|
+
const maxBounds = Math.max(boundSizeX, boundSizeY, boundSizeZ);
|
|
67
|
+
for (let i = 0; i < numIndices; i += 3) {
|
|
68
|
+
const i0 = indexArray[i + 0];
|
|
69
|
+
const i1 = indexArray[i + 1];
|
|
70
|
+
const i2 = indexArray[i + 2];
|
|
71
|
+
position.getElement(i0, v0);
|
|
72
|
+
position.getElement(i1, v1);
|
|
73
|
+
position.getElement(i2, v2);
|
|
74
|
+
e1[0] = v1[0] - v0[0];
|
|
75
|
+
e1[1] = v1[1] - v0[1];
|
|
76
|
+
e1[2] = v1[2] - v0[2];
|
|
77
|
+
e2[0] = v2[0] - v0[0];
|
|
78
|
+
e2[1] = v2[1] - v0[1];
|
|
79
|
+
e2[2] = v2[2] - v0[2];
|
|
80
|
+
// Normalize vertex distance in mesh bounds
|
|
81
|
+
e1[0] /= maxBounds;
|
|
82
|
+
e1[1] /= maxBounds;
|
|
83
|
+
e1[2] /= maxBounds;
|
|
84
|
+
e2[0] /= maxBounds;
|
|
85
|
+
e2[1] /= maxBounds;
|
|
86
|
+
e2[2] /= maxBounds;
|
|
87
|
+
// Cross product to get the area of the triangle
|
|
88
|
+
const cross = [
|
|
89
|
+
e1[1] * e2[2] - e1[2] * e2[1],
|
|
90
|
+
e1[2] * e2[0] - e1[0] * e2[2],
|
|
91
|
+
e1[0] * e2[1] - e1[1] * e2[0]
|
|
92
|
+
];
|
|
93
|
+
// Add the area (half the magnitude of the cross product) to the total
|
|
94
|
+
area += Math.sqrt(cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]) / 2;
|
|
95
|
+
}
|
|
96
|
+
const count = indices.getCount() / 3;
|
|
97
|
+
const density = count / area;
|
|
98
|
+
// const size = [0, 0, 0] as vec3;
|
|
99
|
+
// size[0] = bounds.max[0] - bounds.min[0];
|
|
100
|
+
// size[1] = bounds.max[1] - bounds.min[1];
|
|
101
|
+
// size[2] = bounds.max[2] - bounds.min[2];
|
|
102
|
+
// const volume = size[0] * size[1] * size[2];
|
|
103
|
+
// const density = count / volume;
|
|
104
|
+
return density;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// calculate density if the mesh is not indexed
|
|
108
|
+
const count = position.getCount();
|
|
109
|
+
const size = [0, 0, 0];
|
|
110
|
+
size[0] = bounds.max[0] - bounds.min[0];
|
|
111
|
+
size[1] = bounds.max[1] - bounds.min[1];
|
|
112
|
+
size[2] = bounds.max[2] - bounds.min[2];
|
|
113
|
+
const volume = size[0] * size[1] * size[2];
|
|
114
|
+
const density = count / volume;
|
|
115
|
+
return density;
|
|
116
|
+
}
|
|
117
|
+
return -1;
|
|
118
|
+
function expandBounds(point, target) {
|
|
119
|
+
for (let i = 0; i < 3; i++) {
|
|
120
|
+
target.min[i] = Math.min(point[i], target.min[i]);
|
|
121
|
+
target.max[i] = Math.max(point[i], target.max[i]);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
package/dist/utils/nodeio.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { NodeIO, Document, PlatformIO } from "@gltf-transform/core";
|
|
2
|
-
/**
|
|
3
|
-
* Handle writing glTf, GLB and VRM files
|
|
4
|
-
*/
|
|
5
|
-
export declare function writeNodeIO(nodeio: NodeIO, filename: string, document: Document): Promise<string>;
|
|
6
|
-
export declare function ioTryReadWithMissingResources(io: PlatformIO, filepath: string, iteration?: number): Promise<Document>;
|
|
1
|
+
import { NodeIO, Document, PlatformIO } from "@gltf-transform/core";
|
|
2
|
+
/**
|
|
3
|
+
* Handle writing glTf, GLB and VRM files
|
|
4
|
+
*/
|
|
5
|
+
export declare function writeNodeIO(nodeio: NodeIO, filename: string, document: Document): Promise<string>;
|
|
6
|
+
export declare function ioTryReadWithMissingResources(io: PlatformIO, filepath: string, iteration?: number): Promise<Document>;
|
package/dist/utils/nodeio.js
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
import { existsSync, mkdirSync } from "fs";
|
|
2
|
-
import { writeFile } from "fs/promises";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import sharp from "sharp";
|
|
5
|
-
/**
|
|
6
|
-
* Handle writing glTf, GLB and VRM files
|
|
7
|
-
*/
|
|
8
|
-
export async function writeNodeIO(nodeio, filename, document) {
|
|
9
|
-
const directoryPath = path.dirname(filename);
|
|
10
|
-
if (!existsSync(directoryPath)) {
|
|
11
|
-
mkdirSync(directoryPath);
|
|
12
|
-
}
|
|
13
|
-
// see https://github.com/donmccurdy/glTF-Transform/issues/1390
|
|
14
|
-
if (filename.endsWith(".vrm")) {
|
|
15
|
-
const bin = await nodeio.writeBinary(document);
|
|
16
|
-
await writeFile(filename, bin);
|
|
17
|
-
}
|
|
18
|
-
else
|
|
19
|
-
await nodeio.write(filename, document);
|
|
20
|
-
return filename;
|
|
21
|
-
}
|
|
22
|
-
const openFileRegex = /open \'(?<path>.+?)'/;
|
|
23
|
-
const createdFiles = new Set();
|
|
24
|
-
export async function ioTryReadWithMissingResources(io, filepath, iteration = 0) {
|
|
25
|
-
const document = await io.read(filepath)
|
|
26
|
-
.catch(err => { return err; });
|
|
27
|
-
if (document instanceof Error) {
|
|
28
|
-
const err = document;
|
|
29
|
-
// Handle glTF files where resource are missing
|
|
30
|
-
if (iteration < 100 && err.message?.includes("ENOENT")) {
|
|
31
|
-
try {
|
|
32
|
-
const match = err.message.match(openFileRegex);
|
|
33
|
-
if (match.groups?.path) {
|
|
34
|
-
let missingPath = match.groups.path;
|
|
35
|
-
// check if it's an URL
|
|
36
|
-
if (missingPath.startsWith("http")) {
|
|
37
|
-
throw err;
|
|
38
|
-
}
|
|
39
|
-
if (createdFiles.has(missingPath)) {
|
|
40
|
-
throw err;
|
|
41
|
-
}
|
|
42
|
-
createdFiles.add(missingPath);
|
|
43
|
-
console.warn(`Creating empty file for missing resource: ${missingPath}`);
|
|
44
|
-
const ext = missingPath.split('.').pop();
|
|
45
|
-
if (!ext) {
|
|
46
|
-
console.warn(`Could not determine extension for ${missingPath}`);
|
|
47
|
-
throw err;
|
|
48
|
-
}
|
|
49
|
-
const extLower = ext?.toLowerCase();
|
|
50
|
-
let retry = false;
|
|
51
|
-
// https://sharp.pixelplumbing.com/api-output#tofile
|
|
52
|
-
switch (extLower) {
|
|
53
|
-
case "jpeg":
|
|
54
|
-
case "jpg":
|
|
55
|
-
case "png":
|
|
56
|
-
case "webp":
|
|
57
|
-
case "tiff":
|
|
58
|
-
case "gif":
|
|
59
|
-
{
|
|
60
|
-
await sharp({
|
|
61
|
-
create: {
|
|
62
|
-
width: 64,
|
|
63
|
-
height: 64,
|
|
64
|
-
channels: 4,
|
|
65
|
-
background: { r: 255, g: 255, b: 255, alpha: 1 }
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
|
-
.toFormat(ext)
|
|
69
|
-
.toFile(missingPath);
|
|
70
|
-
retry = true;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (retry) {
|
|
74
|
-
console.warn(`Created empty file for missing resource: ${missingPath}`);
|
|
75
|
-
return ioTryReadWithMissingResources(io, filepath, iteration + 1);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
catch (internal_error) {
|
|
80
|
-
console.warn(internal_error);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
throw err;
|
|
84
|
-
}
|
|
85
|
-
return document;
|
|
86
|
-
}
|
|
1
|
+
import { existsSync, mkdirSync } from "fs";
|
|
2
|
+
import { writeFile } from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import sharp from "sharp";
|
|
5
|
+
/**
|
|
6
|
+
* Handle writing glTf, GLB and VRM files
|
|
7
|
+
*/
|
|
8
|
+
export async function writeNodeIO(nodeio, filename, document) {
|
|
9
|
+
const directoryPath = path.dirname(filename);
|
|
10
|
+
if (!existsSync(directoryPath)) {
|
|
11
|
+
mkdirSync(directoryPath);
|
|
12
|
+
}
|
|
13
|
+
// see https://github.com/donmccurdy/glTF-Transform/issues/1390
|
|
14
|
+
if (filename.endsWith(".vrm")) {
|
|
15
|
+
const bin = await nodeio.writeBinary(document);
|
|
16
|
+
await writeFile(filename, bin);
|
|
17
|
+
}
|
|
18
|
+
else
|
|
19
|
+
await nodeio.write(filename, document);
|
|
20
|
+
return filename;
|
|
21
|
+
}
|
|
22
|
+
const openFileRegex = /open \'(?<path>.+?)'/;
|
|
23
|
+
const createdFiles = new Set();
|
|
24
|
+
export async function ioTryReadWithMissingResources(io, filepath, iteration = 0) {
|
|
25
|
+
const document = await io.read(filepath)
|
|
26
|
+
.catch(err => { return err; });
|
|
27
|
+
if (document instanceof Error) {
|
|
28
|
+
const err = document;
|
|
29
|
+
// Handle glTF files where resource are missing
|
|
30
|
+
if (iteration < 100 && err.message?.includes("ENOENT")) {
|
|
31
|
+
try {
|
|
32
|
+
const match = err.message.match(openFileRegex);
|
|
33
|
+
if (match.groups?.path) {
|
|
34
|
+
let missingPath = match.groups.path;
|
|
35
|
+
// check if it's an URL
|
|
36
|
+
if (missingPath.startsWith("http")) {
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
if (createdFiles.has(missingPath)) {
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
createdFiles.add(missingPath);
|
|
43
|
+
console.warn(`Creating empty file for missing resource: ${missingPath}`);
|
|
44
|
+
const ext = missingPath.split('.').pop();
|
|
45
|
+
if (!ext) {
|
|
46
|
+
console.warn(`Could not determine extension for ${missingPath}`);
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
const extLower = ext?.toLowerCase();
|
|
50
|
+
let retry = false;
|
|
51
|
+
// https://sharp.pixelplumbing.com/api-output#tofile
|
|
52
|
+
switch (extLower) {
|
|
53
|
+
case "jpeg":
|
|
54
|
+
case "jpg":
|
|
55
|
+
case "png":
|
|
56
|
+
case "webp":
|
|
57
|
+
case "tiff":
|
|
58
|
+
case "gif":
|
|
59
|
+
{
|
|
60
|
+
await sharp({
|
|
61
|
+
create: {
|
|
62
|
+
width: 64,
|
|
63
|
+
height: 64,
|
|
64
|
+
channels: 4,
|
|
65
|
+
background: { r: 255, g: 255, b: 255, alpha: 1 }
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
.toFormat(ext)
|
|
69
|
+
.toFile(missingPath);
|
|
70
|
+
retry = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (retry) {
|
|
74
|
+
console.warn(`Created empty file for missing resource: ${missingPath}`);
|
|
75
|
+
return ioTryReadWithMissingResources(io, filepath, iteration + 1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (internal_error) {
|
|
80
|
+
console.warn(internal_error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
return document;
|
|
86
|
+
}
|
package/dist/utils/stats.d.ts
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
import { Logger } from "@donmccurdy/caporal";
|
|
2
|
-
import { Document, JSONDocument, Logger as _Logger } from "@gltf-transform/core";
|
|
3
|
-
import { Config } from "../config/index.js";
|
|
4
|
-
export type ProcessStats = {
|
|
5
|
-
startTime: number;
|
|
6
|
-
totalGPUMemoryInMB: number;
|
|
7
|
-
totalFilesProcessed: number;
|
|
8
|
-
totalFileSizeInMB: number;
|
|
9
|
-
totalFileSizeInMBBefore: number;
|
|
10
|
-
};
|
|
11
|
-
export declare function printStats(stats: ProcessStats, logger: Logger | _Logger, config: Config): void;
|
|
12
|
-
declare class Stats {
|
|
13
|
-
/** Size in bytes */
|
|
14
|
-
size: number;
|
|
15
|
-
asset: {
|
|
16
|
-
version: string;
|
|
17
|
-
generator?: string;
|
|
18
|
-
copyright?: string;
|
|
19
|
-
extras: any;
|
|
20
|
-
};
|
|
21
|
-
json: JSONDocumentInfo;
|
|
22
|
-
nodes: number;
|
|
23
|
-
materials: number;
|
|
24
|
-
meshes: MeshInfo;
|
|
25
|
-
textures: TextureInfo;
|
|
26
|
-
animations: AnimationInfo;
|
|
27
|
-
constructor(document: Document, json: JSONDocument | null, size: number);
|
|
28
|
-
static combine(others: Stats[], type?: "main" | "lods"): Stats | null;
|
|
29
|
-
}
|
|
30
|
-
export declare class FileStats extends Stats {
|
|
31
|
-
readonly filename: string;
|
|
32
|
-
readonly isLOD: boolean;
|
|
33
|
-
constructor(file: string, document: Document, json: JSONDocument);
|
|
34
|
-
}
|
|
35
|
-
export declare class MeshInfo {
|
|
36
|
-
count: number;
|
|
37
|
-
primitives: number;
|
|
38
|
-
vertices: number;
|
|
39
|
-
triangles: number;
|
|
40
|
-
memory: number;
|
|
41
|
-
formats: string[];
|
|
42
|
-
errors?: string[];
|
|
43
|
-
warnings?: string[];
|
|
44
|
-
addFrom(other: MeshInfo): void;
|
|
45
|
-
}
|
|
46
|
-
export declare class TextureInfo {
|
|
47
|
-
count: number;
|
|
48
|
-
memory: number;
|
|
49
|
-
gpu_memory: number;
|
|
50
|
-
formats: string[];
|
|
51
|
-
errors?: string[];
|
|
52
|
-
warnings?: string[];
|
|
53
|
-
addFrom(other: TextureInfo): void;
|
|
54
|
-
}
|
|
55
|
-
export declare class AnimationInfo {
|
|
56
|
-
count: number;
|
|
57
|
-
size: number;
|
|
58
|
-
channels: number;
|
|
59
|
-
addFrom(other: AnimationInfo): void;
|
|
60
|
-
}
|
|
61
|
-
export declare class JSONDocumentInfo {
|
|
62
|
-
size: number;
|
|
63
|
-
addFrom(other: JSONDocumentInfo): void;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Create a new filestats object from a file and a document
|
|
67
|
-
*/
|
|
68
|
-
export declare function createNewFilestats(file: string, document: Document, jsonDocument: JSONDocument): FileStats;
|
|
69
|
-
export declare function writeFileStatsToFile(filestats: FileStats[], output_path: string): string | null;
|
|
70
|
-
export {};
|
|
1
|
+
import { Logger } from "@donmccurdy/caporal";
|
|
2
|
+
import { Document, JSONDocument, Logger as _Logger } from "@gltf-transform/core";
|
|
3
|
+
import { Config } from "../config/index.js";
|
|
4
|
+
export type ProcessStats = {
|
|
5
|
+
startTime: number;
|
|
6
|
+
totalGPUMemoryInMB: number;
|
|
7
|
+
totalFilesProcessed: number;
|
|
8
|
+
totalFileSizeInMB: number;
|
|
9
|
+
totalFileSizeInMBBefore: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function printStats(stats: ProcessStats, logger: Logger | _Logger, config: Config): void;
|
|
12
|
+
declare class Stats {
|
|
13
|
+
/** Size in bytes */
|
|
14
|
+
size: number;
|
|
15
|
+
asset: {
|
|
16
|
+
version: string;
|
|
17
|
+
generator?: string;
|
|
18
|
+
copyright?: string;
|
|
19
|
+
extras: any;
|
|
20
|
+
};
|
|
21
|
+
json: JSONDocumentInfo;
|
|
22
|
+
nodes: number;
|
|
23
|
+
materials: number;
|
|
24
|
+
meshes: MeshInfo;
|
|
25
|
+
textures: TextureInfo;
|
|
26
|
+
animations: AnimationInfo;
|
|
27
|
+
constructor(document: Document, json: JSONDocument | null, size: number);
|
|
28
|
+
static combine(others: Stats[], type?: "main" | "lods"): Stats | null;
|
|
29
|
+
}
|
|
30
|
+
export declare class FileStats extends Stats {
|
|
31
|
+
readonly filename: string;
|
|
32
|
+
readonly isLOD: boolean;
|
|
33
|
+
constructor(file: string, document: Document, json: JSONDocument);
|
|
34
|
+
}
|
|
35
|
+
export declare class MeshInfo {
|
|
36
|
+
count: number;
|
|
37
|
+
primitives: number;
|
|
38
|
+
vertices: number;
|
|
39
|
+
triangles: number;
|
|
40
|
+
memory: number;
|
|
41
|
+
formats: string[];
|
|
42
|
+
errors?: string[];
|
|
43
|
+
warnings?: string[];
|
|
44
|
+
addFrom(other: MeshInfo): void;
|
|
45
|
+
}
|
|
46
|
+
export declare class TextureInfo {
|
|
47
|
+
count: number;
|
|
48
|
+
memory: number;
|
|
49
|
+
gpu_memory: number;
|
|
50
|
+
formats: string[];
|
|
51
|
+
errors?: string[];
|
|
52
|
+
warnings?: string[];
|
|
53
|
+
addFrom(other: TextureInfo): void;
|
|
54
|
+
}
|
|
55
|
+
export declare class AnimationInfo {
|
|
56
|
+
count: number;
|
|
57
|
+
size: number;
|
|
58
|
+
channels: number;
|
|
59
|
+
addFrom(other: AnimationInfo): void;
|
|
60
|
+
}
|
|
61
|
+
export declare class JSONDocumentInfo {
|
|
62
|
+
size: number;
|
|
63
|
+
addFrom(other: JSONDocumentInfo): void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create a new filestats object from a file and a document
|
|
67
|
+
*/
|
|
68
|
+
export declare function createNewFilestats(file: string, document: Document, jsonDocument: JSONDocument): FileStats;
|
|
69
|
+
export declare function writeFileStatsToFile(filestats: FileStats[], output_path: string): string | null;
|
|
70
|
+
export {};
|