@forgeax/engine-runtime 0.1.4 → 0.1.6
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/README.md +49 -83
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-serialize.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-serialize.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts +2 -0
- package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts.map +1 -0
- package/dist/__tests__/asset-error-exhaustive.test-d.d.ts +11 -0
- package/dist/__tests__/asset-error-exhaustive.test-d.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-guid-reverse.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-guid-reverse.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-mounts.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-mounts.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.browser.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.browser.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.dawn.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.listCatalog.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.listCatalog.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.mesh-bin.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.mesh-bin.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.pack-cache.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.pack-cache.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.recursive.spec.d.ts +2 -0
- package/dist/__tests__/asset-registry.recursive.spec.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset.unit.test.d.ts +2 -0
- package/dist/__tests__/asset.unit.test.d.ts.map +1 -0
- package/dist/__tests__/audio-load-by-guid.unit.test.d.ts +2 -0
- package/dist/__tests__/audio-load-by-guid.unit.test.d.ts.map +1 -0
- package/dist/__tests__/backend-selection.integration.test.d.ts +2 -0
- package/dist/__tests__/backend-selection.integration.test.d.ts.map +1 -0
- package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts +2 -0
- package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts.map +1 -0
- package/dist/__tests__/builtin-asset-registry.unit.test.d.ts +2 -0
- package/dist/__tests__/builtin-asset-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/collect-scene-asset.test.d.ts +1 -2
- package/dist/__tests__/collect-scene-asset.test.d.ts.map +1 -1
- package/dist/__tests__/collect-scene-mount-collapse.test.d.ts +2 -0
- package/dist/__tests__/collect-scene-mount-collapse.test.d.ts.map +1 -0
- package/dist/__tests__/collect-transient-roundtrip.test.d.ts +1 -1
- package/dist/__tests__/collect-transient-roundtrip.test.d.ts.map +1 -1
- package/dist/__tests__/collect-transient-skip.test.d.ts +1 -2
- package/dist/__tests__/collect-transient-skip.test.d.ts.map +1 -1
- package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts +2 -0
- package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/draw-published.d.ts +2 -2
- package/dist/__tests__/draw-published.d.ts.map +1 -1
- package/dist/__tests__/dynamic-texture-store.unit.test.d.ts +2 -0
- package/dist/__tests__/dynamic-texture-store.unit.test.d.ts.map +1 -0
- package/dist/__tests__/errors.unit.test.d.ts +2 -0
- package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
- package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts +2 -0
- package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fetch-binary-decompress.test.d.ts +2 -0
- package/dist/__tests__/fetch-binary-decompress.test.d.ts.map +1 -0
- package/dist/__tests__/four-path-compression.integration.test.d.ts +2 -0
- package/dist/__tests__/four-path-compression.integration.test.d.ts.map +1 -0
- package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts +2 -0
- package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/guid-for-asset.unit.test.d.ts +2 -0
- package/dist/__tests__/guid-for-asset.unit.test.d.ts.map +1 -0
- package/dist/__tests__/handle-migration.test.d.ts +2 -0
- package/dist/__tests__/handle-migration.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/register-runtime-components.d.ts.map +1 -1
- package/dist/__tests__/host-custom-kind-contract.test-d.d.ts +2 -0
- package/dist/__tests__/host-custom-kind-contract.test-d.d.ts.map +1 -0
- package/dist/__tests__/host-custom-kind-contract.test.d.ts +2 -0
- package/dist/__tests__/host-custom-kind-contract.test.d.ts.map +1 -0
- package/dist/__tests__/inspect-name.test.d.ts +2 -0
- package/dist/__tests__/inspect-name.test.d.ts.map +1 -0
- package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts +2 -0
- package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts.map +1 -0
- package/dist/__tests__/loadbyguid-payload.unit.test.d.ts +2 -0
- package/dist/__tests__/loadbyguid-payload.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts +2 -0
- package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loader-extract-graceful.test.d.ts +2 -0
- package/dist/__tests__/loader-extract-graceful.test.d.ts.map +1 -0
- package/dist/__tests__/loader-name-survival.test.d.ts +2 -0
- package/dist/__tests__/loader-name-survival.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin-contract.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin-contract.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/new-kind-refs-contract.test.d.ts +2 -0
- package/dist/__tests__/new-kind-refs-contract.test.d.ts.map +1 -0
- package/dist/__tests__/package-promotion.test.d.ts +2 -0
- package/dist/__tests__/package-promotion.test.d.ts.map +1 -0
- package/dist/__tests__/package-rename.test.d.ts +2 -0
- package/dist/__tests__/package-rename.test.d.ts.map +1 -0
- package/dist/__tests__/recover-error-exhaustive.test-d.d.ts +1 -1
- package/dist/__tests__/recover-error-exhaustive.test-d.d.ts.map +1 -1
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts +1 -1
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -1
- package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts +10 -0
- package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts.map +1 -0
- package/dist/__tests__/render-system-extract.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-extract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-test-utils.d.ts +10 -0
- package/dist/__tests__/renderer-test-utils.d.ts.map +1 -0
- package/dist/__tests__/renderer.test-d.d.ts +2 -0
- package/dist/__tests__/renderer.test-d.d.ts.map +1 -0
- package/dist/__tests__/resolve-asset-handle-err.test.d.ts +2 -0
- package/dist/__tests__/resolve-asset-handle-err.test.d.ts.map +1 -0
- package/dist/__tests__/resolve-asset-handle.unit.test.d.ts +2 -0
- package/dist/__tests__/resolve-asset-handle.unit.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName-fallback.test.d.ts +2 -0
- package/dist/__tests__/resolveName-fallback.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName-null-package.test.d.ts +2 -0
- package/dist/__tests__/resolveName-null-package.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName-unified-entry.test.d.ts +2 -0
- package/dist/__tests__/resolveName-unified-entry.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName.test.d.ts +2 -0
- package/dist/__tests__/resolveName.test.d.ts.map +1 -0
- package/dist/__tests__/roots-to-scene-asset.test.d.ts +1 -1
- package/dist/__tests__/roots-to-scene-asset.test.d.ts.map +1 -1
- package/dist/__tests__/roundtrip-primitive.test.d.ts +2 -0
- package/dist/__tests__/roundtrip-primitive.test.d.ts.map +1 -0
- package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts +2 -0
- package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts.map +1 -0
- package/dist/__tests__/scene-instance-authoring.integration.test.d.ts +2 -0
- package/dist/__tests__/scene-instance-authoring.integration.test.d.ts.map +1 -0
- package/dist/__tests__/scene-mount-fixed-point.test.d.ts +2 -0
- package/dist/__tests__/scene-mount-fixed-point.test.d.ts.map +1 -0
- package/dist/__tests__/scene-mount-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/scene-mount-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/scene-sugar-instantiate.test.d.ts +2 -0
- package/dist/__tests__/scene-sugar-instantiate.test.d.ts.map +1 -0
- package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/serialize-scene-asset.test.d.ts +1 -1
- package/dist/__tests__/serialize-scene-asset.test.d.ts.map +1 -1
- package/dist/__tests__/template-game-default-api-contract.test.d.ts +2 -0
- package/dist/__tests__/template-game-default-api-contract.test.d.ts.map +1 -0
- package/dist/__tests__/tileset-asset-validate.test.d.ts +2 -0
- package/dist/__tests__/tileset-asset-validate.test.d.ts.map +1 -0
- package/dist/__tests__/transcode-fallback.unit.test.d.ts +2 -0
- package/dist/__tests__/transcode-fallback.unit.test.d.ts.map +1 -0
- package/dist/__tests__/transient-runtime-behavior.test.d.ts +2 -0
- package/dist/__tests__/transient-runtime-behavior.test.d.ts.map +1 -0
- package/dist/__tests__/video-loader-consumption.test.d.ts +2 -0
- package/dist/__tests__/video-loader-consumption.test.d.ts.map +1 -0
- package/dist/__tests__/video-loader-smoke.dawn.test.d.ts +2 -0
- package/dist/__tests__/video-loader-smoke.dawn.test.d.ts.map +1 -0
- package/dist/backend-selection.d.ts +13 -0
- package/dist/backend-selection.d.ts.map +1 -0
- package/dist/collect-scene-asset.d.ts +3 -3
- package/dist/collect-scene-asset.d.ts.map +1 -1
- package/dist/createRenderer.d.ts +14 -2
- package/dist/createRenderer.d.ts.map +1 -1
- package/dist/errors/environment.d.ts +1 -1
- package/dist/errors/environment.d.ts.map +1 -1
- package/dist/index.d.ts +19 -81
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +105 -108
- package/dist/index.mjs.map +1 -1
- package/dist/renderer-host.d.ts +9 -0
- package/dist/renderer-host.d.ts.map +1 -0
- package/dist/renderer-host.mjs +62 -0
- package/dist/renderer-host.mjs.map +1 -0
- package/dist/scene-instances/index.d.ts +2 -0
- package/dist/scene-instances/index.d.ts.map +1 -0
- package/dist/scene-utils/mount-override-fold.d.ts +1 -2
- package/dist/scene-utils/mount-override-fold.d.ts.map +1 -1
- package/dist/systems/sprite-animation-tick.d.ts +1 -1
- package/dist/systems/sprite-animation-tick.d.ts.map +1 -1
- package/dist/systems/transparent-sort.d.ts +1 -2
- package/dist/systems/transparent-sort.d.ts.map +1 -1
- package/dist/tilemap-register-validate.d.ts.map +1 -1
- package/package.json +34 -33
- package/src/__tests__/active-camera.unit.test.ts +19 -9
- package/src/__tests__/animation-graph-collect-roundtrip.test.ts +213 -0
- package/src/__tests__/animation-graph-serialize.unit.test.ts +171 -0
- package/src/__tests__/append-injection.test.ts +1 -1
- package/src/__tests__/asset-brand-and-name-retirement.test.ts +102 -0
- package/src/__tests__/asset-error-exhaustive.test-d.ts +62 -0
- package/src/__tests__/asset-registry-guid-reverse.test.ts +575 -0
- package/src/__tests__/asset-registry-hdr-equirect.test.ts +78 -0
- package/src/__tests__/asset-registry-mesh-pack-payload.dawn.test.ts +232 -0
- package/src/__tests__/asset-registry-mounts.test.ts +806 -0
- package/src/__tests__/asset-registry.browser.test.ts +81 -0
- package/src/__tests__/asset-registry.dawn.test.ts +94 -0
- package/src/__tests__/asset-registry.listCatalog.test.ts +170 -0
- package/src/__tests__/asset-registry.mesh-bin.test.ts +316 -0
- package/src/__tests__/asset-registry.pack-cache.test.ts +969 -0
- package/src/__tests__/asset-registry.raw-container-failfast.test.ts +225 -0
- package/src/__tests__/asset-registry.recursive.spec.ts +1397 -0
- package/src/__tests__/asset-registry.unit.test.ts +1030 -0
- package/src/__tests__/asset.unit.test.ts +7107 -0
- package/src/__tests__/audio-load-by-guid.unit.test.ts +126 -0
- package/src/__tests__/backend-selection.integration.test.ts +11 -0
- package/src/__tests__/basis-catalog-dispatch.integration.test.ts +320 -0
- package/src/__tests__/bind-group-cache-keying.test.ts +4 -4
- package/src/__tests__/block-upload-math.unit.test.ts +2 -2
- package/src/__tests__/builtin-asset-registry.unit.test.ts +112 -0
- package/src/__tests__/builtin-shader-register-e2e.test.ts +1 -1
- package/src/__tests__/cache-false-eviction.test.ts +2 -1
- package/src/__tests__/cache-isolation-matrix.test.ts +2 -1
- package/src/__tests__/camera-clear-snapshot-equivalence.unit.test.ts +5 -6
- package/src/__tests__/clamp-to-last.e2e.browser.test.ts +29 -19
- package/src/__tests__/collect-scene-asset.test.ts +49 -52
- package/src/__tests__/collect-scene-mount-collapse.test.ts +391 -0
- package/src/__tests__/collect-subtree.unit.test.ts +1 -2
- package/src/__tests__/collect-transient-children-absent.test.ts +24 -10
- package/src/__tests__/collect-transient-roundtrip.test.ts +44 -20
- package/src/__tests__/collect-transient-skip.test.ts +24 -13
- package/src/__tests__/components.test-d.ts +1 -6
- package/src/__tests__/components.unit.test.ts +20 -19
- package/src/__tests__/composite-skybox-cross-world.browser.test.ts +59 -27
- package/src/__tests__/compressed-texture-physical-extent.integration.test.ts +139 -0
- package/src/__tests__/create-renderer-assembly.integration.test.ts +42 -29
- package/src/__tests__/createRenderer-dispose.test.ts +35 -402
- package/src/__tests__/createRenderer.browser-no-webgpu.test.ts +25 -30
- package/src/__tests__/createRenderer.unit.test.ts +1 -1
- package/src/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.ts +27 -63
- package/src/__tests__/dawn/ibl-precompute-readback.dawn.test.ts +56 -47
- package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +49 -29
- package/src/__tests__/dawn/instances-shadow.dawn.test.ts +26 -15
- package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +13 -14
- package/src/__tests__/dawn/material-alpha.dawn.test.ts +23 -31
- package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +0 -18
- package/src/__tests__/dawn/{mesh-update.dawn.test.ts → mesh-update-dawn.test.ts} +42 -134
- package/src/__tests__/dawn/mipmap-srgb-linear.dawn.test.ts +14 -7
- package/src/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.ts +16 -28
- package/src/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.ts +23 -39
- package/src/__tests__/dawn/upload-texture.dawn.test.ts +198 -0
- package/src/__tests__/dawn/user-handle-mesh-render.dawn.test.ts +12 -14
- package/src/__tests__/dawn/user-mesh-upload.dawn.test.ts +27 -22
- package/src/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.ts +25 -28
- package/src/__tests__/dawn/zero-manifest-ready.dawn.test.ts +10 -11
- package/src/__tests__/demo-sortscope-migration.unit.test.ts +5 -5
- package/src/__tests__/derive-bgl-integration.test.ts +34 -44
- package/src/__tests__/derive-render-data-skin.unit.test.ts +1 -1
- package/src/__tests__/draw-published.ts +11 -4
- package/src/__tests__/dynamic-texture-store.unit.test.ts +190 -0
- package/src/__tests__/equirect-bc6h.integration.test.ts +144 -21
- package/src/__tests__/errors.unit.test.ts +1203 -0
- package/src/__tests__/extract-frames-graceful-degradation.test.ts +3 -7
- package/src/__tests__/extract-frames-merge.test.ts +35 -22
- package/src/__tests__/extract-record-no-hardcoded-texture-fields.test.ts +5 -16
- package/src/__tests__/extract-skin-mismatch.unit.test.ts +322 -0
- package/src/__tests__/fetch-binary-decompress.test.ts +356 -0
- package/src/__tests__/four-path-compression.integration.test.ts +395 -0
- package/src/__tests__/frame-targets-shadow-regression.unit.test.ts +1 -1
- package/src/__tests__/fullscreen-feature-host.dawn.test.ts +80 -0
- package/src/__tests__/fullscreen-post-bgl-depth.test.ts +4 -2
- package/src/__tests__/fullscreen-post-depth-params-arity.test.ts +3 -3
- package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +39 -23
- package/src/__tests__/fullscreen-post-process-pass.unit.test.ts +4 -2
- package/src/__tests__/fxaa-pixel-diff.dawn.test.ts +28 -17
- package/src/__tests__/fxaa-validation-and-resize.dawn.test.ts +29 -18
- package/src/__tests__/fxaa-zero-overhead.dawn.test.ts +16 -12
- package/src/__tests__/geometry.unit.test.ts +525 -159
- package/src/__tests__/glyph-tilemap-worldid.test.ts +1 -1
- package/src/__tests__/gpu-resource-cow-survivor.test.ts +6 -4
- package/src/__tests__/guid-for-asset.unit.test.ts +102 -0
- package/src/__tests__/handle-migration.test.ts +136 -0
- package/src/__tests__/helpers/register-runtime-components.ts +4 -2
- package/src/__tests__/helpers/register-scene-components.ts +1 -1
- package/src/__tests__/host-custom-kind-contract.test-d.ts +47 -0
- package/src/__tests__/host-custom-kind-contract.test.ts +578 -0
- package/src/__tests__/inspect-name.test.ts +139 -0
- package/src/__tests__/instances.test-d.ts +1 -1
- package/src/__tests__/instantiate-mount-deferred-wiring.test.ts +112 -0
- package/src/__tests__/light-casters-9-light.browser.test.ts +73 -76
- package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +7 -10
- package/src/__tests__/light-snapshot.test-d.ts +2 -2
- package/src/__tests__/lights-vec-negative.unit.test.ts +1 -1
- package/src/__tests__/lights.unit.test.ts +16 -500
- package/src/__tests__/loadbyguid-payload.unit.test.ts +117 -0
- package/src/__tests__/loadbyguid-texture-intern.unit.test.ts +213 -0
- package/src/__tests__/loader-extract-graceful.test.ts +146 -0
- package/src/__tests__/loader-name-survival.test.ts +213 -0
- package/src/__tests__/m3-vec-negative.unit.test.ts +3 -2
- package/src/__tests__/material-texture-uv-scale.unit.test.ts +101 -31
- package/src/__tests__/materials.unit.test.ts +10 -27
- package/src/__tests__/mesh-bin-contract.test.ts +28 -0
- package/src/__tests__/mesh-bin-skin-roundtrip.unit.test.ts +149 -0
- package/src/__tests__/mesh-bin.test.ts +38 -0
- package/src/__tests__/mesh-loader-skin-contract.unit.test.ts +120 -0
- package/src/__tests__/mesh-ssbo-grow.unit.test.ts +3 -3
- package/src/__tests__/mip-gate.unit.test.ts +1 -1
- package/src/__tests__/msaa-sprite-pixel-diff.dawn.test.ts +29 -68
- package/src/__tests__/new-kind-refs-contract.test.ts +132 -0
- package/src/__tests__/node-shims.d.ts +4 -6
- package/src/__tests__/package-promotion.test.ts +88 -0
- package/src/__tests__/package-rename.test.ts +103 -0
- package/src/__tests__/pass-selector.unit.test.ts +2 -2
- package/src/__tests__/pbr-pipeline.unit.test.ts +14 -21
- package/src/__tests__/pipeline-builder-msaa.unit.test.ts +6 -9
- package/src/__tests__/pipeline-cache-keying.unit.test.ts +6 -9
- package/src/__tests__/pipeline-spec.test.ts +16 -177
- package/src/__tests__/pipeline.unit.test.ts +154 -1693
- package/src/__tests__/point-light-shadow.dawn.test.ts +33 -42
- package/src/__tests__/point-light-shadow.unit.test.ts +19 -60
- package/src/__tests__/post-process-error-codes.unit.test.ts +4 -1
- package/src/__tests__/post-process-params-component.unit.test.ts +1 -1
- package/src/__tests__/post-process-params-extract.unit.test.ts +2 -5
- package/src/__tests__/postprocess-camera-consistency.test.ts +4 -7
- package/src/__tests__/profiler-assembly.integration.test.ts +1 -1
- package/src/__tests__/propagate-transforms.dawn.test.ts +12 -11
- package/src/__tests__/record-worldid-isolation.test.ts +7 -29
- package/src/__tests__/recover-error-exhaustive.test-d.ts +1 -1
- package/src/__tests__/render-error-exhaustive.test-d.ts +81 -71
- package/src/__tests__/render-feature-assembly.test-d.ts +20 -9
- package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +8 -6
- package/src/__tests__/render-feature-prepared-graphics.browser.test.ts +60 -558
- package/src/__tests__/render-feature-prepared-graphics.dawn.test.ts +57 -544
- package/src/__tests__/render-feature-prepared-graphics.fixture.ts +104 -0
- package/src/__tests__/render-feature-prepared-graphics.integration.test.ts +40 -248
- package/src/__tests__/render-feature-prepared-graphics.regression.integration.test.ts +83 -340
- package/src/__tests__/render-feature-recover.integration.test.ts +9 -49
- package/src/__tests__/render-feature-runtime-surface.test-d.ts +17 -20
- package/src/__tests__/render-schema-consumer.integration.test.ts +20 -13
- package/src/__tests__/render-schema-owner-boundary.unit.test.ts +2 -6
- package/src/__tests__/render-system-cross-world-overlay-queue.test.ts +5 -5
- package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +16 -31
- package/src/__tests__/render-system-extract.test.ts +36 -51
- package/src/__tests__/render-system-extract.unit.test.ts +360 -0
- package/src/__tests__/render-system-fold-bucket.unit.test.ts +3 -5
- package/src/__tests__/render-system-fold-fallback.unit.test.ts +6 -3
- package/src/__tests__/render-system-fold-material.unit.test.ts +3 -5
- package/src/__tests__/render-system-fold-metrics.unit.test.ts +5 -5
- package/src/__tests__/render-system-fold-modegate.unit.test.ts +6 -6
- package/src/__tests__/render-system-fold.dawn.test.ts +7 -5
- package/src/__tests__/render-system-mega.test.ts +292 -190
- package/src/__tests__/render-system-owner-split-contract.test.ts +10 -32
- package/src/__tests__/render-system-record-multi-material-textureview.test.ts +59 -45
- package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +23 -29
- package/src/__tests__/render-system-record.test.ts +398 -235
- package/src/__tests__/render-system-record.unit.test.ts +25 -26
- package/src/__tests__/render-system-skin-bg.unit.test.ts +8 -12
- package/src/__tests__/renderer-consumer.test-d.ts +16 -3
- package/src/__tests__/renderer-health.unit.test.ts +26 -916
- package/src/__tests__/renderer-lifecycle.integration.test.ts +19 -6
- package/src/__tests__/renderer-recover.unit.test.ts +49 -1069
- package/src/__tests__/renderer-result.test-d.ts +19 -9
- package/src/__tests__/renderer-surface.unit.test.ts +3 -5
- package/src/__tests__/renderer-test-utils.ts +56 -0
- package/src/__tests__/renderer.test-d.ts +59 -0
- package/src/__tests__/resolve-asset-handle-err.test.ts +111 -0
- package/src/__tests__/resolve-asset-handle.unit.test.ts +64 -0
- package/src/__tests__/resolve-depth-only-view.test.ts +1 -1
- package/src/__tests__/resolveName-fallback.test.ts +64 -0
- package/src/__tests__/resolveName-null-package.test.ts +38 -0
- package/src/__tests__/resolveName-unified-entry.test.ts +65 -0
- package/src/__tests__/resolveName.test.ts +64 -0
- package/src/__tests__/rhi-null-command-flow.unit.test.ts +43 -261
- package/src/__tests__/rhi-null-renderer-lifecycle.unit.test.ts +41 -169
- package/src/__tests__/roots-to-scene-asset.test.ts +199 -93
- package/src/__tests__/roundtrip-primitive.test.ts +351 -0
- package/src/__tests__/scene-bare-guid-refs-instantiate.test.ts +123 -0
- package/src/__tests__/scene-equirect-roundtrip.test.ts +103 -16
- package/src/__tests__/scene-instance-authoring.integration.test.ts +8 -0
- package/src/__tests__/scene-instance-bridge.integration.test.ts +1 -1
- package/src/__tests__/scene-instance-component.test.ts +1 -1
- package/src/__tests__/scene-mount-fixed-point.test.ts +257 -0
- package/src/__tests__/scene-mount-roundtrip.test.ts +987 -0
- package/src/__tests__/scene-mount-wrapper-roundtrip.test.ts +202 -0
- package/src/__tests__/scene-sugar-instantiate.test.ts +324 -0
- package/src/__tests__/serialize-mounts-roundtrip.test.ts +533 -0
- package/src/__tests__/serialize-scene-asset.test.ts +219 -22
- package/src/__tests__/shadow-caster-empty-schema.test.ts +3 -3
- package/src/__tests__/shadow-csm-cascade-loadop.test.ts +37 -17
- package/src/__tests__/shadow-csm-component.test.ts +3 -5
- package/src/__tests__/shadow-csm-extract.test.ts +2 -100
- package/src/__tests__/shadow-csm-orthoz.test.ts +2 -16
- package/src/__tests__/shadow-csm-runtime-vary.dawn.test.ts +19 -14
- package/src/__tests__/shadow-csm-tile-consistency.test.ts +32 -26
- package/src/__tests__/shadow-csm-ubo.dawn.test.ts +8 -49
- package/src/__tests__/shadow-csm-ubo.test.ts +3 -25
- package/src/__tests__/shadow-csm-viewport.browser.test.ts +1 -1
- package/src/__tests__/shadow-fields-observable.dawn.test.ts +67 -56
- package/src/__tests__/shadow-m1.dawn.test.ts +8 -9
- package/src/__tests__/shadow-mesh-ssbo-order.test.ts +11 -27
- package/src/__tests__/skin-errors.unit.test.ts +1 -1
- package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +7 -5
- package/src/__tests__/skylight-lazy-projection.test.ts +36 -15
- package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +5 -5
- package/src/__tests__/sprite-cullmode-flip.dawn.test.ts +47 -64
- package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +12 -11
- package/src/__tests__/sprite-lit-extract-branch.test.ts +1 -1
- package/src/__tests__/sprite-lit-pipeline-cache-key.test.ts +1 -1
- package/src/__tests__/ssao-bgl.test.ts +16 -9
- package/src/__tests__/ssao-buffers.test.ts +2 -2
- package/src/__tests__/ssao-data.test.ts +2 -2
- package/src/__tests__/ssao-errors.test.ts +1 -1
- package/src/__tests__/ssao-passes.test.ts +64 -392
- package/src/__tests__/ssao-pipelines.test.ts +1 -1
- package/src/__tests__/ssao-uniform-layout.test.ts +8 -6
- package/src/__tests__/stencil-outline-pixel.dawn.test.ts +25 -17
- package/src/__tests__/swap-chain-format.unit.test.ts +5 -7
- package/src/__tests__/systems.unit.test.ts +536 -1326
- package/src/__tests__/template-game-default-api-contract.test.ts +362 -0
- package/src/__tests__/text.unit.test.ts +56 -33
- package/src/__tests__/tilemap-childed-despawn.test.ts +8 -14
- package/src/__tests__/tilemap-chunk-extract.overhang-bounds.test.ts +8 -12
- package/src/__tests__/tilemap-chunk-extract.propagate-order.test.ts +2 -1
- package/src/__tests__/tilemap-chunk-extract.test.ts +13 -17
- package/src/__tests__/tilemap-dirty-rebuild.test.ts +7 -11
- package/src/__tests__/tilemap-material-cache.test.ts +8 -13
- package/src/__tests__/tilemap-multi-atlas.test.ts +12 -32
- package/src/__tests__/tilemap-owner-boundary.unit.test.ts +5 -2
- package/src/__tests__/tilemap-region-pack.test.ts +8 -12
- package/src/__tests__/tilemap-spawn-flip-pivot.test.ts +8 -12
- package/src/__tests__/tilemap-uv-inset.test.ts +11 -14
- package/src/__tests__/tilemap-validate.test.ts +1 -1
- package/src/__tests__/tileset-asset-validate.test.ts +638 -0
- package/src/__tests__/transcode-fallback.unit.test.ts +207 -0
- package/src/__tests__/transform-hierarchy-pixel-diff.dawn.test.ts +36 -28
- package/src/__tests__/transient-fields-collect.test.ts +28 -21
- package/src/__tests__/transient-runtime-behavior.test.ts +227 -0
- package/src/__tests__/transparent-sort-tilemap-sprite-interleave.test.ts +4 -4
- package/src/__tests__/variant-selection.unit.test.ts +1 -1
- package/src/__tests__/video-extract-bindgroup.dawn.test.ts +89 -136
- package/src/__tests__/video-loader-consumption.test.ts +86 -0
- package/src/__tests__/video-loader-smoke.dawn.test.ts +60 -0
- package/src/__tests__/view-ubo-layout.browser.test.ts +0 -22
- package/src/__tests__/world-entity-key.test.ts +1 -1
- package/src/__tests__/world-scene-despawn.test.ts +1 -1
- package/src/__tests__/world-scene-instantiate.test.ts +2 -36
- package/src/__tests__/world-scene-nested.test.ts +1 -1
- package/src/__tests__/world-scene-override.test.ts +1 -1
- package/src/backend-selection.ts +69 -0
- package/src/collect-scene-asset.ts +28 -23
- package/src/components/__tests__/camera.test-d.ts +1 -1
- package/src/components/__tests__/camera.test.ts +1 -1
- package/src/components/__tests__/sprite-animation.test-d.ts +2 -2
- package/src/components/__tests__/tile-layer.test-d.ts +1 -1
- package/src/components/__tests__/tile-layer.unit.test.ts +2 -2
- package/src/createRenderer.ts +24 -36
- package/src/errors/environment.ts +1 -1
- package/src/index.ts +47 -113
- package/src/renderer-host.ts +33 -0
- package/src/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.ts +1 -1
- package/src/scene-instances/index.ts +4 -0
- package/src/scene-utils/mount-override-fold.ts +3 -7
- package/src/systems/__tests__/transparent-sort.bench.ts +3 -3
- package/src/systems/sprite-animation-tick.ts +1 -1
- package/src/systems/transparent-sort.ts +38 -38
- package/src/tilemap-register-validate.ts +4 -4
- package/dist/__tests__/bind-group-cache-binding.test.d.ts +0 -2
- package/dist/__tests__/bind-group-cache-binding.test.d.ts.map +0 -1
- package/dist/__tests__/bind-group-cache-frame.test.d.ts +0 -2
- package/dist/__tests__/bind-group-cache-frame.test.d.ts.map +0 -1
- package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts +0 -2
- package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-manifest.d.ts +0 -131
- package/dist/__tests__/fog-producer-manifest.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-pixel-probe.d.ts +0 -42
- package/dist/__tests__/fog-producer-pixel-probe.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-pixel.browser.test.d.ts +0 -2
- package/dist/__tests__/fog-producer-pixel.browser.test.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts +0 -2
- package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-real-fixture.d.ts +0 -5
- package/dist/__tests__/fog-producer-real-fixture.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-vfx-effect.d.ts +0 -3
- package/dist/__tests__/fog-producer-vfx-effect.d.ts.map +0 -1
- package/dist/__tests__/fog-scene-asset.integration.test.d.ts +0 -2
- package/dist/__tests__/fog-scene-asset.integration.test.d.ts.map +0 -1
- package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts +0 -2
- package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts.map +0 -1
- package/dist/__tests__/gpu-resource.test.d.ts +0 -2
- package/dist/__tests__/gpu-resource.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts +0 -2
- package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-buffers.unit.test.d.ts +0 -2
- package/dist/__tests__/hdrp-buffers.unit.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts +0 -2
- package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts +0 -2
- package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts +0 -2
- package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts.map +0 -1
- package/dist/__tests__/hdrp-ssao-boundary.test.d.ts +0 -2
- package/dist/__tests__/hdrp-ssao-boundary.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-ssao-falsification.test.d.ts +0 -2
- package/dist/__tests__/hdrp-ssao-falsification.test.d.ts.map +0 -1
- package/dist/__tests__/helpers/primitive-world.d.ts +0 -8
- package/dist/__tests__/helpers/primitive-world.d.ts.map +0 -1
- package/dist/__tests__/helpers/render-asset-port.d.ts +0 -15
- package/dist/__tests__/helpers/render-asset-port.d.ts.map +0 -1
- package/dist/__tests__/helpers/scene-asset-port.d.ts +0 -9
- package/dist/__tests__/helpers/scene-asset-port.d.ts.map +0 -1
- package/dist/__tests__/material-derived-coordinates.integration.test.d.ts +0 -2
- package/dist/__tests__/material-derived-coordinates.integration.test.d.ts.map +0 -1
- package/dist/__tests__/pipeline-layout-selection.test.d.ts +0 -2
- package/dist/__tests__/pipeline-layout-selection.test.d.ts.map +0 -1
- package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts +0 -2
- package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts.map +0 -1
- package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts +0 -2
- package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts +0 -2
- package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts.map +0 -1
- package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts +0 -2
- package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-caster-membership.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-caster-membership.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-pssm.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-pssm.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-viewport.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-viewport.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-m2.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-m2.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-m3-calibrate.d.ts +0 -83
- package/dist/__tests__/shadow-m3-calibrate.d.ts.map +0 -1
- package/dist/__tests__/shadow-m3.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-m3.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/temporal-off-path.unit.test.d.ts +0 -2
- package/dist/__tests__/temporal-off-path.unit.test.d.ts.map +0 -1
- package/dist/__tests__/video-cache-regression.unit.test.d.ts +0 -2
- package/dist/__tests__/video-cache-regression.unit.test.d.ts.map +0 -1
- package/dist/asset-kind.d.ts +0 -4
- package/dist/asset-kind.d.ts.map +0 -1
- package/dist/errors/sprite-animation.d.ts +0 -3
- package/dist/errors/sprite-animation.d.ts.map +0 -1
- package/dist/scene-asset-port.d.ts +0 -17
- package/dist/scene-asset-port.d.ts.map +0 -1
- package/dist/scene-collect-errors.d.ts +0 -22
- package/dist/scene-collect-errors.d.ts.map +0 -1
- package/dist/shadow-m3-calibrate.d.ts +0 -40
- package/dist/shadow-m3-calibrate.d.ts.map +0 -1
- package/src/__tests__/bind-group-cache-binding.test.ts +0 -2513
- package/src/__tests__/bind-group-cache-frame.test.ts +0 -1511
- package/src/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.ts +0 -204
- package/src/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.ts +0 -297
- package/src/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.ts +0 -271
- package/src/__tests__/dispatch-fullscreen-pass-params.unit.test.ts +0 -321
- package/src/__tests__/fog-producer-manifest.ts +0 -162
- package/src/__tests__/fog-producer-pixel-probe.ts +0 -263
- package/src/__tests__/fog-producer-pixel.browser.test.ts +0 -26
- package/src/__tests__/fog-producer-pixel.dawn.test.ts +0 -55
- package/src/__tests__/fog-producer-real-fixture.ts +0 -805
- package/src/__tests__/fog-producer-vfx-effect.ts +0 -272
- package/src/__tests__/fog-scene-asset.integration.test.ts +0 -123
- package/src/__tests__/gpu-resource-store-cubemap-status.test.ts +0 -207
- package/src/__tests__/gpu-resource.test.ts +0 -1206
- package/src/__tests__/hdrp-bgl-slots.browser.test.ts +0 -50
- package/src/__tests__/hdrp-buffers.unit.test.ts +0 -70
- package/src/__tests__/hdrp-execute-filter.unit.test.ts +0 -200
- package/src/__tests__/hdrp-gbuffer-attachments.browser.test.ts +0 -64
- package/src/__tests__/hdrp-pipeline-asset-type.test-d.ts +0 -139
- package/src/__tests__/hdrp-ssao-boundary.test.ts +0 -237
- package/src/__tests__/hdrp-ssao-falsification.test.ts +0 -289
- package/src/__tests__/helpers/primitive-world.ts +0 -91
- package/src/__tests__/helpers/render-asset-port.ts +0 -65
- package/src/__tests__/helpers/scene-asset-port.ts +0 -23
- package/src/__tests__/material-derived-coordinates.integration.test.ts +0 -100
- package/src/__tests__/pipeline-layout-selection.test.ts +0 -298
- package/src/__tests__/post-process-reads-narrowing.test-d.ts +0 -52
- package/src/__tests__/post-process-register-roundtrip.dawn.test.ts +0 -230
- package/src/__tests__/render-feature-zero-feature.browser.test.ts +0 -152
- package/src/__tests__/render-pipeline-trivial.dawn.test.ts +0 -525
- package/src/__tests__/shadow-csm-caster-membership.test.ts +0 -232
- package/src/__tests__/shadow-csm-pssm.test.ts +0 -142
- package/src/__tests__/shadow-csm-temporal.browser.test.ts +0 -145
- package/src/__tests__/shadow-csm-viewport.test.ts +0 -74
- package/src/__tests__/shadow-m2.dawn.test.ts +0 -394
- package/src/__tests__/shadow-m3-calibrate-run.dawn.test.ts +0 -248
- package/src/__tests__/shadow-m3-calibrate.ts +0 -203
- package/src/__tests__/shadow-m3.dawn.test.ts +0 -288
- package/src/__tests__/shadow-probe-control-flow.dawn.test.ts +0 -264
- package/src/__tests__/shadow-quality-metrics.dawn.test.ts +0 -324
- package/src/__tests__/temporal-off-path.unit.test.ts +0 -69
- package/src/__tests__/video-cache-regression.unit.test.ts +0 -186
- package/src/asset-kind.ts +0 -7
- package/src/errors/sprite-animation.ts +0 -5
- package/src/scene-asset-port.ts +0 -32
- package/src/scene-collect-errors.ts +0 -30
- package/src/shadow-m3-calibrate.ts +0 -171
|
@@ -6,25 +6,13 @@
|
|
|
6
6
|
// Each original file body sits in its own block-scope so helper names
|
|
7
7
|
// cannot collide; describe() inside still registers globally with vitest.
|
|
8
8
|
|
|
9
|
+
import { AssetRegistry } from '@forgeax/engine-assets-runtime';
|
|
9
10
|
import { World } from '@forgeax/engine-ecs';
|
|
11
|
+
import { Camera, MeshFilter, MeshRenderer } from '@forgeax/engine-render';
|
|
10
12
|
import {
|
|
11
13
|
SPRITE_PREMULTIPLIED_ALPHA_BLEND,
|
|
12
14
|
SpriteRegionOverride,
|
|
13
15
|
} from '@forgeax/engine-render/authoring';
|
|
14
|
-
import type { DispatchEntry } from '@forgeax/engine-render/internal';
|
|
15
|
-
import * as recordModule from '@forgeax/engine-render/internal';
|
|
16
|
-
import {
|
|
17
|
-
Camera,
|
|
18
|
-
createEngineMetrics,
|
|
19
|
-
detectNineSliceScaleTooSmall,
|
|
20
|
-
extractFrame,
|
|
21
|
-
isLitMaterialSnapshot,
|
|
22
|
-
type MaterialSnapshot,
|
|
23
|
-
MeshFilter,
|
|
24
|
-
MeshRenderer,
|
|
25
|
-
prepareExtractContext,
|
|
26
|
-
writeMaterialSnapshotPayload,
|
|
27
|
-
} from '@forgeax/engine-render/internal';
|
|
28
16
|
import { propagateTransforms, Transform } from '@forgeax/engine-scene';
|
|
29
17
|
import { ShaderRegistry, type ShaderRegistryDevice } from '@forgeax/engine-shader';
|
|
30
18
|
import type {
|
|
@@ -33,40 +21,200 @@ import type {
|
|
|
33
21
|
MaterialPass,
|
|
34
22
|
MeshAsset,
|
|
35
23
|
ParamSchemaEntry,
|
|
36
|
-
PassSelector,
|
|
37
24
|
} from '@forgeax/engine-types';
|
|
38
25
|
import { derive } from '@forgeax/engine-types';
|
|
39
26
|
import { describe, expect, it } from 'vitest';
|
|
40
|
-
import {
|
|
27
|
+
import { createEngineMetrics } from '../../../render/src/engine-metrics';
|
|
28
|
+
import { isLitMaterialSnapshot } from '../../../render/src/record/helpers';
|
|
29
|
+
import * as recordModule from '../../../render/src/record/main-pass-material';
|
|
30
|
+
import { detectNineSliceScaleTooSmall } from '../../../render/src/record/main-pass-material';
|
|
31
|
+
import * as spriteRecordModule from '../../../render/src/record/main-pass-sprite-draws';
|
|
32
|
+
import { filterDispatchBySelector } from '../../../render/src/record/shadow-pass';
|
|
33
|
+
import type { DispatchEntry, MaterialSnapshot } from '../../../render/src/render-system-extract';
|
|
34
|
+
import { extractFrame, prepareExtractContext } from '../../../render/src/render-system-extract';
|
|
35
|
+
|
|
36
|
+
// ─── from render-system-record-pbr-ubo-stable.test.ts ───
|
|
37
|
+
{
|
|
38
|
+
// render-system-record-pbr-ubo-stable - feat-20260527-sprite-nineslice M2 / w6.
|
|
39
|
+
//
|
|
40
|
+
// PBR Material UBO byte-sequence regression net (D-7 isolation):
|
|
41
|
+
// any deviation in the PBR write path's byte sequence (even 1 byte) caused
|
|
42
|
+
// by the sprite-branch schema-driven UBO extension (w11) MUST fail this test
|
|
43
|
+
// — that triggers R-8 fallback (revert D-7 to physically isolated sprite
|
|
44
|
+
// write function).
|
|
45
|
+
//
|
|
46
|
+
// w11 will extract the inline PBR UBO write path
|
|
47
|
+
// (render-system-record.ts:2194-2277 -- baseColor, metallic, roughness,
|
|
48
|
+
// channelMap u32 packing, emissive, occlusionStrength, paramSnapshot
|
|
49
|
+
// schema-driven overlay) into a pure helper
|
|
50
|
+
// `buildPbrMaterialUboPayload(material) -> Uint8Array(288B)` so this
|
|
51
|
+
// regression test can exercise the PBR write byte-for-byte.
|
|
52
|
+
//
|
|
53
|
+
// The helper MUST produce the exact byte sequence the inline path produced
|
|
54
|
+
// pre-feat (no slices-related side effects on the PBR layout). This test
|
|
55
|
+
// asserts the PBR baseline against literal byte values.
|
|
56
|
+
//
|
|
57
|
+
// Coverage:
|
|
58
|
+
// - 304 B payload (STANDARD_PBR_UBO_SIZE)
|
|
59
|
+
// - slot 0 = baseColor.rgb + 1 (alpha hardcoded)
|
|
60
|
+
// - slot 1 first 8 B = metallic, roughness (f32x2)
|
|
61
|
+
// - slot 1 last 4 u32 (channelMap) = [2, 1, 0, 0]
|
|
62
|
+
// - slot 2 = emissive.rgb + emissiveIntensity
|
|
63
|
+
// - slot 3 first 4 B = occlusionStrength; rest stays 0 (no schema overlay
|
|
64
|
+
// in default-standard-pbr path; paramSnapshot reuses slot 0/1/2 by
|
|
65
|
+
// position).
|
|
66
|
+
//
|
|
67
|
+
// Anchors: plan-strategy §R-8, §5.3 key tests #2; AGENTS.md §Error model
|
|
68
|
+
// (closed-union AssetErrorCode unchanged, baseline test does not depend on
|
|
69
|
+
// new error members).
|
|
41
70
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
textureCoordinates: new Map([
|
|
51
|
-
[
|
|
52
|
-
'albedo',
|
|
53
|
-
{
|
|
54
|
-
set: 0,
|
|
55
|
-
transform: { offset: [0, 0], scale: [1, 1], rotation: 0 },
|
|
56
|
-
physicalUvScale: [1, 1],
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
]),
|
|
60
|
-
},
|
|
61
|
-
16,
|
|
62
|
-
);
|
|
71
|
+
const mod = recordModule as unknown as {
|
|
72
|
+
buildPbrMaterialUboPayload?: (material: MaterialSnapshot) => Uint8Array;
|
|
73
|
+
applyMaterialTextureUvScales?: (
|
|
74
|
+
payload: ArrayBuffer | Uint8Array,
|
|
75
|
+
material: MaterialSnapshot,
|
|
76
|
+
world: World,
|
|
77
|
+
) => void;
|
|
78
|
+
};
|
|
63
79
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
80
|
+
function makePbrSnapshot(opts: {
|
|
81
|
+
baseColor?: readonly [number, number, number, number];
|
|
82
|
+
metallic?: number;
|
|
83
|
+
roughness?: number;
|
|
84
|
+
emissive?: readonly [number, number, number];
|
|
85
|
+
emissiveIntensity?: number;
|
|
86
|
+
occlusionStrength?: number;
|
|
87
|
+
clearcoat?: number;
|
|
88
|
+
clearcoatRoughness?: number;
|
|
89
|
+
specularTint?: readonly [number, number, number];
|
|
90
|
+
}): MaterialSnapshot {
|
|
91
|
+
return {
|
|
92
|
+
baseColor: opts.baseColor ?? [0.5, 0.6, 0.7, 1],
|
|
93
|
+
metallic: opts.metallic ?? 0.1,
|
|
94
|
+
roughness: opts.roughness ?? 0.4,
|
|
95
|
+
materialShaderId: 'forgeax::default-standard-pbr',
|
|
96
|
+
paramSnapshot: undefined,
|
|
97
|
+
...(opts.emissive !== undefined && { emissive: opts.emissive }),
|
|
98
|
+
...(opts.emissiveIntensity !== undefined && { emissiveIntensity: opts.emissiveIntensity }),
|
|
99
|
+
...(opts.occlusionStrength !== undefined && { occlusionStrength: opts.occlusionStrength }),
|
|
100
|
+
...(opts.clearcoat !== undefined && { clearcoat: opts.clearcoat }),
|
|
101
|
+
...(opts.clearcoatRoughness !== undefined && { clearcoatRoughness: opts.clearcoatRoughness }),
|
|
102
|
+
...(opts.specularTint !== undefined && { specularTint: opts.specularTint }),
|
|
103
|
+
} as unknown as MaterialSnapshot;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
describe('PBR Material UBO byte sequence regression net (M2 / w6, D-7 isolation)', () => {
|
|
107
|
+
it('export: buildPbrMaterialUboPayload helper is exported from render-system-record', () => {
|
|
108
|
+
expect(typeof mod.buildPbrMaterialUboPayload).toBe('function');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('304 B payload size + standard PBR slot layout (baseline)', () => {
|
|
112
|
+
if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
|
|
113
|
+
throw new Error('helper not exported yet');
|
|
114
|
+
}
|
|
115
|
+
const snap = makePbrSnapshot({
|
|
116
|
+
baseColor: [0.5, 0.6, 0.7, 1],
|
|
117
|
+
metallic: 0.1,
|
|
118
|
+
roughness: 0.4,
|
|
119
|
+
emissive: [0, 0, 0],
|
|
120
|
+
emissiveIntensity: 0,
|
|
121
|
+
occlusionStrength: 1,
|
|
122
|
+
clearcoat: 0.85,
|
|
123
|
+
clearcoatRoughness: 0.12,
|
|
124
|
+
specularTint: [0.11, 0.22, 0.33],
|
|
125
|
+
});
|
|
126
|
+
const buf = mod.buildPbrMaterialUboPayload(snap);
|
|
127
|
+
expect(buf.byteLength).toBe(304);
|
|
128
|
+
const f32 = new Float32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4);
|
|
129
|
+
// feat-20260613 fix-issue-1 (D-8 channelMap split): the 4 channelMap
|
|
130
|
+
// u32 slots collapse into 4 independent f32 channel selectors at
|
|
131
|
+
// f32[6..9] (metallicChannel/roughnessChannel/aoChannel/extraChannel).
|
|
132
|
+
// baseColor.rgb + alpha=1 (alpha hardcoded in PBR write path).
|
|
133
|
+
expect(f32[0]).toBeCloseTo(0.5);
|
|
134
|
+
expect(f32[1]).toBeCloseTo(0.6);
|
|
135
|
+
expect(f32[2]).toBeCloseTo(0.7);
|
|
136
|
+
expect(f32[3]).toBe(1);
|
|
137
|
+
// metallic + roughness (first 8 B of slot 1).
|
|
138
|
+
expect(f32[4]).toBeCloseTo(0.1);
|
|
139
|
+
expect(f32[5]).toBeCloseTo(0.4);
|
|
140
|
+
// 4 channel selectors as f32 (default = B/G/R/_ glTF packing).
|
|
141
|
+
expect(f32[6]).toBe(2); // metallicChannel <- B
|
|
142
|
+
expect(f32[7]).toBe(1); // roughnessChannel <- G
|
|
143
|
+
expect(f32[8]).toBe(0); // aoChannel <- R
|
|
144
|
+
expect(f32[9]).toBe(0); // extraChannel <- reserved
|
|
145
|
+
// offsets 40..47 implicit pad (vec3 align=16 before emissive).
|
|
146
|
+
expect(f32[10]).toBe(0);
|
|
147
|
+
expect(f32[11]).toBe(0);
|
|
148
|
+
// emissive.rgb + emissiveIntensity (offset 48..63).
|
|
149
|
+
expect(f32[12]).toBe(0);
|
|
150
|
+
expect(f32[13]).toBe(0);
|
|
151
|
+
expect(f32[14]).toBe(0);
|
|
152
|
+
expect(f32[15]).toBe(0);
|
|
153
|
+
// occlusionStrength (offset 64..67).
|
|
154
|
+
expect(f32[16]).toBe(1);
|
|
155
|
+
// alphaCutoff (offset 68).
|
|
156
|
+
expect(f32[17]).toBe(0);
|
|
157
|
+
// clearcoat layer (offsets 72..79).
|
|
158
|
+
expect(f32[18]).toBeCloseTo(0.85);
|
|
159
|
+
expect(f32[19]).toBeCloseTo(0.12);
|
|
160
|
+
// specularTint vec3 (offsets 80..92).
|
|
161
|
+
expect(f32[20]).toBeCloseTo(0.11);
|
|
162
|
+
expect(f32[21]).toBeCloseTo(0.22);
|
|
163
|
+
expect(f32[22]).toBeCloseTo(0.33);
|
|
164
|
+
expect(f32[72]).toBe(1);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('writes schema-carried alphaCutoff into the baseline PBR payload', () => {
|
|
168
|
+
if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
|
|
169
|
+
throw new Error('helper not exported yet');
|
|
170
|
+
}
|
|
171
|
+
const payload = mod.buildPbrMaterialUboPayload({
|
|
172
|
+
...makePbrSnapshot({}),
|
|
173
|
+
paramSnapshot: { alphaCutoff: 0.5 },
|
|
174
|
+
} as MaterialSnapshot);
|
|
175
|
+
const f32 = new Float32Array(payload.buffer, payload.byteOffset, payload.byteLength / 4);
|
|
176
|
+
expect(f32[17]).toBeCloseTo(0.5);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('keeps engine-owned texture UV tails aligned across PBR and sprite layouts', () => {
|
|
180
|
+
const apply = mod.applyMaterialTextureUvScales;
|
|
181
|
+
if (typeof apply !== 'function') throw new Error('helper not exported yet');
|
|
182
|
+
const world = new World();
|
|
183
|
+
const pbrPayload = new ArrayBuffer(304);
|
|
184
|
+
apply(pbrPayload, makePbrSnapshot({}), world);
|
|
185
|
+
const pbrF32 = new Float32Array(pbrPayload);
|
|
186
|
+
expect(pbrF32[26]).toBe(1);
|
|
187
|
+
expect(pbrF32[34]).toBe(1);
|
|
188
|
+
expect(pbrF32[42]).toBe(1);
|
|
189
|
+
expect(pbrF32[50]).toBe(1);
|
|
190
|
+
expect(pbrF32[58]).toBe(1);
|
|
191
|
+
expect(pbrF32[66]).toBe(1);
|
|
192
|
+
|
|
193
|
+
const spritePayload = new ArrayBuffer(128);
|
|
194
|
+
apply(
|
|
195
|
+
spritePayload,
|
|
196
|
+
{ ...makePbrSnapshot({}), materialShaderId: 'forgeax::sprite' } as MaterialSnapshot,
|
|
197
|
+
world,
|
|
198
|
+
);
|
|
199
|
+
const spriteF32 = new Float32Array(spritePayload);
|
|
200
|
+
expect(Array.from(spriteF32.slice(16, 24))).toEqual([0, 0, 1, 1, 0, 0, 1, 1]);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('byte-stable across two equivalent PBR snapshots (idempotent write)', () => {
|
|
204
|
+
if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
|
|
205
|
+
throw new Error('helper not exported yet');
|
|
206
|
+
}
|
|
207
|
+
const snap = makePbrSnapshot({
|
|
208
|
+
baseColor: [0.2, 0.3, 0.4, 1],
|
|
209
|
+
metallic: 0.5,
|
|
210
|
+
roughness: 0.5,
|
|
211
|
+
});
|
|
212
|
+
const a = mod.buildPbrMaterialUboPayload(snap);
|
|
213
|
+
const b = mod.buildPbrMaterialUboPayload(snap);
|
|
214
|
+
expect(new Uint8Array(a)).toEqual(new Uint8Array(b));
|
|
67
215
|
});
|
|
68
216
|
});
|
|
69
|
-
}
|
|
217
|
+
}
|
|
70
218
|
|
|
71
219
|
// ─── from render-system-record-scale-too-small.test.ts ───
|
|
72
220
|
{
|
|
@@ -74,7 +222,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
74
222
|
//
|
|
75
223
|
// AC-16 end-to-end: when a 9-slice sprite entity carries a Transform.scale
|
|
76
224
|
// below the four corner anchors, the detection path bumps
|
|
77
|
-
//
|
|
225
|
+
// the owner metrics snapshot's `nineslice.scale-too-small` key once per offending
|
|
78
226
|
// renderableIndex per RenderSystem lifetime. AI users observe the breach
|
|
79
227
|
// through the EngineMetrics counter rather than parsing console.warn text
|
|
80
228
|
// (charter P3 machine-readable signals).
|
|
@@ -290,7 +438,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
290
438
|
describe('SpriteRegionOverride compose 9-slice (M4 / w17b, AC-14)', () => {
|
|
291
439
|
it('(1) entity without override uses asset-side region', () => {
|
|
292
440
|
const world = new World();
|
|
293
|
-
const assets =
|
|
441
|
+
const assets = new AssetRegistry(makeShaderRegistryWithSprite());
|
|
294
442
|
const mesh = registerSpriteMesh(world);
|
|
295
443
|
const matHandle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
|
|
296
444
|
kind: 'material',
|
|
@@ -318,7 +466,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
318
466
|
|
|
319
467
|
it('(2) entity with override uses the override region in the snapshot', () => {
|
|
320
468
|
const world = new World();
|
|
321
|
-
const assets =
|
|
469
|
+
const assets = new AssetRegistry(makeShaderRegistryWithSprite());
|
|
322
470
|
const mesh = registerSpriteMesh(world);
|
|
323
471
|
const matHandle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
|
|
324
472
|
kind: 'material',
|
|
@@ -352,7 +500,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
352
500
|
|
|
353
501
|
it('(3) two entities sharing one material diverge on effective region (compose with 9-slice)', () => {
|
|
354
502
|
const world = new World();
|
|
355
|
-
const assets =
|
|
503
|
+
const assets = new AssetRegistry(makeShaderRegistryWithSprite());
|
|
356
504
|
const mesh = registerSpriteMesh(world);
|
|
357
505
|
const matHandle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
|
|
358
506
|
kind: 'material',
|
|
@@ -583,15 +731,6 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
583
731
|
//
|
|
584
732
|
// Anchors: plan-strategy section 5.3 key tests; requirements AC-03/AC-04/AC-18.
|
|
585
733
|
|
|
586
|
-
const filterDispatchBySelector = (
|
|
587
|
-
recordModule as unknown as {
|
|
588
|
-
filterDispatchBySelector?: (
|
|
589
|
-
dispatch: readonly DispatchEntry[],
|
|
590
|
-
selector: PassSelector,
|
|
591
|
-
) => readonly DispatchEntry[];
|
|
592
|
-
}
|
|
593
|
-
).filterDispatchBySelector;
|
|
594
|
-
|
|
595
734
|
function makeDispatchEntry(
|
|
596
735
|
renderableIndex: number,
|
|
597
736
|
passIndex: number,
|
|
@@ -890,6 +1029,191 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
890
1029
|
});
|
|
891
1030
|
}
|
|
892
1031
|
|
|
1032
|
+
// --- from feat-20260625-refactor-sprite-as-transparent-mesh M1 / w2 ---
|
|
1033
|
+
{
|
|
1034
|
+
// standard-pbr regression: the generic writer over the engine-shipped
|
|
1035
|
+
// default-standard-pbr.material.json paramSchema (15 numeric entries
|
|
1036
|
+
// std140-packed into 96 B) must produce byte-identical output to
|
|
1037
|
+
// buildPbrMaterialUboPayload. This is the gate plan-strategy section 2
|
|
1038
|
+
// D-2 sets so the generic writer can replace the inline overlay without
|
|
1039
|
+
// perturbing PBR rendering. RED until w3 lands the helper.
|
|
1040
|
+
|
|
1041
|
+
const mod = recordModule as unknown as {
|
|
1042
|
+
applyParamSnapshotToUbo?: (
|
|
1043
|
+
payload: ArrayBuffer | Uint8Array,
|
|
1044
|
+
paramSchema: readonly ParamSchemaEntry[] | undefined,
|
|
1045
|
+
paramSnapshot:
|
|
1046
|
+
| Readonly<Record<string, number | readonly number[] | string | undefined>>
|
|
1047
|
+
| undefined,
|
|
1048
|
+
) => void;
|
|
1049
|
+
buildPbrMaterialUboPayload?: (material: MaterialSnapshot) => Uint8Array;
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
// Mirror the engine-shipped default-standard-pbr.material.json schema
|
|
1053
|
+
// (the on-disk SSOT; inline here to keep the unit suite free of asset
|
|
1054
|
+
// loads).
|
|
1055
|
+
const STANDARD_PBR_SCHEMA: readonly ParamSchemaEntry[] = [
|
|
1056
|
+
{ name: 'baseColor', type: 'color', default: [1, 1, 1, 1] },
|
|
1057
|
+
{ name: 'metallic', type: 'f32', default: 0 },
|
|
1058
|
+
{ name: 'roughness', type: 'f32', default: 0.5 },
|
|
1059
|
+
{ name: 'metallicChannel', type: 'f32', default: 2 },
|
|
1060
|
+
{ name: 'roughnessChannel', type: 'f32', default: 1 },
|
|
1061
|
+
{ name: 'aoChannel', type: 'f32', default: 0 },
|
|
1062
|
+
{ name: 'extraChannel', type: 'f32', default: 0 },
|
|
1063
|
+
{ name: 'emissive', type: 'vec3', default: [0, 0, 0] },
|
|
1064
|
+
{ name: 'emissiveIntensity', type: 'f32', default: 0 },
|
|
1065
|
+
{ name: 'occlusionStrength', type: 'f32', default: 1 },
|
|
1066
|
+
{ name: 'alphaCutoff', type: 'f32', default: 0 },
|
|
1067
|
+
{ name: 'clearcoat', type: 'f32', default: 0 },
|
|
1068
|
+
{ name: 'clearcoatRoughness', type: 'f32', default: 0.5 },
|
|
1069
|
+
{ name: 'specularTint', type: 'vec3', default: [1, 1, 1] },
|
|
1070
|
+
];
|
|
1071
|
+
|
|
1072
|
+
describe('applyParamSnapshotToUbo: standard-pbr byte-identical via derive (M1 / w2)', () => {
|
|
1073
|
+
it('derive(standard-pbr).uboLayout matches the 96 B authored numeric layout', () => {
|
|
1074
|
+
const { uboLayout } = derive(STANDARD_PBR_SCHEMA);
|
|
1075
|
+
expect(uboLayout.totalBytes).toBe(96);
|
|
1076
|
+
const byName = new Map(uboLayout.entries.map((e) => [e.name, e]));
|
|
1077
|
+
expect(byName.get('baseColor')?.offset).toBe(0);
|
|
1078
|
+
expect(byName.get('metallic')?.offset).toBe(16);
|
|
1079
|
+
expect(byName.get('roughness')?.offset).toBe(20);
|
|
1080
|
+
expect(byName.get('metallicChannel')?.offset).toBe(24);
|
|
1081
|
+
expect(byName.get('roughnessChannel')?.offset).toBe(28);
|
|
1082
|
+
expect(byName.get('aoChannel')?.offset).toBe(32);
|
|
1083
|
+
expect(byName.get('extraChannel')?.offset).toBe(36);
|
|
1084
|
+
// vec3 aligns to 16: cursor at 40 rounds up to 48.
|
|
1085
|
+
expect(byName.get('emissive')?.offset).toBe(48);
|
|
1086
|
+
expect(byName.get('emissiveIntensity')?.offset).toBe(60);
|
|
1087
|
+
expect(byName.get('occlusionStrength')?.offset).toBe(64);
|
|
1088
|
+
expect(byName.get('alphaCutoff')?.offset).toBe(68);
|
|
1089
|
+
expect(byName.get('clearcoat')?.offset).toBe(72);
|
|
1090
|
+
expect(byName.get('clearcoatRoughness')?.offset).toBe(76);
|
|
1091
|
+
expect(byName.get('specularTint')?.offset).toBe(80);
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
it('generic writer over standard-pbr snapshot equals buildPbrMaterialUboPayload bytes', () => {
|
|
1095
|
+
if (typeof mod.applyParamSnapshotToUbo !== 'function') {
|
|
1096
|
+
throw new Error('helper not exported yet (red phase)');
|
|
1097
|
+
}
|
|
1098
|
+
if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
|
|
1099
|
+
throw new Error('buildPbrMaterialUboPayload missing -- baseline broken');
|
|
1100
|
+
}
|
|
1101
|
+
// Construct a snapshot equivalent to the explicit material fields the
|
|
1102
|
+
// legacy helper consumes (baseColor / metallic / roughness / emissive /
|
|
1103
|
+
// emissiveIntensity / occlusionStrength + the channelMap defaults the
|
|
1104
|
+
// helper hard-codes).
|
|
1105
|
+
const baseColor = [0.5, 0.6, 0.7, 1] as readonly number[];
|
|
1106
|
+
const metallic = 0.1;
|
|
1107
|
+
const roughness = 0.4;
|
|
1108
|
+
const emissive = [0, 0, 0] as readonly number[];
|
|
1109
|
+
const emissiveIntensity = 0;
|
|
1110
|
+
const occlusionStrength = 1;
|
|
1111
|
+
const material = {
|
|
1112
|
+
baseColor,
|
|
1113
|
+
metallic,
|
|
1114
|
+
roughness,
|
|
1115
|
+
materialShaderId: 'forgeax::default-standard-pbr',
|
|
1116
|
+
paramSnapshot: undefined,
|
|
1117
|
+
emissive,
|
|
1118
|
+
emissiveIntensity,
|
|
1119
|
+
occlusionStrength,
|
|
1120
|
+
alphaCutoff: 0,
|
|
1121
|
+
clearcoat: 0,
|
|
1122
|
+
clearcoatRoughness: 0.5,
|
|
1123
|
+
specularTint: [1, 1, 1],
|
|
1124
|
+
} as unknown as MaterialSnapshot;
|
|
1125
|
+
const baseline = mod.buildPbrMaterialUboPayload(material);
|
|
1126
|
+
// Construct the generic-writer output: start from the same explicit
|
|
1127
|
+
// PBR baseline, then apply the generic overlay over a paramSnapshot
|
|
1128
|
+
// carrying the same values. The overlay must not perturb any byte
|
|
1129
|
+
// the explicit baseline already wrote (charter P4 -- one writer, one
|
|
1130
|
+
// byte layout).
|
|
1131
|
+
const candidate = mod.buildPbrMaterialUboPayload(material);
|
|
1132
|
+
const snapshot = {
|
|
1133
|
+
baseColor,
|
|
1134
|
+
metallic,
|
|
1135
|
+
roughness,
|
|
1136
|
+
metallicChannel: 2,
|
|
1137
|
+
roughnessChannel: 1,
|
|
1138
|
+
aoChannel: 0,
|
|
1139
|
+
extraChannel: 0,
|
|
1140
|
+
emissive,
|
|
1141
|
+
emissiveIntensity,
|
|
1142
|
+
occlusionStrength,
|
|
1143
|
+
specularTint: [1, 1, 1],
|
|
1144
|
+
};
|
|
1145
|
+
mod.applyParamSnapshotToUbo(candidate, STANDARD_PBR_SCHEMA, snapshot);
|
|
1146
|
+
expect(new Uint8Array(candidate)).toEqual(new Uint8Array(baseline));
|
|
1147
|
+
});
|
|
1148
|
+
|
|
1149
|
+
it('overlays non-opaque standard-PBR baseColor alpha over the opaque baseline', () => {
|
|
1150
|
+
if (typeof mod.applyParamSnapshotToUbo !== 'function') {
|
|
1151
|
+
throw new Error('helper not exported yet (red phase)');
|
|
1152
|
+
}
|
|
1153
|
+
if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
|
|
1154
|
+
throw new Error('buildPbrMaterialUboPayload missing -- baseline broken');
|
|
1155
|
+
}
|
|
1156
|
+
const material = {
|
|
1157
|
+
baseColor: [0.5, 0.6, 0.7, 0.5],
|
|
1158
|
+
metallic: 0,
|
|
1159
|
+
roughness: 0.5,
|
|
1160
|
+
materialShaderId: 'forgeax::default-standard-pbr',
|
|
1161
|
+
paramSnapshot: undefined,
|
|
1162
|
+
} as unknown as MaterialSnapshot;
|
|
1163
|
+
const payload = mod.buildPbrMaterialUboPayload(material);
|
|
1164
|
+
// The explicit baseline is intentionally opaque; importer-supplied
|
|
1165
|
+
// paramSnapshot values must overwrite all four baseColor components.
|
|
1166
|
+
expect(new Float32Array(payload.buffer, payload.byteOffset, payload.byteLength / 4)[3]).toBe(
|
|
1167
|
+
1,
|
|
1168
|
+
);
|
|
1169
|
+
mod.applyParamSnapshotToUbo(payload, STANDARD_PBR_SCHEMA, {
|
|
1170
|
+
baseColor: [0.5, 0.6, 0.7, 0.5],
|
|
1171
|
+
});
|
|
1172
|
+
expect(new Float32Array(payload.buffer, payload.byteOffset, payload.byteLength / 4)[3]).toBe(
|
|
1173
|
+
0.5,
|
|
1174
|
+
);
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
it('honours f32 slot offsets independently (slot 1 width = 4 floats from metallic..extraChannel)', () => {
|
|
1178
|
+
if (typeof mod.applyParamSnapshotToUbo !== 'function') {
|
|
1179
|
+
throw new Error('helper not exported yet (red phase)');
|
|
1180
|
+
}
|
|
1181
|
+
const buf = new ArrayBuffer(80);
|
|
1182
|
+
// f32-exact values (powers of 2 / sums) so we can assert toEqual on
|
|
1183
|
+
// every slot; toBeCloseTo would let off-by-one-bit drifts hide.
|
|
1184
|
+
const snapshot = {
|
|
1185
|
+
baseColor: [0.125, 0.25, 0.5, 1] as readonly number[],
|
|
1186
|
+
metallic: 0.5,
|
|
1187
|
+
roughness: 0.25,
|
|
1188
|
+
metallicChannel: 2,
|
|
1189
|
+
roughnessChannel: 1,
|
|
1190
|
+
aoChannel: 0,
|
|
1191
|
+
extraChannel: 0,
|
|
1192
|
+
emissive: [0.5, 0.5, 0.5] as readonly number[],
|
|
1193
|
+
emissiveIntensity: 1.5,
|
|
1194
|
+
occlusionStrength: 0.75,
|
|
1195
|
+
};
|
|
1196
|
+
mod.applyParamSnapshotToUbo(buf, STANDARD_PBR_SCHEMA, snapshot);
|
|
1197
|
+
const f32 = new Float32Array(buf);
|
|
1198
|
+
// baseColor occupies slot 0 (offset 0).
|
|
1199
|
+
expect(Array.from(f32.slice(0, 4))).toEqual([0.125, 0.25, 0.5, 1]);
|
|
1200
|
+
// 4 f32 channels packed at offset 16..36 -- distinct slots, not folded
|
|
1201
|
+
// into one vec4 (regression against legacy "first two f32 only"
|
|
1202
|
+
// overlay at render-system-record.ts:4334-4374).
|
|
1203
|
+
expect(f32[4]).toBe(0.5);
|
|
1204
|
+
expect(f32[5]).toBe(0.25);
|
|
1205
|
+
expect(f32[6]).toBe(2);
|
|
1206
|
+
expect(f32[7]).toBe(1);
|
|
1207
|
+
expect(f32[8]).toBe(0);
|
|
1208
|
+
expect(f32[9]).toBe(0);
|
|
1209
|
+
// emissive vec3 at offset 48 (f32 index 12).
|
|
1210
|
+
expect(Array.from(f32.slice(12, 15))).toEqual([0.5, 0.5, 0.5]);
|
|
1211
|
+
expect(f32[15]).toBe(1.5);
|
|
1212
|
+
expect(f32[16]).toBe(0.75);
|
|
1213
|
+
});
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
|
|
893
1217
|
// --- from feat-20260625-refactor-sprite-as-transparent-mesh M2 / w4 ---
|
|
894
1218
|
{
|
|
895
1219
|
// AC-05: a MaterialSnapshot carrying transparent:true on its source pass
|
|
@@ -927,11 +1251,13 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
927
1251
|
};
|
|
928
1252
|
};
|
|
929
1253
|
|
|
930
|
-
const
|
|
1254
|
+
const spriteMod = spriteRecordModule as unknown as {
|
|
931
1255
|
computeSplitLdrSprite?: (
|
|
932
1256
|
validatedOrdered: readonly (DispatchEntryLike | undefined)[],
|
|
933
1257
|
tonemapActive: boolean,
|
|
934
1258
|
) => boolean;
|
|
1259
|
+
};
|
|
1260
|
+
const mod = recordModule as unknown as {
|
|
935
1261
|
isEntityFullyTransparent?: (source: {
|
|
936
1262
|
material: MaterialSnapshot;
|
|
937
1263
|
materials?: readonly MaterialSnapshot[];
|
|
@@ -962,11 +1288,11 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
962
1288
|
|
|
963
1289
|
describe('transparent decouples from sprite shader (M2 / w4, AC-05)', () => {
|
|
964
1290
|
it('export: computeSplitLdrSprite helper is exported from render-system-record', () => {
|
|
965
|
-
expect(typeof
|
|
1291
|
+
expect(typeof spriteMod.computeSplitLdrSprite).toBe('function');
|
|
966
1292
|
});
|
|
967
1293
|
|
|
968
1294
|
it('non-sprite shader with transparent:true triggers LDR split', () => {
|
|
969
|
-
if (typeof
|
|
1295
|
+
if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
|
|
970
1296
|
throw new Error('computeSplitLdrSprite helper not exported yet (red phase)');
|
|
971
1297
|
}
|
|
972
1298
|
const transparentSnap = makeTransparentSnap({
|
|
@@ -980,7 +1306,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
980
1306
|
// tonemapActive=false (LDR path) + a transparent entry in the
|
|
981
1307
|
// validated list -- the split decision must trip even though the
|
|
982
1308
|
// shader is not forgeax::sprite (AC-05 proves the decoupling).
|
|
983
|
-
const split =
|
|
1309
|
+
const split = spriteMod.computeSplitLdrSprite(
|
|
984
1310
|
[makeValidatedEntry(opaqueSnap), makeValidatedEntry(transparentSnap)],
|
|
985
1311
|
false,
|
|
986
1312
|
);
|
|
@@ -988,7 +1314,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
988
1314
|
});
|
|
989
1315
|
|
|
990
1316
|
it('LDR split stays false on pure-opaque non-sprite list', () => {
|
|
991
|
-
if (typeof
|
|
1317
|
+
if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
|
|
992
1318
|
throw new Error('computeSplitLdrSprite helper not exported yet (red phase)');
|
|
993
1319
|
}
|
|
994
1320
|
const opaqueA = makeTransparentSnap({
|
|
@@ -999,7 +1325,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
999
1325
|
transparent: false,
|
|
1000
1326
|
materialShaderId: 'forgeax::default-standard-pbr',
|
|
1001
1327
|
});
|
|
1002
|
-
const split =
|
|
1328
|
+
const split = spriteMod.computeSplitLdrSprite(
|
|
1003
1329
|
[makeValidatedEntry(opaqueA), makeValidatedEntry(opaqueB)],
|
|
1004
1330
|
false,
|
|
1005
1331
|
);
|
|
@@ -1007,19 +1333,19 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1007
1333
|
});
|
|
1008
1334
|
|
|
1009
1335
|
it('HDR path (tonemapActive=true) suppresses split even with transparent entries', () => {
|
|
1010
|
-
if (typeof
|
|
1336
|
+
if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
|
|
1011
1337
|
throw new Error('computeSplitLdrSprite helper not exported yet (red phase)');
|
|
1012
1338
|
}
|
|
1013
1339
|
const transparentSnap = makeTransparentSnap({
|
|
1014
1340
|
transparent: true,
|
|
1015
1341
|
materialShaderId: 'forgeax::unlit-test',
|
|
1016
1342
|
});
|
|
1017
|
-
const split =
|
|
1343
|
+
const split = spriteMod.computeSplitLdrSprite([makeValidatedEntry(transparentSnap)], true);
|
|
1018
1344
|
expect(split).toBe(false);
|
|
1019
1345
|
});
|
|
1020
1346
|
|
|
1021
1347
|
it('M3 / w13: legacy sprite material without transparent:true does NOT trigger split (union arm deleted)', () => {
|
|
1022
|
-
if (typeof
|
|
1348
|
+
if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
|
|
1023
1349
|
throw new Error('computeSplitLdrSprite helper not exported yet (red phase)');
|
|
1024
1350
|
}
|
|
1025
1351
|
// feat-20260625-refactor-sprite-as-transparent-mesh M3 / w13 (D-3):
|
|
@@ -1035,7 +1361,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1035
1361
|
materialShaderId: 'forgeax::sprite',
|
|
1036
1362
|
paramSnapshot: {},
|
|
1037
1363
|
} as unknown as MaterialSnapshot;
|
|
1038
|
-
const splitWithoutTransparent =
|
|
1364
|
+
const splitWithoutTransparent = spriteMod.computeSplitLdrSprite(
|
|
1039
1365
|
[makeValidatedEntry(legacySpriteNoTransparent)],
|
|
1040
1366
|
false,
|
|
1041
1367
|
);
|
|
@@ -1047,7 +1373,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1047
1373
|
...legacySpriteNoTransparent,
|
|
1048
1374
|
transparent: true,
|
|
1049
1375
|
} as unknown as MaterialSnapshot;
|
|
1050
|
-
const splitWithTransparent =
|
|
1376
|
+
const splitWithTransparent = spriteMod.computeSplitLdrSprite(
|
|
1051
1377
|
[makeValidatedEntry(spriteTransparent)],
|
|
1052
1378
|
false,
|
|
1053
1379
|
);
|
|
@@ -1074,7 +1400,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1074
1400
|
// material[0] is opaque (the crosswalk case: opaque road submesh[0] +
|
|
1075
1401
|
// BLEND decal submesh[1] on one multi-material mesh).
|
|
1076
1402
|
it('per-submesh: split trips when only a non-zero submesh is transparent', () => {
|
|
1077
|
-
if (typeof
|
|
1403
|
+
if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
|
|
1078
1404
|
throw new Error('computeSplitLdrSprite helper not exported yet');
|
|
1079
1405
|
}
|
|
1080
1406
|
const opaque0 = makeTransparentSnap({
|
|
@@ -1089,11 +1415,11 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1089
1415
|
const mixedEntry: DispatchEntryLike = {
|
|
1090
1416
|
source: { material: opaque0, materials: [opaque0, transparent1] },
|
|
1091
1417
|
};
|
|
1092
|
-
expect(
|
|
1418
|
+
expect(spriteMod.computeSplitLdrSprite([mixedEntry], false)).toBe(true);
|
|
1093
1419
|
});
|
|
1094
1420
|
|
|
1095
1421
|
it('per-submesh: split stays false when every submesh material is opaque', () => {
|
|
1096
|
-
if (typeof
|
|
1422
|
+
if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
|
|
1097
1423
|
throw new Error('computeSplitLdrSprite helper not exported yet');
|
|
1098
1424
|
}
|
|
1099
1425
|
const opaque0 = makeTransparentSnap({
|
|
@@ -1107,7 +1433,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1107
1433
|
const opaqueMixed: DispatchEntryLike = {
|
|
1108
1434
|
source: { material: opaque0, materials: [opaque0, opaque1] },
|
|
1109
1435
|
};
|
|
1110
|
-
expect(
|
|
1436
|
+
expect(spriteMod.computeSplitLdrSprite([opaqueMixed], false)).toBe(false);
|
|
1111
1437
|
});
|
|
1112
1438
|
|
|
1113
1439
|
it('isEntityFullyTransparent / entityHasTransparentSubmesh classify mixed meshes', () => {
|
|
@@ -1136,169 +1462,6 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1136
1462
|
});
|
|
1137
1463
|
}
|
|
1138
1464
|
|
|
1139
|
-
// --- from feat-20260625-refactor-sprite-as-transparent-mesh M2 / w5 ---
|
|
1140
|
-
{
|
|
1141
|
-
// AC-14: a transparent material whose target shader pipeline is not yet
|
|
1142
|
-
// cached must surface a structured RhiError (.code / .expected / .hint),
|
|
1143
|
-
// NOT silently fall back to the debug-pink placeholder. The generic
|
|
1144
|
-
// materialShaderId path is the only resolver -- post feat-20260625 M3 / w14
|
|
1145
|
-
// the dedicated sprite PSO fields are gone; sprite uses the same generic
|
|
1146
|
-
// getMaterialShaderPipeline path every transparent material consumes.
|
|
1147
|
-
//
|
|
1148
|
-
// The helper signature added by w7:
|
|
1149
|
-
//
|
|
1150
|
-
// selectMaterialPipelineForRender({
|
|
1151
|
-
// materialShaderId, isHdr, renderState, topology, indexFormat,
|
|
1152
|
-
// variantSet, sampleCount,
|
|
1153
|
-
// getMaterialShaderPipeline, // injected at call site (runtime.getMaterialShaderPipeline)
|
|
1154
|
-
// }): Result<RenderPipeline, RhiError>
|
|
1155
|
-
//
|
|
1156
|
-
// Plan anchors:
|
|
1157
|
-
// - requirements AC-14 (structured RhiError, no debug-pink fall-through)
|
|
1158
|
-
// - plan-strategy section 8.3 (error info AI users consume via property
|
|
1159
|
-
// access: .code / .expected / .hint; charter P3 explicit failure)
|
|
1160
|
-
// - plan-strategy section 2 D-3 (transparent flows through the generic
|
|
1161
|
-
// materialShaderId path; the resolver therefore never branches on
|
|
1162
|
-
// 'forgeax::sprite' to recover)
|
|
1163
|
-
|
|
1164
|
-
type SelectArgs = {
|
|
1165
|
-
readonly materialShaderId: string;
|
|
1166
|
-
readonly isHdr: boolean;
|
|
1167
|
-
readonly renderState: {
|
|
1168
|
-
readonly blend?: {
|
|
1169
|
-
readonly color: { readonly srcFactor: string; readonly dstFactor: string };
|
|
1170
|
-
readonly alpha: { readonly srcFactor: string; readonly dstFactor: string };
|
|
1171
|
-
};
|
|
1172
|
-
};
|
|
1173
|
-
readonly topology: 'triangle-list' | 'triangle-strip';
|
|
1174
|
-
readonly indexFormat: 'uint16' | 'uint32';
|
|
1175
|
-
readonly variantSet: string;
|
|
1176
|
-
readonly sampleCount: number;
|
|
1177
|
-
readonly getMaterialShaderPipeline: (
|
|
1178
|
-
materialShaderId: string,
|
|
1179
|
-
isHdr: boolean,
|
|
1180
|
-
) => unknown | null;
|
|
1181
|
-
};
|
|
1182
|
-
|
|
1183
|
-
const mod = recordModule as unknown as {
|
|
1184
|
-
selectMaterialPipelineForRender?: (
|
|
1185
|
-
args: SelectArgs,
|
|
1186
|
-
) =>
|
|
1187
|
-
| { readonly ok: true; readonly value: unknown }
|
|
1188
|
-
| { readonly ok: false; readonly error: { code: string; expected: string; hint: string } };
|
|
1189
|
-
};
|
|
1190
|
-
|
|
1191
|
-
function makeSelectArgs(overrides: {
|
|
1192
|
-
materialShaderId?: string;
|
|
1193
|
-
getter?: SelectArgs['getMaterialShaderPipeline'];
|
|
1194
|
-
}): SelectArgs {
|
|
1195
|
-
const pipelineStub = { __pipeline: true };
|
|
1196
|
-
return {
|
|
1197
|
-
materialShaderId: overrides.materialShaderId ?? 'forgeax::unlit-test',
|
|
1198
|
-
isHdr: false,
|
|
1199
|
-
renderState: {
|
|
1200
|
-
blend: {
|
|
1201
|
-
color: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },
|
|
1202
|
-
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },
|
|
1203
|
-
},
|
|
1204
|
-
},
|
|
1205
|
-
topology: 'triangle-list',
|
|
1206
|
-
indexFormat: 'uint16',
|
|
1207
|
-
variantSet: '',
|
|
1208
|
-
sampleCount: 1,
|
|
1209
|
-
getMaterialShaderPipeline: overrides.getter ?? (() => pipelineStub),
|
|
1210
|
-
};
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
describe('selectMaterialPipelineForRender pipeline-miss surfaces RhiError (M2 / w5, AC-14)', () => {
|
|
1214
|
-
it('export: selectMaterialPipelineForRender helper is exported from render-system-record', () => {
|
|
1215
|
-
expect(typeof mod.selectMaterialPipelineForRender).toBe('function');
|
|
1216
|
-
});
|
|
1217
|
-
|
|
1218
|
-
it('cache miss returns ok=false with structured RhiError (.code/.expected/.hint)', () => {
|
|
1219
|
-
if (typeof mod.selectMaterialPipelineForRender !== 'function') {
|
|
1220
|
-
throw new Error('selectMaterialPipelineForRender helper not exported yet (red phase)');
|
|
1221
|
-
}
|
|
1222
|
-
const result = mod.selectMaterialPipelineForRender(
|
|
1223
|
-
makeSelectArgs({
|
|
1224
|
-
materialShaderId: 'forgeax::unlit-test',
|
|
1225
|
-
getter: () => null, // simulate cache miss / async build pending
|
|
1226
|
-
}),
|
|
1227
|
-
);
|
|
1228
|
-
expect(result.ok).toBe(false);
|
|
1229
|
-
if (result.ok) throw new Error('unreachable -- result.ok asserted false above');
|
|
1230
|
-
const err = result.error;
|
|
1231
|
-
// charter P3 -- AI users branch on .code (string union member from
|
|
1232
|
-
// RhiErrorCode) and consume .expected / .hint as property reads;
|
|
1233
|
-
// they do NOT parse the human-facing .message string.
|
|
1234
|
-
expect(typeof err.code).toBe('string');
|
|
1235
|
-
expect(err.code.length).toBeGreaterThan(0);
|
|
1236
|
-
expect(typeof err.expected).toBe('string');
|
|
1237
|
-
expect(err.expected.length).toBeGreaterThan(0);
|
|
1238
|
-
expect(typeof err.hint).toBe('string');
|
|
1239
|
-
expect(err.hint.length).toBeGreaterThan(0);
|
|
1240
|
-
});
|
|
1241
|
-
|
|
1242
|
-
it('cache miss .hint references the missing materialShaderId (AI users locate the cache key)', () => {
|
|
1243
|
-
if (typeof mod.selectMaterialPipelineForRender !== 'function') {
|
|
1244
|
-
throw new Error('selectMaterialPipelineForRender helper not exported yet (red phase)');
|
|
1245
|
-
}
|
|
1246
|
-
const result = mod.selectMaterialPipelineForRender(
|
|
1247
|
-
makeSelectArgs({
|
|
1248
|
-
materialShaderId: 'forgeax::missing-shader-id',
|
|
1249
|
-
getter: () => null,
|
|
1250
|
-
}),
|
|
1251
|
-
);
|
|
1252
|
-
expect(result.ok).toBe(false);
|
|
1253
|
-
if (result.ok) throw new Error('unreachable -- result.ok asserted false above');
|
|
1254
|
-
// The shader id must appear in .hint (or .expected) so AI users can
|
|
1255
|
-
// grep the registry / pipeline cache straight from the structured
|
|
1256
|
-
// error -- not from a human-prose substring of .message.
|
|
1257
|
-
const exposed = `${result.error.hint} ${result.error.expected}`;
|
|
1258
|
-
expect(exposed).toContain('forgeax::missing-shader-id');
|
|
1259
|
-
});
|
|
1260
|
-
|
|
1261
|
-
it('cache hit returns ok=true with the pipeline (no error path on success)', () => {
|
|
1262
|
-
if (typeof mod.selectMaterialPipelineForRender !== 'function') {
|
|
1263
|
-
throw new Error('selectMaterialPipelineForRender helper not exported yet (red phase)');
|
|
1264
|
-
}
|
|
1265
|
-
const pipeline = { __pipeline: 'forgeax::unlit-test-pso' };
|
|
1266
|
-
const result = mod.selectMaterialPipelineForRender(
|
|
1267
|
-
makeSelectArgs({
|
|
1268
|
-
materialShaderId: 'forgeax::unlit-test',
|
|
1269
|
-
getter: () => pipeline,
|
|
1270
|
-
}),
|
|
1271
|
-
);
|
|
1272
|
-
expect(result.ok).toBe(true);
|
|
1273
|
-
if (!result.ok) throw new Error('unreachable -- result.ok asserted true above');
|
|
1274
|
-
expect(result.value).toBe(pipeline);
|
|
1275
|
-
});
|
|
1276
|
-
|
|
1277
|
-
it('cache miss does NOT silently substitute a debug-pink fallback pipeline', () => {
|
|
1278
|
-
if (typeof mod.selectMaterialPipelineForRender !== 'function') {
|
|
1279
|
-
throw new Error('selectMaterialPipelineForRender helper not exported yet (red phase)');
|
|
1280
|
-
}
|
|
1281
|
-
// Probe: the only branch the getter ever returns is the one passed in.
|
|
1282
|
-
// A cache miss must surface ok=false, NOT a synthesized pipeline value
|
|
1283
|
-
// that hides the miss (charter P3 -- the pre-M6 silent fallback to
|
|
1284
|
-
// pipelineState.standardPipeline* was exactly this anti-pattern, see
|
|
1285
|
-
// render-system-record.ts:5188-5198 commentary).
|
|
1286
|
-
let getterCallCount = 0;
|
|
1287
|
-
const result = mod.selectMaterialPipelineForRender(
|
|
1288
|
-
makeSelectArgs({
|
|
1289
|
-
materialShaderId: 'forgeax::unlit-test',
|
|
1290
|
-
getter: () => {
|
|
1291
|
-
getterCallCount += 1;
|
|
1292
|
-
return null;
|
|
1293
|
-
},
|
|
1294
|
-
}),
|
|
1295
|
-
);
|
|
1296
|
-
expect(getterCallCount).toBeGreaterThanOrEqual(1);
|
|
1297
|
-
expect(result.ok).toBe(false);
|
|
1298
|
-
});
|
|
1299
|
-
});
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
1465
|
// ─── bug-20260622-tilemap-ysort-transparent-sort-modes-followup M2 m2-1 ───
|
|
1303
1466
|
//
|
|
1304
1467
|
// AC-04 (error signal SSOT) + AC-05 (LAYER_Y footY ordering) + R-2
|
|
@@ -1316,7 +1479,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1316
1479
|
describe('AC-04 setTransparentSortConfig mode=99 returns Result.err (KV untouched)', () => {
|
|
1317
1480
|
it('Result.err carries code/expected/hint/detail + KV resource is NOT inserted', async () => {
|
|
1318
1481
|
const { setTransparentSortConfig, TRANSPARENT_SORT_CONFIG_KEY } = await import(
|
|
1319
|
-
'
|
|
1482
|
+
'../../../render/src/systems/transparent-sort-config'
|
|
1320
1483
|
);
|
|
1321
1484
|
const world = new World();
|
|
1322
1485
|
// Pre-check: resource MUST be absent before the rejected call.
|
|
@@ -1343,7 +1506,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1343
1506
|
describe('AC-05 LAYER_Y footY ordering (same layer, deeper foot draws later)', () => {
|
|
1344
1507
|
it('footY=10/20/30 same layer -> output order footY=30/20/10 (back-to-front)', async () => {
|
|
1345
1508
|
const { setTransparentSortConfig, TRANSPARENT_SORT_MODE_LAYER_Y } = await import(
|
|
1346
|
-
'
|
|
1509
|
+
'../../../render/src/systems/transparent-sort-config'
|
|
1347
1510
|
);
|
|
1348
1511
|
const { transparentSortEntries } = await import('../systems/transparent-sort');
|
|
1349
1512
|
const world = new World();
|
|
@@ -1403,7 +1566,7 @@ describe('derived material record stop-draw (w28)', () => {
|
|
|
1403
1566
|
describe('R-2 mode=DISTANCE + cameraPos absent preserves insertion order', () => {
|
|
1404
1567
|
it('transparentSortEntries(entries, world) with mode=3 + no cameraPos = insertion order', async () => {
|
|
1405
1568
|
const { setTransparentSortConfig, TRANSPARENT_SORT_MODE_DISTANCE } = await import(
|
|
1406
|
-
'
|
|
1569
|
+
'../../../render/src/systems/transparent-sort-config'
|
|
1407
1570
|
);
|
|
1408
1571
|
const { transparentSortEntries } = await import('../systems/transparent-sort');
|
|
1409
1572
|
const world = new World();
|