@babylonjs/lite 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/index.js +596 -526
- package/dist/index.js.map +1 -1
- package/index.d.ts +107 -4
- package/lib/engine/engine.js +1 -1
- package/lib/engine/engine.js.map +1 -1
- package/lib/frame-graph/render-task.js +6 -4
- package/lib/frame-graph/render-task.js.map +1 -1
- package/lib/index.js +4 -1
- package/lib/index.js.map +1 -1
- package/lib/loader-gltf/gltf-ext-quantization.js +4 -1
- package/lib/loader-gltf/gltf-ext-quantization.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-registry.js +11 -1
- package/lib/loader-gltf/gltf-feature-registry.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-variants.js +11 -1
- package/lib/loader-gltf/gltf-feature-variants.js.map +1 -1
- package/lib/loader-gltf/gltf-json-asset.js +8 -1
- package/lib/loader-gltf/gltf-json-asset.js.map +1 -1
- package/lib/loader-gltf/gltf-material.js +4 -29
- package/lib/loader-gltf/gltf-material.js.map +1 -1
- package/lib/loader-gltf/gltf-parser.js +1 -8
- package/lib/loader-gltf/gltf-parser.js.map +1 -1
- package/lib/loader-gltf/gltf-pbr-builder.js +1 -15
- package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
- package/lib/loader-gltf/gltf-variants.js +5 -10
- package/lib/loader-gltf/gltf-variants.js.map +1 -1
- package/lib/loader-gltf/load-gltf.js +19 -29
- package/lib/loader-gltf/load-gltf.js.map +1 -1
- package/lib/material/pbr/background-dds-skybox.js +35 -93
- package/lib/material/pbr/background-dds-skybox.js.map +1 -1
- package/lib/material/pbr/background-ground.js +13 -18
- package/lib/material/pbr/background-ground.js.map +1 -1
- package/lib/material/pbr/background-hdr-skybox.js +35 -93
- package/lib/material/pbr/background-hdr-skybox.js.map +1 -1
- package/lib/material/pbr/background-solid-skybox.js +35 -93
- package/lib/material/pbr/background-solid-skybox.js.map +1 -1
- package/lib/material/pbr/fragments/clearcoat-fragment.js +5 -1
- package/lib/material/pbr/fragments/clearcoat-fragment.js.map +1 -1
- package/lib/material/pbr/fragments/iridescence-fragment.js +4 -1
- package/lib/material/pbr/fragments/iridescence-fragment.js.map +1 -1
- package/lib/material/pbr/fragments/refraction-rtt-fragment.js +7 -2
- package/lib/material/pbr/fragments/refraction-rtt-fragment.js.map +1 -1
- package/lib/material/pbr/fragments/sheen-fragment.js +2 -1
- package/lib/material/pbr/fragments/sheen-fragment.js.map +1 -1
- package/lib/material/pbr/fragments/subsurface-fragment.js +2 -1
- package/lib/material/pbr/fragments/subsurface-fragment.js.map +1 -1
- package/lib/material/pbr/fragments/unlit-fragment.js +1 -2
- package/lib/material/pbr/fragments/unlit-fragment.js.map +1 -1
- package/lib/material/pbr/pbr-compose.js +2 -0
- package/lib/material/pbr/pbr-compose.js.map +1 -1
- package/lib/material/pbr/pbr-flag-bits.js +1 -16
- package/lib/material/pbr/pbr-flag-bits.js.map +1 -1
- package/lib/material/pbr/pbr-flags.js +1 -1
- package/lib/material/pbr/pbr-fog-wgsl.js +1 -1
- package/lib/material/pbr/pbr-fog-wgsl.js.map +1 -1
- package/lib/material/pbr/pbr-geometry-output-shader.js +2 -1
- package/lib/material/pbr/pbr-geometry-output-shader.js.map +1 -1
- package/lib/material/pbr/pbr-geometry-view.js +2 -1
- package/lib/material/pbr/pbr-geometry-view.js.map +1 -1
- package/lib/material/pbr/pbr-renderable.js +4 -0
- package/lib/material/pbr/pbr-renderable.js.map +1 -1
- package/lib/material/pbr/pbr-template-gamma.js +7 -0
- package/lib/material/pbr/pbr-template-gamma.js.map +1 -0
- package/lib/material/pbr/pbr-template.js +2 -2
- package/lib/material/pbr/pbr-template.js.map +1 -1
- package/lib/material/standard/skybox-cubemap.js +1 -1
- package/lib/material/standard/skybox-cubemap.js.map +1 -1
- package/lib/material/standard/standard-template.js +1 -1
- package/lib/material/standard/standard-template.js.map +1 -1
- package/lib/mesh/GaussianSplatting/gaussian-splatting-pipeline-sh.js +3 -5
- package/lib/mesh/GaussianSplatting/gaussian-splatting-pipeline-sh.js.map +1 -1
- package/lib/mesh/GaussianSplatting/gaussian-splatting-pipeline.js +3 -5
- package/lib/mesh/GaussianSplatting/gaussian-splatting-pipeline.js.map +1 -1
- package/lib/particle/node/blocks/particle-condition-block.js +55 -0
- package/lib/particle/node/blocks/particle-condition-block.js.map +1 -0
- package/lib/particle/node/blocks/particle-float-to-int-block.js +28 -0
- package/lib/particle/node/blocks/particle-float-to-int-block.js.map +1 -0
- package/lib/particle/node/blocks/particle-gradient-block.js +32 -0
- package/lib/particle/node/blocks/particle-gradient-block.js.map +1 -0
- package/lib/particle/node/blocks/particle-gradient-value-block.js +11 -0
- package/lib/particle/node/blocks/particle-gradient-value-block.js.map +1 -0
- package/lib/particle/node/blocks/particle-lerp-block.js +2 -24
- package/lib/particle/node/blocks/particle-lerp-block.js.map +1 -1
- package/lib/particle/node/blocks/particle-lerp.js +27 -0
- package/lib/particle/node/blocks/particle-lerp.js.map +1 -0
- package/lib/particle/node/blocks/particle-vector-length-block.js +30 -0
- package/lib/particle/node/blocks/particle-vector-length-block.js.map +1 -0
- package/lib/particle/node/blocks/system-block.js +13 -3
- package/lib/particle/node/blocks/system-block.js.map +1 -1
- package/lib/particle/node/blocks/texture-source-block.js +2 -1
- package/lib/particle/node/blocks/texture-source-block.js.map +1 -1
- package/lib/particle/node/blocks/update-size-block.js +19 -0
- package/lib/particle/node/blocks/update-size-block.js.map +1 -0
- package/lib/particle/node/npe-build-state.js +10 -0
- package/lib/particle/node/npe-build-state.js.map +1 -1
- package/lib/particle/node/npe-registry.js +12 -0
- package/lib/particle/node/npe-registry.js.map +1 -1
- package/lib/particle/particle-system.js +7 -2
- package/lib/particle/particle-system.js.map +1 -1
- package/lib/picking/billboard-pick-pipeline.js +269 -0
- package/lib/picking/billboard-pick-pipeline.js.map +1 -0
- package/lib/picking/gpu-picker.js +37 -37
- package/lib/picking/gpu-picker.js.map +1 -1
- package/lib/picking/gs-picking-pipeline.js +26 -1
- package/lib/picking/gs-picking-pipeline.js.map +1 -1
- package/lib/picking/pick-contributor.js +13 -0
- package/lib/picking/pick-contributor.js.map +1 -0
- package/lib/picking/picking-info.js.map +1 -1
- package/lib/scene/scene-core.js +2 -2
- package/lib/scene/scene-core.js.map +1 -1
- package/lib/shader/wgsl-fog.js +18 -0
- package/lib/shader/wgsl-fog.js.map +1 -0
- package/lib/shader/wgsl-helpers.js +1 -16
- package/lib/shader/wgsl-helpers.js.map +1 -1
- package/lib/sprite/billboard-scene.js +2 -0
- package/lib/sprite/billboard-scene.js.map +1 -1
- package/lib/sprite/picking/pick-billboard.js +16 -0
- package/lib/sprite/picking/pick-billboard.js.map +1 -0
- package/lib/sprite/picking/pick-sprite-2d.js +41 -0
- package/lib/sprite/picking/pick-sprite-2d.js.map +1 -0
- package/lib/sprite/shared/sprite-atlas.js +4 -1
- package/lib/sprite/shared/sprite-atlas.js.map +1 -1
- package/lib/sprite/sprite-2d.js.map +1 -1
- package/lib/sprite/sprite-pipeline.js +18 -1
- package/lib/sprite/sprite-pipeline.js.map +1 -1
- package/lib/sprite/sprite-renderer.js +12 -6
- package/lib/sprite/sprite-renderer.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gltf-parser.js","sources":["../../../src/loader-gltf/gltf-parser.ts"],"sourcesContent":["/**\n * Low-level glTF/GLB parsing helpers:\n * - Accessor resolution (buffer views → typed arrays)\n * - Image extraction (embedded or external)\n * - Node hierarchy traversal with memoized world-matrix computation\n */\nimport { F32, U32, U16, U8, I16, I8 } from \"../engine/typed-arrays.js\";\nimport type { Mat4 } from \"../math/types.js\";\nimport { mat4ComposeInto } from \"../math/mat4-compose-into.js\";\nimport { mat4MultiplyInto } from \"../math/mat4-multiply-into.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\nimport { getLoaderTmpLocal } from \"./_loader-scratch.js\";\n\n// glTF 2.0 component types\nconst FLOAT = 5126;\nconst UNSIGNED_SHORT = 5123;\nconst UNSIGNED_INT = 5125;\nconst UNSIGNED_BYTE = 5121;\n\n// glTF accessor type → component count\nexport const TYPE_SIZES: Record<string, number> = {\n SCALAR: 1,\n VEC2: 2,\n VEC3: 3,\n VEC4: 4,\n MAT2: 4,\n MAT3: 9,\n MAT4: 16,\n};\n\n// --- Accessor Resolution ---\n\nexport interface AccessorView {\n /** @internal */\n _data: ArrayBufferView;\n /** @internal */\n _count: number;\n /** @internal */\n _componentCount: number;\n}\n\nexport function resolveAccessor(json: any, binChunk: DataView, accessorIdx: number): AccessorView {\n const accessor = json.accessors[accessorIdx];\n const componentCount = TYPE_SIZES[accessor.type] ?? 1;\n const count = accessor.count;\n const len = count * componentCount;\n\n let Ctor: Float32ArrayConstructor | Uint16ArrayConstructor | Uint32ArrayConstructor | Uint8ArrayConstructor | Int16ArrayConstructor | Int8ArrayConstructor;\n switch (accessor.componentType) {\n case FLOAT:\n Ctor = F32;\n break;\n case UNSIGNED_SHORT:\n Ctor = U16;\n break;\n case UNSIGNED_INT:\n Ctor = U32;\n break;\n case UNSIGNED_BYTE:\n Ctor = U8;\n break;\n case 5122: // SHORT\n Ctor = I16;\n break;\n case 5120: // BYTE\n Ctor = I8;\n break;\n default:\n throw new Error(`Unsupported component type: ${accessor.componentType}`);\n }\n\n // Spec: an accessor with no `bufferView` is zero-initialized (its values may be supplied by a `sparse`\n // substitution or an extension) — return a zero-filled array instead of dereferencing a missing\n // bufferView. Some skinned rigs ship all-zero morph-target POSITION/NORMAL accessors this way, which\n // otherwise crashed the morph feature with `undefined.byteOffset`.\n const data =\n accessor.bufferView === undefined\n ? new Ctor(len)\n : new Ctor(binChunk.buffer as ArrayBuffer, binChunk.byteOffset + (json.bufferViews[accessor.bufferView].byteOffset ?? 0) + (accessor.byteOffset ?? 0), len);\n\n return { _data: data, _count: count, _componentCount: componentCount };\n}\n\n// --- Image Extraction ---\n\n/** Resolve the image index for a glTF texture, honoring alternate-source\n * extensions such as EXT_texture_webp (WebP decode is native in\n * createImageBitmap, so no extra module is required — we only need to\n * pick the correct image source). */\nexport function getTextureImageIndex(tex: any): number {\n return tex.extensions?.EXT_texture_webp?.source ?? tex.source;\n}\n\n// --- Optional-feature detection (shared by the core loader gate and the\n// dynamically-imported feature registry) ---\n\n/** Returns true if any mesh primitive in the asset matches `pred`. */\nexport function anyPrimitive(json: any, pred: (p: any) => boolean): boolean {\n for (const m of json.meshes ?? []) {\n for (const p of m.primitives ?? []) {\n if (pred(p)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/** Asset has at least one material that needs ORM compositing\n * (separate metallicRoughnessTexture + occlusionTexture pointing at different images). */\nexport function needsOrmComposite(json: any): boolean {\n const mats = json.materials ?? [];\n const textures = json.textures ?? [];\n for (const m of mats) {\n const mr = m.pbrMetallicRoughness?.metallicRoughnessTexture;\n const occ = m.occlusionTexture;\n if (mr && occ && textures[mr.index] && textures[occ.index] && getTextureImageIndex(textures[mr.index]) !== getTextureImageIndex(textures[occ.index])) {\n return true;\n }\n }\n return false;\n}\n\nexport async function resolveImage(json: any, binChunk: DataView, imageIdx: number, baseUrl: string): Promise<ImageBitmap> {\n const image = json.images[imageIdx];\n\n if (image.bufferView !== undefined) {\n // Embedded in binary chunk (GLB)\n const bv = json.bufferViews[image.bufferView];\n const offset = binChunk.byteOffset + (bv.byteOffset ?? 0);\n const slice = binChunk.buffer.slice(offset, offset + bv.byteLength);\n const blob = new Blob([slice as ArrayBuffer], { type: image.mimeType ?? \"image/png\" });\n return createImageBitmap(blob, { premultiplyAlpha: \"none\", colorSpaceConversion: \"none\" });\n }\n\n if (image.uri) {\n // External URI (relative to .gltf base URL)\n const imageUrl = new URL(image.uri, baseUrl + \"x\").href;\n const response = await fetch(imageUrl);\n if (!response.ok) {\n throw new Error(`Failed to load image: ${response.status} ${response.statusText}`);\n }\n const blob = await response.blob();\n const bmp = await createImageBitmap(blob, { premultiplyAlpha: \"none\", colorSpaceConversion: \"none\" });\n return bmp;\n }\n\n throw new Error(\"Image has neither bufferView nor uri\");\n}\n\n// --- Node Hierarchy → World Matrix (Memoized) ---\n\n// Babylon.js RH→LH root: rotation [0,1,0,0] + scale [1,1,-1] = diag(-1,1,1,1)\n// prettier-ignore\nconst RH_TO_LH_ROOT = new F32([-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) as unknown as Mat4;\n\n/** Build a parent index map by scanning node.children arrays once. O(n). */\nexport function buildParentMap(json: any): Map<number, number> {\n const parentMap = new Map<number, number>();\n const nodes = json.nodes ?? [];\n for (let i = 0; i < nodes.length; i++) {\n const children = nodes[i].children;\n if (children) {\n for (const childIdx of children) {\n parentMap.set(childIdx as number, i);\n }\n }\n }\n return parentMap;\n}\n\n/** Look up a node's parent using the pre-built parent map. O(1). */\nexport function findParent(parentMap: Map<number, number>, childIdx: number): number {\n return parentMap.get(childIdx) ?? -1;\n}\n\n/**\n * Compute world matrix for a glTF node with memoization.\n * Uses parentMap for O(1) parent lookup and cache for O(1) repeat queries.\n * Total cost across all nodes: O(n) instead of O(n²).\n *\n * Zero-alloc path for the TRS case (common): `local` is composed into a shared\n * scratch via `mat4ComposeInto`, then multiplied into the freshly-allocated\n * `world` via `mat4MultiplyInto`. Only one Float32Array allocation per node\n * (the cached world matrix itself) instead of two. Recursion always resolves\n * `parentWorld` before touching the scratch, so the shared buffer is safe.\n */\nexport function computeNodeWorldMatrix(json: any, nodeIdx: number, parentMap: Map<number, number>, cache: Map<number, Mat4>): Mat4 {\n const cached = cache.get(nodeIdx);\n if (cached) {\n return cached;\n }\n\n const node = json.nodes[nodeIdx];\n const parentIdx = findParent(parentMap, nodeIdx);\n // Resolve parent FIRST so any recursive call can safely reuse the shared scratch below.\n const parentWorld: Mat4 = parentIdx !== -1 ? computeNodeWorldMatrix(json, parentIdx, parentMap, cache) : RH_TO_LH_ROOT;\n\n let localBuf: import(\"../math/types.js\").Mat4Storage;\n if (node.matrix) {\n // Pre-built matrix — copy into a fresh Float32Array (cannot alias scratch safely across calls).\n localBuf = new F32(node.matrix);\n } else {\n const t = node.translation ?? [0, 0, 0];\n const r = node.rotation ?? [0, 0, 0, 1];\n const s = node.scale ?? [1, 1, 1];\n const local = getLoaderTmpLocal() as unknown as Mat4Storage;\n mat4ComposeInto(local, 0, t[0], t[1], t[2], r[0], r[1], r[2], r[3], s[0], s[1], s[2]);\n localBuf = local;\n }\n\n // Per-node world is allocated fresh because recursion mutates the parser's\n // scratch; it cannot alias the per-call `tmpLocal`. The result is then\n // stashed in the per-load `cache` (Map<nodeIdx, Mat4>) and never shared\n // across loadGltf calls. Allocates F32 directly here — these loader-local\n // world matrices are throwaway intermediaries used only during parsing;\n // mesh runtime world-matrix caches are separately allocated via\n // `allocateMat4()` in `initMeshTransform` and pick up whatever precision\n // the process-global allocator was set to.\n const world = new F32(16) as unknown as Mat4;\n mat4MultiplyInto(world as unknown as Mat4Storage, 0, parentWorld as unknown as Mat4Storage, 0, localBuf, 0);\n\n cache.set(nodeIdx, world);\n return world;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gltf-parser.js","sources":["../../../src/loader-gltf/gltf-parser.ts"],"sourcesContent":["/**\n * Low-level glTF/GLB parsing helpers:\n * - Accessor resolution (buffer views → typed arrays)\n * - Image extraction (embedded or external)\n * - Node hierarchy traversal with memoized world-matrix computation\n */\nimport { F32, U32, U16, U8, I16, I8 } from \"../engine/typed-arrays.js\";\nimport type { Mat4 } from \"../math/types.js\";\nimport { mat4ComposeInto } from \"../math/mat4-compose-into.js\";\nimport { mat4MultiplyInto } from \"../math/mat4-multiply-into.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\nimport { getLoaderTmpLocal } from \"./_loader-scratch.js\";\n\n// glTF 2.0 component types\nconst FLOAT = 5126;\nconst UNSIGNED_SHORT = 5123;\nconst UNSIGNED_INT = 5125;\nconst UNSIGNED_BYTE = 5121;\n\n// glTF accessor type → component count\nexport const TYPE_SIZES: Record<string, number> = {\n SCALAR: 1,\n VEC2: 2,\n VEC3: 3,\n VEC4: 4,\n MAT2: 4,\n MAT3: 9,\n MAT4: 16,\n};\n\n// --- Accessor Resolution ---\n\nexport interface AccessorView {\n /** @internal */\n _data: ArrayBufferView;\n /** @internal */\n _count: number;\n /** @internal */\n _componentCount: number;\n}\n\nexport function resolveAccessor(json: any, binChunk: DataView, accessorIdx: number): AccessorView {\n const accessor = json.accessors[accessorIdx];\n const componentCount = TYPE_SIZES[accessor.type] ?? 1;\n const count = accessor.count;\n const len = count * componentCount;\n\n let Ctor: Float32ArrayConstructor | Uint16ArrayConstructor | Uint32ArrayConstructor | Uint8ArrayConstructor | Int16ArrayConstructor | Int8ArrayConstructor;\n switch (accessor.componentType) {\n case FLOAT:\n Ctor = F32;\n break;\n case UNSIGNED_SHORT:\n Ctor = U16;\n break;\n case UNSIGNED_INT:\n Ctor = U32;\n break;\n case UNSIGNED_BYTE:\n Ctor = U8;\n break;\n case 5122: // SHORT\n Ctor = I16;\n break;\n case 5120: // BYTE\n Ctor = I8;\n break;\n default:\n throw new Error(`Unsupported component type: ${accessor.componentType}`);\n }\n\n // Spec: an accessor with no `bufferView` is zero-initialized (its values may be supplied by a `sparse`\n // substitution or an extension) — return a zero-filled array instead of dereferencing a missing\n // bufferView. Some skinned rigs ship all-zero morph-target POSITION/NORMAL accessors this way, which\n // otherwise crashed the morph feature with `undefined.byteOffset`.\n const data =\n accessor.bufferView === undefined\n ? new Ctor(len)\n : new Ctor(binChunk.buffer as ArrayBuffer, binChunk.byteOffset + (json.bufferViews[accessor.bufferView].byteOffset ?? 0) + (accessor.byteOffset ?? 0), len);\n\n return { _data: data, _count: count, _componentCount: componentCount };\n}\n\n// --- Image Extraction ---\n\n/** Resolve the image index for a glTF texture, honoring alternate-source\n * extensions such as EXT_texture_webp (WebP decode is native in\n * createImageBitmap, so no extra module is required — we only need to\n * pick the correct image source). */\nexport function getTextureImageIndex(tex: any): number {\n return tex.extensions?.EXT_texture_webp?.source ?? tex.source;\n}\n\n// --- Optional-feature detection (shared by the core loader gate and the\n// dynamically-imported feature registry) ---\n\n/** Returns true if any mesh primitive in the asset matches `pred`. */\nexport function anyPrimitive(json: any, pred: (p: any) => boolean): boolean {\n for (const m of json.meshes ?? []) {\n for (const p of m.primitives ?? []) {\n if (pred(p)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/** Asset has at least one material that needs ORM compositing\n * (separate metallicRoughnessTexture + occlusionTexture pointing at different images). */\nexport function needsOrmComposite(json: any): boolean {\n const mats = json.materials ?? [];\n const textures = json.textures ?? [];\n for (const m of mats) {\n const mr = m.pbrMetallicRoughness?.metallicRoughnessTexture;\n const occ = m.occlusionTexture;\n if (mr && occ && textures[mr.index] && textures[occ.index] && getTextureImageIndex(textures[mr.index]) !== getTextureImageIndex(textures[occ.index])) {\n return true;\n }\n }\n return false;\n}\n\nexport async function resolveImage(json: any, binChunk: DataView, imageIdx: number, baseUrl: string): Promise<ImageBitmap> {\n const image = json.images[imageIdx];\n\n if (image.bufferView !== undefined) {\n // Embedded in binary chunk (GLB)\n const bv = json.bufferViews[image.bufferView];\n const offset = binChunk.byteOffset + (bv.byteOffset ?? 0);\n const slice = binChunk.buffer.slice(offset, offset + bv.byteLength);\n const blob = new Blob([slice as ArrayBuffer], { type: image.mimeType ?? \"image/png\" });\n return createImageBitmap(blob, { premultiplyAlpha: \"none\", colorSpaceConversion: \"none\" });\n }\n\n if (image.uri) {\n return (await import(\"./gltf-json-asset.js\")).resolveExternalImage(image.uri, baseUrl);\n }\n\n throw new Error(\"Image has neither bufferView nor uri\");\n}\n\n// --- Node Hierarchy → World Matrix (Memoized) ---\n\n// Babylon.js RH→LH root: rotation [0,1,0,0] + scale [1,1,-1] = diag(-1,1,1,1)\n// prettier-ignore\nconst RH_TO_LH_ROOT = new F32([-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) as unknown as Mat4;\n\n/** Build a parent index map by scanning node.children arrays once. O(n). */\nexport function buildParentMap(json: any): Map<number, number> {\n const parentMap = new Map<number, number>();\n const nodes = json.nodes ?? [];\n for (let i = 0; i < nodes.length; i++) {\n const children = nodes[i].children;\n if (children) {\n for (const childIdx of children) {\n parentMap.set(childIdx as number, i);\n }\n }\n }\n return parentMap;\n}\n\n/** Look up a node's parent using the pre-built parent map. O(1). */\nexport function findParent(parentMap: Map<number, number>, childIdx: number): number {\n return parentMap.get(childIdx) ?? -1;\n}\n\n/**\n * Compute world matrix for a glTF node with memoization.\n * Uses parentMap for O(1) parent lookup and cache for O(1) repeat queries.\n * Total cost across all nodes: O(n) instead of O(n²).\n *\n * Zero-alloc path for the TRS case (common): `local` is composed into a shared\n * scratch via `mat4ComposeInto`, then multiplied into the freshly-allocated\n * `world` via `mat4MultiplyInto`. Only one Float32Array allocation per node\n * (the cached world matrix itself) instead of two. Recursion always resolves\n * `parentWorld` before touching the scratch, so the shared buffer is safe.\n */\nexport function computeNodeWorldMatrix(json: any, nodeIdx: number, parentMap: Map<number, number>, cache: Map<number, Mat4>): Mat4 {\n const cached = cache.get(nodeIdx);\n if (cached) {\n return cached;\n }\n\n const node = json.nodes[nodeIdx];\n const parentIdx = findParent(parentMap, nodeIdx);\n // Resolve parent FIRST so any recursive call can safely reuse the shared scratch below.\n const parentWorld: Mat4 = parentIdx !== -1 ? computeNodeWorldMatrix(json, parentIdx, parentMap, cache) : RH_TO_LH_ROOT;\n\n let localBuf: import(\"../math/types.js\").Mat4Storage;\n if (node.matrix) {\n // Pre-built matrix — copy into a fresh Float32Array (cannot alias scratch safely across calls).\n localBuf = new F32(node.matrix);\n } else {\n const t = node.translation ?? [0, 0, 0];\n const r = node.rotation ?? [0, 0, 0, 1];\n const s = node.scale ?? [1, 1, 1];\n const local = getLoaderTmpLocal() as unknown as Mat4Storage;\n mat4ComposeInto(local, 0, t[0], t[1], t[2], r[0], r[1], r[2], r[3], s[0], s[1], s[2]);\n localBuf = local;\n }\n\n // Per-node world is allocated fresh because recursion mutates the parser's\n // scratch; it cannot alias the per-call `tmpLocal`. The result is then\n // stashed in the per-load `cache` (Map<nodeIdx, Mat4>) and never shared\n // across loadGltf calls. Allocates F32 directly here — these loader-local\n // world matrices are throwaway intermediaries used only during parsing;\n // mesh runtime world-matrix caches are separately allocated via\n // `allocateMat4()` in `initMeshTransform` and pick up whatever precision\n // the process-global allocator was set to.\n const world = new F32(16) as unknown as Mat4;\n mat4MultiplyInto(world as unknown as Mat4Storage, 0, parentWorld as unknown as Mat4Storage, 0, localBuf, 0);\n\n cache.set(nodeIdx, world);\n return world;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -85,20 +85,6 @@ function buildDefaultPbrTextures(engine, mat, sampler, generateMipmaps, getCache
|
|
|
85
85
|
}
|
|
86
86
|
return { baseColorTexture, ormTexture, normalTexture, emissiveTexture };
|
|
87
87
|
}
|
|
88
|
-
async function runMatExts(mat, exts, ctx) {
|
|
89
|
-
if (!exts.length) {
|
|
90
|
-
return void 0;
|
|
91
|
-
}
|
|
92
|
-
const fragments = await Promise.all(exts.map((ext) => ext.applyMaterial(mat, ctx)));
|
|
93
|
-
let layers;
|
|
94
|
-
for (const f of fragments) {
|
|
95
|
-
if (f) {
|
|
96
|
-
layers ??= {};
|
|
97
|
-
Object.assign(layers, f);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return layers;
|
|
101
|
-
}
|
|
102
88
|
|
|
103
|
-
export { assemblePbrProps, buildDefaultPbrTextures, identityTexWrap,
|
|
89
|
+
export { assemblePbrProps, buildDefaultPbrTextures, identityTexWrap, uploadTex };
|
|
104
90
|
//# sourceMappingURL=gltf-pbr-builder.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gltf-pbr-builder.js","sources":["../../../src/loader-gltf/gltf-pbr-builder.ts"],"sourcesContent":["/** Shared PBR-material assembly + texture upload + ext-layer merging.\n * Used by both the core loader (`load-gltf.ts`) and the variants loader\n * (`gltf-variants.ts`) so they can't drift. */\n\nimport { U8 } from \"../engine/typed-arrays.js\";\nimport { TU } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport { getPbrGroupBuilder } from \"../material/pbr/pbr-material.js\";\nimport type { GltfMaterialData, GltfMatExtCtx } from \"./gltf-material.js\";\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport { mipLevelCount } from \"../texture/mip-count.js\";\nimport { linearToSrgbByte } from \"../math/color.js\";\n\n/** Texture post-processor composed from every active feature's `wrapTexture`\n * hook. Identity when no feature contributes one (common case). Kept simple\n * so the core loader stays feature-agnostic and tree-shakes cleanly. */\nexport type TextureWrapFn = (tex: Texture2D, texInfo: unknown) => Texture2D;\nexport const identityTexWrap: TextureWrapFn = (tex) => tex;\n\nexport type GenerateMipmapsFn = (engine: EngineContext, texture: GPUTexture, face?: number) => void;\n\nexport function uploadTex(\n engine: EngineContext,\n bitmap: ImageBitmap | null,\n srgb: boolean,\n sampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n fallback?: Uint8Array\n): Texture2D {\n const device = engine._device;\n const w = bitmap?.width ?? 1;\n const h = bitmap?.height ?? 1;\n const fmt: GPUTextureFormat = srgb ? \"rgba8unorm-srgb\" : \"rgba8unorm\";\n const mips = bitmap ? mipLevelCount(w, h) : 1;\n const tex = device.createTexture({\n size: { width: w, height: h },\n format: fmt,\n usage: TU.TEXTURE_BINDING | TU.COPY_DST | TU.COPY_SRC | TU.RENDER_ATTACHMENT,\n mipLevelCount: mips,\n });\n if (bitmap) {\n device.queue.copyExternalImageToTexture({ source: bitmap }, { texture: tex, premultipliedAlpha: false }, { width: w, height: h });\n generateMipmaps(engine, tex);\n } else {\n device.queue.writeTexture({ texture: tex }, (fallback ?? new U8([255, 255, 255, 255])) as Uint8Array<ArrayBuffer>, { bytesPerRow: 4 }, { width: 1, height: 1 });\n }\n const result: Texture2D = {\n texture: tex,\n view: tex.createView(),\n sampler,\n width: w,\n height: h,\n };\n engine._dlr?.b(result, bitmap, srgb, !!bitmap, fallback);\n return result;\n}\n\n/** Assemble a PbrMaterialProps from parsed glTF material data + already-uploaded\n * textures + per-ext fragment overrides. Fast-path: no wrapTex, no occlusionOnUv2,\n * no occlusionTexture. Slow-path additions live in gltf-pbr-builder-ext.ts. */\nexport function assemblePbrProps(\n mat: GltfMaterialData,\n baseColorTexture: Texture2D,\n ormTexture: Texture2D,\n normalTexture: Texture2D | undefined,\n emissiveTexture: Texture2D | undefined,\n extLayers: Partial<PbrMaterialProps> | undefined\n): PbrMaterialProps {\n const ef = mat._emissiveFactor;\n // emissiveFactor multiplies the emissive texture, so [1,1,1] is a no-op WHEN a texture is\n // present. With no emissive texture, [1,1,1] is a real full-white emissive that must be applied\n // (the glTF default is [0,0,0]) — otherwise the surface renders unlit/dark (Material_03).\n const defaultFactor = (ef[0] === 0 && ef[1] === 0 && ef[2] === 0) || (!!emissiveTexture && ef[0] === 1 && ef[1] === 1 && ef[2] === 1);\n return {\n baseColorTexture,\n normalTexture,\n ormTexture,\n emissiveTexture,\n ...(mat._baseColorImage && !isDefaultBaseColorFactor(mat._baseColorFactor) ? { baseColorFactor: mat._baseColorFactor } : undefined),\n doubleSided: mat._doubleSided,\n occlusionStrength: mat._occlusionImage ? 1.0 : 0,\n ...(mat._normalScale !== 1 ? { normalTextureScale: mat._normalScale } : undefined),\n ...(mat._metallicRoughnessImage ? { metallicFactor: mat._metallicFactor, roughnessFactor: mat._roughnessFactor } : undefined),\n ...(!defaultFactor ? { emissiveColor: [ef[0], ef[1], ef[2]] as [number, number, number] } : undefined),\n enableSpecularAA: true,\n ...(mat._alphaMode === \"BLEND\" ? { alphaBlend: true, alpha: mat._baseColorFactor[3] } : undefined),\n ...(mat._alphaMode === \"MASK\" ? { alpha: mat._baseColorFactor[3], alphaCutOff: mat._alphaCutoff } : undefined),\n ...(mat._rawMatDef?.name ? { name: mat._rawMatDef.name as string } : undefined),\n ...extLayers,\n _buildGroup: getPbrGroupBuilder(),\n _uboVersion: 0,\n } as PbrMaterialProps;\n}\n\nfunction isDefaultBaseColorFactor(f: readonly number[]): boolean {\n return f[0] === 1 && f[1] === 1 && f[2] === 1 && f[3] === 1;\n}\n\n/** Build the always-present default textures (base color + ORM) from a parsed glTF material.\n * Fast-path version: no wrapTex, no occlusion-on-uv2 handling. The slow path lives\n * in gltf-pbr-builder-ext.ts and is lazy-loaded only when needed. */\nexport function buildDefaultPbrTextures(\n engine: EngineContext,\n mat: GltfMaterialData,\n sampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n getCachedTex: (bitmap: ImageBitmap, srgb: boolean) => Texture2D\n): { baseColorTexture: Texture2D; ormTexture: Texture2D; normalTexture: Texture2D | undefined; emissiveTexture: Texture2D | undefined } {\n const baseColorTexture = mat._baseColorImage\n ? getCachedTex(mat._baseColorImage, true)\n : (() => {\n const f = mat._baseColorFactor;\n return uploadTex(\n engine,\n null,\n true,\n sampler,\n generateMipmaps,\n new U8([linearToSrgbByte(f[0]), linearToSrgbByte(f[1]), linearToSrgbByte(f[2]), Math.round(Math.max(0, Math.min(1, f[3])) * 255)])\n );\n })();\n const normalTexture = mat._normalImage ? getCachedTex(mat._normalImage, false) : undefined;\n const emissiveTexture = mat._emissiveImage ? getCachedTex(mat._emissiveImage, true) : undefined;\n\n const single = mat._metallicRoughnessImage ?? mat._occlusionImage;\n let ormTexture: Texture2D;\n if (single && (!mat._metallicRoughnessImage || !mat._occlusionImage || mat._metallicRoughnessImage === mat._occlusionImage)) {\n ormTexture = getCachedTex(single, false);\n } else if (!single) {\n const clamp = (v: number) => Math.round(Math.max(0, Math.min(1, v)) * 255);\n ormTexture = uploadTex(engine, null, false, sampler, generateMipmaps, new U8([255, clamp(mat._roughnessFactor), clamp(mat._metallicFactor), 255]));\n } else {\n ormTexture = getCachedTex(mat._metallicRoughnessImage!, false);\n }\n return { baseColorTexture, ormTexture, normalTexture, emissiveTexture };\n}\n\n/** Run all material-layer features and merge their fragments. */\nexport async function runMatExts(mat: GltfMaterialData, exts: GltfFeature[], ctx: GltfMatExtCtx): Promise<Partial<PbrMaterialProps> | undefined> {\n if (!exts.length) {\n return undefined;\n }\n const fragments = await Promise.all(exts.map((ext) => ext.applyMaterial!(mat, ctx)));\n let layers: Partial<PbrMaterialProps> | undefined;\n for (const f of fragments) {\n if (f) {\n layers ??= {};\n Object.assign(layers, f);\n }\n }\n return layers;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gltf-pbr-builder.js","sources":["../../../src/loader-gltf/gltf-pbr-builder.ts"],"sourcesContent":["/** Shared PBR-material assembly + texture upload + ext-layer merging.\n * Used by both the core loader (`load-gltf.ts`) and the variants loader\n * (`gltf-variants.ts`) so they can't drift. */\n\nimport { U8 } from \"../engine/typed-arrays.js\";\nimport { TU } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport { getPbrGroupBuilder } from \"../material/pbr/pbr-material.js\";\nimport type { GltfMaterialData } from \"./gltf-material.js\";\nimport { mipLevelCount } from \"../texture/mip-count.js\";\nimport { linearToSrgbByte } from \"../math/color.js\";\n\n/** Texture post-processor composed from every active feature's `wrapTexture`\n * hook. Identity when no feature contributes one (common case). Kept simple\n * so the core loader stays feature-agnostic and tree-shakes cleanly. */\nexport type TextureWrapFn = (tex: Texture2D, texInfo: unknown) => Texture2D;\nexport const identityTexWrap: TextureWrapFn = (tex) => tex;\n\nexport type GenerateMipmapsFn = (engine: EngineContext, texture: GPUTexture, face?: number) => void;\n\nexport function uploadTex(\n engine: EngineContext,\n bitmap: ImageBitmap | null,\n srgb: boolean,\n sampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n fallback?: Uint8Array\n): Texture2D {\n const device = engine._device;\n const w = bitmap?.width ?? 1;\n const h = bitmap?.height ?? 1;\n const fmt: GPUTextureFormat = srgb ? \"rgba8unorm-srgb\" : \"rgba8unorm\";\n const mips = bitmap ? mipLevelCount(w, h) : 1;\n const tex = device.createTexture({\n size: { width: w, height: h },\n format: fmt,\n usage: TU.TEXTURE_BINDING | TU.COPY_DST | TU.COPY_SRC | TU.RENDER_ATTACHMENT,\n mipLevelCount: mips,\n });\n if (bitmap) {\n device.queue.copyExternalImageToTexture({ source: bitmap }, { texture: tex, premultipliedAlpha: false }, { width: w, height: h });\n generateMipmaps(engine, tex);\n } else {\n device.queue.writeTexture({ texture: tex }, (fallback ?? new U8([255, 255, 255, 255])) as Uint8Array<ArrayBuffer>, { bytesPerRow: 4 }, { width: 1, height: 1 });\n }\n const result: Texture2D = {\n texture: tex,\n view: tex.createView(),\n sampler,\n width: w,\n height: h,\n };\n engine._dlr?.b(result, bitmap, srgb, !!bitmap, fallback);\n return result;\n}\n\n/** Assemble a PbrMaterialProps from parsed glTF material data + already-uploaded\n * textures + per-ext fragment overrides. Fast-path: no wrapTex, no occlusionOnUv2,\n * no occlusionTexture. Slow-path additions live in gltf-pbr-builder-ext.ts. */\nexport function assemblePbrProps(\n mat: GltfMaterialData,\n baseColorTexture: Texture2D,\n ormTexture: Texture2D,\n normalTexture: Texture2D | undefined,\n emissiveTexture: Texture2D | undefined,\n extLayers: Partial<PbrMaterialProps> | undefined\n): PbrMaterialProps {\n const ef = mat._emissiveFactor;\n // emissiveFactor multiplies the emissive texture, so [1,1,1] is a no-op WHEN a texture is\n // present. With no emissive texture, [1,1,1] is a real full-white emissive that must be applied\n // (the glTF default is [0,0,0]) — otherwise the surface renders unlit/dark (Material_03).\n const defaultFactor = (ef[0] === 0 && ef[1] === 0 && ef[2] === 0) || (!!emissiveTexture && ef[0] === 1 && ef[1] === 1 && ef[2] === 1);\n return {\n baseColorTexture,\n normalTexture,\n ormTexture,\n emissiveTexture,\n ...(mat._baseColorImage && !isDefaultBaseColorFactor(mat._baseColorFactor) ? { baseColorFactor: mat._baseColorFactor } : undefined),\n doubleSided: mat._doubleSided,\n occlusionStrength: mat._occlusionImage ? 1.0 : 0,\n ...(mat._normalScale !== 1 ? { normalTextureScale: mat._normalScale } : undefined),\n ...(mat._metallicRoughnessImage ? { metallicFactor: mat._metallicFactor, roughnessFactor: mat._roughnessFactor } : undefined),\n ...(!defaultFactor ? { emissiveColor: [ef[0], ef[1], ef[2]] as [number, number, number] } : undefined),\n enableSpecularAA: true,\n ...(mat._alphaMode === \"BLEND\" ? { alphaBlend: true, alpha: mat._baseColorFactor[3] } : undefined),\n ...(mat._alphaMode === \"MASK\" ? { alpha: mat._baseColorFactor[3], alphaCutOff: mat._alphaCutoff } : undefined),\n ...(mat._rawMatDef?.name ? { name: mat._rawMatDef.name as string } : undefined),\n ...extLayers,\n _buildGroup: getPbrGroupBuilder(),\n _uboVersion: 0,\n } as PbrMaterialProps;\n}\n\nfunction isDefaultBaseColorFactor(f: readonly number[]): boolean {\n return f[0] === 1 && f[1] === 1 && f[2] === 1 && f[3] === 1;\n}\n\n/** Build the always-present default textures (base color + ORM) from a parsed glTF material.\n * Fast-path version: no wrapTex, no occlusion-on-uv2 handling. The slow path lives\n * in gltf-pbr-builder-ext.ts and is lazy-loaded only when needed. */\nexport function buildDefaultPbrTextures(\n engine: EngineContext,\n mat: GltfMaterialData,\n sampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n getCachedTex: (bitmap: ImageBitmap, srgb: boolean) => Texture2D\n): { baseColorTexture: Texture2D; ormTexture: Texture2D; normalTexture: Texture2D | undefined; emissiveTexture: Texture2D | undefined } {\n const baseColorTexture = mat._baseColorImage\n ? getCachedTex(mat._baseColorImage, true)\n : (() => {\n const f = mat._baseColorFactor;\n return uploadTex(\n engine,\n null,\n true,\n sampler,\n generateMipmaps,\n new U8([linearToSrgbByte(f[0]), linearToSrgbByte(f[1]), linearToSrgbByte(f[2]), Math.round(Math.max(0, Math.min(1, f[3])) * 255)])\n );\n })();\n const normalTexture = mat._normalImage ? getCachedTex(mat._normalImage, false) : undefined;\n const emissiveTexture = mat._emissiveImage ? getCachedTex(mat._emissiveImage, true) : undefined;\n\n const single = mat._metallicRoughnessImage ?? mat._occlusionImage;\n let ormTexture: Texture2D;\n if (single && (!mat._metallicRoughnessImage || !mat._occlusionImage || mat._metallicRoughnessImage === mat._occlusionImage)) {\n ormTexture = getCachedTex(single, false);\n } else if (!single) {\n const clamp = (v: number) => Math.round(Math.max(0, Math.min(1, v)) * 255);\n ormTexture = uploadTex(engine, null, false, sampler, generateMipmaps, new U8([255, clamp(mat._roughnessFactor), clamp(mat._metallicFactor), 255]));\n } else {\n ormTexture = getCachedTex(mat._metallicRoughnessImage!, false);\n }\n return { baseColorTexture, ormTexture, normalTexture, emissiveTexture };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { assembleMaterial, makeImageFetcher } from './gltf-material.js';
|
|
2
2
|
import { getOrCreateSampler } from '../resource/gpu-pool.js';
|
|
3
|
-
import { identityTexWrap,
|
|
3
|
+
import { identityTexWrap, uploadTex } from './gltf-pbr-builder.js';
|
|
4
4
|
import { buildDefaultPbrTexturesExt, assemblePbrPropsExt } from './gltf-pbr-builder-ext.js';
|
|
5
5
|
|
|
6
|
-
async function loadVariantMaterials(json, binChunk, baseUrl, variantNames, meshes, engine, exts, wrapTex = identityTexWrap) {
|
|
6
|
+
async function loadVariantMaterials(json, binChunk, baseUrl, variantNames, meshes, engine, exts, runMatExts, wrapTex = identityTexWrap) {
|
|
7
7
|
const generateMipmaps = (await import('../texture/generate-mipmaps.js')).generateMipmaps;
|
|
8
8
|
const sampler = getOrCreateSampler(engine, {
|
|
9
9
|
magFilter: "linear",
|
|
@@ -13,8 +13,8 @@ async function loadVariantMaterials(json, binChunk, baseUrl, variantNames, meshe
|
|
|
13
13
|
addressModeV: "repeat",
|
|
14
14
|
maxAnisotropy: 4
|
|
15
15
|
});
|
|
16
|
-
const matCache =
|
|
17
|
-
const imageCache =
|
|
16
|
+
const matCache = [];
|
|
17
|
+
const imageCache = [];
|
|
18
18
|
const fetchImg = makeImageFetcher(json, binChunk, baseUrl, imageCache);
|
|
19
19
|
const getCachedTex = (bitmap, srgb) => uploadTex(engine, bitmap, srgb, sampler, generateMipmaps);
|
|
20
20
|
const extCtx = {
|
|
@@ -31,12 +31,7 @@ async function loadVariantMaterials(json, binChunk, baseUrl, variantNames, meshe
|
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
33
|
const getMat = (matIdx) => {
|
|
34
|
-
|
|
35
|
-
if (!p) {
|
|
36
|
-
p = assembleMaterial(json, binChunk, matIdx, baseUrl, imageCache);
|
|
37
|
-
matCache.set(matIdx, p);
|
|
38
|
-
}
|
|
39
|
-
return p;
|
|
34
|
+
return matCache[matIdx] ??= assembleMaterial(json, binChunk, matIdx, baseUrl, imageCache);
|
|
40
35
|
};
|
|
41
36
|
const pbrCache = /* @__PURE__ */ new Map();
|
|
42
37
|
const getPbr = (gltfMat) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gltf-variants.js","sources":["../../../src/loader-gltf/gltf-variants.ts"],"sourcesContent":["/**\n * KHR_materials_variants — glTF parsing + GPU upload for variant materials.\n *\n * Dynamically imported by load-gltf.ts ONLY when the extension is present.\n * This keeps variant code fully tree-shaken from bundles that don't use it.\n */\n\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport type { GltfMaterialData, GltfMatExtCtx } from \"./gltf-material.js\";\nimport { assembleMaterial, makeImageFetcher } from \"./gltf-material.js\";\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport type { MaterialVariantData, VariantMeshEntry } from \"./material-variants.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport { getOrCreateSampler } from \"../resource/gpu-pool.js\";\nimport {
|
|
1
|
+
{"version":3,"file":"gltf-variants.js","sources":["../../../src/loader-gltf/gltf-variants.ts"],"sourcesContent":["/**\n * KHR_materials_variants — glTF parsing + GPU upload for variant materials.\n *\n * Dynamically imported by load-gltf.ts ONLY when the extension is present.\n * This keeps variant code fully tree-shaken from bundles that don't use it.\n */\n\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport type { GltfImageCache, GltfMaterialData, GltfMatExtCtx } from \"./gltf-material.js\";\nimport { assembleMaterial, makeImageFetcher } from \"./gltf-material.js\";\nimport type { GltfFeature, GltfMaterialFeatureRunner } from \"./gltf-feature.js\";\nimport type { MaterialVariantData, VariantMeshEntry } from \"./material-variants.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport { getOrCreateSampler } from \"../resource/gpu-pool.js\";\nimport { uploadTex, type GenerateMipmapsFn, type TextureWrapFn, identityTexWrap } from \"./gltf-pbr-builder.js\";\nimport { buildDefaultPbrTexturesExt, assemblePbrPropsExt } from \"./gltf-pbr-builder-ext.js\";\n\n/**\n * Self-contained variant material loader.\n * Parses variant mappings from glTF JSON primitives, assembles + uploads variant materials,\n * and builds MaterialVariantData. Called only when KHR_materials_variants is present.\n */\nexport async function loadVariantMaterials(\n json: any,\n binChunk: DataView,\n baseUrl: string,\n variantNames: string[],\n meshes: Mesh[],\n engine: EngineContext,\n exts: GltfFeature[],\n runMatExts: GltfMaterialFeatureRunner,\n wrapTex: TextureWrapFn = identityTexWrap\n): Promise<MaterialVariantData> {\n const generateMipmaps: GenerateMipmapsFn = (await import(\"../texture/generate-mipmaps.js\")).generateMipmaps;\n\n const sampler = getOrCreateSampler(engine, {\n magFilter: \"linear\",\n minFilter: \"linear\",\n mipmapFilter: \"linear\",\n addressModeU: \"repeat\",\n addressModeV: \"repeat\",\n maxAnisotropy: 4,\n });\n\n const matCache: Promise<GltfMaterialData>[] = [];\n const imageCache: GltfImageCache = [];\n const fetchImg = makeImageFetcher(json, binChunk, baseUrl, imageCache);\n const getCachedTex = (bitmap: ImageBitmap, srgb: boolean) => uploadTex(engine, bitmap, srgb, sampler, generateMipmaps);\n const extCtx: GltfMatExtCtx = {\n _engine: engine,\n async _texture(texInfo, sRGB) {\n if (!texInfo) {\n return undefined;\n }\n const img = await fetchImg(texInfo);\n return img ? wrapTex(uploadTex(engine, img, sRGB, sampler, generateMipmaps), texInfo) : undefined;\n },\n _uploadImage(bitmap, sRGB) {\n return uploadTex(engine, bitmap, sRGB, sampler, generateMipmaps);\n },\n };\n const getMat = (matIdx: number): Promise<GltfMaterialData> => {\n return (matCache[matIdx] ??= assembleMaterial(json, binChunk, matIdx, baseUrl, imageCache));\n };\n\n const pbrCache = new Map<GltfMaterialData, Promise<PbrMaterialProps>>();\n const getPbr = (gltfMat: GltfMaterialData): Promise<PbrMaterialProps> => {\n let p = pbrCache.get(gltfMat);\n if (!p) {\n p = (async () => {\n const tex = buildDefaultPbrTexturesExt(engine, gltfMat, sampler, generateMipmaps, getCachedTex, wrapTex);\n const layers = await runMatExts(gltfMat, exts, extCtx);\n return assemblePbrPropsExt(gltfMat, tex, layers);\n })();\n pbrCache.set(gltfMat, p);\n }\n return p;\n };\n\n const originals: VariantMeshEntry[] = [];\n const variants: Record<string, VariantMeshEntry[]> = {};\n for (const name of variantNames) {\n variants[name] = [];\n }\n\n let meshIdx = 0;\n for (let nodeIdx = 0; nodeIdx < json.nodes.length; nodeIdx++) {\n const node = json.nodes[nodeIdx];\n if (node.mesh === undefined) {\n continue;\n }\n const gltfMesh = json.meshes[node.mesh];\n for (const primitive of gltfMesh.primitives) {\n const mesh = meshes[meshIdx]!;\n const variantExt = primitive.extensions?.KHR_materials_variants;\n if (variantExt?.mappings) {\n originals.push({ mesh, material: mesh.material });\n for (const mapping of variantExt.mappings as { material: number; variants: number[] }[]) {\n const gltfMat = await getMat(mapping.material);\n const pbrMat = await getPbr(gltfMat);\n for (const vi of mapping.variants) {\n const name = variantNames[vi];\n if (name) {\n variants[name]!.push({ mesh, material: pbrMat });\n }\n }\n }\n }\n meshIdx++;\n }\n }\n\n return { names: variantNames, variants, originals };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ import { getOrCreateSampler } from '../resource/gpu-pool.js';
|
|
|
8
8
|
import { createMappedBuffer } from '../resource/gpu-buffers.js';
|
|
9
9
|
import { buildParentMap, anyPrimitive, needsOrmComposite, computeNodeWorldMatrix, resolveAccessor, TYPE_SIZES } from './gltf-parser.js';
|
|
10
10
|
import { assembleMaterial, makeImageFetcher } from './gltf-material.js';
|
|
11
|
-
import { identityTexWrap,
|
|
11
|
+
import { identityTexWrap, buildDefaultPbrTextures, assemblePbrProps, uploadTex } from './gltf-pbr-builder.js';
|
|
12
12
|
|
|
13
13
|
let _interleavePromise;
|
|
14
14
|
function loadInterleave() {
|
|
@@ -26,7 +26,8 @@ async function loadGltf(engine, source) {
|
|
|
26
26
|
const { json, binChunk, baseUrl } = await fetchGltfAsset(source);
|
|
27
27
|
const parentMap = buildParentMap(json);
|
|
28
28
|
const worldMatrixCache = /* @__PURE__ */ new Map();
|
|
29
|
-
const
|
|
29
|
+
const featureRegistry = assetUsesGltfFeatures(json) ? await importGltfFeatureRegistry() : void 0;
|
|
30
|
+
const features = featureRegistry ? await featureRegistry.loadGltfFeatures(json) : [];
|
|
30
31
|
let activeBin = binChunk;
|
|
31
32
|
for (const f of features) {
|
|
32
33
|
if (f.preParse) {
|
|
@@ -54,6 +55,7 @@ async function loadGltf(engine, source) {
|
|
|
54
55
|
_parentMap: parentMap,
|
|
55
56
|
_worldMatrixCache: worldMatrixCache,
|
|
56
57
|
_matExts: matExts,
|
|
58
|
+
_runMatExts: featureRegistry?.runGltfMaterialFeatures,
|
|
57
59
|
_wrapTex: wrapTex
|
|
58
60
|
};
|
|
59
61
|
const meshes = await uploadMeshes(meshDatas, features, ctx);
|
|
@@ -92,15 +94,10 @@ function assetUsesGltfFeatures(json) {
|
|
|
92
94
|
anyPrimitive(json, (p) => p.mode !== void 0 && p.mode !== 4) || needsOrmComposite(json);
|
|
93
95
|
}
|
|
94
96
|
function buildNodeHierarchy(json, meshes, meshDatas) {
|
|
95
|
-
const nodeToMeshes =
|
|
97
|
+
const nodeToMeshes = [];
|
|
96
98
|
for (let i = 0; i < meshDatas.length; i++) {
|
|
97
99
|
const ni = meshDatas[i]._nodeIndex;
|
|
98
|
-
|
|
99
|
-
if (!arr) {
|
|
100
|
-
arr = [];
|
|
101
|
-
nodeToMeshes.set(ni, arr);
|
|
102
|
-
}
|
|
103
|
-
arr.push(meshes[i]);
|
|
100
|
+
(nodeToMeshes[ni] ??= []).push(meshes[i]);
|
|
104
101
|
}
|
|
105
102
|
const nodeMap = new Array(json.nodes?.length ?? 0);
|
|
106
103
|
function buildNode(nodeIdx) {
|
|
@@ -121,7 +118,7 @@ function buildNodeHierarchy(json, meshes, meshDatas) {
|
|
|
121
118
|
tn.children.push(buildNode(childIdx));
|
|
122
119
|
}
|
|
123
120
|
}
|
|
124
|
-
const nodeMeshes = nodeToMeshes
|
|
121
|
+
const nodeMeshes = nodeToMeshes[nodeIdx] ?? [];
|
|
125
122
|
tn.children.push(...nodeMeshes);
|
|
126
123
|
return tn;
|
|
127
124
|
}
|
|
@@ -132,16 +129,11 @@ function buildNodeHierarchy(json, meshes, meshDatas) {
|
|
|
132
129
|
return { root, nodeMap };
|
|
133
130
|
}
|
|
134
131
|
async function extractAllMeshes(json, binChunk, baseUrl, parentMap, worldMatrixCache, decodedPrimitives) {
|
|
135
|
-
const imageCache =
|
|
136
|
-
const matCache =
|
|
132
|
+
const imageCache = [];
|
|
133
|
+
const matCache = [];
|
|
137
134
|
const getMat = (matIdx) => {
|
|
138
|
-
const key = matIdx ?? -1;
|
|
139
|
-
|
|
140
|
-
if (!p) {
|
|
141
|
-
p = assembleMaterial(json, binChunk, matIdx, baseUrl, imageCache);
|
|
142
|
-
matCache.set(key, p);
|
|
143
|
-
}
|
|
144
|
-
return p;
|
|
135
|
+
const key = (matIdx ?? -1) + 1;
|
|
136
|
+
return matCache[key] ??= assembleMaterial(json, binChunk, key - 1, baseUrl, imageCache);
|
|
145
137
|
};
|
|
146
138
|
const partials = [];
|
|
147
139
|
const matPromises = [];
|
|
@@ -247,22 +239,20 @@ async function uploadMeshes(meshDatas, features, ctx) {
|
|
|
247
239
|
await ensureMipmapModule();
|
|
248
240
|
const meshFeatures = features.filter((f) => f.applyMesh);
|
|
249
241
|
const texCache = /* @__PURE__ */ new Map();
|
|
250
|
-
let texId = 0;
|
|
251
|
-
const bitmapIds = /* @__PURE__ */ new Map();
|
|
252
242
|
function getCachedTexture(bitmap, srgb) {
|
|
253
|
-
let
|
|
254
|
-
if (
|
|
255
|
-
|
|
243
|
+
let textures = texCache.get(bitmap);
|
|
244
|
+
if (!textures) {
|
|
245
|
+
texCache.set(bitmap, textures = []);
|
|
256
246
|
}
|
|
257
|
-
const key =
|
|
258
|
-
let tex =
|
|
247
|
+
const key = +srgb;
|
|
248
|
+
let tex = textures[key];
|
|
259
249
|
if (!tex) {
|
|
260
250
|
tex = uploadTex(engine, bitmap, srgb, sampler, _generateMipmaps);
|
|
261
|
-
|
|
251
|
+
textures[key] = tex;
|
|
262
252
|
}
|
|
263
253
|
return tex;
|
|
264
254
|
}
|
|
265
|
-
const extImageCache = matExts.length ?
|
|
255
|
+
const extImageCache = matExts.length ? [] : null;
|
|
266
256
|
const extFetchImg = extImageCache ? makeImageFetcher(json, binChunk, baseUrl, extImageCache) : null;
|
|
267
257
|
const extCtx = {
|
|
268
258
|
_engine: engine,
|
|
@@ -293,7 +283,7 @@ async function uploadMeshes(meshDatas, features, ctx) {
|
|
|
293
283
|
return cached;
|
|
294
284
|
}
|
|
295
285
|
cached = (async () => {
|
|
296
|
-
const extLayers = await
|
|
286
|
+
const extLayers = matExts.length ? await ctx._runMatExts(mat, matExts, extCtx) : void 0;
|
|
297
287
|
if (_needsPbrExt) {
|
|
298
288
|
const extMod = await _ensurePbrExt();
|
|
299
289
|
const tex2 = extMod.buildDefaultPbrTexturesExt(engine, mat, sampler, _generateMipmaps, getCachedTexture, wrapTex, samplerFor);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-gltf.js","sources":["../../../src/loader-gltf/load-gltf.ts"],"sourcesContent":["import { 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 { computeAabb } from \"../math/compute-aabb.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { TransformNode } from \"../scene/transform-node.js\";\nimport type { AssetContainer } from \"../asset-container.js\";\nimport { createTransformNode } from \"../scene/transform-node.js\";\nimport { createSceneNodeFromMatrix } from \"../scene/scene-node.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport type { Mesh, MeshGPU } from \"../mesh/mesh.js\";\nimport { initMeshTransform } from \"../mesh/mesh.js\";\nimport { getOrCreateSampler } from \"../resource/gpu-pool.js\";\nimport { createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport { resolveAccessor, buildParentMap, computeNodeWorldMatrix, anyPrimitive, needsOrmComposite, TYPE_SIZES } from \"./gltf-parser.js\";\nimport type { AccessorView } from \"./gltf-parser.js\";\nimport type { GltfVb } from \"./gltf-interleave.js\";\nimport type { GltfMaterialData, GltfMatExtCtx } from \"./gltf-material.js\";\nimport { assembleMaterial, makeImageFetcher } from \"./gltf-material.js\";\nimport type { DecodedPrimitive, GltfFeature, GltfLoadCtx } from \"./gltf-feature.js\";\nimport type { TextureWrapFn } from \"./gltf-pbr-builder.js\";\nimport { assemblePbrProps, buildDefaultPbrTextures, identityTexWrap, runMatExts, uploadTex } from \"./gltf-pbr-builder.js\";\nimport type * as GltfColorNormalize from \"./gltf-color-normalize.js\";\nimport type * as GltfFeatureRegistry from \"./gltf-feature-registry.js\";\nimport type * as GltfPbrBuilderExt from \"./gltf-pbr-builder-ext.js\";\n\n/** Dynamically-imported interleave module — loaded only when an asset actually\n * contains a strided bufferView, so non-interleaved scenes pay zero cost. */\ntype InterleaveModule = typeof import(\"./gltf-interleave.js\");\nlet _interleavePromise: Promise<InterleaveModule> | undefined;\nfunction loadInterleave(): Promise<InterleaveModule> {\n return (_interleavePromise ??= import(\"./gltf-interleave.js\"));\n}\n\nlet _gltfFeatureRegistryPromise: Promise<typeof GltfFeatureRegistry> | undefined;\nfunction importGltfFeatureRegistry(): Promise<typeof GltfFeatureRegistry> {\n return (_gltfFeatureRegistryPromise ??= import(\"./gltf-feature-registry.js\"));\n}\n\nlet _colorNormalizePromise: Promise<typeof GltfColorNormalize> | undefined;\nfunction importColorNormalize(): Promise<typeof GltfColorNormalize> {\n return (_colorNormalizePromise ??= import(\"./gltf-color-normalize.js\"));\n}\n\n/** Parsed mesh data ready for GPU upload. */\nexport interface GltfMeshData {\n /** @internal Tight CPU positions, or null when sourced from an interleaved\n * bufferView (in which case `_vb._p` holds the strided source for lazy de-striding). */\n _positions: Float32Array | null;\n /** @internal */\n _normals: Float32Array | null;\n /** @internal */\n _tangents: Float32Array | null;\n /** @internal */\n _uvs: Float32Array | null;\n /** @internal */\n _uv2s: Float32Array | null;\n /** @internal */\n _colors: Float32Array | null;\n /** @internal Primitive had no NORMAL attribute → flat-shade (glTF spec). */\n _flatNormal?: boolean;\n /** @internal Non-triangle-list primitive topology index (1=points, 2=lines,\n * 3=line-strip, 4=triangle-strip) from the glTF primitive `mode`. Undefined =\n * triangle-list (the default). LINE_LOOP/TRIANGLE_FAN are unsupported (so is BJS). */\n _topology?: number;\n /** @internal */\n _indices: Uint16Array | Uint32Array;\n /** @internal */\n _vertexCount: number;\n /** @internal */\n _indexCount: number;\n /** @internal */\n _worldMatrix: Mat4;\n /** @internal */\n _material: GltfMaterialData;\n /** @internal Interleaved vertex sources (genuine GPU interleaving + lazy CPU de-stride).\n * Absent → all tight. */\n _vb?: GltfVb;\n /** @internal glTF node index this mesh came from (for hierarchy reconstruction\n * and for features that need to resolve skin/morph data lazily). */\n _nodeIndex: number;\n /** @internal Raw primitive definition — features (skeleton, morph, …) read their\n * own attributes/targets from here without bloating core extraction. */\n _primitive: any;\n /** @internal Pre-decoded primitive (Draco et al.) if a preMesh feature produced one. */\n _decoded?: DecodedPrimitive;\n}\n\n/**\n * Load a glTF/GLB asset, parse it, and upload mesh + material data to GPU.\n * Registers a deferred PBR renderable builder and automatically parses glTF\n * animations if present.\n *\n * Returns an {@link AssetContainer}. Pass it to {@link addToScene} which adds the\n * hierarchy, registers animation ticks, and applies any scene-level settings.\n *\n * The `source` may be either:\n * - **A URL (`string`)** — fetches the asset. Supports both binary GLB and\n * separate `.gltf` + `.bin` + image files; relative `.bin`/image paths are\n * resolved against the URL.\n * - **Raw data (`ArrayBuffer` | `Blob`)** — loads from already-loaded local data\n * (drag-and-drop, OPFS, a `fetch` body, etc.). GLB-vs-glTF is determined from\n * the data's magic bytes, not a file extension. Because raw data has no base\n * URL it must be self-contained: a GLB, or a glTF whose buffers/images use\n * `data:` URIs. A glTF that references external `.bin`/image files by relative\n * path can only be loaded from a URL.\n *\n * @param engine - The engine to upload GPU resources to.\n * @param source - A URL string, or the raw `ArrayBuffer`/`Blob` of a self-contained glTF/GLB asset.\n */\nexport async function loadGltf(engine: EngineContext, source: string | ArrayBuffer | Blob): Promise<AssetContainer> {\n const { json, binChunk, baseUrl } = await fetchGltfAsset(source);\n\n // Build parent map + world-matrix cache once for O(n) hierarchy traversal\n const parentMap = buildParentMap(json);\n const worldMatrixCache = new Map<number, Mat4>();\n\n // Discover every triggered feature (material exts, skeleton, morph,\n // animations, variants, …). The feature registry + its ~24 dynamic-import\n // thunks live in a separate module that is itself dynamic-imported only when\n // the asset can possibly trigger a feature — so plain metallic-roughness\n // GLBs (no extensions/animations/skins/morphs/ORM-composite) never fetch the\n // registry. Core loader knows zero feature names.\n const features = assetUsesGltfFeatures(json) ? await (await importGltfFeatureRegistry()).loadGltfFeatures(json) : [];\n\n // Pre-parse hooks (EXT_meshopt_compression decompression, KHR_mesh_quantization\n // dequantization) may rewrite bufferViews/accessors and hand back a replacement\n // binary chunk. Run sequentially in registry order so later features see earlier\n // rewrites. No-op (and zero cost) when no triggered feature defines preParse.\n let activeBin = binChunk;\n for (const f of features) {\n if (f.preParse) {\n const replacement = await f.preParse(json, activeBin);\n if (replacement) {\n activeBin = replacement;\n }\n }\n }\n\n const matExts: GltfFeature[] = features.filter((f) => f.applyMaterial);\n // Compose every feature's wrapTexture hook into a single function. Identity\n // when no feature contributes one (common case) — keeps the hot path free\n // of per-texture work and lets bundlers tree-shake the helpers.\n const texWraps = features.filter((f) => f.wrapTexture).map((f) => f.wrapTexture!);\n const wrapTex: TextureWrapFn = !texWraps.length ? identityTexWrap : (tex, ti) => texWraps.reduce((acc, w) => w(acc, ti), tex);\n\n // Run every feature's pre-mesh hook (e.g. Draco decompression) and merge\n // their primitive-keyed decode caches. Features without `preMesh` contribute\n // nothing; the map stays empty when no primitive-level feature triggered.\n const decodedPrimitives = new Map<unknown, DecodedPrimitive>();\n for (const frag of await Promise.all(features.flatMap((f) => (f.preMesh ? [f.preMesh(json, activeBin, baseUrl)] : [])))) {\n for (const [k, v] of frag) {\n decodedPrimitives.set(k, v);\n }\n }\n\n const meshDatas = await extractAllMeshes(json, activeBin, baseUrl, parentMap, worldMatrixCache, decodedPrimitives);\n\n const ctx: GltfLoadCtx = {\n _engine: engine,\n _json: json,\n _binChunk: activeBin,\n _baseUrl: baseUrl,\n _parentMap: parentMap,\n _worldMatrixCache: worldMatrixCache,\n _matExts: matExts,\n _wrapTex: wrapTex,\n };\n\n const meshes = await uploadMeshes(meshDatas, features, ctx);\n\n // Build TransformNode hierarchy from glTF nodes. Returns both the synthetic root\n // and a glTF-node-index → SceneNode map (used by node-visibility + animation-pointer).\n const { root, nodeMap } = buildNodeHierarchy(json, meshes, meshDatas);\n ctx._nodeMap = nodeMap;\n\n // Run every feature's per-asset hook (animations, variants, metadata, …) and\n // merge the returned AssetContainer fragments. `entities` is appended (never\n // overwritten) so features like KHR_lights_punctual can contribute lights\n // without trampling the root TransformNode.\n const assetFragments = await Promise.all(features.flatMap((f) => (f.applyAsset ? [f.applyAsset(meshes, root, ctx)] : [])));\n const container: AssetContainer = { entities: [root] };\n for (const frag of assetFragments) {\n if (frag.entities?.length) {\n container.entities.push(...frag.entities);\n }\n const { entities: _ignored, ...rest } = frag;\n void _ignored;\n Object.assign(container, rest);\n }\n return container;\n}\n\n/** Fetch/resolve + parse a glTF or GLB asset from a URL string, ArrayBuffer, or Blob.\n * Returns the JSON, binary chunk, and base URL (empty for non-URL sources). */\nasync function fetchGltfAsset(source: string | ArrayBuffer | Blob): Promise<{ json: any; binChunk: DataView; baseUrl: string }> {\n // Resolve the source to bytes. Only a URL string yields a base URL for resolving external .bin/image\n // references; ArrayBuffer/Blob inputs are self-contained (GLB, or glTF with data: URIs).\n const isUrl = typeof source === \"string\";\n // Resolve the source to an absolute URL so external .bin / image URIs resolve correctly even when the\n // caller passes a root-relative (\"/models/foo.gltf\") or document-relative path — `new URL(uri, base)`\n // downstream requires an absolute base. Absolute inputs (https://…) are returned unchanged. In a\n // non-DOM context (Node / a worker without `location`) fall back to a plain directory-prefix base.\n const baseUrl = !isUrl ? \"\" : typeof location !== \"undefined\" ? new URL(\".\", new URL(source, location.href)).href : source.slice(0, source.lastIndexOf(\"/\") + 1);\n const buffer = isUrl ? await fetch(source).then((r) => r.arrayBuffer()) : source instanceof Blob ? await source.arrayBuffer() : source;\n\n // Classify by the GLB magic (\"glTF\" = 0x46546c67, little-endian) rather than the URL extension, so\n // object URLs (blob:…), OPFS handles, and extensionless sources are detected correctly. The length guard\n // keeps an empty/too-short input failing with the JSON/GLB parse error below, not a DataView RangeError.\n if (buffer.byteLength >= 4 && new DV(buffer).getUint32(0, true) === 0x46546c67) {\n const glb = await import(\"./gltf-glb-parser.js\");\n return { ...glb.parseGlbContainer(buffer), baseUrl };\n }\n\n const jsonAsset = await import(\"./gltf-json-asset.js\");\n return jsonAsset.parseGltfJsonAsset(buffer, baseUrl);\n}\n\n/** Cheap superset gate: returns true iff the asset can possibly trigger at least\n * one optional glTF feature. Every `_features` predicate in gltf-feature-registry\n * is implied by one of these buckets (all hasExt/hasMatExt features require a\n * non-empty `extensionsUsed`), so when this returns false the registry's\n * `loadGltfFeatures` would return `[]` anyway — letting the core loader skip the\n * registry import entirely and keep its ~24 feature import-thunks out of the\n * bundle for plain metallic-roughness assets. */\nfunction assetUsesGltfFeatures(json: any) {\n return (\n json.extensionsUsed?.length ||\n json.animations?.length ||\n JSON.stringify(json).includes(\"extras\") ||\n (json.skins?.length && anyPrimitive(json, (p) => p.attributes?.JOINTS_0 !== undefined)) ||\n anyPrimitive(json, (p) => !!p.targets?.length) ||\n // A node with a negative-determinant local transform (odd negative scale, or a `matrix`\n // with negative 3x3 determinant) may need the negative-winding feature. This mirrors the\n // registry's `hasNegDetNode` predicate so a positive-determinant `matrix` node — extremely\n // common, e.g. TextureSettingsTest — does NOT needlessly pull the feature registry.\n (json.nodes as any[] | undefined)?.some((n: any) =>\n n.scale\n ? n.scale[0] * n.scale[1] * n.scale[2] < 0\n : n.matrix\n ? n.matrix[0] * (n.matrix[5] * n.matrix[10] - n.matrix[6] * n.matrix[9]) +\n n.matrix[1] * (n.matrix[6] * n.matrix[8] - n.matrix[4] * n.matrix[10]) +\n n.matrix[2] * (n.matrix[4] * n.matrix[9] - n.matrix[5] * n.matrix[8]) <\n 0\n : false\n ) ||\n // Non-triangle primitive topology (POINTS/LINES/LINE_STRIP/TRIANGLE_STRIP).\n anyPrimitive(json, (p) => p.mode !== undefined && p.mode !== 4) ||\n needsOrmComposite(json)\n );\n}\n\n// --- Hierarchy Reconstruction ---\n\n/** Build a TransformNode tree mirroring the glTF node hierarchy.\n * Meshes are attached as children. Non-mesh nodes become\n * pure TransformNodes preserving TRS for cloning/repositioning.\n * Parent links are set by addToScene() when the tree is added to the scene.\n * Also returns a glTF-node-index → SceneNode map used by per-asset features\n * (KHR_node_visibility, KHR_animation_pointer) to address specific nodes. */\nfunction buildNodeHierarchy(json: any, meshes: Mesh[], meshDatas: GltfMeshData[]): { root: TransformNode; nodeMap: (TransformNode | undefined)[] } {\n // Map nodeIndex → uploaded Mesh[]\n const nodeToMeshes = new Map<number, Mesh[]>();\n for (let i = 0; i < meshDatas.length; i++) {\n const ni = meshDatas[i]!._nodeIndex;\n let arr = nodeToMeshes.get(ni);\n if (!arr) {\n arr = [];\n nodeToMeshes.set(ni, arr);\n }\n arr.push(meshes[i]!);\n }\n\n const nodeMap: (TransformNode | undefined)[] = new Array(json.nodes?.length ?? 0);\n\n // Recursive builder\n function buildNode(nodeIdx: number): TransformNode {\n const node = json.nodes[nodeIdx];\n const name = node.name ?? `node_${nodeIdx}`;\n let tn: TransformNode;\n if (node.matrix) {\n tn = createSceneNodeFromMatrix(name, node.matrix as Mat4);\n } else {\n const t = node.translation ?? [0, 0, 0];\n const r = node.rotation ?? [0, 0, 0, 1];\n const s = node.scale ?? [1, 1, 1];\n tn = createTransformNode(name, t[0], t[1], t[2], r[0], r[1], r[2], r[3], s[0], s[1], s[2]);\n }\n nodeMap[nodeIdx] = tn;\n if (node.children) {\n for (const childIdx of node.children) {\n tn.children.push(buildNode(childIdx));\n }\n }\n const nodeMeshes = nodeToMeshes.get(nodeIdx) ?? [];\n tn.children.push(...nodeMeshes);\n return tn;\n }\n\n // Synthetic root (like BJS __root__) — applies RH→LH conversion via scale\n // BJS: rotation [0,1,0,0] + scale [1,1,-1] = diag(-1, 1, 1, 1)\n const sceneRoots: number[] = json.scenes?.[json.scene ?? 0]?.nodes ?? [];\n const rootChildren = sceneRoots.map((ni: number) => buildNode(ni));\n const root = createTransformNode(\"__root__\", 0, 0, 0, 0, 0, 0, 1, -1, 1, 1);\n root.children.push(...rootChildren);\n return { root, nodeMap };\n}\n\n// --- Mesh Extraction ---\n\nasync function extractAllMeshes(\n json: any,\n binChunk: DataView,\n baseUrl: string,\n parentMap: Map<number, number>,\n worldMatrixCache: Map<number, Mat4>,\n decodedPrimitives: Map<unknown, DecodedPrimitive>\n): Promise<GltfMeshData[]> {\n // Per-load image cache — avoids decoding the same glTF image index multiple times\n const imageCache = new Map<number, Promise<ImageBitmap>>();\n\n // Cache material assembly by glTF material index — avoids duplicate image fetches\n const matCache = new Map<number, Promise<GltfMaterialData>>();\n const getMat = (matIdx: number): Promise<GltfMaterialData> => {\n const key = matIdx ?? -1;\n let p = matCache.get(key);\n if (!p) {\n p = assembleMaterial(json, binChunk, matIdx, baseUrl, imageCache);\n matCache.set(key, p);\n }\n return p;\n };\n\n // First pass: do all sync work, fire all material fetches concurrently\n const partials: Array<Omit<GltfMeshData, \"_material\">> = [];\n const matPromises: Promise<GltfMaterialData>[] = [];\n\n // Genuine GPU interleaving is the ONLY reason to touch the interleave module.\n // Many exporters declare `byteStride` even on tightly-packed bufferViews, and a\n // preMesh feature (e.g. the basisu extension's readStridedFloat path) may already\n // de-stride a primitive — so we load the module only for a primitive that is\n // genuinely over-strided AND not already decoded. Other scenes pay zero cost: the\n // module is fetched lazily on the first such primitive (memoized), never before.\n const _accs = json.accessors as any[];\n const _bvs = json.bufferViews as any[] | undefined;\n const _strided = (p: any): boolean => {\n for (const k in p.attributes) {\n const a = _accs[p.attributes[k]];\n const s = _bvs?.[a?.bufferView]?.byteStride;\n if (\n s !== undefined &&\n s !== (TYPE_SIZES[a.type] ?? 1) * (a.componentType === 5126 || a.componentType === 5125 ? 4 : a.componentType === 5123 || a.componentType === 5122 ? 2 : 1)\n ) {\n return true;\n }\n }\n return false;\n };\n\n for (let nodeIdx = 0; nodeIdx < json.nodes.length; nodeIdx++) {\n const node = json.nodes[nodeIdx];\n if (node.mesh === undefined) {\n continue;\n }\n\n const meshIndex = node.mesh as number;\n const mesh = json.meshes[meshIndex];\n const worldMatrix = computeNodeWorldMatrix(json, nodeIdx, parentMap, worldMatrixCache);\n\n for (let primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {\n const primitive = mesh.primitives[primitiveIndex];\n const attrs = primitive.attributes;\n const decoded = decodedPrimitives.get(primitive);\n\n // Genuine GPU interleaving: only a primitive that genuinely sources ≥1\n // attribute from an over-strided bufferView (and was not already decoded\n // by a preMesh feature) takes this path. The module is imported lazily on\n // first need — non-interleaved assets never fetch it. Tight primitives\n // fall through to the path below (byte-identical to non-interleaved).\n if (!decoded && _strided(primitive)) {\n const ip = await (await loadInterleave()).buildInterleavedPartial(json, binChunk, primitive, worldMatrix, nodeIdx);\n if (ip) {\n matPromises.push(getMat(primitive.material));\n partials.push(ip);\n continue;\n }\n }\n\n const resolveAttr = (name: string): AccessorView | null => {\n if (decoded && decoded._attributes.has(name)) {\n const data = decoded._attributes.get(name)!;\n const componentCount = data.length / decoded._vertexCount;\n return { _data: data, _count: decoded._vertexCount, _componentCount: componentCount };\n }\n const idx = attrs[name];\n return idx !== undefined ? resolveAccessor(json, binChunk, idx) : null;\n };\n const posData = resolveAttr(\"POSITION\")!;\n const normData = resolveAttr(\"NORMAL\");\n const uvData = resolveAttr(\"TEXCOORD_0\");\n const uv2Data = resolveAttr(\"TEXCOORD_1\");\n const tanData = resolveAttr(\"TANGENT\");\n const colorData = resolveAttr(\"COLOR_0\");\n const idxData = decoded\n ? decoded._indexCount > 0\n ? { _data: decoded._indices, _count: decoded._indexCount, _componentCount: 1 }\n : null\n : primitive.indices !== undefined\n ? resolveAccessor(json, binChunk, primitive.indices)\n : null;\n const normalsHelper = !idxData || !normData ? await import(\"./gltf-normals.js\") : null;\n // glTF COLOR_0 may be VEC3 or VEC4 with float, normalized ubyte, or normalized\n // ushort components, but the PBR pipeline binds vertex color as a single\n // float32x4 layout (rgb modulates base color, a modulates alpha). Normalize any\n // source to a tight float32 RGBA buffer so the GPU stride matches the layout\n // (otherwise every vertex misaligns -> garbage/black); a VEC3 source gets a=1.\n // The normalizer is imported lazily on first need — colorless assets never fetch it\n // (the runtime caches the module, so the per-primitive import() resolves instantly).\n const colors = colorData ? (await importColorNormalize()).normalizeColorToVec4(colorData._data, colorData._count, colorData._componentCount) : null;\n\n // TEXCOORD_0/_1 may be FLOAT or a normalized UNSIGNED_BYTE/SHORT accessor; the vertex\n // pipeline binds UVs as float32x2, so integer UVs are denormalized to [0,1] (reusing the\n // lazily-imported color/UV normalizer). Float UVs (the common case) pass through untouched.\n const uvs = uvData\n ? uvData._data instanceof F32\n ? (uvData._data as Float32Array)\n : (await importColorNormalize()).normalizeUvToVec2(uvData._data, uvData._count)\n : new F32(posData._count * 2);\n const uv2s = uv2Data\n ? uv2Data._data instanceof F32\n ? (uv2Data._data as Float32Array)\n : (await importColorNormalize()).normalizeUvToVec2(uv2Data._data, uv2Data._count)\n : null;\n\n // Keep vertex data as-is from glTF — RH→LH conversion handled by root world matrix\n const indices = idxData\n ? idxData._data instanceof U32\n ? new U32(idxData._data as Uint32Array)\n : idxData._data instanceof U8\n ? Uint16Array.from(idxData._data as Uint8Array)\n : new U16(idxData._data!.buffer, idxData._data!.byteOffset, idxData._count)\n : normalsHelper!.createSequentialIndices(posData._count);\n\n // Fire material fetch without awaiting — all materials load in parallel\n matPromises.push(getMat(primitive.material));\n\n // Smooth-normal generation is lazily imported on first need — assets that\n // always provide NORMAL (the common case) never bundle or fetch this code.\n const normals = normData ? (normData._data as Float32Array) : normalsHelper!.computeSmoothNormals(posData._data as Float32Array, indices, posData._count);\n\n partials.push({\n _positions: posData._data as Float32Array,\n _normals: normals,\n _tangents: tanData ? (tanData._data as Float32Array) : null,\n _uvs: uvs,\n _uv2s: uv2s,\n _colors: colors,\n _flatNormal: !normData,\n _indices: indices,\n _vertexCount: posData._count,\n _indexCount: indices.length,\n _worldMatrix: worldMatrix,\n _nodeIndex: nodeIdx,\n _primitive: primitive,\n _decoded: decoded,\n });\n }\n }\n\n // Resolve all material fetches in parallel\n const materials = await Promise.all(matPromises);\n return partials.map((p, i) => ({ ...p, _material: materials[i]! }));\n}\n\n// --- GPU Upload ---\n\n// Pre-resolved generateMipmaps function— loaded once before texture uploads\nlet _generateMipmaps: ((engine: EngineContext, texture: GPUTexture, face?: number) => void) | null = null;\n\nasync function ensureMipmapModule(): Promise<void> {\n if (!_generateMipmaps) {\n _generateMipmaps = (await import(\"../texture/generate-mipmaps.js\")).generateMipmaps;\n }\n}\n\nasync function uploadMeshes(meshDatas: GltfMeshData[], features: GltfFeature[], ctx: GltfLoadCtx): Promise<Mesh[]> {\n const { _engine: engine, _json: json, _binChunk: binChunk, _baseUrl: baseUrl, _matExts: matExts, _wrapTex: wrapTex } = ctx;\n // Default sampler (repeat/linear) used for factor textures and when a texture has no glTF sampler.\n const sampler = getOrCreateSampler(engine, {\n magFilter: \"linear\",\n minFilter: \"linear\",\n mipmapFilter: \"linear\",\n addressModeU: \"repeat\",\n addressModeV: \"repeat\",\n maxAnisotropy: 4,\n });\n // Per-texture glTF samplers (wrap/filter) are honored only when the asset declares a\n // NON-default sampler (clamp/mirror wrap, or nearest filtering); the common case\n // (default repeat/linear) uses the single shared sampler above and the master-identical\n // buildDefaultPbrTextures path. Both the descriptor logic AND the sampler-aware texture\n // builder are lazy so default-sampler assets pay zero bundle bytes for the feature.\n let samplerFor: ((texInfo: any) => GPUSampler) | undefined;\n let buildSampledPbrTextures: typeof import(\"./gltf-sampler-desc.js\").buildSampledPbrTextures | undefined;\n if (json.samplers?.some((s: any) => s.wrapS > 10497 || s.wrapT > 10497 || s.magFilter === 9728 || (s.minFilter != null && s.minFilter !== 9729 && s.minFilter !== 9987))) {\n const mod = await import(\"./gltf-sampler-desc.js\");\n samplerFor = mod.makeSamplerFor(engine, json, sampler);\n buildSampledPbrTextures = mod.buildSampledPbrTextures;\n }\n\n await ensureMipmapModule();\n const meshFeatures = features.filter((f) => f.applyMesh);\n\n // Texture cache: shared textures uploaded once, keyed by (bitmap, srgb).\n const texCache = new Map<number, Texture2D>();\n let texId = 0;\n const bitmapIds = new Map<ImageBitmap, number>();\n\n function getCachedTexture(bitmap: ImageBitmap, srgb: boolean): Texture2D {\n let id = bitmapIds.get(bitmap);\n if (id === undefined) {\n bitmapIds.set(bitmap, (id = texId++));\n }\n const key = id * 2 + +srgb;\n let tex = texCache.get(key);\n if (!tex) {\n tex = uploadTex(engine, bitmap, srgb, sampler, _generateMipmaps!);\n texCache.set(key, tex);\n }\n return tex;\n }\n\n // Per-load image fetcher for ext modules (uses same image cache as core).\n const extImageCache = matExts.length ? new Map<number, Promise<ImageBitmap>>() : null;\n const extFetchImg = extImageCache ? makeImageFetcher(json, binChunk, baseUrl, extImageCache) : null;\n const extCtx: GltfMatExtCtx = {\n _engine: engine,\n async _texture(texInfo, sRGB) {\n if (!texInfo || !extFetchImg) {\n return undefined;\n }\n const img = await extFetchImg(texInfo);\n return img ? wrapTex(getCachedTexture(img, sRGB), texInfo) : undefined;\n },\n _uploadImage(bitmap, sRGB) {\n return uploadTex(engine, bitmap, sRGB, sampler, _generateMipmaps!);\n },\n };\n\n // Slow-path trigger: per-texture UV wrapping (KHR_texture_transform)\n // or any core texture declaring texCoord=1. Scene1 stays identity→fast path.\n let _needsPbrExt = wrapTex !== identityTexWrap;\n if (!_needsPbrExt) {\n const mats = (json as { materials?: unknown[] }).materials;\n if (mats && JSON.stringify(mats).includes('\"texCoord\":1')) {\n _needsPbrExt = true;\n }\n }\n let _pbrExtPromise: Promise<typeof GltfPbrBuilderExt> | null = null;\n const _ensurePbrExt = () => (_pbrExtPromise ??= import(\"./gltf-pbr-builder-ext.js\"));\n\n /** Default ORM upload: single MR-or-occlusion image, or 1×1 fallback baked from\n * metallicFactor/roughnessFactor. The composite case (MR+occlusion separate) is\n * handled by the gltf-ext-orm extension which overrides this via `extLayers`. */\n\n // Build a PbrMaterialProps from parsed glTF material data.\n // Uses shared texture caches so identical bitmaps are uploaded once.\n const builtMaterialCache = new Map<GltfMaterialData, Promise<PbrMaterialProps>>();\n async function buildPbrFromGltfMat(mat: GltfMaterialData): Promise<PbrMaterialProps> {\n let cached = builtMaterialCache.get(mat);\n if (cached) {\n return cached;\n }\n cached = (async () => {\n const extLayers = await runMatExts(mat, matExts, extCtx);\n if (_needsPbrExt) {\n const extMod = await _ensurePbrExt();\n const tex = extMod.buildDefaultPbrTexturesExt(engine, mat, sampler, _generateMipmaps!, getCachedTexture, wrapTex, samplerFor);\n return extMod.assemblePbrPropsExt(mat, tex, extLayers);\n }\n const tex = buildSampledPbrTextures\n ? buildSampledPbrTextures(engine, mat, sampler, _generateMipmaps!, samplerFor!, getCachedTexture)\n : buildDefaultPbrTextures(engine, mat, sampler, _generateMipmaps!, getCachedTexture);\n return assemblePbrProps(mat, tex.baseColorTexture, tex.ormTexture, tex.normalTexture, tex.emissiveTexture, extLayers);\n })();\n builtMaterialCache.set(mat, cached);\n return cached;\n }\n\n const meshes = await Promise.all(\n meshDatas.map(async (m, i): Promise<Mesh> => {\n const material = await buildPbrFromGltfMat(m._material);\n const meshName = json.meshes[json.nodes[m._nodeIndex].mesh].name;\n\n // Interleaved meshes are fully built by the dynamic module (kept out of\n // this bundle for non-interleaved scenes). The tight path below is\n // byte-identical to the non-interleaved engine.\n let mesh: Mesh;\n if (m._vb) {\n mesh = (await loadInterleave()).buildInterleavedMesh(engine, m, i, material, meshName) as Mesh;\n } else {\n const [boundMin, boundMax] = computeAabb(m._positions!, m._worldMatrix);\n const gpu: MeshGPU = {\n positionBuffer: createMappedBuffer(engine, m._positions!, BU.VERTEX),\n normalBuffer: createMappedBuffer(engine, m._normals!, BU.VERTEX),\n tangentBuffer: m._tangents ? createMappedBuffer(engine, m._tangents, BU.VERTEX) : null,\n uvBuffer: createMappedBuffer(engine, m._uvs!, BU.VERTEX),\n uv2Buffer: m._uv2s ? createMappedBuffer(engine, m._uv2s, BU.VERTEX) : null,\n colorBuffer: m._colors ? createMappedBuffer(engine, m._colors, BU.VERTEX) : null,\n indexBuffer: createMappedBuffer(engine, m._indices, BU.INDEX),\n indexCount: m._indexCount,\n indexFormat: (m._indices instanceof U32 ? \"uint32\" : \"uint16\") as GPUIndexFormat,\n };\n\n mesh = {\n name: meshName || `gltf_mesh_${i}`,\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 // Retain CPU geometry for detailed picking.\n mesh._cpuPositions = m._positions!;\n mesh._cpuNormals = m._normals!;\n mesh._cpuUvs = m._uvs!;\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\n // Run all per-mesh feature hooks (skeleton, morph, …) in parallel.\n // Each hook mutates `mesh` directly (e.g. attaches mesh.skeleton).\n if (meshFeatures.length > 0) {\n await Promise.all(meshFeatures.map((f) => f.applyMesh!(m, mesh, ctx)));\n }\n\n return mesh;\n })\n );\n\n return meshes;\n}\n"],"names":["tex"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"load-gltf.js","sources":["../../../src/loader-gltf/load-gltf.ts"],"sourcesContent":["import { 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 { computeAabb } from \"../math/compute-aabb.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { TransformNode } from \"../scene/transform-node.js\";\nimport type { AssetContainer } from \"../asset-container.js\";\nimport { createTransformNode } from \"../scene/transform-node.js\";\nimport { createSceneNodeFromMatrix } from \"../scene/scene-node.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport type { Mesh, MeshGPU } from \"../mesh/mesh.js\";\nimport { initMeshTransform } from \"../mesh/mesh.js\";\nimport { getOrCreateSampler } from \"../resource/gpu-pool.js\";\nimport { createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport { resolveAccessor, buildParentMap, computeNodeWorldMatrix, anyPrimitive, needsOrmComposite, TYPE_SIZES } from \"./gltf-parser.js\";\nimport type { AccessorView } from \"./gltf-parser.js\";\nimport type { GltfVb } from \"./gltf-interleave.js\";\nimport type { GltfImageCache, GltfMaterialData, GltfMatExtCtx } from \"./gltf-material.js\";\nimport { assembleMaterial, makeImageFetcher } from \"./gltf-material.js\";\nimport type { DecodedPrimitive, GltfFeature, GltfLoadCtx } from \"./gltf-feature.js\";\nimport type { TextureWrapFn } from \"./gltf-pbr-builder.js\";\nimport { assemblePbrProps, buildDefaultPbrTextures, identityTexWrap, uploadTex } from \"./gltf-pbr-builder.js\";\nimport type * as GltfColorNormalize from \"./gltf-color-normalize.js\";\nimport type * as GltfFeatureRegistry from \"./gltf-feature-registry.js\";\nimport type * as GltfPbrBuilderExt from \"./gltf-pbr-builder-ext.js\";\n\n/** Dynamically-imported interleave module — loaded only when an asset actually\n * contains a strided bufferView, so non-interleaved scenes pay zero cost. */\ntype InterleaveModule = typeof import(\"./gltf-interleave.js\");\nlet _interleavePromise: Promise<InterleaveModule> | undefined;\nfunction loadInterleave(): Promise<InterleaveModule> {\n return (_interleavePromise ??= import(\"./gltf-interleave.js\"));\n}\n\nlet _gltfFeatureRegistryPromise: Promise<typeof GltfFeatureRegistry> | undefined;\nfunction importGltfFeatureRegistry(): Promise<typeof GltfFeatureRegistry> {\n return (_gltfFeatureRegistryPromise ??= import(\"./gltf-feature-registry.js\"));\n}\n\nlet _colorNormalizePromise: Promise<typeof GltfColorNormalize> | undefined;\nfunction importColorNormalize(): Promise<typeof GltfColorNormalize> {\n return (_colorNormalizePromise ??= import(\"./gltf-color-normalize.js\"));\n}\n\n/** Parsed mesh data ready for GPU upload. */\nexport interface GltfMeshData {\n /** @internal Tight CPU positions, or null when sourced from an interleaved\n * bufferView (in which case `_vb._p` holds the strided source for lazy de-striding). */\n _positions: Float32Array | null;\n /** @internal */\n _normals: Float32Array | null;\n /** @internal */\n _tangents: Float32Array | null;\n /** @internal */\n _uvs: Float32Array | null;\n /** @internal */\n _uv2s: Float32Array | null;\n /** @internal */\n _colors: Float32Array | null;\n /** @internal Primitive had no NORMAL attribute → flat-shade (glTF spec). */\n _flatNormal?: boolean;\n /** @internal Non-triangle-list primitive topology index (1=points, 2=lines,\n * 3=line-strip, 4=triangle-strip) from the glTF primitive `mode`. Undefined =\n * triangle-list (the default). LINE_LOOP/TRIANGLE_FAN are unsupported (so is BJS). */\n _topology?: number;\n /** @internal */\n _indices: Uint16Array | Uint32Array;\n /** @internal */\n _vertexCount: number;\n /** @internal */\n _indexCount: number;\n /** @internal */\n _worldMatrix: Mat4;\n /** @internal */\n _material: GltfMaterialData;\n /** @internal Interleaved vertex sources (genuine GPU interleaving + lazy CPU de-stride).\n * Absent → all tight. */\n _vb?: GltfVb;\n /** @internal glTF node index this mesh came from (for hierarchy reconstruction\n * and for features that need to resolve skin/morph data lazily). */\n _nodeIndex: number;\n /** @internal Raw primitive definition — features (skeleton, morph, …) read their\n * own attributes/targets from here without bloating core extraction. */\n _primitive: any;\n /** @internal Pre-decoded primitive (Draco et al.) if a preMesh feature produced one. */\n _decoded?: DecodedPrimitive;\n}\n\n/**\n * Load a glTF/GLB asset, parse it, and upload mesh + material data to GPU.\n * Registers a deferred PBR renderable builder and automatically parses glTF\n * animations if present.\n *\n * Returns an {@link AssetContainer}. Pass it to {@link addToScene} which adds the\n * hierarchy, registers animation ticks, and applies any scene-level settings.\n *\n * The `source` may be either:\n * - **A URL (`string`)** — fetches the asset. Supports both binary GLB and\n * separate `.gltf` + `.bin` + image files; relative `.bin`/image paths are\n * resolved against the URL.\n * - **Raw data (`ArrayBuffer` | `Blob`)** — loads from already-loaded local data\n * (drag-and-drop, OPFS, a `fetch` body, etc.). GLB-vs-glTF is determined from\n * the data's magic bytes, not a file extension. Because raw data has no base\n * URL it must be self-contained: a GLB, or a glTF whose buffers/images use\n * `data:` URIs. A glTF that references external `.bin`/image files by relative\n * path can only be loaded from a URL.\n *\n * @param engine - The engine to upload GPU resources to.\n * @param source - A URL string, or the raw `ArrayBuffer`/`Blob` of a self-contained glTF/GLB asset.\n */\nexport async function loadGltf(engine: EngineContext, source: string | ArrayBuffer | Blob): Promise<AssetContainer> {\n const { json, binChunk, baseUrl } = await fetchGltfAsset(source);\n\n // Build parent map + world-matrix cache once for O(n) hierarchy traversal\n const parentMap = buildParentMap(json);\n const worldMatrixCache = new Map<number, Mat4>();\n\n // Discover every triggered feature (material exts, skeleton, morph,\n // animations, variants, …). The feature registry + its ~24 dynamic-import\n // thunks live in a separate module that is itself dynamic-imported only when\n // the asset can possibly trigger a feature — so plain metallic-roughness\n // GLBs (no extensions/animations/skins/morphs/ORM-composite) never fetch the\n // registry. Core loader knows zero feature names.\n const featureRegistry = assetUsesGltfFeatures(json) ? await importGltfFeatureRegistry() : undefined;\n const features = featureRegistry ? await featureRegistry.loadGltfFeatures(json) : [];\n\n // Pre-parse hooks (EXT_meshopt_compression decompression, KHR_mesh_quantization\n // dequantization) may rewrite bufferViews/accessors and hand back a replacement\n // binary chunk. Run sequentially in registry order so later features see earlier\n // rewrites. No-op (and zero cost) when no triggered feature defines preParse.\n let activeBin = binChunk;\n for (const f of features) {\n if (f.preParse) {\n const replacement = await f.preParse(json, activeBin);\n if (replacement) {\n activeBin = replacement;\n }\n }\n }\n\n const matExts: GltfFeature[] = features.filter((f) => f.applyMaterial);\n // Compose every feature's wrapTexture hook into a single function. Identity\n // when no feature contributes one (common case) — keeps the hot path free\n // of per-texture work and lets bundlers tree-shake the helpers.\n const texWraps = features.filter((f) => f.wrapTexture).map((f) => f.wrapTexture!);\n const wrapTex: TextureWrapFn = !texWraps.length ? identityTexWrap : (tex, ti) => texWraps.reduce((acc, w) => w(acc, ti), tex);\n\n // Run every feature's pre-mesh hook (e.g. Draco decompression) and merge\n // their primitive-keyed decode caches. Features without `preMesh` contribute\n // nothing; the map stays empty when no primitive-level feature triggered.\n const decodedPrimitives = new Map<unknown, DecodedPrimitive>();\n for (const frag of await Promise.all(features.flatMap((f) => (f.preMesh ? [f.preMesh(json, activeBin, baseUrl)] : [])))) {\n for (const [k, v] of frag) {\n decodedPrimitives.set(k, v);\n }\n }\n\n const meshDatas = await extractAllMeshes(json, activeBin, baseUrl, parentMap, worldMatrixCache, decodedPrimitives);\n\n const ctx: GltfLoadCtx = {\n _engine: engine,\n _json: json,\n _binChunk: activeBin,\n _baseUrl: baseUrl,\n _parentMap: parentMap,\n _worldMatrixCache: worldMatrixCache,\n _matExts: matExts,\n _runMatExts: featureRegistry?.runGltfMaterialFeatures,\n _wrapTex: wrapTex,\n };\n\n const meshes = await uploadMeshes(meshDatas, features, ctx);\n\n // Build TransformNode hierarchy from glTF nodes. Returns both the synthetic root\n // and a glTF-node-index → SceneNode map (used by node-visibility + animation-pointer).\n const { root, nodeMap } = buildNodeHierarchy(json, meshes, meshDatas);\n ctx._nodeMap = nodeMap;\n\n // Run every feature's per-asset hook (animations, variants, metadata, …) and\n // merge the returned AssetContainer fragments. `entities` is appended (never\n // overwritten) so features like KHR_lights_punctual can contribute lights\n // without trampling the root TransformNode.\n const assetFragments = await Promise.all(features.flatMap((f) => (f.applyAsset ? [f.applyAsset(meshes, root, ctx)] : [])));\n const container: AssetContainer = { entities: [root] };\n for (const frag of assetFragments) {\n if (frag.entities?.length) {\n container.entities.push(...frag.entities);\n }\n const { entities: _ignored, ...rest } = frag;\n void _ignored;\n Object.assign(container, rest);\n }\n return container;\n}\n\n/** Fetch/resolve + parse a glTF or GLB asset from a URL string, ArrayBuffer, or Blob.\n * Returns the JSON, binary chunk, and base URL (empty for non-URL sources). */\nasync function fetchGltfAsset(source: string | ArrayBuffer | Blob): Promise<{ json: any; binChunk: DataView; baseUrl: string }> {\n // Resolve the source to bytes. Only a URL string yields a base URL for resolving external .bin/image\n // references; ArrayBuffer/Blob inputs are self-contained (GLB, or glTF with data: URIs).\n const isUrl = typeof source === \"string\";\n // Resolve the source to an absolute URL so external .bin / image URIs resolve correctly even when the\n // caller passes a root-relative (\"/models/foo.gltf\") or document-relative path — `new URL(uri, base)`\n // downstream requires an absolute base. Absolute inputs (https://…) are returned unchanged. In a\n // non-DOM context (Node / a worker without `location`) fall back to a plain directory-prefix base.\n const baseUrl = !isUrl ? \"\" : typeof location !== \"undefined\" ? new URL(\".\", new URL(source, location.href)).href : source.slice(0, source.lastIndexOf(\"/\") + 1);\n const buffer = isUrl ? await fetch(source).then((r) => r.arrayBuffer()) : source instanceof Blob ? await source.arrayBuffer() : source;\n\n // Classify by the GLB magic (\"glTF\" = 0x46546c67, little-endian) rather than the URL extension, so\n // object URLs (blob:…), OPFS handles, and extensionless sources are detected correctly. The length guard\n // keeps an empty/too-short input failing with the JSON/GLB parse error below, not a DataView RangeError.\n if (buffer.byteLength >= 4 && new DV(buffer).getUint32(0, true) === 0x46546c67) {\n const glb = await import(\"./gltf-glb-parser.js\");\n return { ...glb.parseGlbContainer(buffer), baseUrl };\n }\n\n const jsonAsset = await import(\"./gltf-json-asset.js\");\n return jsonAsset.parseGltfJsonAsset(buffer, baseUrl);\n}\n\n/** Cheap superset gate: returns true iff the asset can possibly trigger at least\n * one optional glTF feature. Every `_features` predicate in gltf-feature-registry\n * is implied by one of these buckets (all hasExt/hasMatExt features require a\n * non-empty `extensionsUsed`), so when this returns false the registry's\n * `loadGltfFeatures` would return `[]` anyway — letting the core loader skip the\n * registry import entirely and keep its ~24 feature import-thunks out of the\n * bundle for plain metallic-roughness assets. */\nfunction assetUsesGltfFeatures(json: any) {\n return (\n json.extensionsUsed?.length ||\n json.animations?.length ||\n JSON.stringify(json).includes(\"extras\") ||\n (json.skins?.length && anyPrimitive(json, (p) => p.attributes?.JOINTS_0 !== undefined)) ||\n anyPrimitive(json, (p) => !!p.targets?.length) ||\n // A node with a negative-determinant local transform (odd negative scale, or a `matrix`\n // with negative 3x3 determinant) may need the negative-winding feature. This mirrors the\n // registry's `hasNegDetNode` predicate so a positive-determinant `matrix` node — extremely\n // common, e.g. TextureSettingsTest — does NOT needlessly pull the feature registry.\n (json.nodes as any[] | undefined)?.some((n: any) =>\n n.scale\n ? n.scale[0] * n.scale[1] * n.scale[2] < 0\n : n.matrix\n ? n.matrix[0] * (n.matrix[5] * n.matrix[10] - n.matrix[6] * n.matrix[9]) +\n n.matrix[1] * (n.matrix[6] * n.matrix[8] - n.matrix[4] * n.matrix[10]) +\n n.matrix[2] * (n.matrix[4] * n.matrix[9] - n.matrix[5] * n.matrix[8]) <\n 0\n : false\n ) ||\n // Non-triangle primitive topology (POINTS/LINES/LINE_STRIP/TRIANGLE_STRIP).\n anyPrimitive(json, (p) => p.mode !== undefined && p.mode !== 4) ||\n needsOrmComposite(json)\n );\n}\n\n// --- Hierarchy Reconstruction ---\n\n/** Build a TransformNode tree mirroring the glTF node hierarchy.\n * Meshes are attached as children. Non-mesh nodes become\n * pure TransformNodes preserving TRS for cloning/repositioning.\n * Parent links are set by addToScene() when the tree is added to the scene.\n * Also returns a glTF-node-index → SceneNode map used by per-asset features\n * (KHR_node_visibility, KHR_animation_pointer) to address specific nodes. */\nfunction buildNodeHierarchy(json: any, meshes: Mesh[], meshDatas: GltfMeshData[]): { root: TransformNode; nodeMap: (TransformNode | undefined)[] } {\n // Map nodeIndex → uploaded Mesh[]\n const nodeToMeshes: Mesh[][] = [];\n for (let i = 0; i < meshDatas.length; i++) {\n const ni = meshDatas[i]!._nodeIndex;\n (nodeToMeshes[ni] ??= []).push(meshes[i]!);\n }\n\n const nodeMap: (TransformNode | undefined)[] = new Array(json.nodes?.length ?? 0);\n\n // Recursive builder\n function buildNode(nodeIdx: number): TransformNode {\n const node = json.nodes[nodeIdx];\n const name = node.name ?? `node_${nodeIdx}`;\n let tn: TransformNode;\n if (node.matrix) {\n tn = createSceneNodeFromMatrix(name, node.matrix as Mat4);\n } else {\n const t = node.translation ?? [0, 0, 0];\n const r = node.rotation ?? [0, 0, 0, 1];\n const s = node.scale ?? [1, 1, 1];\n tn = createTransformNode(name, t[0], t[1], t[2], r[0], r[1], r[2], r[3], s[0], s[1], s[2]);\n }\n nodeMap[nodeIdx] = tn;\n if (node.children) {\n for (const childIdx of node.children) {\n tn.children.push(buildNode(childIdx));\n }\n }\n const nodeMeshes = nodeToMeshes[nodeIdx] ?? [];\n tn.children.push(...nodeMeshes);\n return tn;\n }\n\n // Synthetic root (like BJS __root__) — applies RH→LH conversion via scale\n // BJS: rotation [0,1,0,0] + scale [1,1,-1] = diag(-1, 1, 1, 1)\n const sceneRoots: number[] = json.scenes?.[json.scene ?? 0]?.nodes ?? [];\n const rootChildren = sceneRoots.map((ni: number) => buildNode(ni));\n const root = createTransformNode(\"__root__\", 0, 0, 0, 0, 0, 0, 1, -1, 1, 1);\n root.children.push(...rootChildren);\n return { root, nodeMap };\n}\n\n// --- Mesh Extraction ---\n\nasync function extractAllMeshes(\n json: any,\n binChunk: DataView,\n baseUrl: string,\n parentMap: Map<number, number>,\n worldMatrixCache: Map<number, Mat4>,\n decodedPrimitives: Map<unknown, DecodedPrimitive>\n): Promise<GltfMeshData[]> {\n // Per-load image cache — avoids decoding the same glTF image index multiple times\n const imageCache: GltfImageCache = [];\n\n // Cache material assembly by glTF material index — avoids duplicate image fetches\n const matCache: Promise<GltfMaterialData>[] = [];\n const getMat = (matIdx: number | undefined): Promise<GltfMaterialData> => {\n const key = (matIdx ?? -1) + 1;\n return (matCache[key] ??= assembleMaterial(json, binChunk, key - 1, baseUrl, imageCache));\n };\n\n // First pass: do all sync work, fire all material fetches concurrently\n const partials: Array<Omit<GltfMeshData, \"_material\">> = [];\n const matPromises: Promise<GltfMaterialData>[] = [];\n\n // Genuine GPU interleaving is the ONLY reason to touch the interleave module.\n // Many exporters declare `byteStride` even on tightly-packed bufferViews, and a\n // preMesh feature (e.g. the basisu extension's readStridedFloat path) may already\n // de-stride a primitive — so we load the module only for a primitive that is\n // genuinely over-strided AND not already decoded. Other scenes pay zero cost: the\n // module is fetched lazily on the first such primitive (memoized), never before.\n const _accs = json.accessors as any[];\n const _bvs = json.bufferViews as any[] | undefined;\n const _strided = (p: any): boolean => {\n for (const k in p.attributes) {\n const a = _accs[p.attributes[k]];\n const s = _bvs?.[a?.bufferView]?.byteStride;\n if (\n s !== undefined &&\n s !== (TYPE_SIZES[a.type] ?? 1) * (a.componentType === 5126 || a.componentType === 5125 ? 4 : a.componentType === 5123 || a.componentType === 5122 ? 2 : 1)\n ) {\n return true;\n }\n }\n return false;\n };\n\n for (let nodeIdx = 0; nodeIdx < json.nodes.length; nodeIdx++) {\n const node = json.nodes[nodeIdx];\n if (node.mesh === undefined) {\n continue;\n }\n\n const meshIndex = node.mesh as number;\n const mesh = json.meshes[meshIndex];\n const worldMatrix = computeNodeWorldMatrix(json, nodeIdx, parentMap, worldMatrixCache);\n\n for (let primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {\n const primitive = mesh.primitives[primitiveIndex];\n const attrs = primitive.attributes;\n const decoded = decodedPrimitives.get(primitive);\n\n // Genuine GPU interleaving: only a primitive that genuinely sources ≥1\n // attribute from an over-strided bufferView (and was not already decoded\n // by a preMesh feature) takes this path. The module is imported lazily on\n // first need — non-interleaved assets never fetch it. Tight primitives\n // fall through to the path below (byte-identical to non-interleaved).\n if (!decoded && _strided(primitive)) {\n const ip = await (await loadInterleave()).buildInterleavedPartial(json, binChunk, primitive, worldMatrix, nodeIdx);\n if (ip) {\n matPromises.push(getMat(primitive.material));\n partials.push(ip);\n continue;\n }\n }\n\n const resolveAttr = (name: string): AccessorView | null => {\n if (decoded && decoded._attributes.has(name)) {\n const data = decoded._attributes.get(name)!;\n const componentCount = data.length / decoded._vertexCount;\n return { _data: data, _count: decoded._vertexCount, _componentCount: componentCount };\n }\n const idx = attrs[name];\n return idx !== undefined ? resolveAccessor(json, binChunk, idx) : null;\n };\n const posData = resolveAttr(\"POSITION\")!;\n const normData = resolveAttr(\"NORMAL\");\n const uvData = resolveAttr(\"TEXCOORD_0\");\n const uv2Data = resolveAttr(\"TEXCOORD_1\");\n const tanData = resolveAttr(\"TANGENT\");\n const colorData = resolveAttr(\"COLOR_0\");\n const idxData = decoded\n ? decoded._indexCount > 0\n ? { _data: decoded._indices, _count: decoded._indexCount, _componentCount: 1 }\n : null\n : primitive.indices !== undefined\n ? resolveAccessor(json, binChunk, primitive.indices)\n : null;\n const normalsHelper = !idxData || !normData ? await import(\"./gltf-normals.js\") : null;\n // glTF COLOR_0 may be VEC3 or VEC4 with float, normalized ubyte, or normalized\n // ushort components, but the PBR pipeline binds vertex color as a single\n // float32x4 layout (rgb modulates base color, a modulates alpha). Normalize any\n // source to a tight float32 RGBA buffer so the GPU stride matches the layout\n // (otherwise every vertex misaligns -> garbage/black); a VEC3 source gets a=1.\n // The normalizer is imported lazily on first need — colorless assets never fetch it\n // (the runtime caches the module, so the per-primitive import() resolves instantly).\n const colors = colorData ? (await importColorNormalize()).normalizeColorToVec4(colorData._data, colorData._count, colorData._componentCount) : null;\n\n // TEXCOORD_0/_1 may be FLOAT or a normalized UNSIGNED_BYTE/SHORT accessor; the vertex\n // pipeline binds UVs as float32x2, so integer UVs are denormalized to [0,1] (reusing the\n // lazily-imported color/UV normalizer). Float UVs (the common case) pass through untouched.\n const uvs = uvData\n ? uvData._data instanceof F32\n ? (uvData._data as Float32Array)\n : (await importColorNormalize()).normalizeUvToVec2(uvData._data, uvData._count)\n : new F32(posData._count * 2);\n const uv2s = uv2Data\n ? uv2Data._data instanceof F32\n ? (uv2Data._data as Float32Array)\n : (await importColorNormalize()).normalizeUvToVec2(uv2Data._data, uv2Data._count)\n : null;\n\n // Keep vertex data as-is from glTF — RH→LH conversion handled by root world matrix\n const indices = idxData\n ? idxData._data instanceof U32\n ? new U32(idxData._data as Uint32Array)\n : idxData._data instanceof U8\n ? Uint16Array.from(idxData._data as Uint8Array)\n : new U16(idxData._data!.buffer, idxData._data!.byteOffset, idxData._count)\n : normalsHelper!.createSequentialIndices(posData._count);\n\n // Fire material fetch without awaiting — all materials load in parallel\n matPromises.push(getMat(primitive.material));\n\n // Smooth-normal generation is lazily imported on first need — assets that\n // always provide NORMAL (the common case) never bundle or fetch this code.\n const normals = normData ? (normData._data as Float32Array) : normalsHelper!.computeSmoothNormals(posData._data as Float32Array, indices, posData._count);\n\n partials.push({\n _positions: posData._data as Float32Array,\n _normals: normals,\n _tangents: tanData ? (tanData._data as Float32Array) : null,\n _uvs: uvs,\n _uv2s: uv2s,\n _colors: colors,\n _flatNormal: !normData,\n _indices: indices,\n _vertexCount: posData._count,\n _indexCount: indices.length,\n _worldMatrix: worldMatrix,\n _nodeIndex: nodeIdx,\n _primitive: primitive,\n _decoded: decoded,\n });\n }\n }\n\n // Resolve all material fetches in parallel\n const materials = await Promise.all(matPromises);\n return partials.map((p, i) => ({ ...p, _material: materials[i]! }));\n}\n\n// --- GPU Upload ---\n\n// Pre-resolved generateMipmaps function— loaded once before texture uploads\nlet _generateMipmaps: ((engine: EngineContext, texture: GPUTexture, face?: number) => void) | null = null;\n\nasync function ensureMipmapModule(): Promise<void> {\n if (!_generateMipmaps) {\n _generateMipmaps = (await import(\"../texture/generate-mipmaps.js\")).generateMipmaps;\n }\n}\n\nasync function uploadMeshes(meshDatas: GltfMeshData[], features: GltfFeature[], ctx: GltfLoadCtx): Promise<Mesh[]> {\n const { _engine: engine, _json: json, _binChunk: binChunk, _baseUrl: baseUrl, _matExts: matExts, _wrapTex: wrapTex } = ctx;\n // Default sampler (repeat/linear) used for factor textures and when a texture has no glTF sampler.\n const sampler = getOrCreateSampler(engine, {\n magFilter: \"linear\",\n minFilter: \"linear\",\n mipmapFilter: \"linear\",\n addressModeU: \"repeat\",\n addressModeV: \"repeat\",\n maxAnisotropy: 4,\n });\n // Per-texture glTF samplers (wrap/filter) are honored only when the asset declares a\n // NON-default sampler (clamp/mirror wrap, or nearest filtering); the common case\n // (default repeat/linear) uses the single shared sampler above and the master-identical\n // buildDefaultPbrTextures path. Both the descriptor logic AND the sampler-aware texture\n // builder are lazy so default-sampler assets pay zero bundle bytes for the feature.\n let samplerFor: ((texInfo: any) => GPUSampler) | undefined;\n let buildSampledPbrTextures: typeof import(\"./gltf-sampler-desc.js\").buildSampledPbrTextures | undefined;\n if (json.samplers?.some((s: any) => s.wrapS > 10497 || s.wrapT > 10497 || s.magFilter === 9728 || (s.minFilter != null && s.minFilter !== 9729 && s.minFilter !== 9987))) {\n const mod = await import(\"./gltf-sampler-desc.js\");\n samplerFor = mod.makeSamplerFor(engine, json, sampler);\n buildSampledPbrTextures = mod.buildSampledPbrTextures;\n }\n\n await ensureMipmapModule();\n const meshFeatures = features.filter((f) => f.applyMesh);\n\n // Texture cache: shared textures uploaded once, keyed by (bitmap, srgb).\n const texCache = new Map<ImageBitmap, Texture2D[]>();\n\n function getCachedTexture(bitmap: ImageBitmap, srgb: boolean): Texture2D {\n let textures = texCache.get(bitmap);\n if (!textures) {\n texCache.set(bitmap, (textures = []));\n }\n const key = +srgb;\n let tex = textures[key];\n if (!tex) {\n tex = uploadTex(engine, bitmap, srgb, sampler, _generateMipmaps!);\n textures[key] = tex;\n }\n return tex;\n }\n\n // Per-load image fetcher for ext modules (uses same image cache as core).\n const extImageCache: GltfImageCache | null = matExts.length ? [] : null;\n const extFetchImg = extImageCache ? makeImageFetcher(json, binChunk, baseUrl, extImageCache) : null;\n const extCtx: GltfMatExtCtx = {\n _engine: engine,\n async _texture(texInfo, sRGB) {\n if (!texInfo || !extFetchImg) {\n return undefined;\n }\n const img = await extFetchImg(texInfo);\n return img ? wrapTex(getCachedTexture(img, sRGB), texInfo) : undefined;\n },\n _uploadImage(bitmap, sRGB) {\n return uploadTex(engine, bitmap, sRGB, sampler, _generateMipmaps!);\n },\n };\n\n // Slow-path trigger: per-texture UV wrapping (KHR_texture_transform)\n // or any core texture declaring texCoord=1. Scene1 stays identity→fast path.\n let _needsPbrExt = wrapTex !== identityTexWrap;\n if (!_needsPbrExt) {\n const mats = (json as { materials?: unknown[] }).materials;\n if (mats && JSON.stringify(mats).includes('\"texCoord\":1')) {\n _needsPbrExt = true;\n }\n }\n let _pbrExtPromise: Promise<typeof GltfPbrBuilderExt> | null = null;\n const _ensurePbrExt = () => (_pbrExtPromise ??= import(\"./gltf-pbr-builder-ext.js\"));\n\n /** Default ORM upload: single MR-or-occlusion image, or 1×1 fallback baked from\n * metallicFactor/roughnessFactor. The composite case (MR+occlusion separate) is\n * handled by the gltf-ext-orm extension which overrides this via `extLayers`. */\n\n // Build a PbrMaterialProps from parsed glTF material data.\n // Uses shared texture caches so identical bitmaps are uploaded once.\n const builtMaterialCache = new Map<GltfMaterialData, Promise<PbrMaterialProps>>();\n async function buildPbrFromGltfMat(mat: GltfMaterialData): Promise<PbrMaterialProps> {\n let cached = builtMaterialCache.get(mat);\n if (cached) {\n return cached;\n }\n cached = (async () => {\n const extLayers = matExts.length ? await ctx._runMatExts!(mat, matExts, extCtx) : undefined;\n if (_needsPbrExt) {\n const extMod = await _ensurePbrExt();\n const tex = extMod.buildDefaultPbrTexturesExt(engine, mat, sampler, _generateMipmaps!, getCachedTexture, wrapTex, samplerFor);\n return extMod.assemblePbrPropsExt(mat, tex, extLayers);\n }\n const tex = buildSampledPbrTextures\n ? buildSampledPbrTextures(engine, mat, sampler, _generateMipmaps!, samplerFor!, getCachedTexture)\n : buildDefaultPbrTextures(engine, mat, sampler, _generateMipmaps!, getCachedTexture);\n return assemblePbrProps(mat, tex.baseColorTexture, tex.ormTexture, tex.normalTexture, tex.emissiveTexture, extLayers);\n })();\n builtMaterialCache.set(mat, cached);\n return cached;\n }\n\n const meshes = await Promise.all(\n meshDatas.map(async (m, i): Promise<Mesh> => {\n const material = await buildPbrFromGltfMat(m._material);\n const meshName = json.meshes[json.nodes[m._nodeIndex].mesh].name;\n\n // Interleaved meshes are fully built by the dynamic module (kept out of\n // this bundle for non-interleaved scenes). The tight path below is\n // byte-identical to the non-interleaved engine.\n let mesh: Mesh;\n if (m._vb) {\n mesh = (await loadInterleave()).buildInterleavedMesh(engine, m, i, material, meshName) as Mesh;\n } else {\n const [boundMin, boundMax] = computeAabb(m._positions!, m._worldMatrix);\n const gpu: MeshGPU = {\n positionBuffer: createMappedBuffer(engine, m._positions!, BU.VERTEX),\n normalBuffer: createMappedBuffer(engine, m._normals!, BU.VERTEX),\n tangentBuffer: m._tangents ? createMappedBuffer(engine, m._tangents, BU.VERTEX) : null,\n uvBuffer: createMappedBuffer(engine, m._uvs!, BU.VERTEX),\n uv2Buffer: m._uv2s ? createMappedBuffer(engine, m._uv2s, BU.VERTEX) : null,\n colorBuffer: m._colors ? createMappedBuffer(engine, m._colors, BU.VERTEX) : null,\n indexBuffer: createMappedBuffer(engine, m._indices, BU.INDEX),\n indexCount: m._indexCount,\n indexFormat: (m._indices instanceof U32 ? \"uint32\" : \"uint16\") as GPUIndexFormat,\n };\n\n mesh = {\n name: meshName || `gltf_mesh_${i}`,\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 // Retain CPU geometry for detailed picking.\n mesh._cpuPositions = m._positions!;\n mesh._cpuNormals = m._normals!;\n mesh._cpuUvs = m._uvs!;\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\n // Run all per-mesh feature hooks (skeleton, morph, …) in parallel.\n // Each hook mutates `mesh` directly (e.g. attaches mesh.skeleton).\n if (meshFeatures.length > 0) {\n await Promise.all(meshFeatures.map((f) => f.applyMesh!(m, mesh, ctx)));\n }\n\n return mesh;\n })\n );\n\n return meshes;\n}\n"],"names":["tex"],"mappings":"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"}
|