@babylonjs/lite 1.4.0 → 1.6.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.
Files changed (152) hide show
  1. package/dist/index.js +512 -512
  2. package/dist/index.js.map +1 -1
  3. package/index.d.ts +829 -28
  4. package/lib/audio/analyzer.js +65 -0
  5. package/lib/audio/analyzer.js.map +1 -0
  6. package/lib/audio/audio-bus.js +38 -0
  7. package/lib/audio/audio-bus.js.map +1 -0
  8. package/lib/audio/audio-engine.js +188 -0
  9. package/lib/audio/audio-engine.js.map +1 -0
  10. package/lib/audio/audio-fetch.js +18 -0
  11. package/lib/audio/audio-fetch.js.map +1 -0
  12. package/lib/audio/audio-param.js +96 -0
  13. package/lib/audio/audio-param.js.map +1 -0
  14. package/lib/audio/audio-signal.js +46 -0
  15. package/lib/audio/audio-signal.js.map +1 -0
  16. package/lib/audio/bus.js +33 -0
  17. package/lib/audio/bus.js.map +1 -0
  18. package/lib/audio/host-types.js +2 -0
  19. package/lib/audio/host-types.js.map +1 -0
  20. package/lib/audio/index.js +12 -0
  21. package/lib/audio/index.js.map +1 -0
  22. package/lib/audio/sound-buffer.js +59 -0
  23. package/lib/audio/sound-buffer.js.map +1 -0
  24. package/lib/audio/sound-source.js +57 -0
  25. package/lib/audio/sound-source.js.map +1 -0
  26. package/lib/audio/sound-sub-graph.js +72 -0
  27. package/lib/audio/sound-sub-graph.js.map +1 -0
  28. package/lib/audio/spatial.js +466 -0
  29. package/lib/audio/spatial.js.map +1 -0
  30. package/lib/audio/static-sound.js +313 -0
  31. package/lib/audio/static-sound.js.map +1 -0
  32. package/lib/audio/stereo.js +40 -0
  33. package/lib/audio/stereo.js.map +1 -0
  34. package/lib/audio/streaming-sound.js +377 -0
  35. package/lib/audio/streaming-sound.js.map +1 -0
  36. package/lib/audio/unmute-ui.js +72 -0
  37. package/lib/audio/unmute-ui.js.map +1 -0
  38. package/lib/audio/visualizer.js +101 -0
  39. package/lib/audio/visualizer.js.map +1 -0
  40. package/lib/camera/geospatial-camera-controls.js +22 -0
  41. package/lib/camera/geospatial-camera-controls.js.map +1 -1
  42. package/lib/camera/geospatial-camera-fly.js +2 -1
  43. package/lib/camera/geospatial-camera-fly.js.map +1 -1
  44. package/lib/effect/effect-renderer.js +1 -1
  45. package/lib/effect/effect-renderer.js.map +1 -1
  46. package/lib/engine/engine.js +1 -1
  47. package/lib/index.js +15 -1
  48. package/lib/index.js.map +1 -1
  49. package/lib/light/types.js.map +1 -1
  50. package/lib/loader-gltf/animation-pointer-basecolor.js +25 -0
  51. package/lib/loader-gltf/animation-pointer-basecolor.js.map +1 -0
  52. package/lib/loader-gltf/animation-pointer-ext.js +244 -0
  53. package/lib/loader-gltf/animation-pointer-ext.js.map +1 -0
  54. package/lib/loader-gltf/animation-pointer-lights.js +46 -0
  55. package/lib/loader-gltf/animation-pointer-lights.js.map +1 -0
  56. package/lib/loader-gltf/animation-pointer.js +4 -1
  57. package/lib/loader-gltf/animation-pointer.js.map +1 -1
  58. package/lib/loader-gltf/gltf-animation.js +5 -3
  59. package/lib/loader-gltf/gltf-animation.js.map +1 -1
  60. package/lib/loader-gltf/gltf-color-normalize.js +10 -1
  61. package/lib/loader-gltf/gltf-color-normalize.js.map +1 -1
  62. package/lib/loader-gltf/gltf-feature-animation-pointer.js +67 -47
  63. package/lib/loader-gltf/gltf-feature-animation-pointer.js.map +1 -1
  64. package/lib/loader-gltf/gltf-feature-lights-punctual.js +51 -9
  65. package/lib/loader-gltf/gltf-feature-lights-punctual.js.map +1 -1
  66. package/lib/loader-gltf/gltf-feature-primitive.js +20 -0
  67. package/lib/loader-gltf/gltf-feature-primitive.js.map +1 -0
  68. package/lib/loader-gltf/gltf-feature-registry.js +25 -0
  69. package/lib/loader-gltf/gltf-feature-registry.js.map +1 -1
  70. package/lib/loader-gltf/gltf-feature-skeleton.js +18 -3
  71. package/lib/loader-gltf/gltf-feature-skeleton.js.map +1 -1
  72. package/lib/loader-gltf/gltf-interleave.js +3 -2
  73. package/lib/loader-gltf/gltf-interleave.js.map +1 -1
  74. package/lib/loader-gltf/gltf-light-pointer-state.js +18 -0
  75. package/lib/loader-gltf/gltf-light-pointer-state.js.map +1 -0
  76. package/lib/loader-gltf/gltf-parser.js +7 -1
  77. package/lib/loader-gltf/gltf-parser.js.map +1 -1
  78. package/lib/loader-gltf/gltf-pbr-builder-ext.js +1 -1
  79. package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
  80. package/lib/loader-gltf/gltf-pbr-builder.js +1 -1
  81. package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
  82. package/lib/loader-gltf/gltf-sampler-denorm.js +20 -0
  83. package/lib/loader-gltf/gltf-sampler-denorm.js.map +1 -0
  84. package/lib/loader-gltf/gltf-sampler-desc.js +11 -2
  85. package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
  86. package/lib/loader-gltf/gltf-uv-denorm.js +28 -0
  87. package/lib/loader-gltf/gltf-uv-denorm.js.map +1 -0
  88. package/lib/loader-gltf/load-gltf.js +15 -6
  89. package/lib/loader-gltf/load-gltf.js.map +1 -1
  90. package/lib/material/material-rebuild.js +4 -0
  91. package/lib/material/material-rebuild.js.map +1 -1
  92. package/lib/material/mesh-features.js +8 -1
  93. package/lib/material/mesh-features.js.map +1 -1
  94. package/lib/material/pbr/fragments/reflectance-fragment.js +1 -1
  95. package/lib/material/pbr/fragments/reflectance-fragment.js.map +1 -1
  96. package/lib/material/pbr/fragments/refraction-rtt-fragment.js +1 -1
  97. package/lib/material/pbr/fragments/refraction-rtt-fragment.js.map +1 -1
  98. package/lib/material/pbr/pbr-pipeline.js +7 -3
  99. package/lib/material/pbr/pbr-pipeline.js.map +1 -1
  100. package/lib/material/pbr/pbr-primitive-resolver.js +34 -0
  101. package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -0
  102. package/lib/material/pbr/pbr-renderable.js +1 -1
  103. package/lib/material/pbr/pbr-renderable.js.map +1 -1
  104. package/lib/material/shader/shader-material.js +9 -5
  105. package/lib/material/shader/shader-material.js.map +1 -1
  106. package/lib/material/shader/shader-thin-instance.js +1 -1
  107. package/lib/material/shader/shader-thin-instance.js.map +1 -1
  108. package/lib/material/standard/standard-renderable.js +1 -1
  109. package/lib/material/standard/standard-renderable.js.map +1 -1
  110. package/lib/mesh/mesh-dispose.js +1 -0
  111. package/lib/mesh/mesh-dispose.js.map +1 -1
  112. package/lib/mesh/thin-instance-cull-binding.js +15 -6
  113. package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
  114. package/lib/post-process/taa.js +193 -0
  115. package/lib/post-process/taa.js.map +1 -0
  116. package/lib/scene/scene-core.js +1 -0
  117. package/lib/scene/scene-core.js.map +1 -1
  118. package/lib/scene/scene-material-swap.js +2 -0
  119. package/lib/scene/scene-material-swap.js.map +1 -1
  120. package/lib/shadow/csm-shadow-task-hooks.js +67 -9
  121. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  122. package/lib/sprite/billboard-custom-shader.js +32 -32
  123. package/lib/sprite/billboard-custom-shader.js.map +1 -1
  124. package/lib/sprite/billboard-pipeline.js +54 -56
  125. package/lib/sprite/billboard-pipeline.js.map +1 -1
  126. package/lib/sprite/custom-shader-core.js +1 -1
  127. package/lib/sprite/custom-shader-core.js.map +1 -1
  128. package/lib/sprite/shared/sprite-atlas.js +2 -2
  129. package/lib/sprite/shared/sprite-atlas.js.map +1 -1
  130. package/lib/sprite/sprite-2d-coverage-gamma.js +58 -0
  131. package/lib/sprite/sprite-2d-coverage-gamma.js.map +1 -0
  132. package/lib/sprite/sprite-2d-uvscroll.js +39 -0
  133. package/lib/sprite/sprite-2d-uvscroll.js.map +1 -0
  134. package/lib/sprite/sprite-2d.js +6 -36
  135. package/lib/sprite/sprite-2d.js.map +1 -1
  136. package/lib/sprite/sprite-coverage-gamma-hook.js +10 -0
  137. package/lib/sprite/sprite-coverage-gamma-hook.js.map +1 -0
  138. package/lib/sprite/sprite-custom-shader.js +2 -2
  139. package/lib/sprite/sprite-custom-shader.js.map +1 -1
  140. package/lib/sprite/sprite-pipeline.js +61 -73
  141. package/lib/sprite/sprite-pipeline.js.map +1 -1
  142. package/lib/sprite/sprite-renderable.js +5 -5
  143. package/lib/sprite/sprite-renderable.js.map +1 -1
  144. package/lib/sprite/sprite-renderer.js +4 -4
  145. package/lib/sprite/sprite-renderer.js.map +1 -1
  146. package/lib/sprite/sprite-scene.js +1 -1
  147. package/lib/sprite/sprite-scene.js.map +1 -1
  148. package/lib/text/_gpu/text-pipeline.js +1 -1
  149. package/lib/text/_gpu/text-pipeline.js.map +1 -1
  150. package/lib/text/text-renderer.js +3 -1
  151. package/lib/text/text-renderer.js.map +1 -1
  152. package/package.json +3 -3
@@ -1,6 +1,25 @@
1
1
  import { MAX_LIGHTS, setMaxLights } from '../light/types.js';
2
2
  import { computeNodeWorldMatrix } from './gltf-parser.js';
3
+ import { setGltfPunctualLight } from './gltf-light-pointer-state.js';
3
4
 
5
+ function bindAnimatedLightVersion(light) {
6
+ const baseGet = Object.getOwnPropertyDescriptor(light, "_lightVersion")?.get;
7
+ let extra = 0;
8
+ Object.defineProperty(light, "_lightVersion", {
9
+ get() {
10
+ return (baseGet ? baseGet.call(light) : 0) + (light.worldMatrixVersion ?? 0) + extra;
11
+ },
12
+ enumerable: false,
13
+ configurable: true
14
+ });
15
+ Object.defineProperty(light, "_bumpLightVersion", {
16
+ value: () => {
17
+ extra++;
18
+ },
19
+ enumerable: false,
20
+ configurable: true
21
+ });
22
+ }
4
23
  const feature = {
5
24
  id: "KHR_lights_punctual",
6
25
  async applyAsset(_meshes, _root, ctx) {
@@ -28,15 +47,23 @@ const feature = {
28
47
  if (!def) {
29
48
  continue;
30
49
  }
31
- const world = computeNodeWorldMatrix(ctx._json, nodeIdx, ctx._parentMap, ctx._worldMatrixCache);
32
- const px = world[12];
33
- const py = world[13];
34
- const pz = world[14];
35
- const fx = -world[8];
36
- const fy = -world[9];
37
- const fz = -world[10];
38
- const flen = Math.hypot(fx, fy, fz) || 1;
39
- const dir = [fx / flen, fy / flen, fz / flen];
50
+ const sourceNode = ctx._nodeMap?.[nodeIdx];
51
+ let px, py, pz;
52
+ let dir;
53
+ if (sourceNode) {
54
+ px = py = pz = 0;
55
+ dir = [0, 0, -1];
56
+ } else {
57
+ const world = computeNodeWorldMatrix(ctx._json, nodeIdx, ctx._parentMap, ctx._worldMatrixCache);
58
+ px = world[12];
59
+ py = world[13];
60
+ pz = world[14];
61
+ const fx = -world[8];
62
+ const fy = -world[9];
63
+ const fz = -world[10];
64
+ const flen = Math.hypot(fx, fy, fz) || 1;
65
+ dir = [fx / flen, fy / flen, fz / flen];
66
+ }
40
67
  const color = def.color ? [def.color[0], def.color[1], def.color[2]] : [1, 1, 1];
41
68
  const intensity = def.intensity ?? 1;
42
69
  const range = def.range !== void 0 ? def.range : Number.MAX_VALUE;
@@ -46,13 +73,23 @@ const feature = {
46
73
  pl.diffuse = color;
47
74
  pl.specular = color;
48
75
  pl.range = range;
76
+ if (sourceNode) {
77
+ pl.parent = sourceNode;
78
+ }
79
+ bindAnimatedLightVersion(pl);
49
80
  lights.push(pl);
81
+ setGltfPunctualLight(ctx._json, lightIdx, pl);
50
82
  } else if (def.type === "directional") {
51
83
  const { createDirectionalLight } = await import('../light/directional-light.js');
52
84
  const dl = createDirectionalLight(dir, intensity);
53
85
  dl.diffuse = color;
54
86
  dl.specular = color;
87
+ if (sourceNode) {
88
+ dl.parent = sourceNode;
89
+ }
90
+ bindAnimatedLightVersion(dl);
55
91
  lights.push(dl);
92
+ setGltfPunctualLight(ctx._json, lightIdx, dl);
56
93
  } else if (def.type === "spot") {
57
94
  const { createSpotLight } = await import('../light/spot-light.js');
58
95
  const outer = def.spot?.outerConeAngle ?? Math.PI / 4;
@@ -60,7 +97,12 @@ const feature = {
60
97
  sl.diffuse = color;
61
98
  sl.specular = color;
62
99
  sl.range = range;
100
+ if (sourceNode) {
101
+ sl.parent = sourceNode;
102
+ }
103
+ bindAnimatedLightVersion(sl);
63
104
  lights.push(sl);
105
+ setGltfPunctualLight(ctx._json, lightIdx, sl);
64
106
  }
65
107
  }
66
108
  return { entities: lights };
@@ -1 +1 @@
1
- {"version":3,"file":"gltf-feature-lights-punctual.js","sources":["../../../src/loader-gltf/gltf-feature-lights-punctual.ts"],"sourcesContent":["/** KHR_lights_punctual glTF extension.\n * Parses point / directional / spot lights from the asset's top-level\n * KHR_lights_punctual.lights array and instantiates one Lite light per\n * referencing node, baking the node's world transform into the light's\n * position / direction. Lights are contributed via the AssetContainer's\n * `entities` array; addToScene() picks them up through the `lightType`\n * branch of its traversal. */\n\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport type { LightBase } from \"../light/types.js\";\nimport { MAX_LIGHTS, setMaxLights } from \"../light/types.js\";\nimport { computeNodeWorldMatrix } from \"./gltf-parser.js\";\n\ninterface GltfLightDef {\n type: \"point\" | \"directional\" | \"spot\";\n color?: [number, number, number];\n intensity?: number;\n range?: number;\n spot?: { innerConeAngle?: number; outerConeAngle?: number };\n}\n\nconst feature: GltfFeature = {\n id: \"KHR_lights_punctual\",\n async applyAsset(_meshes, _root, ctx) {\n const defs: GltfLightDef[] | undefined = ctx._json.extensions?.KHR_lights_punctual?.lights;\n if (!defs?.length) {\n return {};\n }\n const lights: LightBase[] = [];\n const nodes = ctx._json.nodes ?? [];\n // Count lights first so we can raise MAX_LIGHTS before any pipeline is\n // compiled (loadGltf runs before addToScene which triggers pipeline\n // creation). Lite's MAX_LIGHTS is scene-wide, so cover every punctual\n // light declared by the asset rather than Babylon's per-material cap.\n let lightNodeCount = 0;\n for (let i = 0; i < nodes.length; i++) {\n if (nodes[i]?.extensions?.KHR_lights_punctual?.light !== undefined) {\n lightNodeCount++;\n }\n }\n if (lightNodeCount > MAX_LIGHTS) {\n setMaxLights(lightNodeCount);\n }\n for (let nodeIdx = 0; nodeIdx < nodes.length; nodeIdx++) {\n const lightIdx: number | undefined = nodes[nodeIdx]?.extensions?.KHR_lights_punctual?.light;\n if (lightIdx === undefined) {\n continue;\n }\n const def = defs[lightIdx];\n if (!def) {\n continue;\n }\n const world = computeNodeWorldMatrix(ctx._json, nodeIdx, ctx._parentMap, ctx._worldMatrixCache);\n const px = world[12]!;\n const py = world[13]!;\n const pz = world[14]!;\n // glTF convention: light forward is -Z in local space. Extract world-space forward\n // by transforming (0,0,-1) through the node's upper-3x3. Normalize defensively.\n const fx = -world[8]!;\n const fy = -world[9]!;\n const fz = -world[10]!;\n const flen = Math.hypot(fx, fy, fz) || 1;\n const dir: [number, number, number] = [fx / flen, fy / flen, fz / flen];\n const color: [number, number, number] = def.color ? [def.color[0]!, def.color[1]!, def.color[2]!] : [1, 1, 1];\n const intensity = def.intensity ?? 1;\n const range = def.range !== undefined ? def.range : Number.MAX_VALUE;\n\n if (def.type === \"point\") {\n const { createPointLight } = await import(\"../light/point-light.js\");\n const pl = createPointLight([px, py, pz], intensity);\n pl.diffuse = color;\n pl.specular = color;\n pl.range = range;\n lights.push(pl);\n } else if (def.type === \"directional\") {\n const { createDirectionalLight } = await import(\"../light/directional-light.js\");\n const dl = createDirectionalLight(dir, intensity);\n dl.diffuse = color;\n dl.specular = color;\n lights.push(dl);\n } else if (def.type === \"spot\") {\n const { createSpotLight } = await import(\"../light/spot-light.js\");\n const outer = def.spot?.outerConeAngle ?? Math.PI / 4;\n const sl = createSpotLight([px, py, pz], dir, outer * 2, 1, intensity);\n sl.diffuse = color;\n sl.specular = color;\n sl.range = range;\n lights.push(sl);\n }\n }\n return { entities: lights };\n },\n};\nexport default feature;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gltf-feature-lights-punctual.js","sources":["../../../src/loader-gltf/gltf-feature-lights-punctual.ts"],"sourcesContent":["/** KHR_lights_punctual glTF extension.\n * Parses point / directional / spot lights from the asset's top-level\n * KHR_lights_punctual.lights array and instantiates one Lite light per\n * referencing node, baking the node's world transform into the light's\n * position / direction. Lights are contributed via the AssetContainer's\n * `entities` array; addToScene() picks them up through the `lightType`\n * branch of its traversal. */\n\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport type { LightBase } from \"../light/types.js\";\nimport { MAX_LIGHTS, setMaxLights } from \"../light/types.js\";\nimport { computeNodeWorldMatrix } from \"./gltf-parser.js\";\nimport { setGltfPunctualLight } from \"./gltf-light-pointer-state.js\";\n\ninterface GltfLightDef {\n type: \"point\" | \"directional\" | \"spot\";\n color?: [number, number, number];\n intensity?: number;\n range?: number;\n spot?: { innerConeAngle?: number; outerConeAngle?: number };\n}\n\n/** Fold the light's `worldMatrixVersion` (ancestor / animated-node motion) and a bump\n * counter into its `_lightVersion`. The shared lights-UBO refresh (computeLightsVersion\n * sums `_lightVersion`) then picks up an animated light NODE (KHR_animation_pointer node\n * TRS) and direct color/intensity/range pointer writes — with NO change to the core light\n * or lights-UBO code. All cost lives in this lazy KHR_lights_punctual feature, so scenes\n * without punctual lights stay byte-identical. Harmless for static lights (constant offset). */\nfunction bindAnimatedLightVersion(light: LightBase & { worldMatrixVersion?: number }): void {\n const baseGet = Object.getOwnPropertyDescriptor(light, \"_lightVersion\")?.get;\n let extra = 0;\n Object.defineProperty(light, \"_lightVersion\", {\n get(): number {\n return (baseGet ? (baseGet.call(light) as number) : 0) + (light.worldMatrixVersion ?? 0) + extra;\n },\n enumerable: false,\n configurable: true,\n });\n Object.defineProperty(light, \"_bumpLightVersion\", {\n value: () => {\n extra++;\n },\n enumerable: false,\n configurable: true,\n });\n}\n\nconst feature: GltfFeature = {\n id: \"KHR_lights_punctual\",\n async applyAsset(_meshes, _root, ctx) {\n const defs: GltfLightDef[] | undefined = ctx._json.extensions?.KHR_lights_punctual?.lights;\n if (!defs?.length) {\n return {};\n }\n const lights: LightBase[] = [];\n const nodes = ctx._json.nodes ?? [];\n // Count lights first so we can raise MAX_LIGHTS before any pipeline is\n // compiled (loadGltf runs before addToScene which triggers pipeline\n // creation). Lite's MAX_LIGHTS is scene-wide, so cover every punctual\n // light declared by the asset rather than Babylon's per-material cap.\n let lightNodeCount = 0;\n for (let i = 0; i < nodes.length; i++) {\n if (nodes[i]?.extensions?.KHR_lights_punctual?.light !== undefined) {\n lightNodeCount++;\n }\n }\n if (lightNodeCount > MAX_LIGHTS) {\n setMaxLights(lightNodeCount);\n }\n for (let nodeIdx = 0; nodeIdx < nodes.length; nodeIdx++) {\n const lightIdx: number | undefined = nodes[nodeIdx]?.extensions?.KHR_lights_punctual?.light;\n if (lightIdx === undefined) {\n continue;\n }\n const def = defs[lightIdx];\n if (!def) {\n continue;\n }\n // Prefer parenting the light to its source SceneNode so that an animated\n // light node (KHR_animation_pointer / node TRS channels) drives the light's\n // world position + direction every frame. The light then carries only its\n // glTF-local transform (origin, forward = -Z) and inherits the node's world\n // matrix via the shared parent chain. Falls back to baking the world\n // transform when the node is unreachable (no SceneNode), which keeps the\n // exact previous behaviour for assets without a node hierarchy.\n const sourceNode = ctx._nodeMap?.[nodeIdx];\n let px: number, py: number, pz: number;\n let dir: [number, number, number];\n if (sourceNode) {\n // Local: at node origin, forward = -Z. World = nodeWorld · local.\n px = py = pz = 0;\n dir = [0, 0, -1];\n } else {\n const world = computeNodeWorldMatrix(ctx._json, nodeIdx, ctx._parentMap, ctx._worldMatrixCache);\n px = world[12]!;\n py = world[13]!;\n pz = world[14]!;\n // glTF convention: light forward is -Z in local space. Extract world-space forward\n // by transforming (0,0,-1) through the node's upper-3x3. Normalize defensively.\n const fx = -world[8]!;\n const fy = -world[9]!;\n const fz = -world[10]!;\n const flen = Math.hypot(fx, fy, fz) || 1;\n dir = [fx / flen, fy / flen, fz / flen];\n }\n const color: [number, number, number] = def.color ? [def.color[0]!, def.color[1]!, def.color[2]!] : [1, 1, 1];\n const intensity = def.intensity ?? 1;\n const range = def.range !== undefined ? def.range : Number.MAX_VALUE;\n\n if (def.type === \"point\") {\n const { createPointLight } = await import(\"../light/point-light.js\");\n const pl = createPointLight([px, py, pz], intensity);\n pl.diffuse = color;\n pl.specular = color;\n pl.range = range;\n if (sourceNode) {\n pl.parent = sourceNode;\n }\n bindAnimatedLightVersion(pl);\n lights.push(pl);\n setGltfPunctualLight(ctx._json, lightIdx, pl);\n } else if (def.type === \"directional\") {\n const { createDirectionalLight } = await import(\"../light/directional-light.js\");\n const dl = createDirectionalLight(dir, intensity);\n dl.diffuse = color;\n dl.specular = color;\n if (sourceNode) {\n dl.parent = sourceNode;\n }\n bindAnimatedLightVersion(dl);\n lights.push(dl);\n setGltfPunctualLight(ctx._json, lightIdx, dl);\n } else if (def.type === \"spot\") {\n const { createSpotLight } = await import(\"../light/spot-light.js\");\n const outer = def.spot?.outerConeAngle ?? Math.PI / 4;\n const sl = createSpotLight([px, py, pz], dir, outer * 2, 1, intensity);\n sl.diffuse = color;\n sl.specular = color;\n sl.range = range;\n if (sourceNode) {\n sl.parent = sourceNode;\n }\n bindAnimatedLightVersion(sl);\n lights.push(sl);\n setGltfPunctualLight(ctx._json, lightIdx, sl);\n }\n }\n return { entities: lights };\n },\n};\nexport default feature;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import '../material/pbr/pbr-primitive-resolver.js';
2
+
3
+ const feature = {
4
+ id: "_primitive",
5
+ async applyMesh(meshData, mesh) {
6
+ const mode = meshData._primitive?.mode;
7
+ const topo = mode === 0 ? 1 : mode === 1 ? 2 : mode === 3 ? 3 : mode === 5 ? 4 : void 0;
8
+ if (topo) {
9
+ mesh._topology = topo;
10
+ }
11
+ const wm = meshData._worldMatrix;
12
+ const det3 = wm[0] * (wm[5] * wm[10] - wm[6] * wm[9]) + wm[1] * (wm[6] * wm[8] - wm[4] * wm[10]) + wm[2] * (wm[4] * wm[9] - wm[5] * wm[8]);
13
+ if (det3 > 0) {
14
+ mesh._reverseWinding = true;
15
+ }
16
+ }
17
+ };
18
+
19
+ export { feature as default };
20
+ //# sourceMappingURL=gltf-feature-primitive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gltf-feature-primitive.js","sources":["../../../src/loader-gltf/gltf-feature-primitive.ts"],"sourcesContent":["/** Primitive-state feature (non-triangle topology + negative-determinant winding) — dynamically\n * imported, gated on a non-triangle primitive mode OR a negative-determinant node.\n *\n * Records `_topology` (POINTS/LINES/LINE_STRIP/TRIANGLE_STRIP) and/or `_reverseWinding` on each\n * affected mesh and installs the PBR pipeline's primitive resolver (topology + stripIndexFormat +\n * culling). The common triangle-list positive-winding case never loads this module, so the core\n * loader + pipeline chunks stay byte-identical. */\nimport \"../material/pbr/pbr-primitive-resolver.js\";\nimport type { GltfFeature } from \"./gltf-feature.js\";\n\nconst feature: GltfFeature = {\n id: \"_primitive\",\n async applyMesh(meshData, mesh) {\n // Non-triangle topology index from the glTF primitive mode. The unsupported LINE_LOOP(2) /\n // TRIANGLE_FAN(6) modes are left as a triangle list (matching BJS, which can't render them).\n const mode = (meshData as { _primitive?: { mode?: number } })._primitive?.mode;\n const topo = mode === 0 ? 1 : mode === 1 ? 2 : mode === 3 ? 3 : mode === 5 ? 4 : undefined;\n if (topo) {\n (mesh as { _topology?: number })._topology = topo;\n }\n // A mesh whose net world-matrix determinant is positive (mirrored vs the RH→LH root flip) has\n // reversed triangle winding; flag it so the pipeline culls \"front\" (matching BJS, which flips\n // sideOrientation on negative determinant). Normal meshes have a negative world determinant.\n const wm = meshData._worldMatrix as unknown as ArrayLike<number>;\n const det3 = wm[0]! * (wm[5]! * wm[10]! - wm[6]! * wm[9]!) + wm[1]! * (wm[6]! * wm[8]! - wm[4]! * wm[10]!) + wm[2]! * (wm[4]! * wm[9]! - wm[5]! * wm[8]!);\n if (det3 > 0) {\n (mesh as { _reverseWinding?: boolean })._reverseWinding = true;\n }\n },\n};\nexport default feature;\n"],"names":[],"mappings":";;AAUA,MAAM,OAAA,GAAuB;AAAA,EACzB,EAAA,EAAI,YAAA;AAAA,EACJ,MAAM,SAAA,CAAU,QAAA,EAAU,IAAA,EAAM;AAG5B,IAAA,MAAM,IAAA,GAAQ,SAAgD,UAAA,EAAY,IAAA;AAC1E,IAAA,MAAM,IAAA,GAAO,IAAA,KAAS,CAAA,GAAI,CAAA,GAAI,IAAA,KAAS,CAAA,GAAI,CAAA,GAAI,IAAA,KAAS,CAAA,GAAI,CAAA,GAAI,IAAA,KAAS,CAAA,GAAI,CAAA,GAAI,MAAA;AACjF,IAAA,IAAI,IAAA,EAAM;AACN,MAAC,KAAgC,SAAA,GAAY,IAAA;AAAA,IACjD;AAIA,IAAA,MAAM,KAAK,QAAA,CAAS,YAAA;AACpB,IAAA,MAAM,IAAA,GAAO,GAAG,CAAC,CAAA,IAAM,GAAG,CAAC,CAAA,GAAK,GAAG,EAAE,CAAA,GAAK,GAAG,CAAC,CAAA,GAAK,GAAG,CAAC,CAAA,CAAA,GAAM,GAAG,CAAC,CAAA,IAAM,GAAG,CAAC,CAAA,GAAK,GAAG,CAAC,CAAA,GAAK,GAAG,CAAC,CAAA,GAAK,GAAG,EAAE,CAAA,CAAA,GAAM,GAAG,CAAC,CAAA,IAAM,GAAG,CAAC,CAAA,GAAK,GAAG,CAAC,CAAA,GAAK,GAAG,CAAC,CAAA,GAAK,GAAG,CAAC,CAAA,CAAA;AACtJ,IAAA,IAAI,OAAO,CAAA,EAAG;AACV,MAAC,KAAuC,eAAA,GAAkB,IAAA;AAAA,IAC9D;AAAA,EACJ;AACJ;;;;"}
@@ -26,10 +26,17 @@ const _features = [
26
26
  // Per-mesh features (predicates inlined to avoid eager imports)
27
27
  [(j) => !!j.skins?.length && anyPrimitive(j, (p) => p.attributes?.JOINTS_0 !== void 0), () => import('./gltf-feature-skeleton.js')],
28
28
  [(j) => anyPrimitive(j, (p) => !!p.targets?.length), () => import('./gltf-feature-morph.js')],
29
+ // Non-triangle primitive topology (POINTS/LINES/LINE_STRIP/TRIANGLE_STRIP) or a
30
+ // negative-determinant node (negative scale / mirrored matrix): both need the lazy primitive
31
+ // feature (topology threading + winding reversal). Triangle-list positive-winding never triggers.
32
+ [(j) => hasNegDetNode(j) || anyPrimitive(j, (p) => p.mode !== void 0 && p.mode !== 4), () => import('./gltf-feature-primitive.js')],
29
33
  // Per-asset features
30
34
  [hasGltfExtras, () => import('./gltf-feature-extras.js')],
31
35
  ["KHR_lights_punctual", () => import('./gltf-feature-lights-punctual.js')],
32
36
  [(j) => !!j.animations?.length, () => import('./gltf-feature-animations.js')],
37
+ // Non-Float32 / normalized animation sampler accessors (e.g. Animation_SamplerType normalized
38
+ // BYTE/SHORT rotation) need the lazy denorm converter; plain float samplers never load it.
39
+ [hasNonFloatAnimSampler, () => import('./gltf-sampler-denorm.js')],
33
40
  [M + "variants", () => import('./gltf-feature-variants.js')],
34
41
  ["KHR_node_visibility", () => import('./gltf-ext-node-visibility.js')],
35
42
  ["KHR_animation_pointer", () => import('./gltf-feature-animation-pointer.js')],
@@ -45,6 +52,24 @@ function hasGltfExtras(json) {
45
52
  const hasExtras = (item) => item?.extras !== void 0;
46
53
  return hasExtras(json.asset) || !!json.nodes?.some(hasExtras) || !!json.materials?.some(hasExtras) || !!json.animations?.some(hasExtras) || !!json.meshes?.some(hasExtras) || anyPrimitive(json, hasExtras);
47
54
  }
55
+ function hasNonFloatAnimSampler(json) {
56
+ const accessors = json.accessors;
57
+ return !!json.animations?.some(
58
+ (a) => a.samplers?.some((s) => accessors[s.input]?.componentType !== 5126 || accessors[s.output]?.componentType !== 5126)
59
+ );
60
+ }
61
+ function hasNegDetNode(json) {
62
+ return !!json.nodes?.some((n) => {
63
+ if (n.scale) {
64
+ return n.scale[0] * n.scale[1] * n.scale[2] < 0;
65
+ }
66
+ if (n.matrix) {
67
+ const m = n.matrix;
68
+ return m[0] * (m[5] * m[10] - m[6] * m[9]) + m[1] * (m[6] * m[8] - m[4] * m[10]) + m[2] * (m[4] * m[9] - m[5] * m[8]) < 0;
69
+ }
70
+ return false;
71
+ });
72
+ }
48
73
 
49
74
  export { loadGltfFeatures };
50
75
  //# sourceMappingURL=gltf-feature-registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gltf-feature-registry.js","sources":["../../../src/loader-gltf/gltf-feature-registry.ts"],"sourcesContent":["/**\n * glTF optional-feature registry.\n *\n * The `_features` table maps every optional glTF capability to a `[trigger, load]`\n * pair: a cheap trigger plus a dynamic `import()` of the feature's `GltfFeature`\n * module. A trigger is either an exact `extensionsUsed` name (the common case) or\n * a predicate over the parsed JSON for features that aren't a simple extension\n * membership (ORM compositing, skeletons, morph targets, animations, dielectric\n * material cluster).\n *\n * This whole module is itself dynamically imported by the core loader\n * (`load-gltf.ts`) ONLY when the asset can possibly trigger at least one feature\n * — so assets that use no optional features (plain metallic-roughness GLBs) never\n * pay for the table or its import thunks.\n *\n * The core loader knows zero feature names; new extensions are added here alone.\n */\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport { anyPrimitive, needsOrmComposite } from \"./gltf-parser.js\";\n\n/** Dynamic `import()` of a feature's `GltfFeature` module. */\ntype Loader = () => Promise<{ default: GltfFeature }>;\n/** Either an exact `extensionsUsed` name, or a predicate over the parsed JSON. */\ntype Trigger = string | ((json: any) => boolean);\n\nconst M = \"KHR_materials_\";\n\nconst _features: [Trigger, Loader][] = [\n // Pre-parse features (buffer-level): order matters — meshopt decompresses\n // bufferViews first, then quantization dequantizes the resulting accessors.\n [\"EXT_meshopt_compression\", () => import(\"./gltf-feature-meshopt.js\")],\n [\"KHR_mesh_quantization\", () => import(\"./gltf-ext-quantization.js\")],\n // Pre-mesh features (geometry decompression)\n [\"KHR_draco_mesh_compression\", () => import(\"./gltf-feature-draco.js\")],\n // Material extensions\n [M + \"clearcoat\", () => import(\"./gltf-ext-clearcoat.js\")],\n [M + \"iridescence\", () => import(\"./gltf-ext-iridescence.js\")],\n [M + \"emissive_strength\", () => import(\"./gltf-ext-emissive-strength.js\")],\n [M + \"sheen\", () => import(\"./gltf-ext-sheen.js\")],\n [M + \"anisotropy\", () => import(\"./gltf-ext-anisotropy.js\")],\n [M + \"diffuse_transmission\", () => import(\"./gltf-ext-diffuse-transmission.js\")],\n [M + \"unlit\", () => import(\"./gltf-ext-unlit.js\")],\n [M + \"pbrSpecularGlossiness\", () => import(\"./gltf-ext-spec-gloss.js\")],\n // Dielectric cluster (ior/specular/transmission/volume/dispersion) — any of the five triggers the\n // loader; transmission refraction is wired dynamically by the PBR material path when needed.\n [(j) => [\"transmission\", \"volume\", \"ior\", \"specular\", \"dispersion\"].some((e) => j.extensionsUsed?.includes(M + e)), () => import(\"./gltf-ext-dielectric.js\")],\n [\"KHR_texture_transform\", () => import(\"./gltf-ext-uv-transform.js\")],\n [\"KHR_texture_basisu\", () => import(\"./gltf-ext-basisu.js\")],\n [needsOrmComposite, () => import(\"./gltf-ext-orm.js\")],\n // Per-mesh features (predicates inlined to avoid eager imports)\n [(j) => !!j.skins?.length && anyPrimitive(j, (p) => p.attributes?.JOINTS_0 !== undefined), () => import(\"./gltf-feature-skeleton.js\")],\n [(j) => anyPrimitive(j, (p) => !!p.targets?.length), () => import(\"./gltf-feature-morph.js\")],\n // Per-asset features\n [hasGltfExtras, () => import(\"./gltf-feature-extras.js\")],\n [\"KHR_lights_punctual\", () => import(\"./gltf-feature-lights-punctual.js\")],\n [(j) => !!j.animations?.length, () => import(\"./gltf-feature-animations.js\")],\n [M + \"variants\", () => import(\"./gltf-feature-variants.js\")],\n [\"KHR_node_visibility\", () => import(\"./gltf-ext-node-visibility.js\")],\n [\"KHR_animation_pointer\", () => import(\"./gltf-feature-animation-pointer.js\")],\n [\"EXT_mesh_gpu_instancing\", () => import(\"./gltf-feature-gpu-instancing.js\")],\n [\"KHR_xmp_json_ld\", () => import(\"./gltf-feature-xmp.js\")],\n];\n\n/** Dynamic-import every feature the asset triggers. */\nexport async function loadGltfFeatures(json: any): Promise<GltfFeature[]> {\n const used: string[] = json.extensionsUsed ?? [];\n const mods = await Promise.all(_features.flatMap(([t, load]) => ((typeof t === \"string\" ? used.includes(t) : t(json)) ? [load()] : [])));\n return mods.map((m) => m.default);\n}\n\nfunction hasGltfExtras(json: any): boolean {\n const hasExtras = (item: any): boolean => item?.extras !== undefined;\n return (\n hasExtras(json.asset) ||\n !!json.nodes?.some(hasExtras) ||\n !!json.materials?.some(hasExtras) ||\n !!json.animations?.some(hasExtras) ||\n !!json.meshes?.some(hasExtras) ||\n anyPrimitive(json, hasExtras)\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gltf-feature-registry.js","sources":["../../../src/loader-gltf/gltf-feature-registry.ts"],"sourcesContent":["/**\n * glTF optional-feature registry.\n *\n * The `_features` table maps every optional glTF capability to a `[trigger, load]`\n * pair: a cheap trigger plus a dynamic `import()` of the feature's `GltfFeature`\n * module. A trigger is either an exact `extensionsUsed` name (the common case) or\n * a predicate over the parsed JSON for features that aren't a simple extension\n * membership (ORM compositing, skeletons, morph targets, animations, dielectric\n * material cluster).\n *\n * This whole module is itself dynamically imported by the core loader\n * (`load-gltf.ts`) ONLY when the asset can possibly trigger at least one feature\n * — so assets that use no optional features (plain metallic-roughness GLBs) never\n * pay for the table or its import thunks.\n *\n * The core loader knows zero feature names; new extensions are added here alone.\n */\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport { anyPrimitive, needsOrmComposite } from \"./gltf-parser.js\";\n\n/** Dynamic `import()` of a feature's `GltfFeature` module. */\ntype Loader = () => Promise<{ default: GltfFeature }>;\n/** Either an exact `extensionsUsed` name, or a predicate over the parsed JSON. */\ntype Trigger = string | ((json: any) => boolean);\n\nconst M = \"KHR_materials_\";\n\nconst _features: [Trigger, Loader][] = [\n // Pre-parse features (buffer-level): order matters — meshopt decompresses\n // bufferViews first, then quantization dequantizes the resulting accessors.\n [\"EXT_meshopt_compression\", () => import(\"./gltf-feature-meshopt.js\")],\n [\"KHR_mesh_quantization\", () => import(\"./gltf-ext-quantization.js\")],\n // Pre-mesh features (geometry decompression)\n [\"KHR_draco_mesh_compression\", () => import(\"./gltf-feature-draco.js\")],\n // Material extensions\n [M + \"clearcoat\", () => import(\"./gltf-ext-clearcoat.js\")],\n [M + \"iridescence\", () => import(\"./gltf-ext-iridescence.js\")],\n [M + \"emissive_strength\", () => import(\"./gltf-ext-emissive-strength.js\")],\n [M + \"sheen\", () => import(\"./gltf-ext-sheen.js\")],\n [M + \"anisotropy\", () => import(\"./gltf-ext-anisotropy.js\")],\n [M + \"diffuse_transmission\", () => import(\"./gltf-ext-diffuse-transmission.js\")],\n [M + \"unlit\", () => import(\"./gltf-ext-unlit.js\")],\n [M + \"pbrSpecularGlossiness\", () => import(\"./gltf-ext-spec-gloss.js\")],\n // Dielectric cluster (ior/specular/transmission/volume/dispersion) — any of the five triggers the\n // loader; transmission refraction is wired dynamically by the PBR material path when needed.\n [(j) => [\"transmission\", \"volume\", \"ior\", \"specular\", \"dispersion\"].some((e) => j.extensionsUsed?.includes(M + e)), () => import(\"./gltf-ext-dielectric.js\")],\n [\"KHR_texture_transform\", () => import(\"./gltf-ext-uv-transform.js\")],\n [\"KHR_texture_basisu\", () => import(\"./gltf-ext-basisu.js\")],\n [needsOrmComposite, () => import(\"./gltf-ext-orm.js\")],\n // Per-mesh features (predicates inlined to avoid eager imports)\n [(j) => !!j.skins?.length && anyPrimitive(j, (p) => p.attributes?.JOINTS_0 !== undefined), () => import(\"./gltf-feature-skeleton.js\")],\n [(j) => anyPrimitive(j, (p) => !!p.targets?.length), () => import(\"./gltf-feature-morph.js\")],\n // Non-triangle primitive topology (POINTS/LINES/LINE_STRIP/TRIANGLE_STRIP) or a\n // negative-determinant node (negative scale / mirrored matrix): both need the lazy primitive\n // feature (topology threading + winding reversal). Triangle-list positive-winding never triggers.\n [(j) => hasNegDetNode(j) || anyPrimitive(j, (p) => p.mode !== undefined && p.mode !== 4), () => import(\"./gltf-feature-primitive.js\")],\n // Per-asset features\n [hasGltfExtras, () => import(\"./gltf-feature-extras.js\")],\n [\"KHR_lights_punctual\", () => import(\"./gltf-feature-lights-punctual.js\")],\n [(j) => !!j.animations?.length, () => import(\"./gltf-feature-animations.js\")],\n // Non-Float32 / normalized animation sampler accessors (e.g. Animation_SamplerType normalized\n // BYTE/SHORT rotation) need the lazy denorm converter; plain float samplers never load it.\n [hasNonFloatAnimSampler, () => import(\"./gltf-sampler-denorm.js\")],\n [M + \"variants\", () => import(\"./gltf-feature-variants.js\")],\n [\"KHR_node_visibility\", () => import(\"./gltf-ext-node-visibility.js\")],\n [\"KHR_animation_pointer\", () => import(\"./gltf-feature-animation-pointer.js\")],\n [\"EXT_mesh_gpu_instancing\", () => import(\"./gltf-feature-gpu-instancing.js\")],\n [\"KHR_xmp_json_ld\", () => import(\"./gltf-feature-xmp.js\")],\n];\n\n/** Dynamic-import every feature the asset triggers. */\nexport async function loadGltfFeatures(json: any): Promise<GltfFeature[]> {\n const used: string[] = json.extensionsUsed ?? [];\n const mods = await Promise.all(_features.flatMap(([t, load]) => ((typeof t === \"string\" ? used.includes(t) : t(json)) ? [load()] : [])));\n return mods.map((m) => m.default);\n}\n\nfunction hasGltfExtras(json: any): boolean {\n const hasExtras = (item: any): boolean => item?.extras !== undefined;\n return (\n hasExtras(json.asset) ||\n !!json.nodes?.some(hasExtras) ||\n !!json.materials?.some(hasExtras) ||\n !!json.animations?.some(hasExtras) ||\n !!json.meshes?.some(hasExtras) ||\n anyPrimitive(json, hasExtras)\n );\n}\n\n/** True if any animation sampler reads a non-Float32 input/output accessor (normalized BYTE/SHORT\n * rotation output, normalized UNSIGNED_BYTE flags, …) — the only case that needs the lazy sampler\n * denorm converter. Plain Float32 samplers (the overwhelming majority) skip it. */\nfunction hasNonFloatAnimSampler(json: any): boolean {\n const accessors = json.accessors;\n return !!(json.animations as any[] | undefined)?.some((a) =>\n a.samplers?.some((s: any) => accessors[s.input]?.componentType !== 5126 || accessors[s.output]?.componentType !== 5126)\n );\n}\n\n/** True if any node introduces a negative-determinant local transform — a\n * negative scale (odd number of negative components) or a `matrix` with a\n * negative 3x3 determinant. Such a node (or a child of one) can flip a mesh's\n * net world determinant positive, reversing its triangle winding. Gates the\n * lazy negative-winding feature so positive-scale / pure-TRS assets never load\n * it. A negative-determinant node whose meshes' net world determinant stays\n * negative over-triggers harmlessly (the feature then finds a non-positive\n * determinant per mesh and flags nothing). */\nfunction hasNegDetNode(json: any): boolean {\n return !!(json.nodes as any[] | undefined)?.some((n) => {\n if (n.scale) {\n return n.scale[0] * n.scale[1] * n.scale[2] < 0;\n }\n if (n.matrix) {\n const m = n.matrix;\n return m[0] * (m[5] * m[10] - m[6] * m[9]) + m[1] * (m[6] * m[8] - m[4] * m[10]) + m[2] * (m[4] * m[9] - m[5] * m[8]) < 0;\n }\n return false;\n });\n}\n"],"names":[],"mappings":";;AAyBA,MAAM,CAAA,GAAI,gBAAA;AAEV,MAAM,SAAA,GAAiC;AAAA;AAAA;AAAA,EAGnC,CAAC,yBAAA,EAA2B,MAAM,OAAO,2BAA2B,CAAC,CAAA;AAAA,EACrE,CAAC,uBAAA,EAAyB,MAAM,OAAO,4BAA4B,CAAC,CAAA;AAAA;AAAA,EAEpE,CAAC,4BAAA,EAA8B,MAAM,OAAO,yBAAyB,CAAC,CAAA;AAAA;AAAA,EAEtE,CAAC,CAAA,GAAI,WAAA,EAAa,MAAM,OAAO,yBAAyB,CAAC,CAAA;AAAA,EACzD,CAAC,CAAA,GAAI,aAAA,EAAe,MAAM,OAAO,2BAA2B,CAAC,CAAA;AAAA,EAC7D,CAAC,CAAA,GAAI,mBAAA,EAAqB,MAAM,OAAO,iCAAiC,CAAC,CAAA;AAAA,EACzE,CAAC,CAAA,GAAI,OAAA,EAAS,MAAM,OAAO,qBAAqB,CAAC,CAAA;AAAA,EACjD,CAAC,CAAA,GAAI,YAAA,EAAc,MAAM,OAAO,0BAA0B,CAAC,CAAA;AAAA,EAC3D,CAAC,CAAA,GAAI,sBAAA,EAAwB,MAAM,OAAO,oCAAoC,CAAC,CAAA;AAAA,EAC/E,CAAC,CAAA,GAAI,OAAA,EAAS,MAAM,OAAO,qBAAqB,CAAC,CAAA;AAAA,EACjD,CAAC,CAAA,GAAI,uBAAA,EAAyB,MAAM,OAAO,0BAA0B,CAAC,CAAA;AAAA;AAAA;AAAA,EAGtE,CAAC,CAAC,CAAA,KAAM,CAAC,gBAAgB,QAAA,EAAU,KAAA,EAAO,UAAA,EAAY,YAAY,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,cAAA,EAAgB,QAAA,CAAS,CAAA,GAAI,CAAC,CAAC,CAAA,EAAG,MAAM,OAAO,0BAA0B,CAAC,CAAA;AAAA,EAC5J,CAAC,uBAAA,EAAyB,MAAM,OAAO,4BAA4B,CAAC,CAAA;AAAA,EACpE,CAAC,oBAAA,EAAsB,MAAM,OAAO,sBAAsB,CAAC,CAAA;AAAA,EAC3D,CAAC,iBAAA,EAAmB,MAAM,OAAO,mBAAmB,CAAC,CAAA;AAAA;AAAA,EAErD,CAAC,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA,CAAE,KAAA,EAAO,UAAU,YAAA,CAAa,CAAA,EAAG,CAAC,CAAA,KAAM,CAAA,CAAE,YAAY,QAAA,KAAa,MAAS,GAAG,MAAM,OAAO,4BAA4B,CAAC,CAAA;AAAA,EACrI,CAAC,CAAC,CAAA,KAAM,YAAA,CAAa,CAAA,EAAG,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA,CAAE,SAAS,MAAM,CAAA,EAAG,MAAM,OAAO,yBAAyB,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA,EAI5F,CAAC,CAAC,CAAA,KAAM,aAAA,CAAc,CAAC,CAAA,IAAK,YAAA,CAAa,GAAG,CAAC,CAAA,KAAM,EAAE,IAAA,KAAS,MAAA,IAAa,EAAE,IAAA,KAAS,CAAC,GAAG,MAAM,OAAO,6BAA6B,CAAC,CAAA;AAAA;AAAA,EAErI,CAAC,aAAA,EAAe,MAAM,OAAO,0BAA0B,CAAC,CAAA;AAAA,EACxD,CAAC,qBAAA,EAAuB,MAAM,OAAO,mCAAmC,CAAC,CAAA;AAAA,EACzE,CAAC,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA,CAAE,UAAA,EAAY,MAAA,EAAQ,MAAM,OAAO,8BAA8B,CAAC,CAAA;AAAA;AAAA;AAAA,EAG5E,CAAC,sBAAA,EAAwB,MAAM,OAAO,0BAA0B,CAAC,CAAA;AAAA,EACjE,CAAC,CAAA,GAAI,UAAA,EAAY,MAAM,OAAO,4BAA4B,CAAC,CAAA;AAAA,EAC3D,CAAC,qBAAA,EAAuB,MAAM,OAAO,+BAA+B,CAAC,CAAA;AAAA,EACrE,CAAC,uBAAA,EAAyB,MAAM,OAAO,qCAAqC,CAAC,CAAA;AAAA,EAC7E,CAAC,yBAAA,EAA2B,MAAM,OAAO,kCAAkC,CAAC,CAAA;AAAA,EAC5E,CAAC,iBAAA,EAAmB,MAAM,OAAO,uBAAuB,CAAC;AAC7D,CAAA;AAGA,eAAsB,iBAAiB,IAAA,EAAmC;AACtE,EAAA,MAAM,IAAA,GAAiB,IAAA,CAAK,cAAA,IAAkB,EAAC;AAC/C,EAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,GAAA,CAAI,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAG,IAAI,CAAA,KAAA,CAAQ,OAAO,CAAA,KAAM,QAAA,GAAW,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA,GAAI,CAAA,CAAE,IAAI,CAAA,IAAK,CAAC,IAAA,EAAM,CAAA,GAAI,EAAG,CAAC,CAAA;AACvI,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,OAAO,CAAA;AACpC;AAEA,SAAS,cAAc,IAAA,EAAoB;AACvC,EAAA,MAAM,SAAA,GAAY,CAAC,IAAA,KAAuB,IAAA,EAAM,MAAA,KAAW,MAAA;AAC3D,EAAA,OACI,SAAA,CAAU,IAAA,CAAK,KAAK,CAAA,IACpB,CAAC,CAAC,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,SAAS,CAAA,IAC5B,CAAC,CAAC,IAAA,CAAK,WAAW,IAAA,CAAK,SAAS,CAAA,IAChC,CAAC,CAAC,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,SAAS,CAAA,IACjC,CAAC,CAAC,IAAA,CAAK,QAAQ,IAAA,CAAK,SAAS,CAAA,IAC7B,YAAA,CAAa,MAAM,SAAS,CAAA;AAEpC;AAKA,SAAS,uBAAuB,IAAA,EAAoB;AAChD,EAAA,MAAM,YAAY,IAAA,CAAK,SAAA;AACvB,EAAA,OAAO,CAAC,CAAE,IAAA,CAAK,UAAA,EAAkC,IAAA;AAAA,IAAK,CAAC,CAAA,KACnD,CAAA,CAAE,UAAU,IAAA,CAAK,CAAC,MAAW,SAAA,CAAU,CAAA,CAAE,KAAK,CAAA,EAAG,kBAAkB,IAAA,IAAQ,SAAA,CAAU,EAAE,MAAM,CAAA,EAAG,kBAAkB,IAAI;AAAA,GAC1H;AACJ;AAUA,SAAS,cAAc,IAAA,EAAoB;AACvC,EAAA,OAAO,CAAC,CAAE,IAAA,CAAK,KAAA,EAA6B,IAAA,CAAK,CAAC,CAAA,KAAM;AACpD,IAAA,IAAI,EAAE,KAAA,EAAO;AACT,MAAA,OAAO,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,GAAI,CAAA;AAAA,IAClD;AACA,IAAA,IAAI,EAAE,MAAA,EAAQ;AACV,MAAA,MAAM,IAAI,CAAA,CAAE,MAAA;AACZ,MAAA,OAAO,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,EAAE,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,CAAA,GAAK,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,EAAE,CAAA,CAAA,GAAK,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,CAAA,GAAK,CAAA;AAAA,IAC5H;AACA,IAAA,OAAO,KAAA;AAAA,EACX,CAAC,CAAA;AACL;;;;"}
@@ -1,6 +1,19 @@
1
1
  import { resolveAccessor } from './gltf-parser.js';
2
+ import { F32, U16 } from '../engine/typed-arrays.js';
2
3
  import { _boneBuilder } from '../skeleton/bone-control-hooks.js';
3
4
 
5
+ function weightsToFloat32(w) {
6
+ if (w instanceof F32) {
7
+ return w;
8
+ }
9
+ const inv = w instanceof U16 ? 1 / 65535 : 1 / 255;
10
+ const s = w;
11
+ const out = new F32(s.length);
12
+ for (let i = 0; i < s.length; i++) {
13
+ out[i] = s[i] * inv;
14
+ }
15
+ return out;
16
+ }
4
17
  function resolveAttr(name, primitive, decoded, json, binChunk) {
5
18
  if (decoded && decoded._attributes.has(name)) {
6
19
  return decoded._attributes.get(name);
@@ -29,12 +42,14 @@ const feature = {
29
42
  const primitive = meshData._primitive;
30
43
  const decoded = meshData._decoded;
31
44
  const joints = await resolveAttr("JOINTS_0", primitive, decoded, json, binChunk);
32
- const weights = await resolveAttr("WEIGHTS_0", primitive, decoded, json, binChunk);
33
- if (!joints || !weights) {
45
+ const weightsRaw = await resolveAttr("WEIGHTS_0", primitive, decoded, json, binChunk);
46
+ if (!joints || !weightsRaw) {
34
47
  return;
35
48
  }
49
+ const weights = weightsToFloat32(weightsRaw);
36
50
  const joints1 = await resolveAttr("JOINTS_1", primitive, decoded, json, binChunk);
37
- const weights1 = await resolveAttr("WEIGHTS_1", primitive, decoded, json, binChunk);
51
+ const weights1Raw = await resolveAttr("WEIGHTS_1", primitive, decoded, json, binChunk);
52
+ const weights1 = weights1Raw ? weightsToFloat32(weights1Raw) : null;
38
53
  const [{ extractSkin, computeBoneTextureData }, { createSkeleton }] = await Promise.all([import('./gltf-animation.js'), import('../skeleton/create-skeleton.js')]);
39
54
  const skin = extractSkin(json, binChunk, node.skin, meshData._worldMatrix, parentMap, worldMatrixCache);
40
55
  const boneData = computeBoneTextureData(skin);
@@ -1 +1 @@
1
- {"version":3,"file":"gltf-feature-skeleton.js","sources":["../../../src/loader-gltf/gltf-feature-skeleton.ts"],"sourcesContent":["/** Skeletal animation feature. Extracts joints/weights/skin on demand so the\n * core loader doesn't carry any skinning-related code for non-skinned assets. */\n\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport { resolveAccessor } from \"./gltf-parser.js\";\nimport { _boneBuilder } from \"../skeleton/bone-control-hooks.js\";\n\n/** Resolve a vertex attribute by name, preferring any pre-decoded\n * (e.g. Draco) data over the raw accessor. De-strides interleaved sources:\n * `resolveAccessor` assumes tight packing, so strided JOINTS/WEIGHTS — common\n * in skinned rigs that pack both into one bufferView with a byteStride — would\n * otherwise read neighbouring/padding bytes and corrupt the skin (wrong joint\n * indices → exploded or mis-posed mesh). */\nfunction resolveAttr(name: string, primitive: any, decoded: any, json: any, binChunk: DataView): ArrayBufferView | null | Promise<ArrayBufferView> {\n if (decoded && decoded._attributes.has(name)) {\n return decoded._attributes.get(name)!;\n }\n const idx = primitive.attributes?.[name];\n if (idx === undefined) {\n return null;\n }\n const accessor = json.accessors[idx];\n const bv = accessor.bufferView !== undefined ? json.bufferViews[accessor.bufferView] : undefined;\n const compBytes = accessor.componentType === 5126 || accessor.componentType === 5125 ? 4 : accessor.componentType === 5123 || accessor.componentType === 5122 ? 2 : 1;\n const stride = bv?.byteStride;\n // JOINTS_n and WEIGHTS_n are glTF VEC4 attributes.\n if (bv === undefined || stride === undefined || stride === 4 * compBytes) {\n return resolveAccessor(json, binChunk, idx)._data as ArrayBufferView;\n }\n return import(\"./gltf-strided-attribute.js\").then((m) => m.copyStridedAttribute(accessor, bv, binChunk, 4, compBytes));\n}\n\nconst feature: GltfFeature = {\n id: \"_skeleton\",\n async applyMesh(meshData, mesh, ctx) {\n const { _json: json, _binChunk: binChunk, _parentMap: parentMap, _worldMatrixCache: worldMatrixCache } = ctx;\n const node = json.nodes[meshData._nodeIndex];\n if (node.skin === undefined || !json.skins) {\n return;\n }\n const primitive = meshData._primitive;\n const decoded = meshData._decoded;\n const joints = (await resolveAttr(\"JOINTS_0\", primitive, decoded, json, binChunk)) as Uint16Array | Uint8Array | null;\n const weights = (await resolveAttr(\"WEIGHTS_0\", primitive, decoded, json, binChunk)) as Float32Array | null;\n if (!joints || !weights) {\n return;\n }\n const joints1 = (await resolveAttr(\"JOINTS_1\", primitive, decoded, json, binChunk)) as Uint16Array | Uint8Array | null;\n const weights1 = (await resolveAttr(\"WEIGHTS_1\", primitive, decoded, json, binChunk)) as Float32Array | null;\n\n const [{ extractSkin, computeBoneTextureData }, { createSkeleton }] = await Promise.all([import(\"./gltf-animation.js\"), import(\"../skeleton/create-skeleton.js\")]);\n const skin = extractSkin(json, binChunk, node.skin, meshData._worldMatrix, parentMap, worldMatrixCache);\n const boneData = computeBoneTextureData(skin);\n mesh.skeleton = createSkeleton(ctx._engine, joints, weights, skin.jointNodes.length, boneData, joints1, weights1);\n\n // When bone control is enabled, lazily create the asset-wide override map\n // here (per-mesh hook runs before any per-asset hook) so the animation feature\n // and the bone-control builder share the same map race-free.\n if (_boneBuilder && !ctx._boneOverrides) {\n ctx._boneOverrides = new Map();\n }\n },\n async applyAsset(meshes, _root, ctx) {\n // Bone control is opt-in: with the builder hook absent (default), no public\n // skeleton handles are built and `container.skeletons` stays undefined — the\n // whole bone-control implementation tree-shakes away.\n if (!_boneBuilder || !ctx._boneOverrides) {\n return {};\n }\n return _boneBuilder(ctx, meshes, ctx._boneOverrides);\n },\n};\nexport default feature;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gltf-feature-skeleton.js","sources":["../../../src/loader-gltf/gltf-feature-skeleton.ts"],"sourcesContent":["/** Skeletal animation feature. Extracts joints/weights/skin on demand so the\n * core loader doesn't carry any skinning-related code for non-skinned assets. */\n\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport { resolveAccessor } from \"./gltf-parser.js\";\nimport { F32, U16 } from \"../engine/typed-arrays.js\";\nimport { _boneBuilder } from \"../skeleton/bone-control-hooks.js\";\n\n/** Denormalize a resolved WEIGHTS_n attribute to a tight Float32 VEC4 buffer.\n * glTF allows WEIGHTS to be FLOAT or normalized UNSIGNED_BYTE / UNSIGNED_SHORT;\n * the skinning pipeline binds weights as `float32x4`, so integer weights read\n * raw (0..255 / 0..65535) explode the skin (mesh collapses → blank render).\n * Float sources pass through untouched (zero cost for the common case). Kept\n * inline (not lazily imported): the denorm is smaller than a dynamic-import\n * thunk, and it only ships in the already skin-gated feature chunk. */\nfunction weightsToFloat32(w: ArrayBufferView): Float32Array {\n if (w instanceof F32) {\n return w;\n }\n const inv = w instanceof U16 ? 1 / 65535 : 1 / 255;\n const s = w as unknown as { [i: number]: number; length: number };\n const out = new F32(s.length);\n for (let i = 0; i < s.length; i++) {\n out[i] = s[i]! * inv;\n }\n return out;\n}\n\n/** Resolve a vertex attribute by name, preferring any pre-decoded\n * (e.g. Draco) data over the raw accessor. De-strides interleaved sources:\n * `resolveAccessor` assumes tight packing, so strided JOINTS/WEIGHTS — common\n * in skinned rigs that pack both into one bufferView with a byteStride — would\n * otherwise read neighbouring/padding bytes and corrupt the skin (wrong joint\n * indices → exploded or mis-posed mesh). */\nfunction resolveAttr(name: string, primitive: any, decoded: any, json: any, binChunk: DataView): ArrayBufferView | null | Promise<ArrayBufferView> {\n if (decoded && decoded._attributes.has(name)) {\n return decoded._attributes.get(name)!;\n }\n const idx = primitive.attributes?.[name];\n if (idx === undefined) {\n return null;\n }\n const accessor = json.accessors[idx];\n const bv = accessor.bufferView !== undefined ? json.bufferViews[accessor.bufferView] : undefined;\n const compBytes = accessor.componentType === 5126 || accessor.componentType === 5125 ? 4 : accessor.componentType === 5123 || accessor.componentType === 5122 ? 2 : 1;\n const stride = bv?.byteStride;\n // JOINTS_n and WEIGHTS_n are glTF VEC4 attributes.\n if (bv === undefined || stride === undefined || stride === 4 * compBytes) {\n return resolveAccessor(json, binChunk, idx)._data as ArrayBufferView;\n }\n return import(\"./gltf-strided-attribute.js\").then((m) => m.copyStridedAttribute(accessor, bv, binChunk, 4, compBytes));\n}\n\nconst feature: GltfFeature = {\n id: \"_skeleton\",\n async applyMesh(meshData, mesh, ctx) {\n const { _json: json, _binChunk: binChunk, _parentMap: parentMap, _worldMatrixCache: worldMatrixCache } = ctx;\n const node = json.nodes[meshData._nodeIndex];\n if (node.skin === undefined || !json.skins) {\n return;\n }\n const primitive = meshData._primitive;\n const decoded = meshData._decoded;\n const joints = (await resolveAttr(\"JOINTS_0\", primitive, decoded, json, binChunk)) as Uint16Array | Uint8Array | null;\n const weightsRaw = await resolveAttr(\"WEIGHTS_0\", primitive, decoded, json, binChunk);\n if (!joints || !weightsRaw) {\n return;\n }\n const weights = weightsToFloat32(weightsRaw);\n const joints1 = (await resolveAttr(\"JOINTS_1\", primitive, decoded, json, binChunk)) as Uint16Array | Uint8Array | null;\n const weights1Raw = await resolveAttr(\"WEIGHTS_1\", primitive, decoded, json, binChunk);\n const weights1 = weights1Raw ? weightsToFloat32(weights1Raw) : null;\n\n const [{ extractSkin, computeBoneTextureData }, { createSkeleton }] = await Promise.all([import(\"./gltf-animation.js\"), import(\"../skeleton/create-skeleton.js\")]);\n const skin = extractSkin(json, binChunk, node.skin, meshData._worldMatrix, parentMap, worldMatrixCache);\n const boneData = computeBoneTextureData(skin);\n mesh.skeleton = createSkeleton(ctx._engine, joints, weights, skin.jointNodes.length, boneData, joints1, weights1);\n\n // When bone control is enabled, lazily create the asset-wide override map\n // here (per-mesh hook runs before any per-asset hook) so the animation feature\n // and the bone-control builder share the same map race-free.\n if (_boneBuilder && !ctx._boneOverrides) {\n ctx._boneOverrides = new Map();\n }\n },\n async applyAsset(meshes, _root, ctx) {\n // Bone control is opt-in: with the builder hook absent (default), no public\n // skeleton handles are built and `container.skeletons` stays undefined — the\n // whole bone-control implementation tree-shakes away.\n if (!_boneBuilder || !ctx._boneOverrides) {\n return {};\n }\n return _boneBuilder(ctx, meshes, ctx._boneOverrides);\n },\n};\nexport default feature;\n"],"names":[],"mappings":"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"}
@@ -81,7 +81,7 @@ function resolveColorVec4(json, binChunk, idx) {
81
81
  }
82
82
  return out;
83
83
  }
84
- function buildInterleavedPartial(json, binChunk, primitive, worldMatrix, nodeIdx) {
84
+ async function buildInterleavedPartial(json, binChunk, primitive, worldMatrix, nodeIdx) {
85
85
  const attrs = primitive.attributes;
86
86
  let anyStrided = false;
87
87
  for (const name in attrs) {
@@ -112,7 +112,8 @@ function buildInterleavedPartial(json, binChunk, primitive, worldMatrix, nodeIdx
112
112
  vertexCount = pos._count;
113
113
  const nrm = resolveOne("NORMAL", false);
114
114
  vb._n = nrm._il;
115
- const uv = resolveOne("TEXCOORD_0", false);
115
+ const uvIdx = attrs["TEXCOORD_0"];
116
+ const uv = uvIdx !== void 0 && json.accessors[uvIdx].componentType !== FLOAT ? { _tight: (await import('./gltf-uv-denorm.js')).resolveUvVec2(json, binChunk, uvIdx), _count: json.accessors[uvIdx].count } : resolveOne("TEXCOORD_0", false);
116
117
  vb._u = uv._il;
117
118
  const tan = resolveOne("TANGENT", true);
118
119
  vb._t = tan._il;
@@ -1 +1 @@
1
- {"version":3,"file":"gltf-interleave.js","sources":["../../../src/loader-gltf/gltf-interleave.ts"],"sourcesContent":["/**\n * Interleaved (strided) glTF vertex-buffer support — dynamically imported.\n *\n * The engine renders interleaved attributes genuinely: the raw strided\n * bufferView slice is uploaded ONCE as a shared GPU buffer, bound to each\n * attribute slot at byte offset 0, with the per-attribute byte offset encoded in\n * the pipeline vertex layout (`attributes[].offset`) and `arrayStride` set to the\n * bufferView byteStride. This mirrors stock Babylon.js's WebGPU vertex state and\n * avoids a non-zero `setVertexBuffer` bind offset, which corrupts vertex fetch on\n * some AMD (Renoir) / Dawn paths. The loader never rewrites the asset.\n *\n * This whole module is loaded via `await import()` only when an asset actually\n * contains an interleaved bufferView, so non-interleaved scenes pay ZERO bundle\n * cost. The tight CPU copy of position/normal/uv (for AABB, picking, CSG, …) is\n * de-strided LAZILY — only on first CPU read via `installLazyCpu` — so scenes\n * that only render never materialize it.\n */\n\nimport { F32, U32, U16, U8, DV } from \"../engine/typed-arrays.js\";\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { Mat4 } from \"../math/types.js\";\nimport type { Aabb } from \"../math/aabb.js\";\nimport { computeAabb } from \"../math/compute-aabb.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Mesh, MeshGPU } from \"../mesh/mesh.js\";\nimport { initMeshTransform } from \"../mesh/mesh.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport { createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport { resolveAccessor, TYPE_SIZES } from \"./gltf-parser.js\";\nimport { computeSmoothNormals } from \"./gltf-normals.js\";\nimport type { GltfMeshData } from \"./load-gltf.js\";\n\nconst FLOAT = 5126;\nconst UNSIGNED_SHORT = 5123;\nconst UNSIGNED_INT = 5125;\nconst UNSIGNED_BYTE = 5121;\n\nconst COMP_BYTES: Record<number, number> = { [UNSIGNED_BYTE]: 1, [UNSIGNED_SHORT]: 2, [UNSIGNED_INT]: 4, [FLOAT]: 4 };\n\nfunction createSequentialIndices(vertexCount: number): Uint16Array | Uint32Array {\n const indices = vertexCount > 0xffff ? new U32(vertexCount) : new U16(vertexCount);\n for (let i = 0; i < vertexCount; i++) {\n indices[i] = i;\n }\n return indices;\n}\n\n/** Interleave descriptor for one attribute sourced from a strided bufferView.\n * The raw slice is shared across attributes of the same bufferView; the\n * pipeline uses `_stride` as arrayStride and binds at `_offset`. */\nexport interface AccessorInterleave {\n /** @internal glTF bufferView index — shared-buffer key (same view → one GPU buffer). */\n _bufferView: number;\n /** @internal Interleave byte stride (bufferView.byteStride) → pipeline arrayStride. */\n _stride: number;\n /** @internal Attribute byte offset within the bufferView → pipeline vertex layout\n * `attributes[].offset` (the shared buffer is bound at offset 0). */\n _offset: number;\n /** @internal glTF component type (FLOAT, UNSIGNED_SHORT, …). */\n _componentType: number;\n /** @internal Components per vertex. */\n _componentCount: number;\n /** @internal Vertex count. */\n _count: number;\n /** @internal Raw bufferView bytes (shared across attributes). Retained after GPU upload\n * so the CPU copy can be de-strided lazily on demand. */\n _slice?: Uint8Array;\n}\n\n/** Per-attribute interleave sources for a primitive (keys mirror MeshVbLayout). */\nexport interface GltfVb {\n /** @internal */\n _p?: AccessorInterleave;\n /** @internal */\n _n?: AccessorInterleave;\n /** @internal */\n _t?: AccessorInterleave;\n /** @internal */\n _u?: AccessorInterleave;\n /** @internal */\n _u2?: AccessorInterleave;\n /** @internal */\n _c?: AccessorInterleave;\n}\n\n/** True if accessor `idx`'s bufferView is interleaved (byteStride present and\n * larger than the attribute's tightly-packed element size). */\nexport function accessorIsStrided(json: any, idx: number): boolean {\n const a = json.accessors[idx];\n const bv = json.bufferViews[a.bufferView];\n const stride: number | undefined = bv.byteStride;\n if (stride === undefined) {\n return false;\n }\n const elemBytes = (TYPE_SIZES[a.type] ?? 1) * (COMP_BYTES[a.componentType] ?? 4);\n return stride !== elemBytes;\n}\n\n/** Resolve a strided accessor into an {@link AccessorInterleave} descriptor. */\nfunction resolveStrided(json: any, binChunk: DataView, accessorIdx: number): AccessorInterleave {\n const accessor = json.accessors[accessorIdx];\n const bufferView = json.bufferViews[accessor.bufferView];\n const ab = binChunk.buffer as ArrayBuffer;\n return {\n _bufferView: accessor.bufferView,\n _stride: bufferView.byteStride,\n _offset: accessor.byteOffset ?? 0,\n _componentType: accessor.componentType,\n _componentCount: TYPE_SIZES[accessor.type] ?? 1,\n _count: accessor.count,\n _slice: new U8(ab, binChunk.byteOffset + (bufferView.byteOffset ?? 0), bufferView.byteLength),\n };\n}\n\n/** De-stride an interleaved attribute into a tight Float32Array, reading raw\n * component values (no normalization) so the result matches what a tight\n * accessor view would have produced. */\nfunction destrideToTight(il: AccessorInterleave): Float32Array {\n const dv = new DV(il._slice!.buffer, il._slice!.byteOffset, il._slice!.byteLength);\n const cb = COMP_BYTES[il._componentType] ?? 4;\n const ct = il._componentType;\n const cc = il._componentCount;\n const out = new F32(il._count * cc);\n for (let v = 0; v < il._count; v++) {\n const rowBase = il._offset + v * il._stride;\n for (let c = 0; c < cc; c++) {\n const off = rowBase + c * cb;\n out[v * cc + c] =\n ct === FLOAT ? dv.getFloat32(off, true) : ct === UNSIGNED_SHORT ? dv.getUint16(off, true) : ct === UNSIGNED_INT ? dv.getUint32(off, true) : dv.getUint8(off);\n }\n }\n return out;\n}\n\n/** Resolve COLOR_0 to a tight float32 VEC4 [0,1] buffer — the vertex-color layout the\n * PBR pipeline binds (float32x4: rgb modulates base color, a modulates alpha). glTF\n * COLOR_0 may be VEC3 or VEC4, FLOAT or normalized UNSIGNED_BYTE/SHORT, and (here)\n * interleaved with a byteStride. Binding the raw strided/ubyte source as float32x4\n * reads neighbouring bytes as floats (garbage / rainbow colors). This normalizes\n * integer types to [0,1], gives a VEC3 source alpha = 1, and de-strides — mirroring\n * the tight path's normalizeColorToVec4. Reads relative to `binChunk`. */\nfunction resolveColorVec4(json: any, binChunk: DataView, idx: number): Float32Array {\n const accessor = json.accessors[idx];\n const ct = accessor.componentType;\n const cb = COMP_BYTES[ct] ?? 4;\n const comps = TYPE_SIZES[accessor.type] ?? 4;\n const bv = json.bufferViews[accessor.bufferView];\n const stride = bv.byteStride ?? comps * cb;\n const inv = ct === UNSIGNED_BYTE ? 1 / 255 : ct === UNSIGNED_SHORT ? 1 / 65535 : 1;\n const base = (bv.byteOffset ?? 0) + (accessor.byteOffset ?? 0);\n const out = new F32(accessor.count * 4);\n for (let v = 0; v < accessor.count; v++) {\n const row = base + v * stride;\n for (let c = 0; c < 4; c++) {\n if (c === 3 && comps < 4) {\n out[v * 4 + 3] = 1;\n break;\n }\n const off = row + c * cb;\n const raw = ct === FLOAT ? binChunk.getFloat32(off, true) : ct === UNSIGNED_SHORT ? binChunk.getUint16(off, true) : binChunk.getUint8(off);\n out[v * 4 + c] = raw * inv;\n }\n }\n return out;\n}\n\n/** Build a mesh-data partial for a primitive, but ONLY if it actually sources\n * ≥1 attribute from an interleaved (strided) bufferView. Returns `undefined`\n * for fully-tight primitives so the caller falls back to its tight path.\n *\n * Strided POSITION/NORMAL/TEXCOORD_0 attributes keep their raw slice in `_vb`\n * (for genuine GPU interleaving) and leave the tight CPU field `null` — the\n * de-strided copy is materialized lazily on first CPU read (see\n * {@link installLazyCpu}). Strided TANGENT/TEXCOORD_1 are eagerly de-strided\n * (they feed device-lost recovery), but no current asset interleaves them.\n * COLOR_0 is always normalized to a tight float32x3 buffer (see\n * {@link resolveColorVec4}). Tight attributes resolve exactly like the core loader. */\nexport function buildInterleavedPartial(json: any, binChunk: DataView, primitive: any, worldMatrix: Mat4, nodeIdx: number): Omit<GltfMeshData, \"_material\"> | undefined {\n const attrs = primitive.attributes;\n\n // Per-primitive gate: bail (→ tight path) unless a vertex attribute is strided.\n let anyStrided = false;\n for (const name in attrs) {\n if (accessorIsStrided(json, attrs[name])) {\n anyStrided = true;\n break;\n }\n }\n if (!anyStrided) {\n return undefined;\n }\n\n const vb: GltfVb = {};\n let vertexCount = 0;\n\n // Resolve one attribute. Returns the interleave descriptor (when the source is\n // strided) and/or a tight CPU array. `eager` de-strides strided sources up-front\n // (TANGENT/UV2/COLOR feed device-lost recovery); lazy ones leave `_tight` null and\n // are de-strided on demand. The caller assigns `vb.<attr>` with a STATIC property\n // name (never a computed `vb[key]`) — a computed write would stay an unmangled\n // literal while every reader uses the mangled static name, corrupting the object\n // across the dynamic-import chunk boundary.\n const resolveOne = (name: string, eager: boolean): { _tight: Float32Array | null; _il?: AccessorInterleave; _count: number } => {\n const idx = attrs[name];\n if (idx === undefined) {\n return { _tight: null, _count: 0 };\n }\n if (accessorIsStrided(json, idx)) {\n const il = resolveStrided(json, binChunk, idx);\n return { _tight: eager ? destrideToTight(il) : null, _il: il, _count: il._count };\n }\n const av = resolveAccessor(json, binChunk, idx);\n return { _tight: av._data as Float32Array, _count: av._count };\n };\n\n const pos = resolveOne(\"POSITION\", false);\n vb._p = pos._il;\n vertexCount = pos._count;\n const nrm = resolveOne(\"NORMAL\", false);\n vb._n = nrm._il;\n const uv = resolveOne(\"TEXCOORD_0\", false);\n vb._u = uv._il;\n const tan = resolveOne(\"TANGENT\", true);\n vb._t = tan._il;\n const uv2 = resolveOne(\"TEXCOORD_1\", true);\n vb._u2 = uv2._il;\n // COLOR_0 is always materialized as a tight float32x4 [0,1] buffer (see\n // resolveColorVec4) — never bound strided — so ubyte/ushort/VEC3 sources don't\n // misalign against the pipeline's float32x4 vertex-color layout.\n const colorIdx = attrs[\"COLOR_0\"];\n const colors = colorIdx !== undefined ? resolveColorVec4(json, binChunk, colorIdx) : null;\n\n const positions = pos._tight;\n let normals = nrm._tight;\n let uvs = uv._tight;\n const tangents = tan._tight;\n const uv2s = uv2._tight;\n\n const idxData = primitive.indices !== undefined ? resolveAccessor(json, binChunk, primitive.indices) : null;\n const indices = idxData\n ? idxData._data instanceof U32\n ? new U32(idxData._data)\n : idxData._data instanceof U8\n ? Uint16Array.from(idxData._data)\n : new U16(idxData._data.buffer, idxData._data.byteOffset, idxData._count)\n : createSequentialIndices(vertexCount);\n\n // Absent (not merely strided) NORMAL: generate smooth normals to match the core\n // loader's tight path. A zero-filled normal buffer makes every lit fragment's\n // worldNormal NaN/black — e.g. a material-less skinned mesh whose interleaved\n // JOINTS/WEIGHTS route it here (SimpleSkin). computeSmoothNormals is statically\n // imported by this lazy interleave chunk, so non-interleaved scenes (which never\n // load this module) pay zero bundle cost for it.\n if (!normals && !vb._n) {\n const tightPos = positions ?? (vb._p ? destrideToTight(vb._p) : new F32(vertexCount * 3));\n normals = computeSmoothNormals(tightPos, indices, vertexCount);\n }\n if (!uvs && !vb._u) {\n uvs = new F32(vertexCount * 2);\n }\n\n // No NORMAL attribute (neither tight nor strided) → flat-shade per the glTF spec.\n const flatNormal = !nrm._tight && !vb._n;\n\n return {\n _positions: positions,\n _normals: normals,\n _tangents: tangents,\n _uvs: uvs,\n _uv2s: uv2s,\n _colors: colors,\n _flatNormal: flatNormal,\n _indices: indices,\n _vertexCount: vertexCount,\n _indexCount: indices.length,\n _worldMatrix: worldMatrix,\n _vb: vb,\n _nodeIndex: nodeIdx,\n _primitive: primitive,\n };\n}\n\n/** Build the GPU geometry for an interleaved mesh: one shared buffer per\n * bufferView for strided attributes (bound at offset 0; the per-attribute byte\n * offset goes into the pipeline vertex layout, matching stock Babylon.js), tight\n * attributes get their own buffer — byte-identical to non-interleaved meshes.\n * The raw `_slice` is intentionally retained on `_vb` so the CPU copy can be\n * de-strided lazily later (see {@link installLazyCpu}). */\nfunction buildInterleavedGpu(engine: EngineContext, m: GltfMeshData): MeshGPU {\n const vbsrc = m._vb!;\n const shared = new Map<number, GPUBuffer>();\n const vbuf = (a: AccessorInterleave | undefined, tight: Float32Array | null): GPUBuffer | null => {\n if (!a) {\n return tight ? createMappedBuffer(engine, tight, BU.VERTEX) : null;\n }\n let b = shared.get(a._bufferView);\n if (!b) {\n shared.set(a._bufferView, (b = createMappedBuffer(engine, a._slice!, BU.VERTEX)));\n }\n return b;\n };\n // Cache key encodes both stride AND byte offset per attribute: the offsets are\n // now baked into the pipeline vertex layout (attributes[].offset), so two meshes\n // with identical strides but different offsets need distinct pipelines.\n const k = (a: AccessorInterleave | undefined) => `${a?._stride ?? 0},${a?._offset ?? 0}`;\n return {\n positionBuffer: vbuf(vbsrc._p, m._positions)!,\n normalBuffer: vbuf(vbsrc._n, m._normals)!,\n tangentBuffer: m._tangents ? vbuf(vbsrc._t, m._tangents) : null,\n uvBuffer: vbuf(vbsrc._u, m._uvs)!,\n uv2Buffer: m._uv2s ? vbuf(vbsrc._u2, m._uv2s) : null,\n colorBuffer: m._colors ? vbuf(vbsrc._c, m._colors) : null,\n indexBuffer: createMappedBuffer(engine, m._indices, BU.INDEX),\n indexCount: m._indexCount,\n indexFormat: (m._indices instanceof U32 ? \"uint32\" : \"uint16\") as GPUIndexFormat,\n _vbLayout: vbsrc,\n _vbKey: `vb${k(vbsrc._p)}.${k(vbsrc._n)}.${k(vbsrc._t)}.${k(vbsrc._u)}`,\n };\n}\n\n/** Build a complete engine mesh from interleaved glTF mesh-data. Owns ALL\n * interleave-specific work (GPU upload, AABB fold, lazy CPU install, device-lost\n * retention) so the core loader's tight path stays byte-identical to the\n * non-interleaved engine — keeping interleave bytes out of every glTF scene that\n * doesn't use it. */\nexport function buildInterleavedMesh(engine: EngineContext, m: GltfMeshData, index: number, material: PbrMaterialProps, name?: string): Mesh {\n const gpu = buildInterleavedGpu(engine, m);\n\n // AABB: fold strided positions straight from the slice; tight positions normally.\n const [boundMin, boundMax] = m._vb!._p ? computeAabbStrided(m._vb!._p, m._worldMatrix) : computeAabb(m._positions!, m._worldMatrix);\n\n const mesh = {\n name: name || `gltf_mesh_${index}`,\n material,\n receiveShadows: false,\n boundMin,\n boundMax,\n skeleton: null,\n morphTargets: null,\n _gpu: gpu,\n _flatNormal: m._flatNormal,\n } as unknown as Mesh;\n initMeshTransform(mesh);\n\n // Lazy CPU geometry: the de-strided tight copy is built only on first read.\n installLazyCpu(mesh, m);\n mesh._cpuIndices = m._indices instanceof U32 ? m._indices : new U32(m._indices);\n engine._dlr?.m(mesh, m._uv2s, m._tangents, m._colors, m._indices, gpu.indexFormat);\n\n return mesh as Mesh;\n}\n\n/** Fold an AABB directly over an interleaved (strided) FLOAT vec3 position\n * source — no tight copy is materialized. Mirrors {@link computeAabb}'s\n * world-transform handling. All current interleaved assets use FLOAT positions. */\nexport function computeAabbStrided(il: AccessorInterleave, world?: Mat4): Aabb {\n const dv = new DV(il._slice!.buffer, il._slice!.byteOffset, il._slice!.byteLength);\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n for (let v = 0; v < il._count; v++) {\n const base = il._offset + v * il._stride;\n const lx = dv.getFloat32(base, true);\n const ly = dv.getFloat32(base + 4, true);\n const lz = dv.getFloat32(base + 8, true);\n let x = lx,\n y = ly,\n z = lz;\n if (world) {\n x = world[0]! * lx + world[4]! * ly + world[8]! * lz + world[12]!;\n y = world[1]! * lx + world[5]! * ly + world[9]! * lz + world[13]!;\n z = world[2]! * lx + world[6]! * ly + world[10]! * lz + world[14]!;\n }\n if (x < minX) {\n minX = x;\n }\n if (x > maxX) {\n maxX = x;\n }\n if (y < minY) {\n minY = y;\n }\n if (y > maxY) {\n maxY = y;\n }\n if (z < minZ) {\n minZ = z;\n }\n if (z > maxZ) {\n maxZ = z;\n }\n }\n return [\n [minX, minY, minZ],\n [maxX, maxY, maxZ],\n ];\n}\n\n/** Install lazy CPU-geometry accessors on an interleaved mesh. Each of\n * `_cpuPositions/_cpuNormals/_cpuUvs` that comes from a strided source is\n * defined as a getter that de-strides a tight copy on first access and caches\n * it; tight attributes are assigned directly. A mesh that is never picked /\n * CSG'd / navigated never materializes the de-strided arrays.\n *\n * The property names are written as STATIC literals (not a computed key) so the\n * minifier mangles them identically to the static reads in the picking /\n * device-lost code — a computed `defineProperty(mesh, key)` would leave the name\n * an unmangled literal and mismatch those reads across the chunk boundary. */\nexport function installLazyCpu(mesh: any, m: GltfMeshData): void {\n const vb = m._vb!;\n if (vb._p) {\n Object.defineProperty(mesh, \"_cpuPositions\", lazyCpuDesc(vb._p));\n } else if (m._positions) {\n mesh._cpuPositions = m._positions;\n }\n if (vb._n) {\n Object.defineProperty(mesh, \"_cpuNormals\", lazyCpuDesc(vb._n));\n } else if (m._normals) {\n mesh._cpuNormals = m._normals;\n }\n if (vb._u) {\n Object.defineProperty(mesh, \"_cpuUvs\", lazyCpuDesc(vb._u));\n } else if (m._uvs) {\n mesh._cpuUvs = m._uvs;\n }\n}\n\n/** Build a caching lazy-getter descriptor that de-strides `il` on first read. */\nfunction lazyCpuDesc(il: AccessorInterleave): PropertyDescriptor {\n let cached: Float32Array | undefined;\n return {\n configurable: true,\n enumerable: true,\n get(): Float32Array {\n return (cached ??= destrideToTight(il));\n },\n set(v: Float32Array): void {\n cached = v;\n },\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gltf-interleave.js","sources":["../../../src/loader-gltf/gltf-interleave.ts"],"sourcesContent":["/**\n * Interleaved (strided) glTF vertex-buffer support — dynamically imported.\n *\n * The engine renders interleaved attributes genuinely: the raw strided\n * bufferView slice is uploaded ONCE as a shared GPU buffer, bound to each\n * attribute slot at byte offset 0, with the per-attribute byte offset encoded in\n * the pipeline vertex layout (`attributes[].offset`) and `arrayStride` set to the\n * bufferView byteStride. This mirrors stock Babylon.js's WebGPU vertex state and\n * avoids a non-zero `setVertexBuffer` bind offset, which corrupts vertex fetch on\n * some AMD (Renoir) / Dawn paths. The loader never rewrites the asset.\n *\n * This whole module is loaded via `await import()` only when an asset actually\n * contains an interleaved bufferView, so non-interleaved scenes pay ZERO bundle\n * cost. The tight CPU copy of position/normal/uv (for AABB, picking, CSG, …) is\n * de-strided LAZILY — only on first CPU read via `installLazyCpu` — so scenes\n * that only render never materialize it.\n */\n\nimport { F32, U32, U16, U8, DV } from \"../engine/typed-arrays.js\";\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { Mat4 } from \"../math/types.js\";\nimport type { Aabb } from \"../math/aabb.js\";\nimport { computeAabb } from \"../math/compute-aabb.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Mesh, MeshGPU } from \"../mesh/mesh.js\";\nimport { initMeshTransform } from \"../mesh/mesh.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport { createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport { resolveAccessor, TYPE_SIZES } from \"./gltf-parser.js\";\nimport { computeSmoothNormals } from \"./gltf-normals.js\";\nimport type { GltfMeshData } from \"./load-gltf.js\";\n\nconst FLOAT = 5126;\nconst UNSIGNED_SHORT = 5123;\nconst UNSIGNED_INT = 5125;\nconst UNSIGNED_BYTE = 5121;\n\nconst COMP_BYTES: Record<number, number> = { [UNSIGNED_BYTE]: 1, [UNSIGNED_SHORT]: 2, [UNSIGNED_INT]: 4, [FLOAT]: 4 };\n\nfunction createSequentialIndices(vertexCount: number): Uint16Array | Uint32Array {\n const indices = vertexCount > 0xffff ? new U32(vertexCount) : new U16(vertexCount);\n for (let i = 0; i < vertexCount; i++) {\n indices[i] = i;\n }\n return indices;\n}\n\n/** Interleave descriptor for one attribute sourced from a strided bufferView.\n * The raw slice is shared across attributes of the same bufferView; the\n * pipeline uses `_stride` as arrayStride and binds at `_offset`. */\nexport interface AccessorInterleave {\n /** @internal glTF bufferView index — shared-buffer key (same view → one GPU buffer). */\n _bufferView: number;\n /** @internal Interleave byte stride (bufferView.byteStride) → pipeline arrayStride. */\n _stride: number;\n /** @internal Attribute byte offset within the bufferView → pipeline vertex layout\n * `attributes[].offset` (the shared buffer is bound at offset 0). */\n _offset: number;\n /** @internal glTF component type (FLOAT, UNSIGNED_SHORT, …). */\n _componentType: number;\n /** @internal Components per vertex. */\n _componentCount: number;\n /** @internal Vertex count. */\n _count: number;\n /** @internal Raw bufferView bytes (shared across attributes). Retained after GPU upload\n * so the CPU copy can be de-strided lazily on demand. */\n _slice?: Uint8Array;\n}\n\n/** Per-attribute interleave sources for a primitive (keys mirror MeshVbLayout). */\nexport interface GltfVb {\n /** @internal */\n _p?: AccessorInterleave;\n /** @internal */\n _n?: AccessorInterleave;\n /** @internal */\n _t?: AccessorInterleave;\n /** @internal */\n _u?: AccessorInterleave;\n /** @internal */\n _u2?: AccessorInterleave;\n /** @internal */\n _c?: AccessorInterleave;\n}\n\n/** True if accessor `idx`'s bufferView is interleaved (byteStride present and\n * larger than the attribute's tightly-packed element size). */\nexport function accessorIsStrided(json: any, idx: number): boolean {\n const a = json.accessors[idx];\n const bv = json.bufferViews[a.bufferView];\n const stride: number | undefined = bv.byteStride;\n if (stride === undefined) {\n return false;\n }\n const elemBytes = (TYPE_SIZES[a.type] ?? 1) * (COMP_BYTES[a.componentType] ?? 4);\n return stride !== elemBytes;\n}\n\n/** Resolve a strided accessor into an {@link AccessorInterleave} descriptor. */\nfunction resolveStrided(json: any, binChunk: DataView, accessorIdx: number): AccessorInterleave {\n const accessor = json.accessors[accessorIdx];\n const bufferView = json.bufferViews[accessor.bufferView];\n const ab = binChunk.buffer as ArrayBuffer;\n return {\n _bufferView: accessor.bufferView,\n _stride: bufferView.byteStride,\n _offset: accessor.byteOffset ?? 0,\n _componentType: accessor.componentType,\n _componentCount: TYPE_SIZES[accessor.type] ?? 1,\n _count: accessor.count,\n _slice: new U8(ab, binChunk.byteOffset + (bufferView.byteOffset ?? 0), bufferView.byteLength),\n };\n}\n\n/** De-stride an interleaved attribute into a tight Float32Array, reading raw\n * component values (no normalization) so the result matches what a tight\n * accessor view would have produced. */\nfunction destrideToTight(il: AccessorInterleave): Float32Array {\n const dv = new DV(il._slice!.buffer, il._slice!.byteOffset, il._slice!.byteLength);\n const cb = COMP_BYTES[il._componentType] ?? 4;\n const ct = il._componentType;\n const cc = il._componentCount;\n const out = new F32(il._count * cc);\n for (let v = 0; v < il._count; v++) {\n const rowBase = il._offset + v * il._stride;\n for (let c = 0; c < cc; c++) {\n const off = rowBase + c * cb;\n out[v * cc + c] =\n ct === FLOAT ? dv.getFloat32(off, true) : ct === UNSIGNED_SHORT ? dv.getUint16(off, true) : ct === UNSIGNED_INT ? dv.getUint32(off, true) : dv.getUint8(off);\n }\n }\n return out;\n}\n\n/** Resolve COLOR_0 to a tight float32 VEC4 [0,1] buffer — the vertex-color layout the\n * PBR pipeline binds (float32x4: rgb modulates base color, a modulates alpha). glTF\n * COLOR_0 may be VEC3 or VEC4, FLOAT or normalized UNSIGNED_BYTE/SHORT, and (here)\n * interleaved with a byteStride. Binding the raw strided/ubyte source as float32x4\n * reads neighbouring bytes as floats (garbage / rainbow colors). This normalizes\n * integer types to [0,1], gives a VEC3 source alpha = 1, and de-strides — mirroring\n * the tight path's normalizeColorToVec4. Reads relative to `binChunk`. */\nfunction resolveColorVec4(json: any, binChunk: DataView, idx: number): Float32Array {\n const accessor = json.accessors[idx];\n const ct = accessor.componentType;\n const cb = COMP_BYTES[ct] ?? 4;\n const comps = TYPE_SIZES[accessor.type] ?? 4;\n const bv = json.bufferViews[accessor.bufferView];\n const stride = bv.byteStride ?? comps * cb;\n const inv = ct === UNSIGNED_BYTE ? 1 / 255 : ct === UNSIGNED_SHORT ? 1 / 65535 : 1;\n const base = (bv.byteOffset ?? 0) + (accessor.byteOffset ?? 0);\n const out = new F32(accessor.count * 4);\n for (let v = 0; v < accessor.count; v++) {\n const row = base + v * stride;\n for (let c = 0; c < 4; c++) {\n if (c === 3 && comps < 4) {\n out[v * 4 + 3] = 1;\n break;\n }\n const off = row + c * cb;\n const raw = ct === FLOAT ? binChunk.getFloat32(off, true) : ct === UNSIGNED_SHORT ? binChunk.getUint16(off, true) : binChunk.getUint8(off);\n out[v * 4 + c] = raw * inv;\n }\n }\n return out;\n}\n\n/** Build a mesh-data partial for a primitive, but ONLY if it actually sources\n * ≥1 attribute from an interleaved (strided) bufferView. Returns `undefined`\n * for fully-tight primitives so the caller falls back to its tight path.\n *\n * Strided POSITION/NORMAL/TEXCOORD_0 attributes keep their raw slice in `_vb`\n * (for genuine GPU interleaving) and leave the tight CPU field `null` — the\n * de-strided copy is materialized lazily on first CPU read (see\n * {@link installLazyCpu}). Strided TANGENT/TEXCOORD_1 are eagerly de-strided\n * (they feed device-lost recovery), but no current asset interleaves them.\n * COLOR_0 is always normalized to a tight float32x3 buffer (see\n * {@link resolveColorVec4}). Tight attributes resolve exactly like the core loader. */\nexport async function buildInterleavedPartial(\n json: any,\n binChunk: DataView,\n primitive: any,\n worldMatrix: Mat4,\n nodeIdx: number\n): Promise<Omit<GltfMeshData, \"_material\"> | undefined> {\n const attrs = primitive.attributes;\n\n // Per-primitive gate: bail (→ tight path) unless a vertex attribute is strided.\n let anyStrided = false;\n for (const name in attrs) {\n if (accessorIsStrided(json, attrs[name])) {\n anyStrided = true;\n break;\n }\n }\n if (!anyStrided) {\n return undefined;\n }\n\n const vb: GltfVb = {};\n let vertexCount = 0;\n\n // Resolve one attribute. Returns the interleave descriptor (when the source is\n // strided) and/or a tight CPU array. `eager` de-strides strided sources up-front\n // (TANGENT/UV2/COLOR feed device-lost recovery); lazy ones leave `_tight` null and\n // are de-strided on demand. The caller assigns `vb.<attr>` with a STATIC property\n // name (never a computed `vb[key]`) — a computed write would stay an unmangled\n // literal while every reader uses the mangled static name, corrupting the object\n // across the dynamic-import chunk boundary.\n const resolveOne = (name: string, eager: boolean): { _tight: Float32Array | null; _il?: AccessorInterleave; _count: number } => {\n const idx = attrs[name];\n if (idx === undefined) {\n return { _tight: null, _count: 0 };\n }\n if (accessorIsStrided(json, idx)) {\n const il = resolveStrided(json, binChunk, idx);\n return { _tight: eager ? destrideToTight(il) : null, _il: il, _count: il._count };\n }\n const av = resolveAccessor(json, binChunk, idx);\n return { _tight: av._data as Float32Array, _count: av._count };\n };\n\n const pos = resolveOne(\"POSITION\", false);\n vb._p = pos._il;\n vertexCount = pos._count;\n const nrm = resolveOne(\"NORMAL\", false);\n vb._n = nrm._il;\n // A normalized UNSIGNED_BYTE/SHORT TEXCOORD_0 is materialized as a tight float32x2 [0,1] buffer\n // (never bound strided), so integer UVs don't misalign against the float32x2 vertex layout.\n const uvIdx = attrs[\"TEXCOORD_0\"];\n const uv: { _tight: Float32Array | null; _il?: AccessorInterleave; _count: number } =\n uvIdx !== undefined && json.accessors[uvIdx].componentType !== FLOAT\n ? { _tight: (await import(\"./gltf-uv-denorm.js\")).resolveUvVec2(json, binChunk, uvIdx), _count: json.accessors[uvIdx].count }\n : resolveOne(\"TEXCOORD_0\", false);\n vb._u = uv._il;\n const tan = resolveOne(\"TANGENT\", true);\n vb._t = tan._il;\n const uv2 = resolveOne(\"TEXCOORD_1\", true);\n vb._u2 = uv2._il;\n // COLOR_0 is always materialized as a tight float32x4 [0,1] buffer (see\n // resolveColorVec4) — never bound strided — so ubyte/ushort/VEC3 sources don't\n // misalign against the pipeline's float32x4 vertex-color layout.\n const colorIdx = attrs[\"COLOR_0\"];\n const colors = colorIdx !== undefined ? resolveColorVec4(json, binChunk, colorIdx) : null;\n\n const positions = pos._tight;\n let normals = nrm._tight;\n let uvs = uv._tight;\n const tangents = tan._tight;\n const uv2s = uv2._tight;\n\n const idxData = primitive.indices !== undefined ? resolveAccessor(json, binChunk, primitive.indices) : null;\n const indices = idxData\n ? idxData._data instanceof U32\n ? new U32(idxData._data)\n : idxData._data instanceof U8\n ? Uint16Array.from(idxData._data)\n : new U16(idxData._data.buffer, idxData._data.byteOffset, idxData._count)\n : createSequentialIndices(vertexCount);\n\n // Absent (not merely strided) NORMAL: generate smooth normals to match the core\n // loader's tight path. A zero-filled normal buffer makes every lit fragment's\n // worldNormal NaN/black — e.g. a material-less skinned mesh whose interleaved\n // JOINTS/WEIGHTS route it here (SimpleSkin). computeSmoothNormals is statically\n // imported by this lazy interleave chunk, so non-interleaved scenes (which never\n // load this module) pay zero bundle cost for it.\n if (!normals && !vb._n) {\n const tightPos = positions ?? (vb._p ? destrideToTight(vb._p) : new F32(vertexCount * 3));\n normals = computeSmoothNormals(tightPos, indices, vertexCount);\n }\n if (!uvs && !vb._u) {\n uvs = new F32(vertexCount * 2);\n }\n\n // No NORMAL attribute (neither tight nor strided) → flat-shade per the glTF spec.\n const flatNormal = !nrm._tight && !vb._n;\n\n return {\n _positions: positions,\n _normals: normals,\n _tangents: tangents,\n _uvs: uvs,\n _uv2s: uv2s,\n _colors: colors,\n _flatNormal: flatNormal,\n _indices: indices,\n _vertexCount: vertexCount,\n _indexCount: indices.length,\n _worldMatrix: worldMatrix,\n _vb: vb,\n _nodeIndex: nodeIdx,\n _primitive: primitive,\n };\n}\n\n/** Build the GPU geometry for an interleaved mesh: one shared buffer per\n * bufferView for strided attributes (bound at offset 0; the per-attribute byte\n * offset goes into the pipeline vertex layout, matching stock Babylon.js), tight\n * attributes get their own buffer — byte-identical to non-interleaved meshes.\n * The raw `_slice` is intentionally retained on `_vb` so the CPU copy can be\n * de-strided lazily later (see {@link installLazyCpu}). */\nfunction buildInterleavedGpu(engine: EngineContext, m: GltfMeshData): MeshGPU {\n const vbsrc = m._vb!;\n const shared = new Map<number, GPUBuffer>();\n const vbuf = (a: AccessorInterleave | undefined, tight: Float32Array | null): GPUBuffer | null => {\n if (!a) {\n return tight ? createMappedBuffer(engine, tight, BU.VERTEX) : null;\n }\n let b = shared.get(a._bufferView);\n if (!b) {\n shared.set(a._bufferView, (b = createMappedBuffer(engine, a._slice!, BU.VERTEX)));\n }\n return b;\n };\n // Cache key encodes both stride AND byte offset per attribute: the offsets are\n // now baked into the pipeline vertex layout (attributes[].offset), so two meshes\n // with identical strides but different offsets need distinct pipelines.\n const k = (a: AccessorInterleave | undefined) => `${a?._stride ?? 0},${a?._offset ?? 0}`;\n return {\n positionBuffer: vbuf(vbsrc._p, m._positions)!,\n normalBuffer: vbuf(vbsrc._n, m._normals)!,\n tangentBuffer: m._tangents ? vbuf(vbsrc._t, m._tangents) : null,\n uvBuffer: vbuf(vbsrc._u, m._uvs)!,\n uv2Buffer: m._uv2s ? vbuf(vbsrc._u2, m._uv2s) : null,\n colorBuffer: m._colors ? vbuf(vbsrc._c, m._colors) : null,\n indexBuffer: createMappedBuffer(engine, m._indices, BU.INDEX),\n indexCount: m._indexCount,\n indexFormat: (m._indices instanceof U32 ? \"uint32\" : \"uint16\") as GPUIndexFormat,\n _vbLayout: vbsrc,\n _vbKey: `vb${k(vbsrc._p)}.${k(vbsrc._n)}.${k(vbsrc._t)}.${k(vbsrc._u)}`,\n };\n}\n\n/** Build a complete engine mesh from interleaved glTF mesh-data. Owns ALL\n * interleave-specific work (GPU upload, AABB fold, lazy CPU install, device-lost\n * retention) so the core loader's tight path stays byte-identical to the\n * non-interleaved engine — keeping interleave bytes out of every glTF scene that\n * doesn't use it. */\nexport function buildInterleavedMesh(engine: EngineContext, m: GltfMeshData, index: number, material: PbrMaterialProps, name?: string): Mesh {\n const gpu = buildInterleavedGpu(engine, m);\n\n // AABB: fold strided positions straight from the slice; tight positions normally.\n const [boundMin, boundMax] = m._vb!._p ? computeAabbStrided(m._vb!._p, m._worldMatrix) : computeAabb(m._positions!, m._worldMatrix);\n\n const mesh = {\n name: name || `gltf_mesh_${index}`,\n material,\n receiveShadows: false,\n boundMin,\n boundMax,\n skeleton: null,\n morphTargets: null,\n _gpu: gpu,\n _flatNormal: m._flatNormal,\n } as unknown as Mesh;\n initMeshTransform(mesh);\n\n // Lazy CPU geometry: the de-strided tight copy is built only on first read.\n installLazyCpu(mesh, m);\n mesh._cpuIndices = m._indices instanceof U32 ? m._indices : new U32(m._indices);\n engine._dlr?.m(mesh, m._uv2s, m._tangents, m._colors, m._indices, gpu.indexFormat);\n\n return mesh as Mesh;\n}\n\n/** Fold an AABB directly over an interleaved (strided) FLOAT vec3 position\n * source — no tight copy is materialized. Mirrors {@link computeAabb}'s\n * world-transform handling. All current interleaved assets use FLOAT positions. */\nexport function computeAabbStrided(il: AccessorInterleave, world?: Mat4): Aabb {\n const dv = new DV(il._slice!.buffer, il._slice!.byteOffset, il._slice!.byteLength);\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n for (let v = 0; v < il._count; v++) {\n const base = il._offset + v * il._stride;\n const lx = dv.getFloat32(base, true);\n const ly = dv.getFloat32(base + 4, true);\n const lz = dv.getFloat32(base + 8, true);\n let x = lx,\n y = ly,\n z = lz;\n if (world) {\n x = world[0]! * lx + world[4]! * ly + world[8]! * lz + world[12]!;\n y = world[1]! * lx + world[5]! * ly + world[9]! * lz + world[13]!;\n z = world[2]! * lx + world[6]! * ly + world[10]! * lz + world[14]!;\n }\n if (x < minX) {\n minX = x;\n }\n if (x > maxX) {\n maxX = x;\n }\n if (y < minY) {\n minY = y;\n }\n if (y > maxY) {\n maxY = y;\n }\n if (z < minZ) {\n minZ = z;\n }\n if (z > maxZ) {\n maxZ = z;\n }\n }\n return [\n [minX, minY, minZ],\n [maxX, maxY, maxZ],\n ];\n}\n\n/** Install lazy CPU-geometry accessors on an interleaved mesh. Each of\n * `_cpuPositions/_cpuNormals/_cpuUvs` that comes from a strided source is\n * defined as a getter that de-strides a tight copy on first access and caches\n * it; tight attributes are assigned directly. A mesh that is never picked /\n * CSG'd / navigated never materializes the de-strided arrays.\n *\n * The property names are written as STATIC literals (not a computed key) so the\n * minifier mangles them identically to the static reads in the picking /\n * device-lost code — a computed `defineProperty(mesh, key)` would leave the name\n * an unmangled literal and mismatch those reads across the chunk boundary. */\nexport function installLazyCpu(mesh: any, m: GltfMeshData): void {\n const vb = m._vb!;\n if (vb._p) {\n Object.defineProperty(mesh, \"_cpuPositions\", lazyCpuDesc(vb._p));\n } else if (m._positions) {\n mesh._cpuPositions = m._positions;\n }\n if (vb._n) {\n Object.defineProperty(mesh, \"_cpuNormals\", lazyCpuDesc(vb._n));\n } else if (m._normals) {\n mesh._cpuNormals = m._normals;\n }\n if (vb._u) {\n Object.defineProperty(mesh, \"_cpuUvs\", lazyCpuDesc(vb._u));\n } else if (m._uvs) {\n mesh._cpuUvs = m._uvs;\n }\n}\n\n/** Build a caching lazy-getter descriptor that de-strides `il` on first read. */\nfunction lazyCpuDesc(il: AccessorInterleave): PropertyDescriptor {\n let cached: Float32Array | undefined;\n return {\n configurable: true,\n enumerable: true,\n get(): Float32Array {\n return (cached ??= destrideToTight(il));\n },\n set(v: Float32Array): void {\n cached = v;\n },\n };\n}\n"],"names":[],"mappings":";;;;;;;;AAgCA,MAAM,KAAA,GAAQ,IAAA;AACd,MAAM,cAAA,GAAiB,IAAA;AACvB,MAAM,YAAA,GAAe,IAAA;AACrB,MAAM,aAAA,GAAgB,IAAA;AAEtB,MAAM,aAAqC,EAAE,CAAC,aAAa,GAAG,GAAG,CAAC,cAAc,GAAG,CAAA,EAAG,CAAC,YAAY,GAAG,GAAG,CAAC,KAAK,GAAG,CAAA,EAAE;AAEpH,SAAS,wBAAwB,WAAA,EAAgD;AAC7E,EAAA,MAAM,OAAA,GAAU,cAAc,KAAA,GAAS,IAAI,IAAI,WAAW,CAAA,GAAI,IAAI,GAAA,CAAI,WAAW,CAAA;AACjF,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,WAAA,EAAa,CAAA,EAAA,EAAK;AAClC,IAAA,OAAA,CAAQ,CAAC,CAAA,GAAI,CAAA;AAAA,EACjB;AACA,EAAA,OAAO,OAAA;AACX;AA0CO,SAAS,iBAAA,CAAkB,MAAW,GAAA,EAAsB;AAC/D,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA;AAC5B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,WAAA,CAAY,CAAA,CAAE,UAAU,CAAA;AACxC,EAAA,MAAM,SAA6B,EAAA,CAAG,UAAA;AACtC,EAAA,IAAI,WAAW,MAAA,EAAW;AACtB,IAAA,OAAO,KAAA;AAAA,EACX;AACA,EAAA,MAAM,SAAA,GAAA,CAAa,WAAW,CAAA,CAAE,IAAI,KAAK,CAAA,KAAM,UAAA,CAAW,CAAA,CAAE,aAAa,CAAA,IAAK,CAAA,CAAA;AAC9E,EAAA,OAAO,MAAA,KAAW,SAAA;AACtB;AAGA,SAAS,cAAA,CAAe,IAAA,EAAW,QAAA,EAAoB,WAAA,EAAyC;AAC5F,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,WAAW,CAAA;AAC3C,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,WAAA,CAAY,QAAA,CAAS,UAAU,CAAA;AACvD,EAAA,MAAM,KAAK,QAAA,CAAS,MAAA;AACpB,EAAA,OAAO;AAAA,IACH,aAAa,QAAA,CAAS,UAAA;AAAA,IACtB,SAAS,UAAA,CAAW,UAAA;AAAA,IACpB,OAAA,EAAS,SAAS,UAAA,IAAc,CAAA;AAAA,IAChC,gBAAgB,QAAA,CAAS,aAAA;AAAA,IACzB,eAAA,EAAiB,UAAA,CAAW,QAAA,CAAS,IAAI,CAAA,IAAK,CAAA;AAAA,IAC9C,QAAQ,QAAA,CAAS,KAAA;AAAA,IACjB,MAAA,EAAQ,IAAI,EAAA,CAAG,EAAA,EAAI,QAAA,CAAS,cAAc,UAAA,CAAW,UAAA,IAAc,CAAA,CAAA,EAAI,UAAA,CAAW,UAAU;AAAA,GAChG;AACJ;AAKA,SAAS,gBAAgB,EAAA,EAAsC;AAC3D,EAAA,MAAM,EAAA,GAAK,IAAI,EAAA,CAAG,EAAA,CAAG,MAAA,CAAQ,MAAA,EAAQ,EAAA,CAAG,MAAA,CAAQ,UAAA,EAAY,EAAA,CAAG,MAAA,CAAQ,UAAU,CAAA;AACjF,EAAA,MAAM,EAAA,GAAK,UAAA,CAAW,EAAA,CAAG,cAAc,CAAA,IAAK,CAAA;AAC5C,EAAA,MAAM,KAAK,EAAA,CAAG,cAAA;AACd,EAAA,MAAM,KAAK,EAAA,CAAG,eAAA;AACd,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,EAAA,CAAG,SAAS,EAAE,CAAA;AAClC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,EAAA,CAAG,QAAQ,CAAA,EAAA,EAAK;AAChC,IAAA,MAAM,OAAA,GAAU,EAAA,CAAG,OAAA,GAAU,CAAA,GAAI,EAAA,CAAG,OAAA;AACpC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,EAAA,EAAI,CAAA,EAAA,EAAK;AACzB,MAAA,MAAM,GAAA,GAAM,UAAU,CAAA,GAAI,EAAA;AAC1B,MAAA,GAAA,CAAI,CAAA,GAAI,EAAA,GAAK,CAAC,CAAA,GACV,EAAA,KAAO,KAAA,GAAQ,EAAA,CAAG,UAAA,CAAW,GAAA,EAAK,IAAI,CAAA,GAAI,EAAA,KAAO,cAAA,GAAiB,EAAA,CAAG,SAAA,CAAU,GAAA,EAAK,IAAI,CAAA,GAAI,EAAA,KAAO,YAAA,GAAe,EAAA,CAAG,SAAA,CAAU,GAAA,EAAK,IAAI,CAAA,GAAI,EAAA,CAAG,QAAA,CAAS,GAAG,CAAA;AAAA,IACnK;AAAA,EACJ;AACA,EAAA,OAAO,GAAA;AACX;AASA,SAAS,gBAAA,CAAiB,IAAA,EAAW,QAAA,EAAoB,GAAA,EAA2B;AAChF,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA;AACnC,EAAA,MAAM,KAAK,QAAA,CAAS,aAAA;AACpB,EAAA,MAAM,EAAA,GAAK,UAAA,CAAW,EAAE,CAAA,IAAK,CAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,QAAA,CAAS,IAAI,CAAA,IAAK,CAAA;AAC3C,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,WAAA,CAAY,QAAA,CAAS,UAAU,CAAA;AAC/C,EAAA,MAAM,MAAA,GAAS,EAAA,CAAG,UAAA,IAAc,KAAA,GAAQ,EAAA;AACxC,EAAA,MAAM,GAAA,GAAM,OAAO,aAAA,GAAgB,CAAA,GAAI,MAAM,EAAA,KAAO,cAAA,GAAiB,IAAI,KAAA,GAAQ,CAAA;AACjF,EAAA,MAAM,IAAA,GAAA,CAAQ,EAAA,CAAG,UAAA,IAAc,CAAA,KAAM,SAAS,UAAA,IAAc,CAAA,CAAA;AAC5D,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAC,CAAA;AACtC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,OAAO,CAAA,EAAA,EAAK;AACrC,IAAA,MAAM,GAAA,GAAM,OAAO,CAAA,GAAI,MAAA;AACvB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AACxB,MAAA,IAAI,CAAA,KAAM,CAAA,IAAK,KAAA,GAAQ,CAAA,EAAG;AACtB,QAAA,GAAA,CAAI,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA,GAAI,CAAA;AACjB,QAAA;AAAA,MACJ;AACA,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,GAAI,EAAA;AACtB,MAAA,MAAM,MAAM,EAAA,KAAO,KAAA,GAAQ,QAAA,CAAS,UAAA,CAAW,KAAK,IAAI,CAAA,GAAI,EAAA,KAAO,cAAA,GAAiB,SAAS,SAAA,CAAU,GAAA,EAAK,IAAI,CAAA,GAAI,QAAA,CAAS,SAAS,GAAG,CAAA;AACzI,MAAA,GAAA,CAAI,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA,GAAM,GAAA;AAAA,IAC3B;AAAA,EACJ;AACA,EAAA,OAAO,GAAA;AACX;AAaA,eAAsB,uBAAA,CAClB,IAAA,EACA,QAAA,EACA,SAAA,EACA,aACA,OAAA,EACoD;AACpD,EAAA,MAAM,QAAQ,SAAA,CAAU,UAAA;AAGxB,EAAA,IAAI,UAAA,GAAa,KAAA;AACjB,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACtB,IAAA,IAAI,iBAAA,CAAkB,IAAA,EAAM,KAAA,CAAM,IAAI,CAAC,CAAA,EAAG;AACtC,MAAA,UAAA,GAAa,IAAA;AACb,MAAA;AAAA,IACJ;AAAA,EACJ;AACA,EAAA,IAAI,CAAC,UAAA,EAAY;AACb,IAAA,OAAO,MAAA;AAAA,EACX;AAEA,EAAA,MAAM,KAAa,EAAC;AACpB,EAAA,IAAI,WAAA,GAAc,CAAA;AASlB,EAAA,MAAM,UAAA,GAAa,CAAC,IAAA,EAAc,KAAA,KAA8F;AAC5H,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AACtB,IAAA,IAAI,QAAQ,MAAA,EAAW;AACnB,MAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,MAAA,EAAQ,CAAA,EAAE;AAAA,IACrC;AACA,IAAA,IAAI,iBAAA,CAAkB,IAAA,EAAM,GAAG,CAAA,EAAG;AAC9B,MAAA,MAAM,EAAA,GAAK,cAAA,CAAe,IAAA,EAAM,QAAA,EAAU,GAAG,CAAA;AAC7C,MAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,GAAQ,eAAA,CAAgB,EAAE,CAAA,GAAI,IAAA,EAAM,GAAA,EAAK,EAAA,EAAI,MAAA,EAAQ,EAAA,CAAG,MAAA,EAAO;AAAA,IACpF;AACA,IAAA,MAAM,EAAA,GAAK,eAAA,CAAgB,IAAA,EAAM,QAAA,EAAU,GAAG,CAAA;AAC9C,IAAA,OAAO,EAAE,MAAA,EAAQ,EAAA,CAAG,KAAA,EAAuB,MAAA,EAAQ,GAAG,MAAA,EAAO;AAAA,EACjE,CAAA;AAEA,EAAA,MAAM,GAAA,GAAM,UAAA,CAAW,UAAA,EAAY,KAAK,CAAA;AACxC,EAAA,EAAA,CAAG,KAAK,GAAA,CAAI,GAAA;AACZ,EAAA,WAAA,GAAc,GAAA,CAAI,MAAA;AAClB,EAAA,MAAM,GAAA,GAAM,UAAA,CAAW,QAAA,EAAU,KAAK,CAAA;AACtC,EAAA,EAAA,CAAG,KAAK,GAAA,CAAI,GAAA;AAGZ,EAAA,MAAM,KAAA,GAAQ,MAAM,YAAY,CAAA;AAChC,EAAA,MAAM,EAAA,GACF,KAAA,KAAU,MAAA,IAAa,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,CAAE,aAAA,KAAkB,KAAA,GACzD,EAAE,MAAA,EAAA,CAAS,MAAM,OAAO,qBAAqB,CAAA,EAAG,aAAA,CAAc,IAAA,EAAM,QAAA,EAAU,KAAK,CAAA,EAAG,MAAA,EAAQ,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,CAAE,KAAA,EAAM,GAC1H,UAAA,CAAW,cAAc,KAAK,CAAA;AACxC,EAAA,EAAA,CAAG,KAAK,EAAA,CAAG,GAAA;AACX,EAAA,MAAM,GAAA,GAAM,UAAA,CAAW,SAAA,EAAW,IAAI,CAAA;AACtC,EAAA,EAAA,CAAG,KAAK,GAAA,CAAI,GAAA;AACZ,EAAA,MAAM,GAAA,GAAM,UAAA,CAAW,YAAA,EAAc,IAAI,CAAA;AACzC,EAAA,EAAA,CAAG,MAAM,GAAA,CAAI,GAAA;AAIb,EAAA,MAAM,QAAA,GAAW,MAAM,SAAS,CAAA;AAChC,EAAA,MAAM,SAAS,QAAA,KAAa,MAAA,GAAY,iBAAiB,IAAA,EAAM,QAAA,EAAU,QAAQ,CAAA,GAAI,IAAA;AAErF,EAAA,MAAM,YAAY,GAAA,CAAI,MAAA;AACtB,EAAA,IAAI,UAAU,GAAA,CAAI,MAAA;AAClB,EAAA,IAAI,MAAM,EAAA,CAAG,MAAA;AACb,EAAA,MAAM,WAAW,GAAA,CAAI,MAAA;AACrB,EAAA,MAAM,OAAO,GAAA,CAAI,MAAA;AAEjB,EAAA,MAAM,OAAA,GAAU,UAAU,OAAA,KAAY,MAAA,GAAY,gBAAgB,IAAA,EAAM,QAAA,EAAU,SAAA,CAAU,OAAO,CAAA,GAAI,IAAA;AACvG,EAAA,MAAM,OAAA,GAAU,OAAA,GACV,OAAA,CAAQ,KAAA,YAAiB,GAAA,GACrB,IAAI,GAAA,CAAI,OAAA,CAAQ,KAAK,CAAA,GACrB,OAAA,CAAQ,KAAA,YAAiB,KACvB,WAAA,CAAY,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA,GAC9B,IAAI,GAAA,CAAI,OAAA,CAAQ,KAAA,CAAM,MAAA,EAAQ,OAAA,CAAQ,KAAA,CAAM,UAAA,EAAY,OAAA,CAAQ,MAAM,CAAA,GAC5E,wBAAwB,WAAW,CAAA;AAQzC,EAAA,IAAI,CAAC,OAAA,IAAW,CAAC,EAAA,CAAG,EAAA,EAAI;AACpB,IAAA,MAAM,QAAA,GAAW,SAAA,KAAc,EAAA,CAAG,EAAA,GAAK,eAAA,CAAgB,EAAA,CAAG,EAAE,CAAA,GAAI,IAAI,GAAA,CAAI,WAAA,GAAc,CAAC,CAAA,CAAA;AACvF,IAAA,OAAA,GAAU,oBAAA,CAAqB,QAAA,EAAU,OAAA,EAAS,WAAW,CAAA;AAAA,EACjE;AACA,EAAA,IAAI,CAAC,GAAA,IAAO,CAAC,EAAA,CAAG,EAAA,EAAI;AAChB,IAAA,GAAA,GAAM,IAAI,GAAA,CAAI,WAAA,GAAc,CAAC,CAAA;AAAA,EACjC;AAGA,EAAA,MAAM,UAAA,GAAa,CAAC,GAAA,CAAI,MAAA,IAAU,CAAC,EAAA,CAAG,EAAA;AAEtC,EAAA,OAAO;AAAA,IACH,UAAA,EAAY,SAAA;AAAA,IACZ,QAAA,EAAU,OAAA;AAAA,IACV,SAAA,EAAW,QAAA;AAAA,IACX,IAAA,EAAM,GAAA;AAAA,IACN,KAAA,EAAO,IAAA;AAAA,IACP,OAAA,EAAS,MAAA;AAAA,IACT,WAAA,EAAa,UAAA;AAAA,IACb,QAAA,EAAU,OAAA;AAAA,IACV,YAAA,EAAc,WAAA;AAAA,IACd,aAAa,OAAA,CAAQ,MAAA;AAAA,IACrB,YAAA,EAAc,WAAA;AAAA,IACd,GAAA,EAAK,EAAA;AAAA,IACL,UAAA,EAAY,OAAA;AAAA,IACZ,UAAA,EAAY;AAAA,GAChB;AACJ;AAQA,SAAS,mBAAA,CAAoB,QAAuB,CAAA,EAA0B;AAC1E,EAAA,MAAM,QAAQ,CAAA,CAAE,GAAA;AAChB,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAuB;AAC1C,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,EAAmC,KAAA,KAAiD;AAC9F,IAAA,IAAI,CAAC,CAAA,EAAG;AACJ,MAAA,OAAO,QAAQ,kBAAA,CAAmB,MAAA,EAAQ,KAAA,EAAO,EAAA,CAAG,MAAM,CAAA,GAAI,IAAA;AAAA,IAClE;AACA,IAAA,IAAI,CAAA,GAAI,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,WAAW,CAAA;AAChC,IAAA,IAAI,CAAC,CAAA,EAAG;AACJ,MAAA,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,WAAA,EAAc,CAAA,GAAI,kBAAA,CAAmB,QAAQ,CAAA,CAAE,MAAA,EAAS,EAAA,CAAG,MAAM,CAAE,CAAA;AAAA,IACpF;AACA,IAAA,OAAO,CAAA;AAAA,EACX,CAAA;AAIA,EAAA,MAAM,CAAA,GAAI,CAAC,CAAA,KAAsC,CAAA,EAAG,CAAA,EAAG,WAAW,CAAC,CAAA,CAAA,EAAI,CAAA,EAAG,OAAA,IAAW,CAAC,CAAA,CAAA;AACtF,EAAA,OAAO;AAAA,IACH,cAAA,EAAgB,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,UAAU,CAAA;AAAA,IAC3C,YAAA,EAAc,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,QAAQ,CAAA;AAAA,IACvC,aAAA,EAAe,EAAE,SAAA,GAAY,IAAA,CAAK,MAAM,EAAA,EAAI,CAAA,CAAE,SAAS,CAAA,GAAI,IAAA;AAAA,IAC3D,QAAA,EAAU,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,IAAI,CAAA;AAAA,IAC/B,SAAA,EAAW,EAAE,KAAA,GAAQ,IAAA,CAAK,MAAM,GAAA,EAAK,CAAA,CAAE,KAAK,CAAA,GAAI,IAAA;AAAA,IAChD,WAAA,EAAa,EAAE,OAAA,GAAU,IAAA,CAAK,MAAM,EAAA,EAAI,CAAA,CAAE,OAAO,CAAA,GAAI,IAAA;AAAA,IACrD,aAAa,kBAAA,CAAmB,MAAA,EAAQ,CAAA,CAAE,QAAA,EAAU,GAAG,KAAK,CAAA;AAAA,IAC5D,YAAY,CAAA,CAAE,WAAA;AAAA,IACd,WAAA,EAAc,CAAA,CAAE,QAAA,YAAoB,GAAA,GAAM,QAAA,GAAW,QAAA;AAAA,IACrD,SAAA,EAAW,KAAA;AAAA,IACX,MAAA,EAAQ,KAAK,CAAA,CAAE,KAAA,CAAM,EAAE,CAAC,CAAA,CAAA,EAAI,EAAE,KAAA,CAAM,EAAE,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,MAAM,EAAE,CAAC,IAAI,CAAA,CAAE,KAAA,CAAM,EAAE,CAAC,CAAA;AAAA,GACzE;AACJ;AAOO,SAAS,oBAAA,CAAqB,MAAA,EAAuB,CAAA,EAAiB,KAAA,EAAe,UAA4B,IAAA,EAAqB;AACzI,EAAA,MAAM,GAAA,GAAM,mBAAA,CAAoB,MAAA,EAAQ,CAAC,CAAA;AAGzC,EAAA,MAAM,CAAC,QAAA,EAAU,QAAQ,IAAI,CAAA,CAAE,GAAA,CAAK,KAAK,kBAAA,CAAmB,CAAA,CAAE,GAAA,CAAK,EAAA,EAAI,EAAE,YAAY,CAAA,GAAI,YAAY,CAAA,CAAE,UAAA,EAAa,EAAE,YAAY,CAAA;AAElI,EAAA,MAAM,IAAA,GAAO;AAAA,IACT,IAAA,EAAM,IAAA,IAAQ,CAAA,UAAA,EAAa,KAAK,CAAA,CAAA;AAAA,IAChC,QAAA;AAAA,IACA,cAAA,EAAgB,KAAA;AAAA,IAChB,QAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA,EAAU,IAAA;AAAA,IACV,YAAA,EAAc,IAAA;AAAA,IACd,IAAA,EAAM,GAAA;AAAA,IACN,aAAa,CAAA,CAAE;AAAA,GACnB;AACA,EAAA,iBAAA,CAAkB,IAAI,CAAA;AAGtB,EAAA,cAAA,CAAe,MAAM,CAAC,CAAA;AACtB,EAAA,IAAA,CAAK,WAAA,GAAc,EAAE,QAAA,YAAoB,GAAA,GAAM,EAAE,QAAA,GAAW,IAAI,GAAA,CAAI,CAAA,CAAE,QAAQ,CAAA;AAC9E,EAAA,MAAA,CAAO,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,KAAA,EAAO,CAAA,CAAE,SAAA,EAAW,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA,EAAU,GAAA,CAAI,WAAW,CAAA;AAEjF,EAAA,OAAO,IAAA;AACX;AAKO,SAAS,kBAAA,CAAmB,IAAwB,KAAA,EAAoB;AAC3E,EAAA,MAAM,EAAA,GAAK,IAAI,EAAA,CAAG,EAAA,CAAG,MAAA,CAAQ,MAAA,EAAQ,EAAA,CAAG,MAAA,CAAQ,UAAA,EAAY,EAAA,CAAG,MAAA,CAAQ,UAAU,CAAA;AACjF,EAAA,IAAI,IAAA,GAAO,QAAA,EACP,IAAA,GAAO,QAAA,EACP,IAAA,GAAO,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA,QAAA,EACP,IAAA,GAAO,CAAA,QAAA,EACP,IAAA,GAAO,CAAA,QAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,EAAA,CAAG,QAAQ,CAAA,EAAA,EAAK;AAChC,IAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,GAAU,CAAA,GAAI,EAAA,CAAG,OAAA;AACjC,IAAA,MAAM,EAAA,GAAK,EAAA,CAAG,UAAA,CAAW,IAAA,EAAM,IAAI,CAAA;AACnC,IAAA,MAAM,EAAA,GAAK,EAAA,CAAG,UAAA,CAAW,IAAA,GAAO,GAAG,IAAI,CAAA;AACvC,IAAA,MAAM,EAAA,GAAK,EAAA,CAAG,UAAA,CAAW,IAAA,GAAO,GAAG,IAAI,CAAA;AACvC,IAAA,IAAI,CAAA,GAAI,EAAA,EACJ,CAAA,GAAI,EAAA,EACJ,CAAA,GAAI,EAAA;AACR,IAAA,IAAI,KAAA,EAAO;AACP,MAAA,CAAA,GAAI,KAAA,CAAM,CAAC,CAAA,GAAK,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAK,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAK,EAAA,GAAK,MAAM,EAAE,CAAA;AAC/D,MAAA,CAAA,GAAI,KAAA,CAAM,CAAC,CAAA,GAAK,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAK,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAK,EAAA,GAAK,MAAM,EAAE,CAAA;AAC/D,MAAA,CAAA,GAAI,KAAA,CAAM,CAAC,CAAA,GAAK,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAK,EAAA,GAAK,KAAA,CAAM,EAAE,CAAA,GAAK,EAAA,GAAK,MAAM,EAAE,CAAA;AAAA,IACpE;AACA,IAAA,IAAI,IAAI,IAAA,EAAM;AACV,MAAA,IAAA,GAAO,CAAA;AAAA,IACX;AACA,IAAA,IAAI,IAAI,IAAA,EAAM;AACV,MAAA,IAAA,GAAO,CAAA;AAAA,IACX;AACA,IAAA,IAAI,IAAI,IAAA,EAAM;AACV,MAAA,IAAA,GAAO,CAAA;AAAA,IACX;AACA,IAAA,IAAI,IAAI,IAAA,EAAM;AACV,MAAA,IAAA,GAAO,CAAA;AAAA,IACX;AACA,IAAA,IAAI,IAAI,IAAA,EAAM;AACV,MAAA,IAAA,GAAO,CAAA;AAAA,IACX;AACA,IAAA,IAAI,IAAI,IAAA,EAAM;AACV,MAAA,IAAA,GAAO,CAAA;AAAA,IACX;AAAA,EACJ;AACA,EAAA,OAAO;AAAA,IACH,CAAC,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAAA,IACjB,CAAC,IAAA,EAAM,IAAA,EAAM,IAAI;AAAA,GACrB;AACJ;AAYO,SAAS,cAAA,CAAe,MAAW,CAAA,EAAuB;AAC7D,EAAA,MAAM,KAAK,CAAA,CAAE,GAAA;AACb,EAAA,IAAI,GAAG,EAAA,EAAI;AACP,IAAA,MAAA,CAAO,eAAe,IAAA,EAAM,eAAA,EAAiB,WAAA,CAAY,EAAA,CAAG,EAAE,CAAC,CAAA;AAAA,EACnE,CAAA,MAAA,IAAW,EAAE,UAAA,EAAY;AACrB,IAAA,IAAA,CAAK,gBAAgB,CAAA,CAAE,UAAA;AAAA,EAC3B;AACA,EAAA,IAAI,GAAG,EAAA,EAAI;AACP,IAAA,MAAA,CAAO,eAAe,IAAA,EAAM,aAAA,EAAe,WAAA,CAAY,EAAA,CAAG,EAAE,CAAC,CAAA;AAAA,EACjE,CAAA,MAAA,IAAW,EAAE,QAAA,EAAU;AACnB,IAAA,IAAA,CAAK,cAAc,CAAA,CAAE,QAAA;AAAA,EACzB;AACA,EAAA,IAAI,GAAG,EAAA,EAAI;AACP,IAAA,MAAA,CAAO,eAAe,IAAA,EAAM,SAAA,EAAW,WAAA,CAAY,EAAA,CAAG,EAAE,CAAC,CAAA;AAAA,EAC7D,CAAA,MAAA,IAAW,EAAE,IAAA,EAAM;AACf,IAAA,IAAA,CAAK,UAAU,CAAA,CAAE,IAAA;AAAA,EACrB;AACJ;AAGA,SAAS,YAAY,EAAA,EAA4C;AAC7D,EAAA,IAAI,MAAA;AACJ,EAAA,OAAO;AAAA,IACH,YAAA,EAAc,IAAA;AAAA,IACd,UAAA,EAAY,IAAA;AAAA,IACZ,GAAA,GAAoB;AAChB,MAAA,OAAQ,MAAA,KAAW,gBAAgB,EAAE,CAAA;AAAA,IACzC,CAAA;AAAA,IACA,IAAI,CAAA,EAAuB;AACvB,MAAA,MAAA,GAAS,CAAA;AAAA,IACb;AAAA,GACJ;AACJ;;;;"}
@@ -0,0 +1,18 @@
1
+ let _lightsByJson = null;
2
+ function map() {
3
+ return _lightsByJson ??= /* @__PURE__ */ new WeakMap();
4
+ }
5
+ function setGltfPunctualLight(json, lightIndex, light) {
6
+ let lights = map().get(json);
7
+ if (!lights) {
8
+ lights = [];
9
+ map().set(json, lights);
10
+ }
11
+ lights[lightIndex] = light;
12
+ }
13
+ function getGltfPunctualLight(json, lightIndex) {
14
+ return json ? _lightsByJson?.get(json)?.[lightIndex] : void 0;
15
+ }
16
+
17
+ export { getGltfPunctualLight, setGltfPunctualLight };
18
+ //# sourceMappingURL=gltf-light-pointer-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gltf-light-pointer-state.js","sources":["../../../src/loader-gltf/gltf-light-pointer-state.ts"],"sourcesContent":["import type { LightBase } from \"../light/types.js\";\n\nlet _lightsByJson: WeakMap<object, (LightBase | undefined)[]> | null = null;\n\nfunction map(): WeakMap<object, (LightBase | undefined)[]> {\n return (_lightsByJson ??= new WeakMap());\n}\n\nexport function setGltfPunctualLight(json: object, lightIndex: number, light: LightBase): void {\n let lights = map().get(json);\n if (!lights) {\n lights = [];\n map().set(json, lights);\n }\n lights[lightIndex] = light;\n}\n\nexport function getGltfPunctualLight(json: object | undefined, lightIndex: number): LightBase | undefined {\n return json ? _lightsByJson?.get(json)?.[lightIndex] : undefined;\n}\n"],"names":[],"mappings":"AAEA,IAAI,aAAA,GAAmE,IAAA;AAEvE,SAAS,GAAA,GAAkD;AACvD,EAAA,OAAQ,aAAA,yBAAsB,OAAA,EAAQ;AAC1C;AAEO,SAAS,oBAAA,CAAqB,IAAA,EAAc,UAAA,EAAoB,KAAA,EAAwB;AAC3F,EAAA,IAAI,MAAA,GAAS,GAAA,EAAI,CAAE,GAAA,CAAI,IAAI,CAAA;AAC3B,EAAA,IAAI,CAAC,MAAA,EAAQ;AACT,IAAA,MAAA,GAAS,EAAC;AACV,IAAA,GAAA,EAAI,CAAE,GAAA,CAAI,IAAA,EAAM,MAAM,CAAA;AAAA,EAC1B;AACA,EAAA,MAAA,CAAO,UAAU,CAAA,GAAI,KAAA;AACzB;AAEO,SAAS,oBAAA,CAAqB,MAA0B,UAAA,EAA2C;AACtG,EAAA,OAAO,OAAO,aAAA,EAAe,GAAA,CAAI,IAAI,CAAA,GAAI,UAAU,CAAA,GAAI,MAAA;AAC3D;;;;"}
@@ -1,4 +1,4 @@
1
- import { F32, U8, U32, U16 } from '../engine/typed-arrays.js';
1
+ import { F32, I8, I16, U8, U32, U16 } from '../engine/typed-arrays.js';
2
2
  import { mat4ComposeInto } from '../math/mat4-compose-into.js';
3
3
  import { mat4MultiplyInto } from '../math/mat4-multiply-into.js';
4
4
  import { getLoaderTmpLocal } from './_loader-scratch.js';
@@ -35,6 +35,12 @@ function resolveAccessor(json, binChunk, accessorIdx) {
35
35
  case UNSIGNED_BYTE:
36
36
  Ctor = U8;
37
37
  break;
38
+ case 5122:
39
+ Ctor = I16;
40
+ break;
41
+ case 5120:
42
+ Ctor = I8;
43
+ break;
38
44
  default:
39
45
  throw new Error(`Unsupported component type: ${accessor.componentType}`);
40
46
  }