@holoscript/core 6.0.4 → 7.0.0
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/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/compiler/index.d.ts +82 -0
- package/dist/constants.d.ts +3 -2
- package/dist/coordinators/index.d.ts +189 -0
- package/dist/index.d.ts +501 -19
- package/dist/paper-0c-spike/index.d.ts +29 -0
- package/dist/reconstruction/index.d.ts +78 -0
- package/dist/tools/index.d.ts +22 -1
- package/dist/traitDocs/traitDocs.d.ts +69 -0
- package/dist/traits/index.d.ts +61 -0
- package/package.json +105 -57
- package/dist/GLTFPipeline-DEN36VNK.js +0 -12
- package/dist/GLTFPipeline-YPCAK236.cjs +0 -33
- package/dist/HoloScriptPlusParser-BN6KVRCM.js +0 -692
- package/dist/HoloScriptPlusParser-NC5FE6AL.cjs +0 -697
- package/dist/USDZExporter-NTMBNTDB.js +0 -707
- package/dist/USDZExporter-UWGWNMMD.cjs +0 -709
- package/dist/chunk-27LWW5FU.cjs +0 -410
- package/dist/chunk-2CWOLHTE.js +0 -69
- package/dist/chunk-33LSUQDD.cjs +0 -835
- package/dist/chunk-3FJCK5XA.js +0 -2232
- package/dist/chunk-3FXV5S25.cjs +0 -633
- package/dist/chunk-3FYZOR7S.cjs +0 -69
- package/dist/chunk-3SAK5KFL.cjs +0 -83
- package/dist/chunk-4XSNJCLC.cjs +0 -1859
- package/dist/chunk-54FHG2MX.js +0 -655
- package/dist/chunk-56IF4NTA.js +0 -56
- package/dist/chunk-5BGSECRJ.cjs +0 -2237
- package/dist/chunk-5GLCTO44.js +0 -161
- package/dist/chunk-5O6TQC6M.cjs +0 -1871
- package/dist/chunk-5OEOHAAW.cjs +0 -682
- package/dist/chunk-5TOFIR6L.js +0 -407
- package/dist/chunk-5WUNN6ZN.cjs +0 -428
- package/dist/chunk-6TZPZCOJ.cjs +0 -1404
- package/dist/chunk-6UEHYZ7V.cjs +0 -773
- package/dist/chunk-6XSERL6L.js +0 -5678
- package/dist/chunk-72EQECGT.cjs +0 -908
- package/dist/chunk-7AGYRWKW.cjs +0 -507
- package/dist/chunk-7LCYLPW2.cjs +0 -663
- package/dist/chunk-A7PIMZGU.js +0 -263
- package/dist/chunk-ATSKSYVE.cjs +0 -51683
- package/dist/chunk-B5TCIAPQ.cjs +0 -117
- package/dist/chunk-BF2235SI.cjs +0 -5714
- package/dist/chunk-BKIGPPVM.js +0 -629
- package/dist/chunk-BND3ST2K.cjs +0 -662
- package/dist/chunk-BU7VWW2K.js +0 -2522
- package/dist/chunk-BWFJEM5A.js +0 -5419
- package/dist/chunk-CAUCGUEA.cjs +0 -130
- package/dist/chunk-CBJSLA2E.cjs +0 -5423
- package/dist/chunk-CDPGV4DN.js +0 -114
- package/dist/chunk-CLYEIWA5.cjs +0 -408
- package/dist/chunk-CS2EMTGF.js +0 -1966
- package/dist/chunk-DMG7C4H2.js +0 -975
- package/dist/chunk-DXJQDCFL.js +0 -468
- package/dist/chunk-E3FWRT3Z.js +0 -608
- package/dist/chunk-E3UALNFA.js +0 -421
- package/dist/chunk-EONILVMF.js +0 -762
- package/dist/chunk-EQV4R3EV.cjs +0 -769
- package/dist/chunk-F3HH56EB.cjs +0 -5538
- package/dist/chunk-F4IULT7N.js +0 -1488
- package/dist/chunk-FF3Q7ADR.js +0 -380
- package/dist/chunk-FFKU7BTK.cjs +0 -1046
- package/dist/chunk-FHQVYCH2.js +0 -70
- package/dist/chunk-FSF7EQVA.cjs +0 -1974
- package/dist/chunk-G4VZTCIB.js +0 -659
- package/dist/chunk-G7CT3EMP.cjs +0 -1002
- package/dist/chunk-GGHSW2NN.js +0 -51334
- package/dist/chunk-GVUR45UF.cjs +0 -777
- package/dist/chunk-H5Z7NASB.js +0 -9662
- package/dist/chunk-HE7ULERA.cjs +0 -697
- package/dist/chunk-HJJLD366.js +0 -1169
- package/dist/chunk-HPS76H7Q.js +0 -309
- package/dist/chunk-HQUEA5R6.cjs +0 -424
- package/dist/chunk-HYNTS5CP.js +0 -422
- package/dist/chunk-I6XZ5DZF.cjs +0 -488
- package/dist/chunk-IBDG74G2.cjs +0 -1219
- package/dist/chunk-IFNQFCTM.js +0 -3098
- package/dist/chunk-IHOUYQIA.js +0 -406
- package/dist/chunk-ILRBGFVD.cjs +0 -72
- package/dist/chunk-IWI6J7FX.js +0 -421
- package/dist/chunk-K3JDKWGI.cjs +0 -270
- package/dist/chunk-K6EKD26I.js +0 -630
- package/dist/chunk-KCQ5NDYC.cjs +0 -3172
- package/dist/chunk-KED34ILP.js +0 -832
- package/dist/chunk-KSGXLT74.cjs +0 -457
- package/dist/chunk-L4G4RLXX.js +0 -767
- package/dist/chunk-LDP5OK6G.js +0 -1216
- package/dist/chunk-LGGRPKTV.cjs +0 -735
- package/dist/chunk-LK5IAVH6.cjs +0 -1173
- package/dist/chunk-LSW7P7ML.js +0 -3675
- package/dist/chunk-LXJ4667L.cjs +0 -3874
- package/dist/chunk-LZ266PCM.cjs +0 -4499
- package/dist/chunk-MD6KDHVE.cjs +0 -237
- package/dist/chunk-MEASWI2Y.js +0 -126
- package/dist/chunk-MPXBVFHQ.js +0 -768
- package/dist/chunk-N5FTS757.cjs +0 -415
- package/dist/chunk-NCUKG4SK.cjs +0 -3075
- package/dist/chunk-NDQNIJEH.js +0 -1715
- package/dist/chunk-NOZZ46QU.js +0 -168
- package/dist/chunk-OFKWH2IP.js +0 -449
- package/dist/chunk-PHENW4MQ.js +0 -65
- package/dist/chunk-PMGODDJA.cjs +0 -319
- package/dist/chunk-Q4QX3AET.cjs +0 -1505
- package/dist/chunk-Q56TT7IL.js +0 -483
- package/dist/chunk-Q5JT3YML.cjs +0 -129
- package/dist/chunk-Q5SJOGHQ.cjs +0 -4256
- package/dist/chunk-QGKNANZ3.js +0 -3071
- package/dist/chunk-QLEAOI3Q.cjs +0 -424
- package/dist/chunk-R7MA7QWV.js +0 -732
- package/dist/chunk-RVYPEYPX.js +0 -678
- package/dist/chunk-S2N5TNMA.js +0 -1855
- package/dist/chunk-S565K7NK.js +0 -752
- package/dist/chunk-SDAMZIRE.js +0 -765
- package/dist/chunk-T36DDXSF.js +0 -4250
- package/dist/chunk-T4NKMBDL.js +0 -5474
- package/dist/chunk-T7LEXZUZ.cjs +0 -2526
- package/dist/chunk-TEWCN33Y.js +0 -694
- package/dist/chunk-TQSZUOW5.cjs +0 -793
- package/dist/chunk-TSH3MSQU.cjs +0 -129
- package/dist/chunk-UERJ3YJV.js +0 -504
- package/dist/chunk-UPJBDCVF.js +0 -1395
- package/dist/chunk-V3NN3HPP.js +0 -4462
- package/dist/chunk-VJ3L7CHT.cjs +0 -169
- package/dist/chunk-WB4Z63GG.js +0 -229
- package/dist/chunk-WDW67DZB.cjs +0 -9728
- package/dist/chunk-WGMEAYBG.js +0 -126
- package/dist/chunk-X4ZF6CNE.cjs +0 -473
- package/dist/chunk-X6SEAXAX.cjs +0 -3681
- package/dist/chunk-XCWFGZAA.js +0 -1043
- package/dist/chunk-XD6IYDUX.js +0 -903
- package/dist/chunk-XG23EUQX.cjs +0 -1717
- package/dist/chunk-XRKWN5PL.cjs +0 -173
- package/dist/chunk-XUILI4KB.cjs +0 -430
- package/dist/chunk-XUTX5CBW.js +0 -126
- package/dist/chunk-XWPNTWDN.cjs +0 -755
- package/dist/chunk-XXINBTZK.cjs +0 -633
- package/dist/chunk-YCXFCXDS.js +0 -1868
- package/dist/chunk-YQK5JNFK.js +0 -3725
- package/dist/chunk-YYXH45E2.js +0 -426
- package/dist/chunk-Z34RLXRA.cjs +0 -612
- package/dist/chunk-ZP4D3CSX.cjs +0 -72
- package/dist/cli/holoscript-runner.cjs +0 -2259
- package/dist/cli/holoscript-runner.js +0 -2234
- package/dist/codebase/index.cjs +0 -336
- package/dist/codebase/index.js +0 -331
- package/dist/compiler/agent-inference.cjs +0 -28
- package/dist/compiler/agent-inference.js +0 -5
- package/dist/compiler/android-xr.cjs +0 -19
- package/dist/compiler/android-xr.js +0 -9
- package/dist/compiler/android.cjs +0 -20
- package/dist/compiler/android.js +0 -10
- package/dist/compiler/ar.cjs +0 -20
- package/dist/compiler/ar.js +0 -8
- package/dist/compiler/babylon.cjs +0 -17
- package/dist/compiler/babylon.js +0 -11
- package/dist/compiler/coco.cjs +0 -27
- package/dist/compiler/coco.js +0 -4
- package/dist/compiler/domain-block-utils.cjs +0 -602
- package/dist/compiler/domain-block-utils.js +0 -8
- package/dist/compiler/dtdl.cjs +0 -24
- package/dist/compiler/dtdl.js +0 -8
- package/dist/compiler/gltf-pipeline.cjs +0 -39
- package/dist/compiler/gltf-pipeline.js +0 -4
- package/dist/compiler/godot.cjs +0 -15
- package/dist/compiler/godot.js +0 -9
- package/dist/compiler/incremental.cjs +0 -29
- package/dist/compiler/incremental.js +0 -4
- package/dist/compiler/index.cjs +0 -2578
- package/dist/compiler/index.js +0 -2383
- package/dist/compiler/ios.cjs +0 -20
- package/dist/compiler/ios.js +0 -10
- package/dist/compiler/multi-layer.cjs +0 -20
- package/dist/compiler/multi-layer.js +0 -11
- package/dist/compiler/nodetoy.cjs +0 -23
- package/dist/compiler/nodetoy.js +0 -4
- package/dist/compiler/openxr.cjs +0 -15
- package/dist/compiler/openxr.js +0 -9
- package/dist/compiler/playcanvas.cjs +0 -16
- package/dist/compiler/playcanvas.js +0 -10
- package/dist/compiler/r3f.cjs +0 -34
- package/dist/compiler/r3f.js +0 -12
- package/dist/compiler/remotion.cjs +0 -23
- package/dist/compiler/remotion.js +0 -4
- package/dist/compiler/reproducibility.cjs +0 -39
- package/dist/compiler/reproducibility.js +0 -4
- package/dist/compiler/sdf.cjs +0 -21
- package/dist/compiler/sdf.js +0 -9
- package/dist/compiler/semantic-scene.cjs +0 -31
- package/dist/compiler/semantic-scene.js +0 -4
- package/dist/compiler/state.cjs +0 -17
- package/dist/compiler/state.js +0 -7
- package/dist/compiler/trait-composition.cjs +0 -26
- package/dist/compiler/trait-composition.js +0 -5
- package/dist/compiler/unity.cjs +0 -15
- package/dist/compiler/unity.js +0 -9
- package/dist/compiler/unreal.cjs +0 -19
- package/dist/compiler/unreal.js +0 -9
- package/dist/compiler/urdf.cjs +0 -45
- package/dist/compiler/urdf.js +0 -9
- package/dist/compiler/usd-physics.cjs +0 -23
- package/dist/compiler/usd-physics.js +0 -6
- package/dist/compiler/visionos.cjs +0 -15
- package/dist/compiler/visionos.js +0 -9
- package/dist/compiler/vrchat.cjs +0 -19
- package/dist/compiler/vrchat.js +0 -9
- package/dist/compiler/vrr.cjs +0 -21
- package/dist/compiler/vrr.js +0 -9
- package/dist/compiler/wasm.cjs +0 -33
- package/dist/compiler/wasm.js +0 -9
- package/dist/compiler/webgpu.cjs +0 -15
- package/dist/compiler/webgpu.js +0 -9
- package/dist/debugger.cjs +0 -21
- package/dist/debugger.js +0 -8
- package/dist/entries/interop.cjs +0 -62
- package/dist/entries/interop.js +0 -5
- package/dist/entries/scripting.cjs +0 -68
- package/dist/entries/scripting.js +0 -11
- package/dist/index.cjs +0 -40921
- package/dist/index.js +0 -37763
- package/dist/math/vec3.cjs +0 -57
- package/dist/math/vec3.js +0 -4
- package/dist/ml-dsa-PHCWUBPX.cjs +0 -1178
- package/dist/ml-dsa-WYLJHJO6.js +0 -1178
- package/dist/parser.cjs +0 -27
- package/dist/parser.js +0 -10
- package/dist/playwright-5OSAPTNH.js +0 -98660
- package/dist/playwright-RL6GY4F7.cjs +0 -98673
- package/dist/runtime.cjs +0 -16
- package/dist/runtime.js +0 -7
- package/dist/storage/index.cjs +0 -37
- package/dist/storage/index.js +0 -4
- package/dist/traits/index.cjs +0 -14649
- package/dist/traits/index.js +0 -12243
- package/dist/type-checker.cjs +0 -18
- package/dist/type-checker.js +0 -5
package/dist/chunk-5BGSECRJ.cjs
DELETED
|
@@ -1,2237 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunkLK5IAVH6_cjs = require('./chunk-LK5IAVH6.cjs');
|
|
4
|
-
var chunkQ5SJOGHQ_cjs = require('./chunk-Q5SJOGHQ.cjs');
|
|
5
|
-
var chunkX4ZF6CNE_cjs = require('./chunk-X4ZF6CNE.cjs');
|
|
6
|
-
var chunkLXJ4667L_cjs = require('./chunk-LXJ4667L.cjs');
|
|
7
|
-
var chunkBF2235SI_cjs = require('./chunk-BF2235SI.cjs');
|
|
8
|
-
var platform = require('@holoscript/platform');
|
|
9
|
-
|
|
10
|
-
// src/compiler/GLTFPipeline.ts
|
|
11
|
-
chunkX4ZF6CNE_cjs.init_TraitCompositor();
|
|
12
|
-
chunkQ5SJOGHQ_cjs.init_R3FCompiler();
|
|
13
|
-
chunkBF2235SI_cjs.init_CompilerBase();
|
|
14
|
-
chunkLXJ4667L_cjs.init_DomainBlockCompilerMixin();
|
|
15
|
-
|
|
16
|
-
// src/compiler/gltf/extensions.ts
|
|
17
|
-
function createEmissiveStrengthExtension(strength) {
|
|
18
|
-
return {
|
|
19
|
-
KHR_materials_emissive_strength: {
|
|
20
|
-
emissiveStrength: Math.max(0, strength)
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function createClearcoatExtension(options) {
|
|
25
|
-
return {
|
|
26
|
-
KHR_materials_clearcoat: {
|
|
27
|
-
clearcoatFactor: options.factor ?? 1,
|
|
28
|
-
clearcoatRoughnessFactor: options.roughness ?? 0
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
function createTransmissionExtension(factor) {
|
|
33
|
-
return {
|
|
34
|
-
KHR_materials_transmission: {
|
|
35
|
-
transmissionFactor: Math.max(0, Math.min(1, factor))
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
function createIORExtension(ior) {
|
|
40
|
-
return {
|
|
41
|
-
KHR_materials_ior: {
|
|
42
|
-
ior: Math.max(1, ior)
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
function createSheenExtension(options) {
|
|
47
|
-
return {
|
|
48
|
-
KHR_materials_sheen: {
|
|
49
|
-
sheenColorFactor: options.color ?? [1, 1, 1],
|
|
50
|
-
sheenRoughnessFactor: options.roughness ?? 0.5
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function createAnisotropyExtension(options) {
|
|
55
|
-
return {
|
|
56
|
-
KHR_materials_anisotropy: {
|
|
57
|
-
anisotropyStrength: Math.max(0, Math.min(1, options.strength ?? 0.5)),
|
|
58
|
-
anisotropyRotation: options.rotation ?? 0
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
function createVolumeExtension(options) {
|
|
63
|
-
return {
|
|
64
|
-
KHR_materials_volume: {
|
|
65
|
-
thicknessFactor: options.thickness ?? 1,
|
|
66
|
-
attenuationDistance: options.attenuationDistance ?? 1,
|
|
67
|
-
attenuationColor: options.attenuationColor ?? [1, 1, 1]
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function createIridescenceExtension(options) {
|
|
72
|
-
return {
|
|
73
|
-
KHR_materials_iridescence: {
|
|
74
|
-
iridescenceFactor: options.factor ?? 1,
|
|
75
|
-
iridescenceIor: options.ior ?? 1.3,
|
|
76
|
-
iridescenceThicknessMinimum: options.thicknessRange?.[0] ?? 100,
|
|
77
|
-
iridescenceThicknessMaximum: options.thicknessRange?.[1] ?? 400
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function collectUsedExtensions(gltf) {
|
|
82
|
-
const extensions = /* @__PURE__ */ new Set();
|
|
83
|
-
const materials = gltf.materials;
|
|
84
|
-
if (materials) {
|
|
85
|
-
for (const material of materials) {
|
|
86
|
-
if (material.extensions) {
|
|
87
|
-
Object.keys(material.extensions).forEach((ext) => extensions.add(ext));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
const nodes = gltf.nodes;
|
|
92
|
-
if (nodes) {
|
|
93
|
-
for (const node of nodes) {
|
|
94
|
-
if (node.extensions) {
|
|
95
|
-
Object.keys(node.extensions).forEach((ext) => extensions.add(ext));
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
if (gltf.extensions) {
|
|
100
|
-
Object.keys(gltf.extensions).forEach((ext) => extensions.add(ext));
|
|
101
|
-
}
|
|
102
|
-
return Array.from(extensions);
|
|
103
|
-
}
|
|
104
|
-
function isExtensionRequired(extension) {
|
|
105
|
-
const requiredExtensions = [
|
|
106
|
-
"KHR_draco_mesh_compression",
|
|
107
|
-
"KHR_mesh_quantization",
|
|
108
|
-
"KHR_texture_basisu"
|
|
109
|
-
];
|
|
110
|
-
return requiredExtensions.includes(extension);
|
|
111
|
-
}
|
|
112
|
-
function declareExtensions(gltf) {
|
|
113
|
-
const usedExtensions = collectUsedExtensions(gltf);
|
|
114
|
-
if (usedExtensions.length === 0) return;
|
|
115
|
-
gltf.extensionsUsed = usedExtensions;
|
|
116
|
-
const required = usedExtensions.filter(isExtensionRequired);
|
|
117
|
-
if (required.length > 0) {
|
|
118
|
-
gltf.extensionsRequired = required;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// src/compiler/GLTFPipeline.ts
|
|
123
|
-
chunkQ5SJOGHQ_cjs.init_ObjectPool();
|
|
124
|
-
var gltfNodePool = new chunkQ5SJOGHQ_cjs.ASTNodePool(
|
|
125
|
-
() => ({ name: "" }),
|
|
126
|
-
(node) => {
|
|
127
|
-
node.name = "";
|
|
128
|
-
node.translation = void 0;
|
|
129
|
-
node.rotation = void 0;
|
|
130
|
-
node.scale = void 0;
|
|
131
|
-
node.mesh = void 0;
|
|
132
|
-
node.skin = void 0;
|
|
133
|
-
node.children = void 0;
|
|
134
|
-
node.camera = void 0;
|
|
135
|
-
node.extras = void 0;
|
|
136
|
-
},
|
|
137
|
-
0
|
|
138
|
-
// Was 10000 — demand-allocate instead of pre-allocating
|
|
139
|
-
);
|
|
140
|
-
var PRIMITIVE_GENERATORS = {
|
|
141
|
-
cube: generateCubeGeometry,
|
|
142
|
-
box: generateCubeGeometry,
|
|
143
|
-
sphere: generateSphereGeometry,
|
|
144
|
-
orb: generateSphereGeometry,
|
|
145
|
-
cylinder: generateCylinderGeometry,
|
|
146
|
-
cone: generateConeGeometry,
|
|
147
|
-
pyramid: generateConeGeometry,
|
|
148
|
-
plane: generatePlaneGeometry,
|
|
149
|
-
ground: generatePlaneGeometry
|
|
150
|
-
};
|
|
151
|
-
function generateScaleTexture(size = 512, baseColor = [30, 15, 61], borderColor = [20, 12, 40], highlightColor = [70, 50, 120]) {
|
|
152
|
-
const data = new Uint8Array(size * size * 4);
|
|
153
|
-
const scaleSize = size / 16;
|
|
154
|
-
const hexH = scaleSize;
|
|
155
|
-
const hexW = scaleSize * Math.sqrt(3);
|
|
156
|
-
function scaleHash(row, col) {
|
|
157
|
-
let h = row * 73856093 ^ col * 19349663;
|
|
158
|
-
h = (h >> 16 ^ h) * 73244475;
|
|
159
|
-
h = (h >> 16 ^ h) * 73244475;
|
|
160
|
-
return (h >> 16 ^ h) & 255;
|
|
161
|
-
}
|
|
162
|
-
for (let y = 0; y < size; y++) {
|
|
163
|
-
for (let x = 0; x < size; x++) {
|
|
164
|
-
const row = Math.floor(y / (hexH * 0.75));
|
|
165
|
-
const isOddRow = row % 2 === 1;
|
|
166
|
-
const xOff = isOddRow ? hexW * 0.5 : 0;
|
|
167
|
-
const col = Math.floor((x + xOff) / hexW);
|
|
168
|
-
const cx = col * hexW - xOff + hexW * 0.5;
|
|
169
|
-
const cy = row * hexH * 0.75 + hexH * 0.5;
|
|
170
|
-
const dx = (x - cx) / (hexW * 0.5);
|
|
171
|
-
const dy = (y - cy) / (hexH * 0.5);
|
|
172
|
-
const q = Math.abs(dx);
|
|
173
|
-
const r = Math.abs(dy);
|
|
174
|
-
const hexDist = Math.max(q, (q + r * Math.sqrt(3)) / 2);
|
|
175
|
-
const jitter = (scaleHash(row, col) / 255 - 0.5) * 40;
|
|
176
|
-
const jR = Math.round(jitter * 0.4);
|
|
177
|
-
const jG = Math.round(jitter * 0.3);
|
|
178
|
-
const jB = Math.round(jitter * 0.6);
|
|
179
|
-
const idx = (y * size + x) * 4;
|
|
180
|
-
if (hexDist > 0.94) {
|
|
181
|
-
data[idx] = Math.max(0, borderColor[0] + jR);
|
|
182
|
-
data[idx + 1] = Math.max(0, borderColor[1] + jG);
|
|
183
|
-
data[idx + 2] = Math.max(0, borderColor[2] + jB);
|
|
184
|
-
data[idx + 3] = 255;
|
|
185
|
-
} else if (hexDist < 0.12) {
|
|
186
|
-
const t = hexDist / 0.12;
|
|
187
|
-
const specR = 100, specG = 80, specB = 160;
|
|
188
|
-
data[idx] = Math.min(255, Math.round(specR * (1 - t) + highlightColor[0] * t) + jR);
|
|
189
|
-
data[idx + 1] = Math.min(255, Math.round(specG * (1 - t) + highlightColor[1] * t) + jG);
|
|
190
|
-
data[idx + 2] = Math.min(255, Math.round(specB * (1 - t) + highlightColor[2] * t) + jB);
|
|
191
|
-
data[idx + 3] = 255;
|
|
192
|
-
} else if (hexDist < 0.35) {
|
|
193
|
-
const t = (hexDist - 0.12) / 0.23;
|
|
194
|
-
data[idx] = Math.min(255, Math.round(highlightColor[0] * (1 - t) + baseColor[0] * t) + jR);
|
|
195
|
-
data[idx + 1] = Math.min(
|
|
196
|
-
255,
|
|
197
|
-
Math.round(highlightColor[1] * (1 - t) + baseColor[1] * t) + jG
|
|
198
|
-
);
|
|
199
|
-
data[idx + 2] = Math.min(
|
|
200
|
-
255,
|
|
201
|
-
Math.round(highlightColor[2] * (1 - t) + baseColor[2] * t) + jB
|
|
202
|
-
);
|
|
203
|
-
data[idx + 3] = 255;
|
|
204
|
-
} else {
|
|
205
|
-
const t = (hexDist - 0.35) / 0.59;
|
|
206
|
-
data[idx] = Math.max(
|
|
207
|
-
0,
|
|
208
|
-
Math.min(255, Math.round(baseColor[0] * (1 - t * 0.3) + borderColor[0] * (t * 0.3)) + jR)
|
|
209
|
-
);
|
|
210
|
-
data[idx + 1] = Math.max(
|
|
211
|
-
0,
|
|
212
|
-
Math.min(255, Math.round(baseColor[1] * (1 - t * 0.3) + borderColor[1] * (t * 0.3)) + jG)
|
|
213
|
-
);
|
|
214
|
-
data[idx + 2] = Math.max(
|
|
215
|
-
0,
|
|
216
|
-
Math.min(255, Math.round(baseColor[2] * (1 - t * 0.3) + borderColor[2] * (t * 0.3)) + jB)
|
|
217
|
-
);
|
|
218
|
-
data[idx + 3] = 255;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return data;
|
|
223
|
-
}
|
|
224
|
-
function generateScaleNormalMap(size = 512) {
|
|
225
|
-
const data = new Uint8Array(size * size * 4);
|
|
226
|
-
const scaleSize = size / 16;
|
|
227
|
-
const hexH = scaleSize;
|
|
228
|
-
const hexW = scaleSize * Math.sqrt(3);
|
|
229
|
-
for (let y = 0; y < size; y++) {
|
|
230
|
-
for (let x = 0; x < size; x++) {
|
|
231
|
-
const row = Math.floor(y / (hexH * 0.75));
|
|
232
|
-
const isOddRow = row % 2 === 1;
|
|
233
|
-
const xOff = isOddRow ? hexW * 0.5 : 0;
|
|
234
|
-
const col = Math.floor((x + xOff) / hexW);
|
|
235
|
-
const cx = col * hexW - xOff + hexW * 0.5;
|
|
236
|
-
const cy = row * hexH * 0.75 + hexH * 0.5;
|
|
237
|
-
const dx = (x - cx) / (hexW * 0.5);
|
|
238
|
-
const dy = (y - cy) / (hexH * 0.5);
|
|
239
|
-
const q = Math.abs(dx);
|
|
240
|
-
const r = Math.abs(dy);
|
|
241
|
-
const hexDist = Math.max(q, (q + r * Math.sqrt(3)) / 2);
|
|
242
|
-
const idx = (y * size + x) * 4;
|
|
243
|
-
let nx = 0, ny = 0, nz = 1;
|
|
244
|
-
if (hexDist > 0.92 && hexDist < 1) {
|
|
245
|
-
const len = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
246
|
-
const strength = 0.55;
|
|
247
|
-
nx = dx / len * strength;
|
|
248
|
-
ny = dy / len * strength;
|
|
249
|
-
nz = Math.sqrt(Math.max(0, 1 - nx * nx - ny * ny));
|
|
250
|
-
} else if (hexDist < 0.5) {
|
|
251
|
-
const strength = 0.25;
|
|
252
|
-
nx = -dx * strength;
|
|
253
|
-
ny = -dy * strength;
|
|
254
|
-
nz = Math.sqrt(Math.max(0, 1 - nx * nx - ny * ny));
|
|
255
|
-
}
|
|
256
|
-
data[idx] = Math.round((nx * 0.5 + 0.5) * 255);
|
|
257
|
-
data[idx + 1] = Math.round((ny * 0.5 + 0.5) * 255);
|
|
258
|
-
data[idx + 2] = Math.round((nz * 0.5 + 0.5) * 255);
|
|
259
|
-
data[idx + 3] = 255;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return data;
|
|
263
|
-
}
|
|
264
|
-
function encodePNG(pixels, width, height) {
|
|
265
|
-
const rowSize = width * 4 + 1;
|
|
266
|
-
const rawData = new Uint8Array(rowSize * height);
|
|
267
|
-
for (let y = 0; y < height; y++) {
|
|
268
|
-
rawData[y * rowSize] = 0;
|
|
269
|
-
rawData.set(pixels.slice(y * width * 4, (y + 1) * width * 4), y * rowSize + 1);
|
|
270
|
-
}
|
|
271
|
-
const deflated = deflateStored(rawData);
|
|
272
|
-
const crcTable = [];
|
|
273
|
-
for (let n = 0; n < 256; n++) {
|
|
274
|
-
let c = n;
|
|
275
|
-
for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
276
|
-
crcTable[n] = c;
|
|
277
|
-
}
|
|
278
|
-
function crc32(buf) {
|
|
279
|
-
let crc = 4294967295;
|
|
280
|
-
for (let i = 0; i < buf.length; i++) crc = crcTable[(crc ^ buf[i]) & 255] ^ crc >>> 8;
|
|
281
|
-
return (crc ^ 4294967295) >>> 0;
|
|
282
|
-
}
|
|
283
|
-
function writeChunk(type, data) {
|
|
284
|
-
const chunk = new Uint8Array(4 + 4 + data.length + 4);
|
|
285
|
-
const dv = new DataView(chunk.buffer);
|
|
286
|
-
dv.setUint32(0, data.length);
|
|
287
|
-
for (let i = 0; i < 4; i++) chunk[4 + i] = type.charCodeAt(i);
|
|
288
|
-
chunk.set(data, 8);
|
|
289
|
-
const crcInput = new Uint8Array(4 + data.length);
|
|
290
|
-
crcInput.set(chunk.slice(4, 8));
|
|
291
|
-
crcInput.set(data, 4);
|
|
292
|
-
dv.setUint32(8 + data.length, crc32(crcInput));
|
|
293
|
-
return chunk;
|
|
294
|
-
}
|
|
295
|
-
const signature = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
296
|
-
const ihdr = new Uint8Array(13);
|
|
297
|
-
const ihdrDV = new DataView(ihdr.buffer);
|
|
298
|
-
ihdrDV.setUint32(0, width);
|
|
299
|
-
ihdrDV.setUint32(4, height);
|
|
300
|
-
ihdr[8] = 8;
|
|
301
|
-
ihdr[9] = 6;
|
|
302
|
-
ihdr[10] = 0;
|
|
303
|
-
ihdr[11] = 0;
|
|
304
|
-
ihdr[12] = 0;
|
|
305
|
-
const ihdrChunk = writeChunk("IHDR", ihdr);
|
|
306
|
-
const idatChunk = writeChunk("IDAT", deflated);
|
|
307
|
-
const iendChunk = writeChunk("IEND", new Uint8Array(0));
|
|
308
|
-
const png = new Uint8Array(
|
|
309
|
-
signature.length + ihdrChunk.length + idatChunk.length + iendChunk.length
|
|
310
|
-
);
|
|
311
|
-
let offset = 0;
|
|
312
|
-
png.set(signature, offset);
|
|
313
|
-
offset += signature.length;
|
|
314
|
-
png.set(ihdrChunk, offset);
|
|
315
|
-
offset += ihdrChunk.length;
|
|
316
|
-
png.set(idatChunk, offset);
|
|
317
|
-
offset += idatChunk.length;
|
|
318
|
-
png.set(iendChunk, offset);
|
|
319
|
-
return png;
|
|
320
|
-
}
|
|
321
|
-
function decimateGeometry(geometry, ratio) {
|
|
322
|
-
const cellSize = Math.max(0.01, (1 - ratio) * 0.3);
|
|
323
|
-
const positions = geometry.positions;
|
|
324
|
-
const normals = geometry.normals;
|
|
325
|
-
const uvs = geometry.uvs;
|
|
326
|
-
const indices = geometry.indices;
|
|
327
|
-
const vertCount = positions.length / 3;
|
|
328
|
-
const cellMap = /* @__PURE__ */ new Map();
|
|
329
|
-
const remap = new Int32Array(vertCount);
|
|
330
|
-
const newPositions = [];
|
|
331
|
-
const newNormals = [];
|
|
332
|
-
const newUVs = [];
|
|
333
|
-
let newIdx = 0;
|
|
334
|
-
for (let i = 0; i < vertCount; i++) {
|
|
335
|
-
const px = positions[i * 3], py = positions[i * 3 + 1], pz = positions[i * 3 + 2];
|
|
336
|
-
const cx = Math.round(px / cellSize), cy = Math.round(py / cellSize), cz = Math.round(pz / cellSize);
|
|
337
|
-
const key = `${cx},${cy},${cz}`;
|
|
338
|
-
if (cellMap.has(key)) {
|
|
339
|
-
remap[i] = cellMap.get(key);
|
|
340
|
-
} else {
|
|
341
|
-
cellMap.set(key, newIdx);
|
|
342
|
-
remap[i] = newIdx;
|
|
343
|
-
newPositions.push(px, py, pz);
|
|
344
|
-
newNormals.push(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]);
|
|
345
|
-
newUVs.push(uvs[i * 2], uvs[i * 2 + 1]);
|
|
346
|
-
newIdx++;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
const newIndices = [];
|
|
350
|
-
for (let i = 0; i < indices.length; i += 3) {
|
|
351
|
-
const a = remap[indices[i]], b = remap[indices[i + 1]], c = remap[indices[i + 2]];
|
|
352
|
-
if (a !== b && b !== c && a !== c) {
|
|
353
|
-
newIndices.push(a, b, c);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
const newVertexCount = newPositions.length / 3;
|
|
357
|
-
const IndexArrayType = newVertexCount > 65535 ? Uint32Array : Uint16Array;
|
|
358
|
-
return {
|
|
359
|
-
positions: new Float32Array(newPositions),
|
|
360
|
-
normals: new Float32Array(newNormals),
|
|
361
|
-
uvs: new Float32Array(newUVs),
|
|
362
|
-
indices: new IndexArrayType(newIndices)
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
var DRAGON_SKELETON = [
|
|
366
|
-
{ name: "Root", position: [0, 2.5, 0] },
|
|
367
|
-
{ name: "Spine", position: [0, 2.5, 0], parent: "Root" },
|
|
368
|
-
{ name: "Neck", position: [0, 3.5, 2], parent: "Spine" },
|
|
369
|
-
{ name: "Head", position: [0, 4.5, 4.2], parent: "Neck" },
|
|
370
|
-
{ name: "Jaw", position: [0, 4.2, 4.6], parent: "Head" },
|
|
371
|
-
{ name: "Tail1", position: [0, 2.2, -2], parent: "Spine" },
|
|
372
|
-
{ name: "Tail2", position: [0, 1, -3.5], parent: "Tail1" },
|
|
373
|
-
{ name: "TailTip", position: [0, -0.05, -4.6], parent: "Tail2" },
|
|
374
|
-
{ name: "LeftWing", position: [-1.2, 3, 0.2], parent: "Spine" },
|
|
375
|
-
{ name: "LeftWingTip", position: [-2.6, 3.8, 0.2], parent: "LeftWing" },
|
|
376
|
-
{ name: "RightWing", position: [1.2, 3, 0.2], parent: "Spine" },
|
|
377
|
-
{ name: "RightWingTip", position: [2.6, 3.8, 0.2], parent: "RightWing" },
|
|
378
|
-
{ name: "LeftFrontLeg", position: [-0.9, 1.6, 1.2], parent: "Spine" },
|
|
379
|
-
{ name: "LeftFrontFoot", position: [-0.95, 0.15, 1.4], parent: "LeftFrontLeg" },
|
|
380
|
-
{ name: "RightFrontLeg", position: [0.9, 1.6, 1.2], parent: "Spine" },
|
|
381
|
-
{ name: "RightFrontFoot", position: [0.95, 0.15, 1.4], parent: "RightFrontLeg" },
|
|
382
|
-
{ name: "LeftBackLeg", position: [-0.9, 1.5, -1], parent: "Spine" },
|
|
383
|
-
{ name: "LeftBackFoot", position: [-0.95, 0.1, -1.15], parent: "LeftBackLeg" },
|
|
384
|
-
{ name: "RightBackLeg", position: [0.9, 1.5, -1], parent: "Spine" },
|
|
385
|
-
{ name: "RightBackFoot", position: [0.95, 0.1, -1.15], parent: "RightBackLeg" }
|
|
386
|
-
];
|
|
387
|
-
function deflateStored(data) {
|
|
388
|
-
const BLOCK_MAX = 65535;
|
|
389
|
-
const numBlocks = Math.ceil(data.length / BLOCK_MAX) || 1;
|
|
390
|
-
let size = 2 + 4;
|
|
391
|
-
for (let i = 0; i < numBlocks; i++) {
|
|
392
|
-
size += 5;
|
|
393
|
-
const blockLen = Math.min(BLOCK_MAX, data.length - i * BLOCK_MAX);
|
|
394
|
-
size += blockLen;
|
|
395
|
-
}
|
|
396
|
-
const out = new Uint8Array(size);
|
|
397
|
-
let pos = 0;
|
|
398
|
-
out[pos++] = 120;
|
|
399
|
-
out[pos++] = 1;
|
|
400
|
-
for (let i = 0; i < numBlocks; i++) {
|
|
401
|
-
const blockStart = i * BLOCK_MAX;
|
|
402
|
-
const blockLen = Math.min(BLOCK_MAX, data.length - blockStart);
|
|
403
|
-
const isLast = i === numBlocks - 1;
|
|
404
|
-
out[pos++] = isLast ? 1 : 0;
|
|
405
|
-
out[pos++] = blockLen & 255;
|
|
406
|
-
out[pos++] = blockLen >> 8 & 255;
|
|
407
|
-
out[pos++] = ~blockLen & 255;
|
|
408
|
-
out[pos++] = ~blockLen >> 8 & 255;
|
|
409
|
-
out.set(data.slice(blockStart, blockStart + blockLen), pos);
|
|
410
|
-
pos += blockLen;
|
|
411
|
-
}
|
|
412
|
-
let a = 1, b = 0;
|
|
413
|
-
for (let i = 0; i < data.length; i++) {
|
|
414
|
-
a = (a + data[i]) % 65521;
|
|
415
|
-
b = (b + a) % 65521;
|
|
416
|
-
}
|
|
417
|
-
const adler = (b << 16 | a) >>> 0;
|
|
418
|
-
out[pos++] = adler >> 24 & 255;
|
|
419
|
-
out[pos++] = adler >> 16 & 255;
|
|
420
|
-
out[pos++] = adler >> 8 & 255;
|
|
421
|
-
out[pos++] = adler & 255;
|
|
422
|
-
return out;
|
|
423
|
-
}
|
|
424
|
-
var ADVANCED_GEOMETRY_TYPES = /* @__PURE__ */ new Set(["spline", "membrane", "hull", "blob", "metaball"]);
|
|
425
|
-
function generateCubeGeometry(scale) {
|
|
426
|
-
const [sx, sy, sz] = scale.map((s) => s * 0.5);
|
|
427
|
-
const positions = new Float32Array([
|
|
428
|
-
// Front face
|
|
429
|
-
-sx,
|
|
430
|
-
-sy,
|
|
431
|
-
sz,
|
|
432
|
-
sx,
|
|
433
|
-
-sy,
|
|
434
|
-
sz,
|
|
435
|
-
sx,
|
|
436
|
-
sy,
|
|
437
|
-
sz,
|
|
438
|
-
-sx,
|
|
439
|
-
sy,
|
|
440
|
-
sz,
|
|
441
|
-
// Back face
|
|
442
|
-
-sx,
|
|
443
|
-
-sy,
|
|
444
|
-
-sz,
|
|
445
|
-
-sx,
|
|
446
|
-
sy,
|
|
447
|
-
-sz,
|
|
448
|
-
sx,
|
|
449
|
-
sy,
|
|
450
|
-
-sz,
|
|
451
|
-
sx,
|
|
452
|
-
-sy,
|
|
453
|
-
-sz,
|
|
454
|
-
// Top face
|
|
455
|
-
-sx,
|
|
456
|
-
sy,
|
|
457
|
-
-sz,
|
|
458
|
-
-sx,
|
|
459
|
-
sy,
|
|
460
|
-
sz,
|
|
461
|
-
sx,
|
|
462
|
-
sy,
|
|
463
|
-
sz,
|
|
464
|
-
sx,
|
|
465
|
-
sy,
|
|
466
|
-
-sz,
|
|
467
|
-
// Bottom face
|
|
468
|
-
-sx,
|
|
469
|
-
-sy,
|
|
470
|
-
-sz,
|
|
471
|
-
sx,
|
|
472
|
-
-sy,
|
|
473
|
-
-sz,
|
|
474
|
-
sx,
|
|
475
|
-
-sy,
|
|
476
|
-
sz,
|
|
477
|
-
-sx,
|
|
478
|
-
-sy,
|
|
479
|
-
sz,
|
|
480
|
-
// Right face
|
|
481
|
-
sx,
|
|
482
|
-
-sy,
|
|
483
|
-
-sz,
|
|
484
|
-
sx,
|
|
485
|
-
sy,
|
|
486
|
-
-sz,
|
|
487
|
-
sx,
|
|
488
|
-
sy,
|
|
489
|
-
sz,
|
|
490
|
-
sx,
|
|
491
|
-
-sy,
|
|
492
|
-
sz,
|
|
493
|
-
// Left face
|
|
494
|
-
-sx,
|
|
495
|
-
-sy,
|
|
496
|
-
-sz,
|
|
497
|
-
-sx,
|
|
498
|
-
-sy,
|
|
499
|
-
sz,
|
|
500
|
-
-sx,
|
|
501
|
-
sy,
|
|
502
|
-
sz,
|
|
503
|
-
-sx,
|
|
504
|
-
sy,
|
|
505
|
-
-sz
|
|
506
|
-
]);
|
|
507
|
-
const normals = new Float32Array([
|
|
508
|
-
// Front
|
|
509
|
-
0,
|
|
510
|
-
0,
|
|
511
|
-
1,
|
|
512
|
-
0,
|
|
513
|
-
0,
|
|
514
|
-
1,
|
|
515
|
-
0,
|
|
516
|
-
0,
|
|
517
|
-
1,
|
|
518
|
-
0,
|
|
519
|
-
0,
|
|
520
|
-
1,
|
|
521
|
-
// Back
|
|
522
|
-
0,
|
|
523
|
-
0,
|
|
524
|
-
-1,
|
|
525
|
-
0,
|
|
526
|
-
0,
|
|
527
|
-
-1,
|
|
528
|
-
0,
|
|
529
|
-
0,
|
|
530
|
-
-1,
|
|
531
|
-
0,
|
|
532
|
-
0,
|
|
533
|
-
-1,
|
|
534
|
-
// Top
|
|
535
|
-
0,
|
|
536
|
-
1,
|
|
537
|
-
0,
|
|
538
|
-
0,
|
|
539
|
-
1,
|
|
540
|
-
0,
|
|
541
|
-
0,
|
|
542
|
-
1,
|
|
543
|
-
0,
|
|
544
|
-
0,
|
|
545
|
-
1,
|
|
546
|
-
0,
|
|
547
|
-
// Bottom
|
|
548
|
-
0,
|
|
549
|
-
-1,
|
|
550
|
-
0,
|
|
551
|
-
0,
|
|
552
|
-
-1,
|
|
553
|
-
0,
|
|
554
|
-
0,
|
|
555
|
-
-1,
|
|
556
|
-
0,
|
|
557
|
-
0,
|
|
558
|
-
-1,
|
|
559
|
-
0,
|
|
560
|
-
// Right
|
|
561
|
-
1,
|
|
562
|
-
0,
|
|
563
|
-
0,
|
|
564
|
-
1,
|
|
565
|
-
0,
|
|
566
|
-
0,
|
|
567
|
-
1,
|
|
568
|
-
0,
|
|
569
|
-
0,
|
|
570
|
-
1,
|
|
571
|
-
0,
|
|
572
|
-
0,
|
|
573
|
-
// Left
|
|
574
|
-
-1,
|
|
575
|
-
0,
|
|
576
|
-
0,
|
|
577
|
-
-1,
|
|
578
|
-
0,
|
|
579
|
-
0,
|
|
580
|
-
-1,
|
|
581
|
-
0,
|
|
582
|
-
0,
|
|
583
|
-
-1,
|
|
584
|
-
0,
|
|
585
|
-
0
|
|
586
|
-
]);
|
|
587
|
-
const uvs = new Float32Array([
|
|
588
|
-
// Front
|
|
589
|
-
0,
|
|
590
|
-
0,
|
|
591
|
-
1,
|
|
592
|
-
0,
|
|
593
|
-
1,
|
|
594
|
-
1,
|
|
595
|
-
0,
|
|
596
|
-
1,
|
|
597
|
-
// Back
|
|
598
|
-
1,
|
|
599
|
-
0,
|
|
600
|
-
1,
|
|
601
|
-
1,
|
|
602
|
-
0,
|
|
603
|
-
1,
|
|
604
|
-
0,
|
|
605
|
-
0,
|
|
606
|
-
// Top
|
|
607
|
-
0,
|
|
608
|
-
1,
|
|
609
|
-
0,
|
|
610
|
-
0,
|
|
611
|
-
1,
|
|
612
|
-
0,
|
|
613
|
-
1,
|
|
614
|
-
1,
|
|
615
|
-
// Bottom
|
|
616
|
-
1,
|
|
617
|
-
1,
|
|
618
|
-
0,
|
|
619
|
-
1,
|
|
620
|
-
0,
|
|
621
|
-
0,
|
|
622
|
-
1,
|
|
623
|
-
0,
|
|
624
|
-
// Right
|
|
625
|
-
1,
|
|
626
|
-
0,
|
|
627
|
-
1,
|
|
628
|
-
1,
|
|
629
|
-
0,
|
|
630
|
-
1,
|
|
631
|
-
0,
|
|
632
|
-
0,
|
|
633
|
-
// Left
|
|
634
|
-
0,
|
|
635
|
-
0,
|
|
636
|
-
1,
|
|
637
|
-
0,
|
|
638
|
-
1,
|
|
639
|
-
1,
|
|
640
|
-
0,
|
|
641
|
-
1
|
|
642
|
-
]);
|
|
643
|
-
const indices = new Uint16Array([
|
|
644
|
-
0,
|
|
645
|
-
1,
|
|
646
|
-
2,
|
|
647
|
-
0,
|
|
648
|
-
2,
|
|
649
|
-
3,
|
|
650
|
-
// Front
|
|
651
|
-
4,
|
|
652
|
-
5,
|
|
653
|
-
6,
|
|
654
|
-
4,
|
|
655
|
-
6,
|
|
656
|
-
7,
|
|
657
|
-
// Back
|
|
658
|
-
8,
|
|
659
|
-
9,
|
|
660
|
-
10,
|
|
661
|
-
8,
|
|
662
|
-
10,
|
|
663
|
-
11,
|
|
664
|
-
// Top
|
|
665
|
-
12,
|
|
666
|
-
13,
|
|
667
|
-
14,
|
|
668
|
-
12,
|
|
669
|
-
14,
|
|
670
|
-
15,
|
|
671
|
-
// Bottom
|
|
672
|
-
16,
|
|
673
|
-
17,
|
|
674
|
-
18,
|
|
675
|
-
16,
|
|
676
|
-
18,
|
|
677
|
-
19,
|
|
678
|
-
// Right
|
|
679
|
-
20,
|
|
680
|
-
21,
|
|
681
|
-
22,
|
|
682
|
-
20,
|
|
683
|
-
22,
|
|
684
|
-
23
|
|
685
|
-
// Left
|
|
686
|
-
]);
|
|
687
|
-
return { positions, normals, uvs, indices };
|
|
688
|
-
}
|
|
689
|
-
function generateSphereGeometry(scale) {
|
|
690
|
-
const sx = scale[0] * 0.5;
|
|
691
|
-
const sy = scale[1] * 0.5;
|
|
692
|
-
const sz = scale[2] * 0.5;
|
|
693
|
-
const segments = 32;
|
|
694
|
-
const rings = 24;
|
|
695
|
-
const positions = [];
|
|
696
|
-
const normals = [];
|
|
697
|
-
const uvs = [];
|
|
698
|
-
const indices = [];
|
|
699
|
-
for (let y = 0; y <= rings; y++) {
|
|
700
|
-
const v = y / rings;
|
|
701
|
-
const theta = v * Math.PI;
|
|
702
|
-
for (let x = 0; x <= segments; x++) {
|
|
703
|
-
const u = x / segments;
|
|
704
|
-
const phi = u * Math.PI * 2;
|
|
705
|
-
const nx = Math.sin(theta) * Math.cos(phi);
|
|
706
|
-
const ny = Math.cos(theta);
|
|
707
|
-
const nz = Math.sin(theta) * Math.sin(phi);
|
|
708
|
-
positions.push(nx * sx);
|
|
709
|
-
positions.push(ny * sy);
|
|
710
|
-
positions.push(nz * sz);
|
|
711
|
-
normals.push(nx, ny, nz);
|
|
712
|
-
uvs.push(u, 1 - v);
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
for (let y = 0; y < rings; y++) {
|
|
716
|
-
for (let x = 0; x < segments; x++) {
|
|
717
|
-
const a = y * (segments + 1) + x;
|
|
718
|
-
const b = a + segments + 1;
|
|
719
|
-
indices.push(a, b, a + 1);
|
|
720
|
-
indices.push(b, b + 1, a + 1);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
return {
|
|
724
|
-
positions: new Float32Array(positions),
|
|
725
|
-
normals: new Float32Array(normals),
|
|
726
|
-
uvs: new Float32Array(uvs),
|
|
727
|
-
indices: new Uint16Array(indices)
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
|
-
function generateCylinderGeometry(scale) {
|
|
731
|
-
const radiusTop = scale[0] * 0.5;
|
|
732
|
-
const radiusBottom = scale[2] * 0.5;
|
|
733
|
-
const height = scale[1];
|
|
734
|
-
const segments = 32;
|
|
735
|
-
const positions = [];
|
|
736
|
-
const normals = [];
|
|
737
|
-
const uvs = [];
|
|
738
|
-
const indices = [];
|
|
739
|
-
const halfHeight = height / 2;
|
|
740
|
-
for (let y = 0; y <= 1; y++) {
|
|
741
|
-
const radius = y === 0 ? radiusBottom : radiusTop;
|
|
742
|
-
const posY = y === 0 ? -halfHeight : halfHeight;
|
|
743
|
-
for (let x = 0; x <= segments; x++) {
|
|
744
|
-
const u = x / segments;
|
|
745
|
-
const theta = u * Math.PI * 2;
|
|
746
|
-
const cosTheta = Math.cos(theta);
|
|
747
|
-
const sinTheta = Math.sin(theta);
|
|
748
|
-
positions.push(radius * cosTheta, posY, radius * sinTheta);
|
|
749
|
-
normals.push(cosTheta, 0, sinTheta);
|
|
750
|
-
uvs.push(u, y);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
for (let x = 0; x < segments; x++) {
|
|
754
|
-
const a = x;
|
|
755
|
-
const b = x + segments + 1;
|
|
756
|
-
indices.push(a, b, a + 1);
|
|
757
|
-
indices.push(b, b + 1, a + 1);
|
|
758
|
-
}
|
|
759
|
-
const topCenterIndex = positions.length / 3;
|
|
760
|
-
positions.push(0, halfHeight, 0);
|
|
761
|
-
normals.push(0, 1, 0);
|
|
762
|
-
uvs.push(0.5, 0.5);
|
|
763
|
-
for (let x = 0; x <= segments; x++) {
|
|
764
|
-
const u = x / segments;
|
|
765
|
-
const theta = u * Math.PI * 2;
|
|
766
|
-
positions.push(radiusTop * Math.cos(theta), halfHeight, radiusTop * Math.sin(theta));
|
|
767
|
-
normals.push(0, 1, 0);
|
|
768
|
-
uvs.push(Math.cos(theta) * 0.5 + 0.5, Math.sin(theta) * 0.5 + 0.5);
|
|
769
|
-
}
|
|
770
|
-
for (let x = 0; x < segments; x++) {
|
|
771
|
-
indices.push(topCenterIndex, topCenterIndex + x + 1, topCenterIndex + x + 2);
|
|
772
|
-
}
|
|
773
|
-
const bottomCenterIndex = positions.length / 3;
|
|
774
|
-
positions.push(0, -halfHeight, 0);
|
|
775
|
-
normals.push(0, -1, 0);
|
|
776
|
-
uvs.push(0.5, 0.5);
|
|
777
|
-
for (let x = 0; x <= segments; x++) {
|
|
778
|
-
const u = x / segments;
|
|
779
|
-
const theta = u * Math.PI * 2;
|
|
780
|
-
positions.push(radiusBottom * Math.cos(theta), -halfHeight, radiusBottom * Math.sin(theta));
|
|
781
|
-
normals.push(0, -1, 0);
|
|
782
|
-
uvs.push(Math.cos(theta) * 0.5 + 0.5, Math.sin(theta) * 0.5 + 0.5);
|
|
783
|
-
}
|
|
784
|
-
for (let x = 0; x < segments; x++) {
|
|
785
|
-
indices.push(bottomCenterIndex, bottomCenterIndex + x + 2, bottomCenterIndex + x + 1);
|
|
786
|
-
}
|
|
787
|
-
return {
|
|
788
|
-
positions: new Float32Array(positions),
|
|
789
|
-
normals: new Float32Array(normals),
|
|
790
|
-
uvs: new Float32Array(uvs),
|
|
791
|
-
indices: new Uint16Array(indices)
|
|
792
|
-
};
|
|
793
|
-
}
|
|
794
|
-
function generateConeGeometry(scale) {
|
|
795
|
-
return generateCylinderGeometry([1e-3, scale[1], scale[2]]);
|
|
796
|
-
}
|
|
797
|
-
function generatePlaneGeometry(scale) {
|
|
798
|
-
const [sx, _, sz] = scale.map((s) => s * 0.5);
|
|
799
|
-
const positions = new Float32Array([
|
|
800
|
-
-sx,
|
|
801
|
-
0,
|
|
802
|
-
-sz,
|
|
803
|
-
sx,
|
|
804
|
-
0,
|
|
805
|
-
-sz,
|
|
806
|
-
sx,
|
|
807
|
-
0,
|
|
808
|
-
sz,
|
|
809
|
-
-sx,
|
|
810
|
-
0,
|
|
811
|
-
sz
|
|
812
|
-
]);
|
|
813
|
-
const normals = new Float32Array([
|
|
814
|
-
0,
|
|
815
|
-
1,
|
|
816
|
-
0,
|
|
817
|
-
0,
|
|
818
|
-
1,
|
|
819
|
-
0,
|
|
820
|
-
0,
|
|
821
|
-
1,
|
|
822
|
-
0,
|
|
823
|
-
0,
|
|
824
|
-
1,
|
|
825
|
-
0
|
|
826
|
-
]);
|
|
827
|
-
const uvs = new Float32Array([
|
|
828
|
-
0,
|
|
829
|
-
0,
|
|
830
|
-
1,
|
|
831
|
-
0,
|
|
832
|
-
1,
|
|
833
|
-
1,
|
|
834
|
-
0,
|
|
835
|
-
1
|
|
836
|
-
]);
|
|
837
|
-
const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
|
|
838
|
-
return { positions, normals, uvs, indices };
|
|
839
|
-
}
|
|
840
|
-
var INITIAL_COMPILE_BUFFER_SIZE = 1024 * 1024;
|
|
841
|
-
var MAX_RETAINED_BUFFER_SIZE = 1024 * 1024 * 20;
|
|
842
|
-
var SHARED_COMPILE_BUFFER = new Uint8Array(INITIAL_COMPILE_BUFFER_SIZE);
|
|
843
|
-
var GLTFPipeline = class extends chunkBF2235SI_cjs.CompilerBase {
|
|
844
|
-
constructor(options = {}) {
|
|
845
|
-
super();
|
|
846
|
-
this.compilerName = "GLTFPipeline";
|
|
847
|
-
this.bufferByteLength = 0;
|
|
848
|
-
this.accessors = [];
|
|
849
|
-
this.bufferViews = [];
|
|
850
|
-
this.meshes = [];
|
|
851
|
-
this.materials = [];
|
|
852
|
-
this.nodes = [];
|
|
853
|
-
this.scenes = [];
|
|
854
|
-
this.animations = [];
|
|
855
|
-
this.materialMap = /* @__PURE__ */ new Map();
|
|
856
|
-
this.images = [];
|
|
857
|
-
this.textures = [];
|
|
858
|
-
this.samplers = [];
|
|
859
|
-
this.scaleTextureIndex = -1;
|
|
860
|
-
this.scaleNormalTextureIndex = -1;
|
|
861
|
-
this.textureIndexMap = /* @__PURE__ */ new Map();
|
|
862
|
-
this.stats = {
|
|
863
|
-
nodeCount: 0,
|
|
864
|
-
meshCount: 0,
|
|
865
|
-
materialCount: 0,
|
|
866
|
-
textureCount: 0,
|
|
867
|
-
animationCount: 0,
|
|
868
|
-
totalVertices: 0,
|
|
869
|
-
totalTriangles: 0,
|
|
870
|
-
fileSizeBytes: 0
|
|
871
|
-
};
|
|
872
|
-
this._lodCoverages = null;
|
|
873
|
-
this._skins = null;
|
|
874
|
-
this._jointStartIndex = 0;
|
|
875
|
-
this.options = {
|
|
876
|
-
format: options.format ?? "glb",
|
|
877
|
-
dracoCompression: options.dracoCompression ?? false,
|
|
878
|
-
quantize: options.quantize ?? true,
|
|
879
|
-
prune: options.prune ?? true,
|
|
880
|
-
dedupe: options.dedupe ?? true,
|
|
881
|
-
embedTextures: options.embedTextures ?? true,
|
|
882
|
-
textureData: options.textureData ?? {},
|
|
883
|
-
generator: options.generator ?? "HoloScript GLTFPipeline v1.0.0",
|
|
884
|
-
copyright: options.copyright ?? ""
|
|
885
|
-
};
|
|
886
|
-
this.compositor = new chunkX4ZF6CNE_cjs.TraitCompositor();
|
|
887
|
-
}
|
|
888
|
-
getRequiredCapability() {
|
|
889
|
-
return platform.ANSCapabilityPath.GLTF;
|
|
890
|
-
}
|
|
891
|
-
get bufferData() {
|
|
892
|
-
return SHARED_COMPILE_BUFFER;
|
|
893
|
-
}
|
|
894
|
-
set bufferData(v) {
|
|
895
|
-
SHARED_COMPILE_BUFFER = v;
|
|
896
|
-
}
|
|
897
|
-
ensureBufferCapacity(needed) {
|
|
898
|
-
if (this.bufferByteLength + needed > this.bufferData.length) {
|
|
899
|
-
const newLen = Math.max(this.bufferData.length * 2, this.bufferByteLength + needed);
|
|
900
|
-
const newArr = new Uint8Array(newLen);
|
|
901
|
-
newArr.set(this.bufferData.subarray(0, this.bufferByteLength));
|
|
902
|
-
this.bufferData = newArr;
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
appendToBuffer(data) {
|
|
906
|
-
this.ensureBufferCapacity(data.length);
|
|
907
|
-
this.bufferData.set(data, this.bufferByteLength);
|
|
908
|
-
this.bufferByteLength += data.length;
|
|
909
|
-
}
|
|
910
|
-
padBuffer(alignment) {
|
|
911
|
-
const remainder = this.bufferByteLength % alignment;
|
|
912
|
-
if (remainder !== 0) {
|
|
913
|
-
const padding = alignment - remainder;
|
|
914
|
-
this.ensureBufferCapacity(padding);
|
|
915
|
-
this.bufferByteLength += padding;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
/**
|
|
919
|
-
* Global smooth normals pass.
|
|
920
|
-
* Finds vertices at the same 3D position across all meshes and averages
|
|
921
|
-
* their normals. This eliminates hard seams where separate meshes meet
|
|
922
|
-
* (e.g., neck spline meets the head sphere).
|
|
923
|
-
*/
|
|
924
|
-
smoothNormalsGlobal() {
|
|
925
|
-
const QUANT = 100;
|
|
926
|
-
const posMap = /* @__PURE__ */ new Map();
|
|
927
|
-
for (const mesh of this.meshes) {
|
|
928
|
-
for (const prim of mesh.primitives) {
|
|
929
|
-
const posIdx = prim.attributes.POSITION;
|
|
930
|
-
const nrmIdx = prim.attributes.NORMAL;
|
|
931
|
-
if (posIdx === void 0 || nrmIdx === void 0) continue;
|
|
932
|
-
const posAcc = this.accessors[posIdx];
|
|
933
|
-
const nrmAcc = this.accessors[nrmIdx];
|
|
934
|
-
if (!posAcc || !nrmAcc) continue;
|
|
935
|
-
const posBV = this.bufferViews[posAcc.bufferView];
|
|
936
|
-
const nrmBV = this.bufferViews[nrmAcc.bufferView];
|
|
937
|
-
if (!posBV || !nrmBV) continue;
|
|
938
|
-
const count = posAcc.count;
|
|
939
|
-
for (let i = 0; i < count; i++) {
|
|
940
|
-
const pOff = posBV.byteOffset + i * 12;
|
|
941
|
-
const px = this.readFloat32(pOff);
|
|
942
|
-
const py = this.readFloat32(pOff + 4);
|
|
943
|
-
const pz = this.readFloat32(pOff + 8);
|
|
944
|
-
const nOff = nrmBV.byteOffset + i * 12;
|
|
945
|
-
const nx = this.readFloat32(nOff);
|
|
946
|
-
const ny = this.readFloat32(nOff + 4);
|
|
947
|
-
const nz = this.readFloat32(nOff + 8);
|
|
948
|
-
const key = `${Math.round(px * QUANT)},${Math.round(py * QUANT)},${Math.round(pz * QUANT)}`;
|
|
949
|
-
let entries = posMap.get(key);
|
|
950
|
-
if (!entries) {
|
|
951
|
-
entries = [];
|
|
952
|
-
posMap.set(key, entries);
|
|
953
|
-
}
|
|
954
|
-
entries.push({ nx, ny, nz, byteOffset: nOff });
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
for (const entries of posMap.values()) {
|
|
959
|
-
if (entries.length < 2) continue;
|
|
960
|
-
let ax = 0, ay = 0, az = 0;
|
|
961
|
-
for (const e of entries) {
|
|
962
|
-
ax += e.nx;
|
|
963
|
-
ay += e.ny;
|
|
964
|
-
az += e.nz;
|
|
965
|
-
}
|
|
966
|
-
const len = Math.sqrt(ax * ax + ay * ay + az * az);
|
|
967
|
-
if (len < 1e-8) continue;
|
|
968
|
-
ax /= len;
|
|
969
|
-
ay /= len;
|
|
970
|
-
az /= len;
|
|
971
|
-
for (const e of entries) {
|
|
972
|
-
this.writeFloat32(e.byteOffset, ax);
|
|
973
|
-
this.writeFloat32(e.byteOffset + 4, ay);
|
|
974
|
-
this.writeFloat32(e.byteOffset + 8, az);
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
/** Read a Float32 from the buffer at byteOffset */
|
|
979
|
-
readFloat32(byteOffset) {
|
|
980
|
-
const bytes = new Uint8Array(4);
|
|
981
|
-
bytes.set(this.bufferData.subarray(byteOffset, byteOffset + 4));
|
|
982
|
-
return new Float32Array(bytes.buffer)[0];
|
|
983
|
-
}
|
|
984
|
-
/** Write a Float32 to the buffer at byteOffset */
|
|
985
|
-
writeFloat32(byteOffset, value) {
|
|
986
|
-
const f32 = new Float32Array([value]);
|
|
987
|
-
const view = new Uint8Array(f32.buffer);
|
|
988
|
-
this.bufferData.set(view, byteOffset);
|
|
989
|
-
}
|
|
990
|
-
/**
|
|
991
|
-
* Generate LOD meshes for the MSFT_lod extension.
|
|
992
|
-
* Creates 2 lower detail levels (50% and 25%) per mesh.
|
|
993
|
-
*/
|
|
994
|
-
generateLODs() {
|
|
995
|
-
const ratios = [0.5, 0.25];
|
|
996
|
-
const originalCount = this.meshes.length;
|
|
997
|
-
const coverages = [];
|
|
998
|
-
for (let mi = 0; mi < originalCount; mi++) {
|
|
999
|
-
const mesh = this.meshes[mi];
|
|
1000
|
-
const lodIds = [];
|
|
1001
|
-
for (const ratio of ratios) {
|
|
1002
|
-
for (const prim of mesh.primitives) {
|
|
1003
|
-
const posIdx = prim.attributes.POSITION;
|
|
1004
|
-
const nrmIdx = prim.attributes.NORMAL;
|
|
1005
|
-
const uvIdx = prim.attributes.TEXCOORD_0;
|
|
1006
|
-
const idxIdx = prim.indices;
|
|
1007
|
-
if (posIdx === void 0 || nrmIdx === void 0 || idxIdx === void 0) continue;
|
|
1008
|
-
const posAcc = this.accessors[posIdx];
|
|
1009
|
-
const nrmAcc = this.accessors[nrmIdx];
|
|
1010
|
-
const idxAcc = this.accessors[idxIdx];
|
|
1011
|
-
if (!posAcc || !nrmAcc || !idxAcc) continue;
|
|
1012
|
-
const posBV = this.bufferViews[posAcc.bufferView];
|
|
1013
|
-
const nrmBV = this.bufferViews[nrmAcc.bufferView];
|
|
1014
|
-
const idxBV = this.bufferViews[idxAcc.bufferView];
|
|
1015
|
-
if (!posBV || !nrmBV || !idxBV) continue;
|
|
1016
|
-
const vCount = posAcc.count;
|
|
1017
|
-
const iCount = idxAcc.count;
|
|
1018
|
-
const positions = new Float32Array(vCount * 3);
|
|
1019
|
-
const normals = new Float32Array(vCount * 3);
|
|
1020
|
-
const uvs = new Float32Array(vCount * 2);
|
|
1021
|
-
const indices = new Uint16Array(iCount);
|
|
1022
|
-
for (let i = 0; i < vCount * 3; i++) {
|
|
1023
|
-
positions[i] = this.readFloat32(posBV.byteOffset + i * 4);
|
|
1024
|
-
normals[i] = this.readFloat32(nrmBV.byteOffset + i * 4);
|
|
1025
|
-
}
|
|
1026
|
-
if (uvIdx !== void 0) {
|
|
1027
|
-
const uvAcc = this.accessors[uvIdx];
|
|
1028
|
-
const uvBV = uvAcc ? this.bufferViews[uvAcc.bufferView] : null;
|
|
1029
|
-
if (uvBV) {
|
|
1030
|
-
for (let i = 0; i < vCount * 2; i++) {
|
|
1031
|
-
uvs[i] = this.readFloat32(uvBV.byteOffset + i * 4);
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
const compSize = idxAcc.componentType === 5123 ? 2 : 4;
|
|
1036
|
-
for (let i = 0; i < iCount; i++) {
|
|
1037
|
-
const off = idxBV.byteOffset + i * compSize;
|
|
1038
|
-
if (compSize === 2) {
|
|
1039
|
-
indices[i] = this.bufferData[off] | this.bufferData[off + 1] << 8;
|
|
1040
|
-
} else {
|
|
1041
|
-
indices[i] = this.readFloat32(off);
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
const geom = { positions, normals, uvs, indices };
|
|
1045
|
-
const decimated = decimateGeometry(geom, ratio);
|
|
1046
|
-
const lodMeshIndex = this.meshes.length;
|
|
1047
|
-
const lodPrim = { attributes: {}, material: prim.material };
|
|
1048
|
-
lodPrim.attributes.POSITION = this.createAccessor(decimated.positions, "VEC3", true);
|
|
1049
|
-
lodPrim.attributes.NORMAL = this.createAccessor(decimated.normals, "VEC3");
|
|
1050
|
-
lodPrim.attributes.TEXCOORD_0 = this.createAccessor(decimated.uvs, "VEC2");
|
|
1051
|
-
lodPrim.indices = this.createAccessor(decimated.indices, "SCALAR");
|
|
1052
|
-
this.meshes.push({ name: `LOD${ratio}_mesh${mi}`, primitives: [lodPrim] });
|
|
1053
|
-
lodIds.push(lodMeshIndex);
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
if (lodIds.length > 0) {
|
|
1057
|
-
mesh["extensions"] = {
|
|
1058
|
-
MSFT_lod: { ids: lodIds }
|
|
1059
|
-
};
|
|
1060
|
-
coverages.push(0.5, 0.2);
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
if (coverages.length > 0) {
|
|
1064
|
-
this._lodCoverages = coverages;
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
/**
|
|
1068
|
-
* Build skeleton hierarchy and embed as glTF skin.
|
|
1069
|
-
* Creates 20 joint nodes with inverse bind matrices.
|
|
1070
|
-
*/
|
|
1071
|
-
buildSkeleton() {
|
|
1072
|
-
const bones = DRAGON_SKELETON;
|
|
1073
|
-
const boneNameToIdx = /* @__PURE__ */ new Map();
|
|
1074
|
-
const jointStartIndex = this.nodes.length;
|
|
1075
|
-
for (let i = 0; i < bones.length; i++) {
|
|
1076
|
-
const bone = bones[i];
|
|
1077
|
-
const nodeIdx = this.nodes.length;
|
|
1078
|
-
boneNameToIdx.set(bone.name, nodeIdx);
|
|
1079
|
-
const node = {
|
|
1080
|
-
name: `Joint_${bone.name}`,
|
|
1081
|
-
translation: bone.position
|
|
1082
|
-
};
|
|
1083
|
-
this.nodes.push(node);
|
|
1084
|
-
}
|
|
1085
|
-
for (const bone of bones) {
|
|
1086
|
-
if (bone.parent) {
|
|
1087
|
-
const parentIdx = boneNameToIdx.get(bone.parent);
|
|
1088
|
-
const childIdx = boneNameToIdx.get(bone.name);
|
|
1089
|
-
if (parentIdx !== void 0 && childIdx !== void 0) {
|
|
1090
|
-
const parentNode = this.nodes[parentIdx];
|
|
1091
|
-
if (!parentNode.children) parentNode.children = [];
|
|
1092
|
-
parentNode.children.push(childIdx);
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
const ibmData = new Float32Array(bones.length * 16);
|
|
1097
|
-
for (let i = 0; i < bones.length; i++) {
|
|
1098
|
-
const p = bones[i].position;
|
|
1099
|
-
const off = i * 16;
|
|
1100
|
-
ibmData[off + 0] = 1;
|
|
1101
|
-
ibmData[off + 5] = 1;
|
|
1102
|
-
ibmData[off + 10] = 1;
|
|
1103
|
-
ibmData[off + 15] = 1;
|
|
1104
|
-
ibmData[off + 12] = -p[0];
|
|
1105
|
-
ibmData[off + 13] = -p[1];
|
|
1106
|
-
ibmData[off + 14] = -p[2];
|
|
1107
|
-
}
|
|
1108
|
-
const ibmAccessor = this.createAccessorRaw(ibmData, "MAT4", 5126);
|
|
1109
|
-
const joints = [];
|
|
1110
|
-
for (let i = 0; i < bones.length; i++) {
|
|
1111
|
-
joints.push(jointStartIndex + i);
|
|
1112
|
-
}
|
|
1113
|
-
this._skins = [
|
|
1114
|
-
{
|
|
1115
|
-
skeleton: jointStartIndex,
|
|
1116
|
-
joints,
|
|
1117
|
-
inverseBindMatrices: ibmAccessor
|
|
1118
|
-
}
|
|
1119
|
-
];
|
|
1120
|
-
this._jointStartIndex = jointStartIndex;
|
|
1121
|
-
}
|
|
1122
|
-
/**
|
|
1123
|
-
* Skin all mesh nodes to the skeleton.
|
|
1124
|
-
* For each vertex, finds the 4 nearest bones by distance and assigns
|
|
1125
|
-
* normalized inverse-distance weights. Writes JOINTS_0 (Uint8) and
|
|
1126
|
-
* WEIGHTS_0 (Float32) attributes into each mesh primitive.
|
|
1127
|
-
*/
|
|
1128
|
-
skinMeshes() {
|
|
1129
|
-
if (!this._skins || this._skins.length === 0) return;
|
|
1130
|
-
const bones = DRAGON_SKELETON;
|
|
1131
|
-
const bonePositions = bones.map((b) => b.position);
|
|
1132
|
-
const originalNodeCount = this._jointStartIndex;
|
|
1133
|
-
for (let ni = 0; ni < originalNodeCount; ni++) {
|
|
1134
|
-
const node = this.nodes[ni];
|
|
1135
|
-
if (node.mesh === void 0) continue;
|
|
1136
|
-
const mesh = this.meshes[node.mesh];
|
|
1137
|
-
if (!mesh) continue;
|
|
1138
|
-
for (const prim of mesh.primitives) {
|
|
1139
|
-
const posIdx = prim.attributes.POSITION;
|
|
1140
|
-
if (posIdx === void 0) continue;
|
|
1141
|
-
const posAcc = this.accessors[posIdx];
|
|
1142
|
-
if (!posAcc) continue;
|
|
1143
|
-
const posBV = this.bufferViews[posAcc.bufferView];
|
|
1144
|
-
if (!posBV) continue;
|
|
1145
|
-
const vCount = posAcc.count;
|
|
1146
|
-
if (vCount === 0) continue;
|
|
1147
|
-
const tx = node.translation ? node.translation[0] : 0;
|
|
1148
|
-
const ty = node.translation ? node.translation[1] : 0;
|
|
1149
|
-
const tz = node.translation ? node.translation[2] : 0;
|
|
1150
|
-
const jointsData = new Uint8Array(vCount * 4);
|
|
1151
|
-
const weightsData = new Float32Array(vCount * 4);
|
|
1152
|
-
for (let vi = 0; vi < vCount; vi++) {
|
|
1153
|
-
const pOff = posBV.byteOffset + vi * 12;
|
|
1154
|
-
const vx = this.readFloat32(pOff) + tx;
|
|
1155
|
-
const vy = this.readFloat32(pOff + 4) + ty;
|
|
1156
|
-
const vz = this.readFloat32(pOff + 8) + tz;
|
|
1157
|
-
const distances = [];
|
|
1158
|
-
for (let bi = 0; bi < bonePositions.length; bi++) {
|
|
1159
|
-
const bp = bonePositions[bi];
|
|
1160
|
-
const dx = vx - bp[0], dy = vy - bp[1], dz = vz - bp[2];
|
|
1161
|
-
distances.push({ boneIdx: bi, distSq: dx * dx + dy * dy + dz * dz });
|
|
1162
|
-
}
|
|
1163
|
-
distances.sort((a, b) => a.distSq - b.distSq);
|
|
1164
|
-
const top4 = distances.slice(0, 4);
|
|
1165
|
-
let totalWeight = 0;
|
|
1166
|
-
const rawWeights = [];
|
|
1167
|
-
for (const d of top4) {
|
|
1168
|
-
const w = 1 / (d.distSq + 1e-4);
|
|
1169
|
-
rawWeights.push(w);
|
|
1170
|
-
totalWeight += w;
|
|
1171
|
-
}
|
|
1172
|
-
const off = vi * 4;
|
|
1173
|
-
for (let j = 0; j < 4; j++) {
|
|
1174
|
-
if (j < top4.length) {
|
|
1175
|
-
jointsData[off + j] = top4[j].boneIdx;
|
|
1176
|
-
weightsData[off + j] = rawWeights[j] / totalWeight;
|
|
1177
|
-
} else {
|
|
1178
|
-
jointsData[off + j] = 0;
|
|
1179
|
-
weightsData[off + j] = 0;
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
prim.attributes.JOINTS_0 = this.createAccessorRaw(jointsData, "VEC4", 5121);
|
|
1184
|
-
prim.attributes.WEIGHTS_0 = this.createAccessor(weightsData, "VEC4");
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
/**
|
|
1189
|
-
* Compile a HoloScript composition to glTF format
|
|
1190
|
-
*/
|
|
1191
|
-
compile(composition, agentToken, outputPath) {
|
|
1192
|
-
this.validateCompilerAccess(agentToken, outputPath);
|
|
1193
|
-
this.reset();
|
|
1194
|
-
this.processComposition(composition);
|
|
1195
|
-
this.smoothNormalsGlobal();
|
|
1196
|
-
this.generateLODs();
|
|
1197
|
-
this.buildSkeleton();
|
|
1198
|
-
this.skinMeshes();
|
|
1199
|
-
const buffer = this.bufferData.slice(0, this.bufferByteLength);
|
|
1200
|
-
if (SHARED_COMPILE_BUFFER.length > MAX_RETAINED_BUFFER_SIZE) {
|
|
1201
|
-
SHARED_COMPILE_BUFFER = new Uint8Array(INITIAL_COMPILE_BUFFER_SIZE);
|
|
1202
|
-
}
|
|
1203
|
-
const gltf = this.buildDocument(composition.name, buffer.byteLength);
|
|
1204
|
-
if (this.options.format === "glb") {
|
|
1205
|
-
const binary = this.createGLB(gltf, buffer);
|
|
1206
|
-
this.stats.fileSizeBytes = binary.byteLength;
|
|
1207
|
-
return {
|
|
1208
|
-
binary,
|
|
1209
|
-
stats: { ...this.stats }
|
|
1210
|
-
};
|
|
1211
|
-
} else {
|
|
1212
|
-
this.stats.fileSizeBytes = JSON.stringify(gltf).length + buffer.byteLength;
|
|
1213
|
-
return {
|
|
1214
|
-
json: gltf,
|
|
1215
|
-
buffer,
|
|
1216
|
-
stats: { ...this.stats }
|
|
1217
|
-
};
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
/**
|
|
1221
|
-
* Reset pipeline state for new compilation
|
|
1222
|
-
*/
|
|
1223
|
-
reset() {
|
|
1224
|
-
this.bufferByteLength = 0;
|
|
1225
|
-
this.accessors = [];
|
|
1226
|
-
this.bufferViews = [];
|
|
1227
|
-
this.meshes = [];
|
|
1228
|
-
this.materials = [];
|
|
1229
|
-
this.nodes = [];
|
|
1230
|
-
this.scenes = [];
|
|
1231
|
-
this.animations = [];
|
|
1232
|
-
this.materialMap.clear();
|
|
1233
|
-
this.images = [];
|
|
1234
|
-
this.textures = [];
|
|
1235
|
-
this.samplers = [];
|
|
1236
|
-
this.scaleTextureIndex = -1;
|
|
1237
|
-
this.scaleNormalTextureIndex = -1;
|
|
1238
|
-
this.textureIndexMap.clear();
|
|
1239
|
-
this.stats = {
|
|
1240
|
-
nodeCount: 0,
|
|
1241
|
-
meshCount: 0,
|
|
1242
|
-
materialCount: 0,
|
|
1243
|
-
textureCount: 0,
|
|
1244
|
-
animationCount: 0,
|
|
1245
|
-
totalVertices: 0,
|
|
1246
|
-
totalTriangles: 0,
|
|
1247
|
-
fileSizeBytes: 0
|
|
1248
|
-
};
|
|
1249
|
-
}
|
|
1250
|
-
/**
|
|
1251
|
-
* Process the entire composition
|
|
1252
|
-
*/
|
|
1253
|
-
processComposition(composition) {
|
|
1254
|
-
const rootNodes = [];
|
|
1255
|
-
for (const object of composition.objects || []) {
|
|
1256
|
-
const nodeIndex = this.processObject(object);
|
|
1257
|
-
if (nodeIndex !== -1) {
|
|
1258
|
-
rootNodes.push(nodeIndex);
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
for (const group of composition.spatialGroups || []) {
|
|
1262
|
-
const nodeIndex = this.processSpatialGroup(group);
|
|
1263
|
-
if (nodeIndex !== -1) {
|
|
1264
|
-
rootNodes.push(nodeIndex);
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
for (const light of composition.lights || []) {
|
|
1268
|
-
const nodeIndex = this.processLight(light);
|
|
1269
|
-
if (nodeIndex !== -1) {
|
|
1270
|
-
rootNodes.push(nodeIndex);
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
|
-
if (composition.camera) {
|
|
1274
|
-
const nodeIndex = this.processCamera(composition.camera);
|
|
1275
|
-
if (nodeIndex !== -1) {
|
|
1276
|
-
rootNodes.push(nodeIndex);
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
for (const timeline of composition.timelines || []) {
|
|
1280
|
-
this.processTimeline(timeline);
|
|
1281
|
-
}
|
|
1282
|
-
const domainBlocks = composition.domainBlocks ?? [];
|
|
1283
|
-
if (domainBlocks.length > 0) {
|
|
1284
|
-
chunkLXJ4667L_cjs.compileDomainBlocks(
|
|
1285
|
-
domainBlocks,
|
|
1286
|
-
{
|
|
1287
|
-
material: (block) => {
|
|
1288
|
-
const mat = chunkLXJ4667L_cjs.compileMaterialBlock(block);
|
|
1289
|
-
const gltfMat = chunkLXJ4667L_cjs.materialToGLTF(mat);
|
|
1290
|
-
this.materials.push(gltfMat);
|
|
1291
|
-
this.stats.materialCount++;
|
|
1292
|
-
return "";
|
|
1293
|
-
}
|
|
1294
|
-
},
|
|
1295
|
-
() => ""
|
|
1296
|
-
);
|
|
1297
|
-
}
|
|
1298
|
-
this.scenes.push({
|
|
1299
|
-
name: composition.name,
|
|
1300
|
-
nodes: rootNodes
|
|
1301
|
-
});
|
|
1302
|
-
}
|
|
1303
|
-
/**
|
|
1304
|
-
* Process a single object
|
|
1305
|
-
*/
|
|
1306
|
-
processObject(object) {
|
|
1307
|
-
const position = this.extractVec3Prop(object, "position", [0, 0, 0]);
|
|
1308
|
-
const rotation = this.extractVec3Prop(object, "rotation", [0, 0, 0]);
|
|
1309
|
-
const scale = this.extractVec3Prop(object, "scale", [1, 1, 1]);
|
|
1310
|
-
const geometryProp = this.findProp(object, "geometry") || this.findProp(object, "mesh") || this.findProp(object, "type");
|
|
1311
|
-
const shapeType = (typeof geometryProp === "string" ? geometryProp : "box").toLowerCase();
|
|
1312
|
-
let meshIndex;
|
|
1313
|
-
if (PRIMITIVE_GENERATORS[shapeType]) {
|
|
1314
|
-
meshIndex = this.createPrimitiveMesh(object.name, shapeType, scale, object);
|
|
1315
|
-
} else if (ADVANCED_GEOMETRY_TYPES.has(shapeType)) {
|
|
1316
|
-
meshIndex = this.createAdvancedMesh(object.name, shapeType, scale, object);
|
|
1317
|
-
}
|
|
1318
|
-
const node = gltfNodePool.acquire();
|
|
1319
|
-
node.name = object.name || `node_${this.nodes.length}`;
|
|
1320
|
-
node.translation = position;
|
|
1321
|
-
node.rotation = this.eulerToQuaternion(rotation);
|
|
1322
|
-
node.scale = [1, 1, 1];
|
|
1323
|
-
if (meshIndex !== void 0) {
|
|
1324
|
-
node.mesh = meshIndex;
|
|
1325
|
-
}
|
|
1326
|
-
if (object.children && object.children.length > 0) {
|
|
1327
|
-
const childIndices = [];
|
|
1328
|
-
for (const child of object.children) {
|
|
1329
|
-
const childIdx = this.processObject(child);
|
|
1330
|
-
if (childIdx !== -1) childIndices.push(childIdx);
|
|
1331
|
-
}
|
|
1332
|
-
if (childIndices.length > 0) node.children = childIndices;
|
|
1333
|
-
}
|
|
1334
|
-
const nodeIndex = this.nodes.length;
|
|
1335
|
-
this.nodes.push(node);
|
|
1336
|
-
this.stats.nodeCount++;
|
|
1337
|
-
return nodeIndex;
|
|
1338
|
-
}
|
|
1339
|
-
/**
|
|
1340
|
-
* Process a spatial group
|
|
1341
|
-
*/
|
|
1342
|
-
processSpatialGroup(group) {
|
|
1343
|
-
const childIndices = [];
|
|
1344
|
-
for (const child of group.objects || []) {
|
|
1345
|
-
const childIndex = this.processObject(child);
|
|
1346
|
-
if (childIndex !== -1) {
|
|
1347
|
-
childIndices.push(childIndex);
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
if (group.groups) {
|
|
1351
|
-
for (const sub of group.groups) {
|
|
1352
|
-
const subIdx = this.processSpatialGroup(sub);
|
|
1353
|
-
if (subIdx !== -1) childIndices.push(subIdx);
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
const posProp = (group.properties || []).find((p) => p.key === "position");
|
|
1357
|
-
const position = posProp && Array.isArray(posProp.value) ? [
|
|
1358
|
-
Number(posProp.value[0]) || 0,
|
|
1359
|
-
Number(posProp.value[1]) || 0,
|
|
1360
|
-
Number(posProp.value[2]) || 0
|
|
1361
|
-
] : [0, 0, 0];
|
|
1362
|
-
const node = gltfNodePool.acquire();
|
|
1363
|
-
node.name = group.name || `group_${this.nodes.length}`;
|
|
1364
|
-
node.translation = position;
|
|
1365
|
-
if (childIndices.length > 0) {
|
|
1366
|
-
node.children = childIndices;
|
|
1367
|
-
}
|
|
1368
|
-
const nodeIndex = this.nodes.length;
|
|
1369
|
-
this.nodes.push(node);
|
|
1370
|
-
this.stats.nodeCount++;
|
|
1371
|
-
return nodeIndex;
|
|
1372
|
-
}
|
|
1373
|
-
/**
|
|
1374
|
-
* Process a timeline as animation.
|
|
1375
|
-
*
|
|
1376
|
-
* HoloTimeline has entries: HoloTimelineEntry[] where each entry has
|
|
1377
|
-
* { time: number, action: HoloTimelineAction }.
|
|
1378
|
-
* We extract 'animate' actions and group them by target + property.
|
|
1379
|
-
*/
|
|
1380
|
-
processTimeline(timeline) {
|
|
1381
|
-
if (!timeline.entries || timeline.entries.length === 0) return;
|
|
1382
|
-
const animateEntries = timeline.entries.filter((e) => e.action.kind === "animate").map((e) => ({
|
|
1383
|
-
time: e.time,
|
|
1384
|
-
target: e.action.target,
|
|
1385
|
-
properties: e.action.properties
|
|
1386
|
-
}));
|
|
1387
|
-
if (animateEntries.length === 0) return;
|
|
1388
|
-
const channels = [];
|
|
1389
|
-
const samplers = [];
|
|
1390
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
1391
|
-
for (const entry of animateEntries) {
|
|
1392
|
-
const targetNodeIndex = this.nodes.findIndex((n) => n.name === entry.target);
|
|
1393
|
-
if (targetNodeIndex === -1) continue;
|
|
1394
|
-
for (const [prop, value] of Object.entries(entry.properties)) {
|
|
1395
|
-
const gltfPath = this.mapPropertyToGLTFPath(prop);
|
|
1396
|
-
if (!gltfPath) continue;
|
|
1397
|
-
const key = `${targetNodeIndex}:${gltfPath}`;
|
|
1398
|
-
if (!grouped.has(key)) grouped.set(key, []);
|
|
1399
|
-
grouped.get(key).push({ time: entry.time, value });
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
for (const [key, keyframes] of grouped) {
|
|
1403
|
-
const [nodeIdxStr, gltfPath] = key.split(":");
|
|
1404
|
-
const nodeIdx = parseInt(nodeIdxStr, 10);
|
|
1405
|
-
const times = keyframes.map((kf) => kf.time / 1e3);
|
|
1406
|
-
const inputAccessor = this.createAccessor(new Float32Array(times), "SCALAR");
|
|
1407
|
-
const values = [];
|
|
1408
|
-
for (const kf of keyframes) {
|
|
1409
|
-
if (Array.isArray(kf.value)) {
|
|
1410
|
-
if (gltfPath === "rotation") {
|
|
1411
|
-
const quat = this.eulerToQuaternion(kf.value);
|
|
1412
|
-
values.push(...quat);
|
|
1413
|
-
} else {
|
|
1414
|
-
values.push(...kf.value);
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
const outputType = gltfPath === "rotation" ? "VEC4" : "VEC3";
|
|
1419
|
-
const outputAccessor = this.createAccessor(new Float32Array(values), outputType);
|
|
1420
|
-
const samplerIndex = samplers.length;
|
|
1421
|
-
samplers.push({ input: inputAccessor, interpolation: "LINEAR", output: outputAccessor });
|
|
1422
|
-
channels.push({ sampler: samplerIndex, target: { node: nodeIdx, path: gltfPath } });
|
|
1423
|
-
}
|
|
1424
|
-
if (channels.length > 0) {
|
|
1425
|
-
this.animations.push({
|
|
1426
|
-
name: timeline.name || `animation_${this.animations.length}`,
|
|
1427
|
-
channels,
|
|
1428
|
-
samplers
|
|
1429
|
-
});
|
|
1430
|
-
this.stats.animationCount++;
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
/**
|
|
1434
|
-
* Create a primitive mesh
|
|
1435
|
-
*/
|
|
1436
|
-
createPrimitiveMesh(name, shapeType, scale, object) {
|
|
1437
|
-
const generator = PRIMITIVE_GENERATORS[shapeType];
|
|
1438
|
-
if (!generator) return -1;
|
|
1439
|
-
const geometry = generator(scale);
|
|
1440
|
-
const positionAccessor = this.createAccessor(geometry.positions, "VEC3", true);
|
|
1441
|
-
const normalAccessor = this.createAccessor(geometry.normals, "VEC3");
|
|
1442
|
-
const uvAccessor = this.createAccessor(geometry.uvs, "VEC2");
|
|
1443
|
-
const indexAccessor = this.createAccessor(geometry.indices, "SCALAR");
|
|
1444
|
-
const materialIndex = this.getOrCreateMaterial(object, shapeType);
|
|
1445
|
-
const mesh = {
|
|
1446
|
-
name: name || `mesh_${this.meshes.length}`,
|
|
1447
|
-
primitives: [
|
|
1448
|
-
{
|
|
1449
|
-
attributes: {
|
|
1450
|
-
POSITION: positionAccessor,
|
|
1451
|
-
NORMAL: normalAccessor,
|
|
1452
|
-
TEXCOORD_0: uvAccessor
|
|
1453
|
-
},
|
|
1454
|
-
indices: indexAccessor,
|
|
1455
|
-
material: materialIndex,
|
|
1456
|
-
mode: 4
|
|
1457
|
-
// TRIANGLES
|
|
1458
|
-
}
|
|
1459
|
-
]
|
|
1460
|
-
};
|
|
1461
|
-
const meshIndex = this.meshes.length;
|
|
1462
|
-
this.meshes.push(mesh);
|
|
1463
|
-
this.stats.meshCount++;
|
|
1464
|
-
this.stats.totalVertices += geometry.positions.length / 3;
|
|
1465
|
-
this.stats.totalTriangles += geometry.indices.length / 3;
|
|
1466
|
-
return meshIndex;
|
|
1467
|
-
}
|
|
1468
|
-
/**
|
|
1469
|
-
* Create an advanced mesh (spline, membrane, hull/metaball).
|
|
1470
|
-
* These geometry types need additional properties beyond scale.
|
|
1471
|
-
*/
|
|
1472
|
-
createAdvancedMesh(name, shapeType, scale, object) {
|
|
1473
|
-
let geometry;
|
|
1474
|
-
switch (shapeType) {
|
|
1475
|
-
case "spline": {
|
|
1476
|
-
const pointsProp = this.findProp(object, "points");
|
|
1477
|
-
const radiiProp = this.findProp(object, "radii");
|
|
1478
|
-
const segmentsProp = this.findProp(object, "segments");
|
|
1479
|
-
const stepsProp = this.findProp(object, "steps");
|
|
1480
|
-
const points = this.extractNestedArray(pointsProp, 3);
|
|
1481
|
-
const radii = Array.isArray(radiiProp) ? radiiProp.map(Number) : [0.1];
|
|
1482
|
-
while (radii.length < points.length) {
|
|
1483
|
-
radii.push(radii[radii.length - 1] ?? 0.1);
|
|
1484
|
-
}
|
|
1485
|
-
const radialSegments = typeof segmentsProp === "number" ? segmentsProp : 24;
|
|
1486
|
-
const lengthSteps = typeof stepsProp === "number" ? stepsProp : 8;
|
|
1487
|
-
geometry = chunkLK5IAVH6_cjs.generateSplineGeometry(points, radii, radialSegments, lengthSteps);
|
|
1488
|
-
break;
|
|
1489
|
-
}
|
|
1490
|
-
case "membrane": {
|
|
1491
|
-
const anchorsProp = this.findProp(object, "anchors");
|
|
1492
|
-
const subdivisionsProp = this.findProp(object, "subdivisions");
|
|
1493
|
-
const bulgeProp = this.findProp(object, "bulge");
|
|
1494
|
-
const anchors = this.extractNestedArray(anchorsProp, 3);
|
|
1495
|
-
const subdivisions = typeof subdivisionsProp === "number" ? subdivisionsProp : 8;
|
|
1496
|
-
const bulge = typeof bulgeProp === "number" ? bulgeProp : 0.15;
|
|
1497
|
-
geometry = chunkLK5IAVH6_cjs.generateMembraneGeometry(anchors, subdivisions, bulge);
|
|
1498
|
-
break;
|
|
1499
|
-
}
|
|
1500
|
-
case "hull":
|
|
1501
|
-
case "blob":
|
|
1502
|
-
case "metaball": {
|
|
1503
|
-
const blobsProp = this.findProp(object, "blobs");
|
|
1504
|
-
const resolutionProp = this.findProp(object, "resolution");
|
|
1505
|
-
const thresholdProp = this.findProp(object, "threshold");
|
|
1506
|
-
const blobs = [];
|
|
1507
|
-
if (Array.isArray(blobsProp)) {
|
|
1508
|
-
for (const blobItem of blobsProp) {
|
|
1509
|
-
if (blobItem && typeof blobItem === "object") {
|
|
1510
|
-
const b = blobItem;
|
|
1511
|
-
const center = Array.isArray(b.center) ? b.center.map(Number) : [0, 0, 0];
|
|
1512
|
-
const radius = Array.isArray(b.radius) ? b.radius.map(Number) : [0.5, 0.5, 0.5];
|
|
1513
|
-
blobs.push({ center, radius });
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
if (blobs.length === 0) {
|
|
1518
|
-
blobs.push({
|
|
1519
|
-
center: [0, 0, 0],
|
|
1520
|
-
radius: [scale[0] * 0.5, scale[1] * 0.5, scale[2] * 0.5]
|
|
1521
|
-
});
|
|
1522
|
-
}
|
|
1523
|
-
const resolution = typeof resolutionProp === "number" ? resolutionProp : 24;
|
|
1524
|
-
const threshold = typeof thresholdProp === "number" ? thresholdProp : 1;
|
|
1525
|
-
geometry = chunkLK5IAVH6_cjs.generateHullGeometry(blobs, resolution, threshold);
|
|
1526
|
-
break;
|
|
1527
|
-
}
|
|
1528
|
-
default:
|
|
1529
|
-
return -1;
|
|
1530
|
-
}
|
|
1531
|
-
const positionAccessor = this.createAccessor(geometry.positions, "VEC3", true);
|
|
1532
|
-
const normalAccessor = this.createAccessor(geometry.normals, "VEC3");
|
|
1533
|
-
const uvAccessor = this.createAccessor(geometry.uvs, "VEC2");
|
|
1534
|
-
const indexAccessor = this.createAccessor(geometry.indices, "SCALAR");
|
|
1535
|
-
const materialIndex = this.getOrCreateMaterial(object, shapeType);
|
|
1536
|
-
const mesh = {
|
|
1537
|
-
name: name || `mesh_${this.meshes.length}`,
|
|
1538
|
-
primitives: [
|
|
1539
|
-
{
|
|
1540
|
-
attributes: {
|
|
1541
|
-
POSITION: positionAccessor,
|
|
1542
|
-
NORMAL: normalAccessor,
|
|
1543
|
-
TEXCOORD_0: uvAccessor
|
|
1544
|
-
},
|
|
1545
|
-
indices: indexAccessor,
|
|
1546
|
-
material: materialIndex,
|
|
1547
|
-
mode: 4
|
|
1548
|
-
// TRIANGLES
|
|
1549
|
-
}
|
|
1550
|
-
]
|
|
1551
|
-
};
|
|
1552
|
-
const meshIndex = this.meshes.length;
|
|
1553
|
-
this.meshes.push(mesh);
|
|
1554
|
-
this.stats.meshCount++;
|
|
1555
|
-
this.stats.totalVertices += geometry.positions.length / 3;
|
|
1556
|
-
this.stats.totalTriangles += geometry.indices.length / 3;
|
|
1557
|
-
return meshIndex;
|
|
1558
|
-
}
|
|
1559
|
-
/**
|
|
1560
|
-
* Extract a nested array of vec3s from a HoloValue.
|
|
1561
|
-
* e.g. [[0, 1, 2], [3, 4, 5]] => [[0,1,2], [3,4,5]]
|
|
1562
|
-
*/
|
|
1563
|
-
extractNestedArray(val, expectedLength) {
|
|
1564
|
-
const result = [];
|
|
1565
|
-
if (!Array.isArray(val)) return result;
|
|
1566
|
-
for (const item of val) {
|
|
1567
|
-
if (Array.isArray(item) && item.length >= expectedLength) {
|
|
1568
|
-
result.push(item.slice(0, expectedLength).map(Number));
|
|
1569
|
-
}
|
|
1570
|
-
}
|
|
1571
|
-
return result;
|
|
1572
|
-
}
|
|
1573
|
-
/**
|
|
1574
|
-
* Get or create a material from object properties + traits.
|
|
1575
|
-
*
|
|
1576
|
-
* Material composition order (later overrides earlier):
|
|
1577
|
-
* 1. Defaults (white, metallic 0, roughness 0.5)
|
|
1578
|
-
* 2. Named material preset (e.g., material: "glass")
|
|
1579
|
-
* 3. TraitCompositor output (PBR from visual presets)
|
|
1580
|
-
* 4. Direct property overrides (color, opacity)
|
|
1581
|
-
*/
|
|
1582
|
-
getOrCreateMaterial(object, shapeType) {
|
|
1583
|
-
let color = [1, 1, 1];
|
|
1584
|
-
let metallic = 0;
|
|
1585
|
-
let roughness = 0.5;
|
|
1586
|
-
let opacity = 1;
|
|
1587
|
-
let emissive = [0, 0, 0];
|
|
1588
|
-
let transmission = 0;
|
|
1589
|
-
let ior = 1.5;
|
|
1590
|
-
let thickness = 0;
|
|
1591
|
-
let clearcoat = 0;
|
|
1592
|
-
let clearcoatRoughness = 0;
|
|
1593
|
-
let sheen = 0;
|
|
1594
|
-
let sheenRoughness = 0.5;
|
|
1595
|
-
let sheenColor = [1, 1, 1];
|
|
1596
|
-
let iridescence = 0;
|
|
1597
|
-
let iridescenceIOR = 1.3;
|
|
1598
|
-
let anisotropy = 0;
|
|
1599
|
-
let anisotropyRotation = 0;
|
|
1600
|
-
let attenuationColor;
|
|
1601
|
-
let attenuationDistance;
|
|
1602
|
-
const namedMat = this.findProp(object, "material");
|
|
1603
|
-
if (typeof namedMat === "string" && chunkQ5SJOGHQ_cjs.MATERIAL_PRESETS[namedMat]) {
|
|
1604
|
-
const preset = chunkQ5SJOGHQ_cjs.MATERIAL_PRESETS[namedMat];
|
|
1605
|
-
if (preset.color) color = this.parseColorString(preset.color);
|
|
1606
|
-
if (preset.metalness !== void 0) metallic = preset.metalness;
|
|
1607
|
-
if (preset.roughness !== void 0) roughness = preset.roughness;
|
|
1608
|
-
if (preset.opacity !== void 0) opacity = preset.opacity;
|
|
1609
|
-
if (preset.transparent && opacity >= 1) opacity = 0.99;
|
|
1610
|
-
if (preset.emissive) emissive = this.parseColorString(preset.emissive);
|
|
1611
|
-
if (preset.transmission !== void 0) transmission = preset.transmission;
|
|
1612
|
-
if (preset.ior !== void 0) ior = preset.ior;
|
|
1613
|
-
if (preset.thickness !== void 0) thickness = preset.thickness;
|
|
1614
|
-
if (preset.clearcoat !== void 0) clearcoat = preset.clearcoat;
|
|
1615
|
-
if (preset.clearcoatRoughness !== void 0) clearcoatRoughness = preset.clearcoatRoughness;
|
|
1616
|
-
if (preset.sheen !== void 0) sheen = preset.sheen;
|
|
1617
|
-
if (preset.sheenRoughness !== void 0) sheenRoughness = preset.sheenRoughness;
|
|
1618
|
-
if (preset.sheenColor) sheenColor = this.parseColorString(preset.sheenColor);
|
|
1619
|
-
if (preset.iridescence !== void 0) iridescence = preset.iridescence;
|
|
1620
|
-
if (preset.iridescenceIOR !== void 0) iridescenceIOR = preset.iridescenceIOR;
|
|
1621
|
-
if (preset.anisotropy !== void 0) anisotropy = preset.anisotropy;
|
|
1622
|
-
if (preset.anisotropyRotation !== void 0) anisotropyRotation = preset.anisotropyRotation;
|
|
1623
|
-
if (preset.attenuationColor)
|
|
1624
|
-
attenuationColor = this.parseColorString(preset.attenuationColor);
|
|
1625
|
-
if (preset.attenuationDistance !== void 0)
|
|
1626
|
-
attenuationDistance = preset.attenuationDistance;
|
|
1627
|
-
}
|
|
1628
|
-
const traitNames = (object.traits || []).map((t) => t.name);
|
|
1629
|
-
if (traitNames.length > 0) {
|
|
1630
|
-
const composed = this.compositor.compose(traitNames);
|
|
1631
|
-
if (composed.color) color = this.parseColorString(composed.color);
|
|
1632
|
-
if (composed.metalness !== void 0) metallic = composed.metalness;
|
|
1633
|
-
if (composed.roughness !== void 0) roughness = composed.roughness;
|
|
1634
|
-
if (composed.opacity !== void 0) opacity = composed.opacity;
|
|
1635
|
-
if (composed.emissive) emissive = this.parseColorString(composed.emissive);
|
|
1636
|
-
if (composed.transparent) opacity = Math.min(opacity, 0.9);
|
|
1637
|
-
if (composed.transmission !== void 0) transmission = composed.transmission;
|
|
1638
|
-
if (composed.ior !== void 0) ior = composed.ior;
|
|
1639
|
-
if (composed.thickness !== void 0) thickness = composed.thickness;
|
|
1640
|
-
if (composed.clearcoat !== void 0) clearcoat = composed.clearcoat;
|
|
1641
|
-
if (composed.clearcoatRoughness !== void 0)
|
|
1642
|
-
clearcoatRoughness = composed.clearcoatRoughness;
|
|
1643
|
-
if (composed.sheen !== void 0) sheen = composed.sheen;
|
|
1644
|
-
if (composed.sheenRoughness !== void 0) sheenRoughness = composed.sheenRoughness;
|
|
1645
|
-
if (composed.sheenColor) sheenColor = this.parseColorString(composed.sheenColor);
|
|
1646
|
-
if (composed.iridescence !== void 0) iridescence = composed.iridescence;
|
|
1647
|
-
if (composed.iridescenceIOR !== void 0) iridescenceIOR = composed.iridescenceIOR;
|
|
1648
|
-
if (composed.anisotropy !== void 0) anisotropy = composed.anisotropy;
|
|
1649
|
-
if (composed.anisotropyRotation !== void 0)
|
|
1650
|
-
anisotropyRotation = composed.anisotropyRotation;
|
|
1651
|
-
if (composed.attenuationColor)
|
|
1652
|
-
attenuationColor = this.parseColorString(composed.attenuationColor);
|
|
1653
|
-
if (composed.attenuationDistance !== void 0)
|
|
1654
|
-
attenuationDistance = composed.attenuationDistance;
|
|
1655
|
-
}
|
|
1656
|
-
const colorProp = this.findProp(object, "color");
|
|
1657
|
-
if (typeof colorProp === "string") {
|
|
1658
|
-
color = this.parseColorString(colorProp);
|
|
1659
|
-
} else if (Array.isArray(colorProp) && colorProp.length >= 3) {
|
|
1660
|
-
color = [Number(colorProp[0]), Number(colorProp[1]), Number(colorProp[2])];
|
|
1661
|
-
}
|
|
1662
|
-
const opacityProp = this.findProp(object, "opacity");
|
|
1663
|
-
if (typeof opacityProp === "number") opacity = opacityProp;
|
|
1664
|
-
const metallicProp = this.findProp(object, "metallic") ?? this.findProp(object, "metalness");
|
|
1665
|
-
if (typeof metallicProp === "number") metallic = metallicProp;
|
|
1666
|
-
const roughnessProp = this.findProp(object, "roughness");
|
|
1667
|
-
if (typeof roughnessProp === "number") roughness = roughnessProp;
|
|
1668
|
-
const emissiveIntensityProp = this.findProp(object, "emissiveIntensity");
|
|
1669
|
-
const emissiveIntensity = typeof emissiveIntensityProp === "number" ? emissiveIntensityProp : 1;
|
|
1670
|
-
const emissiveProp = this.findProp(object, "emissive");
|
|
1671
|
-
if (typeof emissiveProp === "string") emissive = this.parseColorString(emissiveProp);
|
|
1672
|
-
const transmissionProp = this.findProp(object, "transmission");
|
|
1673
|
-
if (typeof transmissionProp === "number") transmission = transmissionProp;
|
|
1674
|
-
const iorProp = this.findProp(object, "ior");
|
|
1675
|
-
if (typeof iorProp === "number") ior = iorProp;
|
|
1676
|
-
const clearcoatProp = this.findProp(object, "clearcoat");
|
|
1677
|
-
if (typeof clearcoatProp === "number") clearcoat = clearcoatProp;
|
|
1678
|
-
const texturePaths = {};
|
|
1679
|
-
const TEX_PROP_MAP = {
|
|
1680
|
-
// HoloScript property name → glTF slot key
|
|
1681
|
-
baseColorMap: "baseColor",
|
|
1682
|
-
albedo_map: "baseColor",
|
|
1683
|
-
colorMap: "baseColor",
|
|
1684
|
-
normalMap: "normal",
|
|
1685
|
-
normal_map: "normal",
|
|
1686
|
-
roughnessMap: "metallicRoughness",
|
|
1687
|
-
roughness_map: "metallicRoughness",
|
|
1688
|
-
metallicMap: "metallicRoughness",
|
|
1689
|
-
metallic_map: "metallicRoughness",
|
|
1690
|
-
metalnessMap: "metallicRoughness",
|
|
1691
|
-
occlusionMap: "occlusion",
|
|
1692
|
-
ao_map: "occlusion",
|
|
1693
|
-
ambientOcclusionMap: "occlusion",
|
|
1694
|
-
emissiveMap: "emissive",
|
|
1695
|
-
emissive_map: "emissive",
|
|
1696
|
-
emissionMap: "emissive"
|
|
1697
|
-
};
|
|
1698
|
-
for (const [propName, slotKey] of Object.entries(TEX_PROP_MAP)) {
|
|
1699
|
-
const val = this.findProp(object, propName);
|
|
1700
|
-
if (typeof val === "string" && val.length > 0 && !texturePaths[slotKey]) {
|
|
1701
|
-
texturePaths[slotKey] = val;
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
const key = JSON.stringify({
|
|
1705
|
-
color,
|
|
1706
|
-
metallic,
|
|
1707
|
-
roughness,
|
|
1708
|
-
opacity,
|
|
1709
|
-
emissive,
|
|
1710
|
-
transmission,
|
|
1711
|
-
ior,
|
|
1712
|
-
thickness,
|
|
1713
|
-
clearcoat,
|
|
1714
|
-
clearcoatRoughness,
|
|
1715
|
-
sheen,
|
|
1716
|
-
sheenRoughness,
|
|
1717
|
-
sheenColor,
|
|
1718
|
-
iridescence,
|
|
1719
|
-
iridescenceIOR,
|
|
1720
|
-
anisotropy,
|
|
1721
|
-
anisotropyRotation,
|
|
1722
|
-
attenuationColor,
|
|
1723
|
-
attenuationDistance,
|
|
1724
|
-
texturePaths
|
|
1725
|
-
});
|
|
1726
|
-
if (this.materialMap.has(key)) {
|
|
1727
|
-
return this.materialMap.get(key);
|
|
1728
|
-
}
|
|
1729
|
-
const material = {
|
|
1730
|
-
name: `material_${this.materials.length}`,
|
|
1731
|
-
pbrMetallicRoughness: {
|
|
1732
|
-
baseColorFactor: [...color, opacity],
|
|
1733
|
-
metallicFactor: metallic,
|
|
1734
|
-
roughnessFactor: roughness
|
|
1735
|
-
},
|
|
1736
|
-
doubleSided: opacity < 1 || transmission > 0
|
|
1737
|
-
};
|
|
1738
|
-
if (opacity < 1 || transmission > 0) {
|
|
1739
|
-
material.alphaMode = "BLEND";
|
|
1740
|
-
}
|
|
1741
|
-
const emissiveSum = emissive[0] + emissive[1] + emissive[2];
|
|
1742
|
-
if (emissiveSum > 0) {
|
|
1743
|
-
material.emissiveFactor = emissive.map((c) => c * emissiveIntensity);
|
|
1744
|
-
}
|
|
1745
|
-
const extensions = {};
|
|
1746
|
-
if (transmission > 0) {
|
|
1747
|
-
Object.assign(extensions, createTransmissionExtension(transmission));
|
|
1748
|
-
}
|
|
1749
|
-
if (ior !== 1.5) {
|
|
1750
|
-
Object.assign(extensions, createIORExtension(ior));
|
|
1751
|
-
}
|
|
1752
|
-
if (clearcoat > 0) {
|
|
1753
|
-
Object.assign(
|
|
1754
|
-
extensions,
|
|
1755
|
-
createClearcoatExtension({ factor: clearcoat, roughness: clearcoatRoughness })
|
|
1756
|
-
);
|
|
1757
|
-
}
|
|
1758
|
-
if (sheen > 0) {
|
|
1759
|
-
Object.assign(
|
|
1760
|
-
extensions,
|
|
1761
|
-
createSheenExtension({ color: sheenColor, roughness: sheenRoughness })
|
|
1762
|
-
);
|
|
1763
|
-
}
|
|
1764
|
-
if (iridescence > 0) {
|
|
1765
|
-
Object.assign(
|
|
1766
|
-
extensions,
|
|
1767
|
-
createIridescenceExtension({ factor: iridescence, ior: iridescenceIOR })
|
|
1768
|
-
);
|
|
1769
|
-
}
|
|
1770
|
-
if (anisotropy > 0) {
|
|
1771
|
-
Object.assign(
|
|
1772
|
-
extensions,
|
|
1773
|
-
createAnisotropyExtension({ strength: anisotropy, rotation: anisotropyRotation })
|
|
1774
|
-
);
|
|
1775
|
-
}
|
|
1776
|
-
if (thickness > 0 || attenuationDistance !== void 0) {
|
|
1777
|
-
Object.assign(
|
|
1778
|
-
extensions,
|
|
1779
|
-
createVolumeExtension({
|
|
1780
|
-
thickness: thickness || 1,
|
|
1781
|
-
attenuationDistance,
|
|
1782
|
-
attenuationColor
|
|
1783
|
-
})
|
|
1784
|
-
);
|
|
1785
|
-
}
|
|
1786
|
-
if (emissiveIntensity > 1) {
|
|
1787
|
-
Object.assign(extensions, createEmissiveStrengthExtension(emissiveIntensity));
|
|
1788
|
-
}
|
|
1789
|
-
if (Object.keys(extensions).length > 0) {
|
|
1790
|
-
material.extensions = extensions;
|
|
1791
|
-
}
|
|
1792
|
-
const isScaledGeometry = shapeType === "hull" || shapeType === "metaball";
|
|
1793
|
-
const isScaledMaterial = typeof namedMat === "string" && (namedMat === "skin_dark" || namedMat === "leather");
|
|
1794
|
-
if (isScaledGeometry || isScaledMaterial) {
|
|
1795
|
-
const texIdx = this.ensureScaleTexture();
|
|
1796
|
-
if (texIdx >= 0) {
|
|
1797
|
-
material.pbrMetallicRoughness.baseColorTexture = {
|
|
1798
|
-
index: texIdx,
|
|
1799
|
-
texCoord: 0
|
|
1800
|
-
};
|
|
1801
|
-
if (this.scaleNormalTextureIndex >= 0) {
|
|
1802
|
-
material.normalTexture = {
|
|
1803
|
-
index: this.scaleNormalTextureIndex,
|
|
1804
|
-
texCoord: 0,
|
|
1805
|
-
scale: 1
|
|
1806
|
-
};
|
|
1807
|
-
}
|
|
1808
|
-
this.stats.textureCount = 2;
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
if (Object.keys(texturePaths).length > 0) {
|
|
1812
|
-
const pbr = material.pbrMetallicRoughness;
|
|
1813
|
-
if (texturePaths.baseColor && !pbr.baseColorTexture) {
|
|
1814
|
-
const idx = this.getOrCreateExternalTexture(texturePaths.baseColor);
|
|
1815
|
-
if (idx >= 0) pbr.baseColorTexture = { index: idx, texCoord: 0 };
|
|
1816
|
-
}
|
|
1817
|
-
if (texturePaths.metallicRoughness && !pbr.metallicRoughnessTexture) {
|
|
1818
|
-
const idx = this.getOrCreateExternalTexture(texturePaths.metallicRoughness);
|
|
1819
|
-
if (idx >= 0) pbr.metallicRoughnessTexture = { index: idx, texCoord: 0 };
|
|
1820
|
-
}
|
|
1821
|
-
const matRecord = material;
|
|
1822
|
-
if (texturePaths.normal && !matRecord.normalTexture) {
|
|
1823
|
-
const idx = this.getOrCreateExternalTexture(texturePaths.normal);
|
|
1824
|
-
if (idx >= 0) matRecord.normalTexture = { index: idx, texCoord: 0, scale: 1 };
|
|
1825
|
-
}
|
|
1826
|
-
if (texturePaths.occlusion && !matRecord.occlusionTexture) {
|
|
1827
|
-
const idx = this.getOrCreateExternalTexture(texturePaths.occlusion);
|
|
1828
|
-
if (idx >= 0) matRecord.occlusionTexture = { index: idx, texCoord: 0, strength: 1 };
|
|
1829
|
-
}
|
|
1830
|
-
if (texturePaths.emissive && !matRecord.emissiveTexture) {
|
|
1831
|
-
const idx = this.getOrCreateExternalTexture(texturePaths.emissive);
|
|
1832
|
-
if (idx >= 0) matRecord.emissiveTexture = { index: idx, texCoord: 0 };
|
|
1833
|
-
}
|
|
1834
|
-
}
|
|
1835
|
-
const materialIndex = this.materials.length;
|
|
1836
|
-
this.materials.push(material);
|
|
1837
|
-
this.materialMap.set(key, materialIndex);
|
|
1838
|
-
this.stats.materialCount++;
|
|
1839
|
-
return materialIndex;
|
|
1840
|
-
}
|
|
1841
|
-
/**
|
|
1842
|
-
* Embed an external texture image in the glTF buffer. Returns the texture
|
|
1843
|
-
* index, or -1 if the image data is not available in options.textureData.
|
|
1844
|
-
* Caches by path so the same image is only embedded once.
|
|
1845
|
-
*/
|
|
1846
|
-
getOrCreateExternalTexture(path) {
|
|
1847
|
-
if (this.textureIndexMap.has(path)) {
|
|
1848
|
-
return this.textureIndexMap.get(path);
|
|
1849
|
-
}
|
|
1850
|
-
const imageData = this.options.textureData[path];
|
|
1851
|
-
if (!imageData || imageData.length === 0) {
|
|
1852
|
-
return -1;
|
|
1853
|
-
}
|
|
1854
|
-
const isPNG = imageData[0] === 137 && imageData[1] === 80;
|
|
1855
|
-
const isJPEG = imageData[0] === 255 && imageData[1] === 216;
|
|
1856
|
-
const mimeType = isPNG ? "image/png" : isJPEG ? "image/jpeg" : "image/png";
|
|
1857
|
-
const byteOffset = this.bufferByteLength;
|
|
1858
|
-
this.appendToBuffer(imageData);
|
|
1859
|
-
this.padBuffer(4);
|
|
1860
|
-
const bufferViewIndex = this.bufferViews.length;
|
|
1861
|
-
this.bufferViews.push({
|
|
1862
|
-
buffer: 0,
|
|
1863
|
-
byteOffset,
|
|
1864
|
-
byteLength: imageData.length
|
|
1865
|
-
});
|
|
1866
|
-
const imageIndex = this.images.length;
|
|
1867
|
-
this.images.push({
|
|
1868
|
-
bufferView: bufferViewIndex,
|
|
1869
|
-
mimeType
|
|
1870
|
-
});
|
|
1871
|
-
let samplerIndex;
|
|
1872
|
-
if (this.samplers.length > 0) {
|
|
1873
|
-
samplerIndex = 0;
|
|
1874
|
-
} else {
|
|
1875
|
-
samplerIndex = this.samplers.length;
|
|
1876
|
-
this.samplers.push({
|
|
1877
|
-
magFilter: 9729,
|
|
1878
|
-
// LINEAR
|
|
1879
|
-
minFilter: 9987,
|
|
1880
|
-
// LINEAR_MIPMAP_LINEAR
|
|
1881
|
-
wrapS: 10497,
|
|
1882
|
-
// REPEAT
|
|
1883
|
-
wrapT: 10497
|
|
1884
|
-
// REPEAT
|
|
1885
|
-
});
|
|
1886
|
-
}
|
|
1887
|
-
const textureIndex = this.textures.length;
|
|
1888
|
-
this.textures.push({
|
|
1889
|
-
source: imageIndex,
|
|
1890
|
-
sampler: samplerIndex
|
|
1891
|
-
});
|
|
1892
|
-
this.textureIndexMap.set(path, textureIndex);
|
|
1893
|
-
this.stats.textureCount++;
|
|
1894
|
-
return textureIndex;
|
|
1895
|
-
}
|
|
1896
|
-
/**
|
|
1897
|
-
* Ensure the procedural scale texture is generated and embedded in the glTF.
|
|
1898
|
-
* Returns the texture index, or -1 if generation failed.
|
|
1899
|
-
*/
|
|
1900
|
-
ensureScaleTexture() {
|
|
1901
|
-
if (this.scaleTextureIndex >= 0) return this.scaleTextureIndex;
|
|
1902
|
-
const TEX_SIZE = 256;
|
|
1903
|
-
const pixels = generateScaleTexture(TEX_SIZE);
|
|
1904
|
-
const pngData = encodePNG(pixels, TEX_SIZE, TEX_SIZE);
|
|
1905
|
-
const byteOffset = this.bufferByteLength;
|
|
1906
|
-
this.appendToBuffer(pngData);
|
|
1907
|
-
this.padBuffer(4);
|
|
1908
|
-
const bufferViewIndex = this.bufferViews.length;
|
|
1909
|
-
this.bufferViews.push({
|
|
1910
|
-
buffer: 0,
|
|
1911
|
-
byteOffset,
|
|
1912
|
-
byteLength: pngData.length
|
|
1913
|
-
});
|
|
1914
|
-
const imageIndex = this.images.length;
|
|
1915
|
-
this.images.push({
|
|
1916
|
-
bufferView: bufferViewIndex,
|
|
1917
|
-
mimeType: "image/png"
|
|
1918
|
-
});
|
|
1919
|
-
const samplerIndex = this.samplers.length;
|
|
1920
|
-
this.samplers.push({
|
|
1921
|
-
magFilter: 9729,
|
|
1922
|
-
// LINEAR
|
|
1923
|
-
minFilter: 9987,
|
|
1924
|
-
// LINEAR_MIPMAP_LINEAR
|
|
1925
|
-
wrapS: 10497,
|
|
1926
|
-
// REPEAT
|
|
1927
|
-
wrapT: 10497
|
|
1928
|
-
// REPEAT
|
|
1929
|
-
});
|
|
1930
|
-
this.scaleTextureIndex = this.textures.length;
|
|
1931
|
-
this.textures.push({
|
|
1932
|
-
source: imageIndex,
|
|
1933
|
-
sampler: samplerIndex
|
|
1934
|
-
});
|
|
1935
|
-
const normalPixels = generateScaleNormalMap(TEX_SIZE);
|
|
1936
|
-
const normalPng = encodePNG(normalPixels, TEX_SIZE, TEX_SIZE);
|
|
1937
|
-
const normalByteOffset = this.bufferByteLength;
|
|
1938
|
-
this.appendToBuffer(normalPng);
|
|
1939
|
-
this.padBuffer(4);
|
|
1940
|
-
const normalBVIndex = this.bufferViews.length;
|
|
1941
|
-
this.bufferViews.push({
|
|
1942
|
-
buffer: 0,
|
|
1943
|
-
byteOffset: normalByteOffset,
|
|
1944
|
-
byteLength: normalPng.length
|
|
1945
|
-
});
|
|
1946
|
-
const normalImageIndex = this.images.length;
|
|
1947
|
-
this.images.push({
|
|
1948
|
-
bufferView: normalBVIndex,
|
|
1949
|
-
mimeType: "image/png"
|
|
1950
|
-
});
|
|
1951
|
-
this.scaleNormalTextureIndex = this.textures.length;
|
|
1952
|
-
this.textures.push({
|
|
1953
|
-
source: normalImageIndex,
|
|
1954
|
-
sampler: samplerIndex
|
|
1955
|
-
// reuse same sampler
|
|
1956
|
-
});
|
|
1957
|
-
return this.scaleTextureIndex;
|
|
1958
|
-
}
|
|
1959
|
-
/**
|
|
1960
|
-
* Create an accessor with arbitrary type string (e.g., MAT4 for skeleton data, VEC4 for skinning).
|
|
1961
|
-
* Supports Uint8Array for UNSIGNED_BYTE (5121), Uint16Array for UNSIGNED_SHORT (5123),
|
|
1962
|
-
* Uint32Array for UNSIGNED_INT (5125), and Float32Array for FLOAT (5126).
|
|
1963
|
-
*/
|
|
1964
|
-
createAccessorRaw(data, type, componentType) {
|
|
1965
|
-
const byteOffset = this.bufferByteLength;
|
|
1966
|
-
const view = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
1967
|
-
this.appendToBuffer(view);
|
|
1968
|
-
this.padBuffer(4);
|
|
1969
|
-
const bufferViewIndex = this.bufferViews.length;
|
|
1970
|
-
this.bufferViews.push({
|
|
1971
|
-
buffer: 0,
|
|
1972
|
-
byteOffset,
|
|
1973
|
-
byteLength: data.byteLength
|
|
1974
|
-
});
|
|
1975
|
-
const comps = type === "MAT4" ? 16 : type === "VEC4" ? 4 : type === "VEC3" ? 3 : type === "VEC2" ? 2 : 1;
|
|
1976
|
-
const count = data.length / comps;
|
|
1977
|
-
const accessorIndex = this.accessors.length;
|
|
1978
|
-
this.accessors.push({
|
|
1979
|
-
bufferView: bufferViewIndex,
|
|
1980
|
-
componentType,
|
|
1981
|
-
count,
|
|
1982
|
-
type
|
|
1983
|
-
});
|
|
1984
|
-
return accessorIndex;
|
|
1985
|
-
}
|
|
1986
|
-
/**
|
|
1987
|
-
* Create an accessor and buffer view for data
|
|
1988
|
-
*/
|
|
1989
|
-
createAccessor(data, type, computeBounds = false) {
|
|
1990
|
-
const byteOffset = this.bufferByteLength;
|
|
1991
|
-
const componentType = data instanceof Uint32Array ? 5125 : data instanceof Uint16Array ? 5123 : 5126;
|
|
1992
|
-
const view = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
1993
|
-
this.appendToBuffer(view);
|
|
1994
|
-
this.padBuffer(4);
|
|
1995
|
-
const bufferViewIndex = this.bufferViews.length;
|
|
1996
|
-
const bufferView = {
|
|
1997
|
-
buffer: 0,
|
|
1998
|
-
byteOffset,
|
|
1999
|
-
byteLength: data.byteLength
|
|
2000
|
-
};
|
|
2001
|
-
if (componentType === 5126) {
|
|
2002
|
-
bufferView.target = 34962;
|
|
2003
|
-
} else {
|
|
2004
|
-
bufferView.target = 34963;
|
|
2005
|
-
}
|
|
2006
|
-
this.bufferViews.push(bufferView);
|
|
2007
|
-
const componentsPerElement = type === "SCALAR" ? 1 : type === "VEC2" ? 2 : type === "VEC3" ? 3 : 4;
|
|
2008
|
-
const count = data.length / componentsPerElement;
|
|
2009
|
-
const accessor = {
|
|
2010
|
-
bufferView: bufferViewIndex,
|
|
2011
|
-
componentType,
|
|
2012
|
-
count,
|
|
2013
|
-
type
|
|
2014
|
-
};
|
|
2015
|
-
if (computeBounds && type === "VEC3" && data instanceof Float32Array) {
|
|
2016
|
-
const min = [Infinity, Infinity, Infinity];
|
|
2017
|
-
const max = [-Infinity, -Infinity, -Infinity];
|
|
2018
|
-
for (let i = 0; i < data.length; i += 3) {
|
|
2019
|
-
min[0] = Math.min(min[0], data[i]);
|
|
2020
|
-
min[1] = Math.min(min[1], data[i + 1]);
|
|
2021
|
-
min[2] = Math.min(min[2], data[i + 2]);
|
|
2022
|
-
max[0] = Math.max(max[0], data[i]);
|
|
2023
|
-
max[1] = Math.max(max[1], data[i + 1]);
|
|
2024
|
-
max[2] = Math.max(max[2], data[i + 2]);
|
|
2025
|
-
}
|
|
2026
|
-
accessor.min = min;
|
|
2027
|
-
accessor.max = max;
|
|
2028
|
-
}
|
|
2029
|
-
const accessorIndex = this.accessors.length;
|
|
2030
|
-
this.accessors.push(accessor);
|
|
2031
|
-
return accessorIndex;
|
|
2032
|
-
}
|
|
2033
|
-
/**
|
|
2034
|
-
* Build the glTF JSON document
|
|
2035
|
-
*/
|
|
2036
|
-
buildDocument(name, bufferLength) {
|
|
2037
|
-
const gltf = {
|
|
2038
|
-
asset: {
|
|
2039
|
-
version: "2.0",
|
|
2040
|
-
generator: this.options.generator
|
|
2041
|
-
},
|
|
2042
|
-
scene: 0,
|
|
2043
|
-
scenes: this.scenes,
|
|
2044
|
-
nodes: this.nodes,
|
|
2045
|
-
meshes: this.meshes,
|
|
2046
|
-
materials: this.materials,
|
|
2047
|
-
accessors: this.accessors,
|
|
2048
|
-
bufferViews: this.bufferViews,
|
|
2049
|
-
buffers: [
|
|
2050
|
-
{
|
|
2051
|
-
byteLength: bufferLength
|
|
2052
|
-
}
|
|
2053
|
-
]
|
|
2054
|
-
};
|
|
2055
|
-
if (this.options.copyright) {
|
|
2056
|
-
gltf.asset.copyright = this.options.copyright;
|
|
2057
|
-
}
|
|
2058
|
-
if (this.animations.length > 0) {
|
|
2059
|
-
gltf.animations = this.animations;
|
|
2060
|
-
}
|
|
2061
|
-
if (this.images.length > 0) {
|
|
2062
|
-
gltf.images = this.images;
|
|
2063
|
-
gltf.textures = this.textures;
|
|
2064
|
-
gltf.samplers = this.samplers;
|
|
2065
|
-
}
|
|
2066
|
-
if (this._skins && this._skins.length > 0) {
|
|
2067
|
-
gltf.skins = this._skins;
|
|
2068
|
-
}
|
|
2069
|
-
declareExtensions(gltf);
|
|
2070
|
-
if (this.options.format === "gltf") {
|
|
2071
|
-
gltf.buffers[0].uri = `${name}.bin`;
|
|
2072
|
-
}
|
|
2073
|
-
return gltf;
|
|
2074
|
-
}
|
|
2075
|
-
/**
|
|
2076
|
-
* Create a GLB binary file
|
|
2077
|
-
*/
|
|
2078
|
-
createGLB(gltf, buffer) {
|
|
2079
|
-
const jsonString = JSON.stringify(gltf);
|
|
2080
|
-
const jsonBuffer = new TextEncoder().encode(jsonString);
|
|
2081
|
-
const jsonPadding = (4 - jsonBuffer.byteLength % 4) % 4;
|
|
2082
|
-
const paddedJsonLength = jsonBuffer.byteLength + jsonPadding;
|
|
2083
|
-
const binPadding = (4 - buffer.byteLength % 4) % 4;
|
|
2084
|
-
const paddedBinLength = buffer.byteLength + binPadding;
|
|
2085
|
-
const totalSize = 12 + 8 + paddedJsonLength + 8 + paddedBinLength;
|
|
2086
|
-
const output = new ArrayBuffer(totalSize);
|
|
2087
|
-
const view = new DataView(output);
|
|
2088
|
-
const bytes = new Uint8Array(output);
|
|
2089
|
-
let offset = 0;
|
|
2090
|
-
view.setUint32(offset, 1179937895, true);
|
|
2091
|
-
offset += 4;
|
|
2092
|
-
view.setUint32(offset, 2, true);
|
|
2093
|
-
offset += 4;
|
|
2094
|
-
view.setUint32(offset, totalSize, true);
|
|
2095
|
-
offset += 4;
|
|
2096
|
-
view.setUint32(offset, paddedJsonLength, true);
|
|
2097
|
-
offset += 4;
|
|
2098
|
-
view.setUint32(offset, 1313821514, true);
|
|
2099
|
-
offset += 4;
|
|
2100
|
-
bytes.set(jsonBuffer, offset);
|
|
2101
|
-
offset += jsonBuffer.byteLength;
|
|
2102
|
-
for (let i = 0; i < jsonPadding; i++) {
|
|
2103
|
-
bytes[offset++] = 32;
|
|
2104
|
-
}
|
|
2105
|
-
view.setUint32(offset, paddedBinLength, true);
|
|
2106
|
-
offset += 4;
|
|
2107
|
-
view.setUint32(offset, 5130562, true);
|
|
2108
|
-
offset += 4;
|
|
2109
|
-
bytes.set(buffer, offset);
|
|
2110
|
-
offset += buffer.byteLength;
|
|
2111
|
-
for (let i = 0; i < binPadding; i++) {
|
|
2112
|
-
bytes[offset++] = 0;
|
|
2113
|
-
}
|
|
2114
|
-
return new Uint8Array(output);
|
|
2115
|
-
}
|
|
2116
|
-
/**
|
|
2117
|
-
* Process a light node (stored as extras for universal glTF compatibility)
|
|
2118
|
-
*/
|
|
2119
|
-
processLight(light) {
|
|
2120
|
-
const props = light.properties || [];
|
|
2121
|
-
const findLightProp = (key) => props.find((p) => p.key === key)?.value;
|
|
2122
|
-
const position = findLightProp("position");
|
|
2123
|
-
const node = {
|
|
2124
|
-
name: light.name || `light_${this.nodes.length}`,
|
|
2125
|
-
translation: position ? [position[0], position[1], position[2]] : [0, 0, 0],
|
|
2126
|
-
extras: {
|
|
2127
|
-
type: "light",
|
|
2128
|
-
lightType: light.lightType,
|
|
2129
|
-
color: findLightProp("color") || "#ffffff",
|
|
2130
|
-
intensity: findLightProp("intensity") ?? 1
|
|
2131
|
-
}
|
|
2132
|
-
};
|
|
2133
|
-
const nodeIndex = this.nodes.length;
|
|
2134
|
-
this.nodes.push(node);
|
|
2135
|
-
this.stats.nodeCount++;
|
|
2136
|
-
return nodeIndex;
|
|
2137
|
-
}
|
|
2138
|
-
/**
|
|
2139
|
-
* Process a camera node
|
|
2140
|
-
*/
|
|
2141
|
-
processCamera(camera) {
|
|
2142
|
-
const props = camera.properties || [];
|
|
2143
|
-
const findCamProp = (key) => props.find((p) => p.key === key)?.value;
|
|
2144
|
-
const position = findCamProp("position");
|
|
2145
|
-
const node = {
|
|
2146
|
-
name: "Camera",
|
|
2147
|
-
translation: position ? [position[0], position[1], position[2]] : [0, 0, 0],
|
|
2148
|
-
extras: {
|
|
2149
|
-
type: "camera",
|
|
2150
|
-
cameraType: camera.cameraType,
|
|
2151
|
-
fov: findCamProp("fov") ?? 75,
|
|
2152
|
-
near: findCamProp("near") ?? 0.1,
|
|
2153
|
-
far: findCamProp("far") ?? 1e3
|
|
2154
|
-
}
|
|
2155
|
-
};
|
|
2156
|
-
const nodeIndex = this.nodes.length;
|
|
2157
|
-
this.nodes.push(node);
|
|
2158
|
-
this.stats.nodeCount++;
|
|
2159
|
-
return nodeIndex;
|
|
2160
|
-
}
|
|
2161
|
-
// =============================================================================
|
|
2162
|
-
// UTILITY METHODS
|
|
2163
|
-
// =============================================================================
|
|
2164
|
-
/** Find a property by key in a HoloObjectDecl's property array. */
|
|
2165
|
-
findProp(object, key) {
|
|
2166
|
-
return object.properties?.find((p) => p.key === key)?.value;
|
|
2167
|
-
}
|
|
2168
|
-
/** Extract a vec3 from an object's properties array. */
|
|
2169
|
-
extractVec3Prop(object, key, defaultValue) {
|
|
2170
|
-
const val = this.findProp(object, key);
|
|
2171
|
-
if (Array.isArray(val) && val.length >= 3) {
|
|
2172
|
-
return [Number(val[0]) || 0, Number(val[1]) || 0, Number(val[2]) || 0];
|
|
2173
|
-
}
|
|
2174
|
-
return defaultValue;
|
|
2175
|
-
}
|
|
2176
|
-
parseColorString(color) {
|
|
2177
|
-
if (color.startsWith("#")) {
|
|
2178
|
-
const hex = color.slice(1);
|
|
2179
|
-
if (hex.length >= 6) {
|
|
2180
|
-
const r = parseInt(hex.slice(0, 2), 16) / 255;
|
|
2181
|
-
const g = parseInt(hex.slice(2, 4), 16) / 255;
|
|
2182
|
-
const b = parseInt(hex.slice(4, 6), 16) / 255;
|
|
2183
|
-
return [r, g, b];
|
|
2184
|
-
}
|
|
2185
|
-
}
|
|
2186
|
-
const colors = {
|
|
2187
|
-
red: [1, 0, 0],
|
|
2188
|
-
green: [0, 1, 0],
|
|
2189
|
-
blue: [0, 0, 1],
|
|
2190
|
-
white: [1, 1, 1],
|
|
2191
|
-
black: [0, 0, 0],
|
|
2192
|
-
yellow: [1, 1, 0],
|
|
2193
|
-
cyan: [0, 1, 1],
|
|
2194
|
-
magenta: [1, 0, 1],
|
|
2195
|
-
orange: [1, 0.5, 0],
|
|
2196
|
-
purple: [0.5, 0, 0.5]
|
|
2197
|
-
};
|
|
2198
|
-
return colors[color.toLowerCase()] || [1, 1, 1];
|
|
2199
|
-
}
|
|
2200
|
-
eulerToQuaternion(euler) {
|
|
2201
|
-
const toRad = Math.PI / 180;
|
|
2202
|
-
const x = euler[0] * toRad / 2;
|
|
2203
|
-
const y = euler[1] * toRad / 2;
|
|
2204
|
-
const z = euler[2] * toRad / 2;
|
|
2205
|
-
const cx = Math.cos(x);
|
|
2206
|
-
const sx = Math.sin(x);
|
|
2207
|
-
const cy = Math.cos(y);
|
|
2208
|
-
const sy = Math.sin(y);
|
|
2209
|
-
const cz = Math.cos(z);
|
|
2210
|
-
const sz = Math.sin(z);
|
|
2211
|
-
return [
|
|
2212
|
-
sx * cy * cz - cx * sy * sz,
|
|
2213
|
-
cx * sy * cz + sx * cy * sz,
|
|
2214
|
-
cx * cy * sz - sx * sy * cz,
|
|
2215
|
-
cx * cy * cz + sx * sy * sz
|
|
2216
|
-
];
|
|
2217
|
-
}
|
|
2218
|
-
mapPropertyToGLTFPath(property) {
|
|
2219
|
-
const mapping = {
|
|
2220
|
-
position: "translation",
|
|
2221
|
-
translation: "translation",
|
|
2222
|
-
rotation: "rotation",
|
|
2223
|
-
scale: "scale"
|
|
2224
|
-
};
|
|
2225
|
-
return mapping[property.toLowerCase()] || null;
|
|
2226
|
-
}
|
|
2227
|
-
};
|
|
2228
|
-
function createGLTFPipeline(options) {
|
|
2229
|
-
return new GLTFPipeline(options);
|
|
2230
|
-
}
|
|
2231
|
-
|
|
2232
|
-
exports.GLTFPipeline = GLTFPipeline;
|
|
2233
|
-
exports.createGLTFPipeline = createGLTFPipeline;
|
|
2234
|
-
exports.generateScaleNormalMap = generateScaleNormalMap;
|
|
2235
|
-
exports.generateScaleTexture = generateScaleTexture;
|
|
2236
|
-
//# sourceMappingURL=chunk-5BGSECRJ.cjs.map
|
|
2237
|
-
//# sourceMappingURL=chunk-5BGSECRJ.cjs.map
|