@forgeax/engine-runtime 0.1.23 → 0.1.24
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 +15 -6
- package/dist/__tests__/advance-animation-player.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/advance-animation-player.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-aabb.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-aabb.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-bootstrap.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-bootstrap.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-builtin-nineslice.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-builtin-nineslice.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-d9-tile-sampler-soft-warn.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-d9-tile-sampler-soft-warn.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-guid.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-guid.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-material-validate.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-material-validate.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-mesh-fail-fast.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-mesh-fail-fast.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-scene.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-scene.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-sprite-slices-validate.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-sprite-slices-validate.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-renderer-assembly.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-renderer-assembly.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/asset.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/bloom-gating.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/bloom-gating.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/builtin-guid-ssot.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/builtin-guid-ssot.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/builtin-pack.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/builtin-pack.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/camera-antialias.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/camera-antialias.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/camera-bloom.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/camera-bloom.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/camera-clear-schema.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/camera-clear-schema.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/camera-ortho.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/camera-ortho.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/cluster-binner.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/cluster-binner.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/create-renderer-fallback-shader-manifest.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/create-renderer-fallback-shader-manifest.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/create-renderer-uniform-fallback.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/create-renderer-uniform-fallback.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/cubemap-upload.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/cubemap-upload.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/dev-import-transport.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/dev-import-transport.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/engine-metrics.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/engine-metrics.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/equirect-projection-error.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/equirect-projection-error.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/font-asset-load.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/font-asset-load.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fxaa-intermediate-texture.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/fxaa-intermediate-texture.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fxaa-pipeline.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/fxaa-pipeline.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/gpu-residency.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/gpu-residency.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/gpu-resource-release.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/gpu-resource-release.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/handle-quad.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/handle-quad.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-bgl-slots.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/hdrp-bgl-slots.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-grid-invalid.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/hdrp-grid-invalid.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-index-list-overflow-once.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/hdrp-index-list-overflow-once.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-light-budget.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/hdrp-light-budget.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-pipeline-asset-config.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/hdrp-pipeline-asset-config.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/renderer-device-loss-dawn.d.ts +25 -0
- package/dist/__tests__/helpers/renderer-device-loss-dawn.d.ts.map +1 -0
- package/dist/__tests__/helpers/standard-material-manifest.d.ts +0 -1
- package/dist/__tests__/helpers/standard-material-manifest.d.ts.map +1 -1
- package/dist/__tests__/ibl-pipeline-cache.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/ibl-pipeline-cache.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/lazy-catalog.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/lazy-catalog.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/load-by-guid-hdr.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/load-by-guid-hdr.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/load-by-guid-prod-material-parent.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/load-by-guid-prod-material-parent.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/load-by-guid-prod.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/load-by-guid-prod.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loader-registry.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/loader-registry.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/m7-hdrp-demo-shape.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/m7-hdrp-demo-shape.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mipmap-formula.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/mipmap-formula.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mipmap-pipeline-cache.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/mipmap-pipeline-cache.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/parse-asset-payload-material.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/parse-asset-payload-material.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/parse-asset-payload-texture.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/parse-asset-payload-texture.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/parse-scene-payload-refs.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/parse-scene-payload-refs.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pass-selector.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/pass-selector.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline-builder.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/pipeline-builder.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline-cache-key-topology.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/pipeline-cache-key-topology.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline-vertex-stride-branch.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/pipeline-vertex-stride-branch.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/pipeline.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/post-process-register.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/post-process-register.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/propagate-transforms.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/propagate-transforms.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/record-all-topology.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/record-all-topology.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/record-draw-branch.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/record-draw-branch.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/record-strip-index-format.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/record-strip-index-format.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/register-with-guid-rgba16float.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/register-with-guid-rgba16float.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-data.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/render-data.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -1
- package/dist/__tests__/render-query-regression.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/render-query-regression.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-record-submesh.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-record-submesh.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-record-warn-once.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-record-warn-once.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-device-loss-multi-world.integration.test.d.ts +2 -0
- package/dist/__tests__/renderer-device-loss-multi-world.integration.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-device-loss-provider-feasibility.dawn.test.d.ts +2 -0
- package/dist/__tests__/renderer-device-loss-provider-feasibility.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-device-loss-recovery.dawn.test.d.ts +2 -0
- package/dist/__tests__/renderer-device-loss-recovery.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-draw-world.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/renderer-draw-world.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-recovery-consumer.integration.test.d.ts +2 -0
- package/dist/__tests__/renderer-recovery-consumer.integration.test.d.ts.map +1 -0
- package/dist/__tests__/renderstate-pipeline-cache.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/renderstate-pipeline-cache.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/resolve-scene-guids.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/resolve-scene-guids.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-skip-non-triangle.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/shadow-skip-non-triangle.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-errors-kebab-case.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-errors-kebab-case.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-instances-coexist.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-instances-coexist.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-m2-extract-happy.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-m2-extract-happy.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-m2-extract-joint-error.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-m2-extract-joint-error.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-m2-extract-null-assets.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-m2-extract-null-assets.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-m2-extract-skeleton-error.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-m2-extract-skeleton-error.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-m3-record-cache.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-m3-record-cache.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-palette-extract.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-palette-extract.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-pipeline-routing.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-pipeline-routing.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skin.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skybox-extract.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skybox-extract.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skybox-shader-compile.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skybox-shader-compile.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skylight-bind-group.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skylight-bind-group.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skylight-component.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skylight-component.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skylight-fallback-path.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skylight-fallback-path.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skylight-pipeline-layout.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skylight-pipeline-layout.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skylight-solid-color-extract.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/skylight-solid-color-extract.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-animation-tick-boundary.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/sprite-animation-tick-boundary.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-animation-tick-clamp.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/sprite-animation-tick-clamp.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-animation-tick-frame-duration-negative.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/sprite-animation-tick-frame-duration-negative.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-animation-tick-frame-duration-zero.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/sprite-animation-tick-frame-duration-zero.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-animation-tick-loop.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/sprite-animation-tick-loop.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-animation-tick-override-probe.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/sprite-animation-tick-override-probe.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-animation-tick-regions-mismatch.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/sprite-animation-tick-regions-mismatch.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/storage-buffer-caps.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/storage-buffer-caps.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/systems.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/systems.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/tonemap-hdr-target.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/tonemap-hdr-target.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/tonemap-pipeline-split.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/tonemap-pipeline-split.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/tonemap.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/tonemap.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/transparent-sort-config-get.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/transparent-sort-config-get.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/transparent-sort-config-set.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/transparent-sort-config-set.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/transparent-sort.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/transparent-sort.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/upload-texture-consistency.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/upload-texture-consistency.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/verify-revisions.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/verify-revisions.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/wire-default-loaders.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/wire-default-loaders.cases.unit.test.d.ts.map +1 -0
- package/dist/__tests__/zero-camera-clear-fallback.cases.unit.test.d.ts +2 -0
- package/dist/__tests__/zero-camera-clear-fallback.cases.unit.test.d.ts.map +1 -0
- package/dist/dev-import-transport.d.ts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +30 -30
- package/src/__tests__/advance-animation-player.cases.unit.test.ts +1666 -0
- package/src/__tests__/asset-registry-aabb.cases.unit.test.ts +676 -0
- package/src/__tests__/asset-registry-bootstrap.cases.unit.test.ts +472 -0
- package/src/__tests__/asset-registry-builtin-nineslice.cases.unit.test.ts +481 -0
- package/src/__tests__/asset-registry-d9-tile-sampler-soft-warn.cases.unit.test.ts +568 -0
- package/src/__tests__/asset-registry-guid.cases.unit.test.ts +500 -0
- package/src/__tests__/asset-registry-material-validate.cases.unit.test.ts +756 -0
- package/src/__tests__/asset-registry-mesh-fail-fast.cases.unit.test.ts +591 -0
- package/src/__tests__/asset-registry-scene.cases.unit.test.ts +501 -0
- package/src/__tests__/asset-registry-sprite-slices-validate.cases.unit.test.ts +536 -0
- package/src/__tests__/asset-renderer-assembly.cases.unit.test.ts +496 -0
- package/src/__tests__/asset.cases.unit.test.ts +439 -0
- package/src/__tests__/bind-group-cache-keying.test.ts +6 -2
- package/src/__tests__/bloom-gating.cases.unit.test.ts +428 -0
- package/src/__tests__/builtin-guid-ssot.cases.unit.test.ts +472 -0
- package/src/__tests__/builtin-pack.cases.unit.test.ts +639 -0
- package/src/__tests__/builtin-shader-register-e2e.test.ts +1 -1
- package/src/__tests__/camera-antialias.cases.unit.test.ts +372 -0
- package/src/__tests__/camera-bloom.cases.unit.test.ts +396 -0
- package/src/__tests__/camera-clear-schema.cases.unit.test.ts +391 -0
- package/src/__tests__/camera-ortho.cases.unit.test.ts +484 -0
- package/src/__tests__/cluster-binner.cases.unit.test.ts +817 -0
- package/src/__tests__/collect-scene-mount-collapse.test.ts +5 -1
- package/src/__tests__/create-renderer-fallback-shader-manifest.cases.unit.test.ts +345 -0
- package/src/__tests__/create-renderer-uniform-fallback.cases.unit.test.ts +445 -0
- package/src/__tests__/cubemap-upload.cases.unit.test.ts +593 -0
- package/src/__tests__/dawn/ibl-precompute-readback.dawn.test.ts +184 -17
- package/src/__tests__/dawn/material-alpha.dawn.test.ts +17 -4
- package/src/__tests__/derive-bgl-integration.test.ts +8 -8
- package/src/__tests__/dev-import-transport.cases.unit.test.ts +503 -0
- package/src/__tests__/engine-metrics.cases.unit.test.ts +371 -0
- package/src/__tests__/equirect-projection-error.cases.unit.test.ts +416 -0
- package/src/__tests__/font-asset-load.cases.unit.test.ts +510 -0
- package/src/__tests__/fxaa-intermediate-texture.cases.unit.test.ts +690 -0
- package/src/__tests__/fxaa-pipeline.cases.unit.test.ts +546 -0
- package/src/__tests__/gpu-residency.cases.unit.test.ts +479 -0
- package/src/__tests__/gpu-resource-release.cases.unit.test.ts +929 -0
- package/src/__tests__/handle-quad.cases.unit.test.ts +491 -0
- package/src/__tests__/hdrp-bgl-slots.cases.unit.test.ts +451 -0
- package/src/__tests__/hdrp-grid-invalid.cases.unit.test.ts +408 -0
- package/src/__tests__/hdrp-index-list-overflow-once.cases.unit.test.ts +405 -0
- package/src/__tests__/hdrp-light-budget.cases.unit.test.ts +483 -0
- package/src/__tests__/hdrp-pipeline-asset-config.cases.unit.test.ts +441 -0
- package/src/__tests__/helpers/renderer-device-loss-dawn.ts +69 -0
- package/src/__tests__/helpers/standard-material-manifest.ts +11 -15
- package/src/__tests__/ibl-pipeline-cache.cases.unit.test.ts +415 -0
- package/src/__tests__/lazy-catalog.cases.unit.test.ts +848 -0
- package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +6 -5
- package/src/__tests__/load-by-guid-hdr.cases.unit.test.ts +582 -0
- package/src/__tests__/load-by-guid-prod-material-parent.cases.unit.test.ts +1514 -0
- package/src/__tests__/load-by-guid-prod.cases.unit.test.ts +557 -0
- package/src/__tests__/loader-registry.cases.unit.test.ts +767 -0
- package/src/__tests__/m7-hdrp-demo-shape.cases.unit.test.ts +361 -0
- package/src/__tests__/material-texture-uv-scale.unit.test.ts +2 -2
- package/src/__tests__/materials.unit.test.ts +29 -10
- package/src/__tests__/mipmap-formula.cases.unit.test.ts +434 -0
- package/src/__tests__/mipmap-pipeline-cache.cases.unit.test.ts +490 -0
- package/src/__tests__/parse-asset-payload-material.cases.unit.test.ts +565 -0
- package/src/__tests__/parse-asset-payload-texture.cases.unit.test.ts +720 -0
- package/src/__tests__/parse-scene-payload-refs.cases.unit.test.ts +767 -0
- package/src/__tests__/pass-selector.cases.unit.test.ts +376 -0
- package/src/__tests__/pbr-pipeline.unit.test.ts +23 -5
- package/src/__tests__/pipeline-builder.cases.unit.test.ts +624 -0
- package/src/__tests__/pipeline-cache-key-topology.cases.unit.test.ts +807 -0
- package/src/__tests__/pipeline-vertex-stride-branch.cases.unit.test.ts +379 -0
- package/src/__tests__/pipeline.cases.unit.test.ts +370 -0
- package/src/__tests__/post-process-register.cases.unit.test.ts +405 -0
- package/src/__tests__/propagate-transforms.cases.unit.test.ts +502 -0
- package/src/__tests__/propagate-transforms.dawn.test.ts +19 -2
- package/src/__tests__/record-all-topology.cases.unit.test.ts +608 -0
- package/src/__tests__/record-draw-branch.cases.unit.test.ts +621 -0
- package/src/__tests__/record-strip-index-format.cases.unit.test.ts +419 -0
- package/src/__tests__/register-with-guid-rgba16float.cases.unit.test.ts +469 -0
- package/src/__tests__/render-data.cases.unit.test.ts +553 -0
- package/src/__tests__/render-error-exhaustive.test-d.ts +1 -0
- package/src/__tests__/render-query-regression.cases.unit.test.ts +531 -0
- package/src/__tests__/render-system-record-submesh.cases.unit.test.ts +740 -0
- package/src/__tests__/render-system-record-warn-once.cases.unit.test.ts +418 -0
- package/src/__tests__/render-system-record.test.ts +15 -33
- package/src/__tests__/renderer-device-loss-multi-world.integration.test.ts +103 -0
- package/src/__tests__/renderer-device-loss-provider-feasibility.dawn.test.ts +124 -0
- package/src/__tests__/renderer-device-loss-recovery.dawn.test.ts +50 -0
- package/src/__tests__/renderer-draw-world.cases.unit.test.ts +514 -0
- package/src/__tests__/renderer-recovery-consumer.integration.test.ts +96 -0
- package/src/__tests__/renderstate-pipeline-cache.cases.unit.test.ts +631 -0
- package/src/__tests__/resolve-scene-guids.cases.unit.test.ts +1123 -0
- package/src/__tests__/shadow-caster-empty-schema.test.ts +1 -1
- package/src/__tests__/shadow-fields-observable.dawn.test.ts +2 -2
- package/src/__tests__/shadow-m1.dawn.test.ts +1 -1
- package/src/__tests__/shadow-skip-non-triangle.cases.unit.test.ts +681 -0
- package/src/__tests__/skin-errors-kebab-case.cases.unit.test.ts +475 -0
- package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +5 -4
- package/src/__tests__/skin-instances-coexist.cases.unit.test.ts +375 -0
- package/src/__tests__/skin-m2-extract-happy.cases.unit.test.ts +592 -0
- package/src/__tests__/skin-m2-extract-joint-error.cases.unit.test.ts +619 -0
- package/src/__tests__/skin-m2-extract-null-assets.cases.unit.test.ts +569 -0
- package/src/__tests__/skin-m2-extract-skeleton-error.cases.unit.test.ts +585 -0
- package/src/__tests__/skin-m3-record-cache.cases.unit.test.ts +457 -0
- package/src/__tests__/skin-palette-extract.cases.unit.test.ts +635 -0
- package/src/__tests__/skin-pipeline-routing.cases.unit.test.ts +411 -0
- package/src/__tests__/skin.cases.unit.test.ts +421 -0
- package/src/__tests__/skybox-extract.cases.unit.test.ts +511 -0
- package/src/__tests__/skybox-shader-compile.cases.unit.test.ts +437 -0
- package/src/__tests__/skylight-bind-group.cases.unit.test.ts +642 -0
- package/src/__tests__/skylight-component.cases.unit.test.ts +386 -0
- package/src/__tests__/skylight-fallback-path.cases.unit.test.ts +566 -0
- package/src/__tests__/skylight-lazy-projection.test.ts +35 -20
- package/src/__tests__/skylight-pipeline-layout.cases.unit.test.ts +506 -0
- package/src/__tests__/skylight-solid-color-extract.cases.unit.test.ts +399 -0
- package/src/__tests__/sprite-animation-tick-boundary.cases.unit.test.ts +521 -0
- package/src/__tests__/sprite-animation-tick-clamp.cases.unit.test.ts +453 -0
- package/src/__tests__/sprite-animation-tick-frame-duration-negative.cases.unit.test.ts +447 -0
- package/src/__tests__/sprite-animation-tick-frame-duration-zero.cases.unit.test.ts +395 -0
- package/src/__tests__/sprite-animation-tick-loop.cases.unit.test.ts +494 -0
- package/src/__tests__/sprite-animation-tick-override-probe.cases.unit.test.ts +439 -0
- package/src/__tests__/sprite-animation-tick-regions-mismatch.cases.unit.test.ts +466 -0
- package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +5 -5
- package/src/__tests__/sprite-lit-pipeline-cache-key.test.ts +1 -1
- package/src/__tests__/ssao-pipelines.test.ts +1 -1
- package/src/__tests__/storage-buffer-caps.cases.unit.test.ts +373 -0
- package/src/__tests__/systems.cases.unit.test.ts +425 -0
- package/src/__tests__/tilemap-chunk-extract.overhang-bounds.test.ts +1 -1
- package/src/__tests__/tonemap-hdr-target.cases.unit.test.ts +670 -0
- package/src/__tests__/tonemap-pipeline-split.cases.unit.test.ts +867 -0
- package/src/__tests__/tonemap.cases.unit.test.ts +446 -0
- package/src/__tests__/transparent-sort-config-get.cases.unit.test.ts +395 -0
- package/src/__tests__/transparent-sort-config-set.cases.unit.test.ts +424 -0
- package/src/__tests__/transparent-sort.cases.unit.test.ts +684 -0
- package/src/__tests__/upload-texture-consistency.cases.unit.test.ts +478 -0
- package/src/__tests__/verify-revisions.cases.unit.test.ts +619 -0
- package/src/__tests__/wire-default-loaders.cases.unit.test.ts +461 -0
- package/src/__tests__/zero-camera-clear-fallback.cases.unit.test.ts +374 -0
- package/src/dev-import-transport.ts +2 -1
- package/dist/__tests__/asset.unit.test.d.ts +0 -2
- package/dist/__tests__/asset.unit.test.d.ts.map +0 -1
- package/dist/__tests__/pipeline.unit.test.d.ts +0 -2
- package/dist/__tests__/pipeline.unit.test.d.ts.map +0 -1
- package/dist/__tests__/systems.unit.test.d.ts +0 -2
- package/dist/__tests__/systems.unit.test.d.ts.map +0 -1
- package/src/__tests__/asset.unit.test.ts +0 -7113
- package/src/__tests__/pipeline.unit.test.ts +0 -5279
- package/src/__tests__/systems.unit.test.ts +0 -9061
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
// @ts-nocheck — merged file: indexed-access checks cascade across noUncheckedIndexedAccess for blocks originally outside src/ rootDir
|
|
2
|
+
// Consolidated by feat-20260609-test-pool-startup-reduction-merge-tiny-test-files
|
|
3
|
+
// biome-ignore-all lint/complexity/noUselessLoneBlockStatements: block-scope isolation between merged source files (consolidation paradigm)
|
|
4
|
+
//
|
|
5
|
+
// Source files (N=44):
|
|
6
|
+
// - packages/runtime/__tests__/antialias-from-f32.test.ts
|
|
7
|
+
// - packages/runtime/src/__tests__/bloom-gating.test.ts
|
|
8
|
+
// - packages/runtime/src/__tests__/camera-antialias.test.ts
|
|
9
|
+
// - packages/runtime/src/__tests__/camera-bloom.test.ts
|
|
10
|
+
// - packages/runtime/src/__tests__/camera-clear-schema.test.ts
|
|
11
|
+
// - packages/runtime/src/__tests__/camera-ortho.test.ts
|
|
12
|
+
// - packages/runtime/src/__tests__/fxaa-intermediate-texture.test.ts
|
|
13
|
+
// - packages/runtime/src/__tests__/fxaa-pipeline.test.ts
|
|
14
|
+
// - packages/runtime/src/__tests__/ibl-pipeline-cache.test.ts
|
|
15
|
+
// - packages/runtime/src/__tests__/ibl-runtime-probe.test.ts
|
|
16
|
+
// - packages/runtime/src/__tests__/render-system-record-warn-once.test.ts
|
|
17
|
+
// - packages/runtime/src/__tests__/shadow-skip-non-triangle.test.ts
|
|
18
|
+
// - packages/runtime/src/__tests__/skin-errors-kebab-case.test.ts
|
|
19
|
+
// - packages/runtime/src/__tests__/skybox-error.test.ts
|
|
20
|
+
// - packages/runtime/src/__tests__/skybox-shader-compile.test.ts
|
|
21
|
+
// - packages/runtime/src/__tests__/skylight-bind-group.test.ts
|
|
22
|
+
// - packages/runtime/src/__tests__/skylight-component.test.ts
|
|
23
|
+
// - packages/runtime/src/__tests__/skylight-fallback-path.test.ts
|
|
24
|
+
// - packages/runtime/src/__tests__/skylight-pipeline-layout.test.ts
|
|
25
|
+
// - packages/runtime/src/__tests__/tonemap-hdr-target.test.ts
|
|
26
|
+
// - packages/runtime/src/__tests__/tonemap-pipeline-split.test.ts
|
|
27
|
+
// - packages/runtime/src/__tests__/zero-camera-clear-fallback.test.ts
|
|
28
|
+
// - packages/runtime/src/components/__tests__/skin.test.ts
|
|
29
|
+
// - packages/runtime/src/systems/__tests__/advance-animation-player.test.ts
|
|
30
|
+
// - packages/runtime/src/systems/__tests__/graph-skybox.test.ts
|
|
31
|
+
// - packages/runtime/src/systems/__tests__/propagate-transforms.test.ts
|
|
32
|
+
// - packages/runtime/src/systems/__tests__/skin-cap-gate.test.ts
|
|
33
|
+
// - packages/runtime/src/systems/__tests__/skin-instances-coexist.test.ts
|
|
34
|
+
// - packages/runtime/src/systems/__tests__/skin-palette-extract.test.ts
|
|
35
|
+
// - packages/runtime/src/systems/__tests__/skin-pipeline-routing.test.ts
|
|
36
|
+
// - packages/runtime/src/systems/__tests__/skybox-extract.test.ts
|
|
37
|
+
// - packages/runtime/src/systems/__tests__/sprite-animation-tick-boundary.test.ts
|
|
38
|
+
// - packages/runtime/src/systems/__tests__/sprite-animation-tick-clamp.test.ts
|
|
39
|
+
// - packages/runtime/src/systems/__tests__/sprite-animation-tick-frame-duration-negative.test.ts
|
|
40
|
+
// - packages/runtime/src/systems/__tests__/sprite-animation-tick-frame-duration-zero.test.ts
|
|
41
|
+
// - packages/runtime/src/systems/__tests__/sprite-animation-tick-loop.test.ts
|
|
42
|
+
// - packages/runtime/src/systems/__tests__/sprite-animation-tick-override-probe.test.ts
|
|
43
|
+
// - packages/runtime/src/systems/__tests__/sprite-animation-tick-regions-mismatch.test.ts
|
|
44
|
+
// - packages/runtime/src/systems/__tests__/tonemap.test.ts
|
|
45
|
+
// - packages/runtime/src/systems/__tests__/transparent-sort-config-get.test.ts
|
|
46
|
+
// - packages/runtime/src/systems/__tests__/transparent-sort-config-set.test.ts
|
|
47
|
+
// - packages/runtime/src/systems/__tests__/transparent-sort.test.ts
|
|
48
|
+
// - packages/runtime/src/__tests__/render-system-multi-material.test.ts
|
|
49
|
+
// - packages/runtime/src/__tests__/render-system-record-submesh.test.ts
|
|
50
|
+
//
|
|
51
|
+
// Paradigm: each block-scope wraps a source file. ancestorTitles[0] is the
|
|
52
|
+
// source-preserved inner describe (NOT the source filename for these 3 files
|
|
53
|
+
// — recovery path: vitest report ancestorTitles -> grep this file -> upstream
|
|
54
|
+
// `// ─── from <name>.test.ts ───` block separator -> source filename).
|
|
55
|
+
// Top-level imports merged + deduped.
|
|
56
|
+
|
|
57
|
+
import { readFileSync } from 'node:fs';
|
|
58
|
+
import { resolve } from 'node:path';
|
|
59
|
+
import { fileURLToPath } from 'node:url';
|
|
60
|
+
import { AnimationPlayer } from '@forgeax/engine-animation';
|
|
61
|
+
import type { AssetRuntimeErrorCode } from '@forgeax/engine-assets-runtime';
|
|
62
|
+
import { AssetRegistry } from '@forgeax/engine-assets-runtime';
|
|
63
|
+
import type { EntityHandle, World as WorldType } from '@forgeax/engine-ecs';
|
|
64
|
+
import { ENTITY_NULL_RAW, World } from '@forgeax/engine-ecs';
|
|
65
|
+
import { SpriteAnimationInvalidError } from '@forgeax/engine-ecs/projection';
|
|
66
|
+
import { mat4, vec3 } from '@forgeax/engine-math';
|
|
67
|
+
import type { RenderErrorCode, Renderer as RendererType } from '@forgeax/engine-render';
|
|
68
|
+
import {
|
|
69
|
+
ANTIALIAS_FXAA,
|
|
70
|
+
ANTIALIAS_NONE,
|
|
71
|
+
BLOOM_DISABLED,
|
|
72
|
+
BLOOM_ENABLED,
|
|
73
|
+
CAMERA_PROJECTION_ORTHOGRAPHIC,
|
|
74
|
+
CAMERA_PROJECTION_PERSPECTIVE,
|
|
75
|
+
Camera,
|
|
76
|
+
MeshFilter,
|
|
77
|
+
MeshRenderer,
|
|
78
|
+
SkyboxBackground,
|
|
79
|
+
Skylight,
|
|
80
|
+
} from '@forgeax/engine-render';
|
|
81
|
+
import type { BindGroupEntry, Buffer, Sampler, Texture, TextureView } from '@forgeax/engine-rhi';
|
|
82
|
+
import { ok as rhiOk } from '@forgeax/engine-rhi';
|
|
83
|
+
import { ChildOf, Name, propagateTransforms, Transform } from '@forgeax/engine-scene';
|
|
84
|
+
import { TONEMAP_LUMINANCE_EPSILON } from '@forgeax/engine-shader';
|
|
85
|
+
import type { SkinErrorCode } from '@forgeax/engine-skinning';
|
|
86
|
+
import {
|
|
87
|
+
Skin,
|
|
88
|
+
SkinInstancesCoexistForbiddenError,
|
|
89
|
+
SkinJointCountExceededError,
|
|
90
|
+
SkinJointDespawnedError,
|
|
91
|
+
SkinJointPathUnresolvedError,
|
|
92
|
+
} from '@forgeax/engine-skinning';
|
|
93
|
+
import type {
|
|
94
|
+
Handle,
|
|
95
|
+
MaterialAsset,
|
|
96
|
+
MeshAsset,
|
|
97
|
+
SkeletonAsset,
|
|
98
|
+
TextureFormat,
|
|
99
|
+
} from '@forgeax/engine-types';
|
|
100
|
+
import { toShared } from '@forgeax/engine-types';
|
|
101
|
+
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
102
|
+
import { worldInternal } from '../../../ecs/src/world-internal';
|
|
103
|
+
import {
|
|
104
|
+
SPRITE_PLAYBACK_MODE_CLAMP,
|
|
105
|
+
SPRITE_PLAYBACK_MODE_LOOP,
|
|
106
|
+
SpriteAnimation,
|
|
107
|
+
SpriteRegionOverride,
|
|
108
|
+
} from '../../../render/src/components';
|
|
109
|
+
import {
|
|
110
|
+
type CameraProjection,
|
|
111
|
+
cameraProjectionFromF32,
|
|
112
|
+
} from '../../../render/src/components/camera';
|
|
113
|
+
import {
|
|
114
|
+
assembleMaterialWithSkylightEntries,
|
|
115
|
+
createSkylightFallback,
|
|
116
|
+
mergeSkylightIntoMaterialBgl,
|
|
117
|
+
} from '../../../render/src/ibl/skylight-bind-group';
|
|
118
|
+
import { buildPbrPipelineLayouts, buildUnlitMaterialBgl } from '../../../render/src/pbr-pipeline';
|
|
119
|
+
import { INSTANCE_STORAGE_STRIDE_FLOATS } from '../../../render/src/record/mesh-ssbo';
|
|
120
|
+
import { selectSwapChainFormat } from '../../../render/src/render-system';
|
|
121
|
+
import { createSkinPaletteAllocator } from '../../../render/src/systems/skin-palette-allocator';
|
|
122
|
+
import type { TransparentEntry } from '../../../render/src/systems/transparent-sort-config';
|
|
123
|
+
import { standardMaterialShaderVariants } from './helpers/standard-material-manifest';
|
|
124
|
+
import { drawWithOwners } from './renderer-test-utils';
|
|
125
|
+
|
|
126
|
+
function componentFieldType(component: { fields: Record<string, { type: string }> }, name: string) {
|
|
127
|
+
return component.fields[name]?.type;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function componentFieldDefault(
|
|
131
|
+
component: { fields: Record<string, { default?: unknown }> },
|
|
132
|
+
name: string,
|
|
133
|
+
) {
|
|
134
|
+
return component.fields[name]?.default;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function componentSchemaTypes(component: { fields: Record<string, { type: string }> }) {
|
|
138
|
+
return Object.fromEntries(
|
|
139
|
+
Object.entries(component.fields).map(([name, field]) => [name, field.type]),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
afterEach(() => vi.restoreAllMocks());
|
|
144
|
+
|
|
145
|
+
type RendererErrorObservation = {
|
|
146
|
+
readonly code: string;
|
|
147
|
+
readonly detail?: unknown;
|
|
148
|
+
readonly hint?: string;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
function unwrapRendererError(value: unknown): RendererErrorObservation {
|
|
152
|
+
let current = value as RendererErrorObservation;
|
|
153
|
+
while (
|
|
154
|
+
current.detail !== undefined &&
|
|
155
|
+
typeof current.detail === 'object' &&
|
|
156
|
+
current.detail !== null
|
|
157
|
+
) {
|
|
158
|
+
const cause = (current.detail as { cause?: unknown }).cause;
|
|
159
|
+
if (
|
|
160
|
+
cause === undefined ||
|
|
161
|
+
typeof cause !== 'object' ||
|
|
162
|
+
cause === null ||
|
|
163
|
+
typeof (cause as { code?: unknown }).code !== 'string'
|
|
164
|
+
) {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
current = cause as RendererErrorObservation;
|
|
168
|
+
}
|
|
169
|
+
return current;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function subscribeRendererErrors(
|
|
173
|
+
renderer: RendererType,
|
|
174
|
+
listener: (error: RendererErrorObservation) => void,
|
|
175
|
+
): () => void {
|
|
176
|
+
return renderer.subscribe((event) => {
|
|
177
|
+
if (event.kind === 'error') listener(unwrapRendererError(event.error));
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function drawPublished(renderer: RendererType, world: WorldType) {
|
|
182
|
+
const attached = renderer.attach(world);
|
|
183
|
+
if (!attached.ok) throw attached.error;
|
|
184
|
+
world.update().unwrap();
|
|
185
|
+
return drawWithOwners(renderer, world);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// feat-20260704-runtime-tier1-decomposition M2 / w12: reconstitute the
|
|
189
|
+
// eliminated top-level RuntimeErrorCode aggregate union (D-3) as a test-local
|
|
190
|
+
// alias so the exhaustive-switch bodies below stay byte-identical (AC-09).
|
|
191
|
+
type RuntimeLayerErrorCode = RenderErrorCode | AssetRuntimeErrorCode | SkinErrorCode;
|
|
192
|
+
|
|
193
|
+
import {
|
|
194
|
+
AnimationTargetId,
|
|
195
|
+
bindAnimationTargets,
|
|
196
|
+
advanceAnimationPlayer as canonicalAdvanceAnimationPlayer,
|
|
197
|
+
} from '@forgeax/engine-animation';
|
|
198
|
+
import { deriveAnimationTargetId } from '@forgeax/engine-animation/target-id';
|
|
199
|
+
import { DeviceScope } from '../../../render/src/device/device-scope';
|
|
200
|
+
import { GpuBuffer } from '../../../render/src/gpu-resource';
|
|
201
|
+
import { getOrCreateIblCache, hasIblCache } from '../../../render/src/ibl/IblPipelineCache';
|
|
202
|
+
import {
|
|
203
|
+
disposeInstanceBuffers,
|
|
204
|
+
type InstanceBufferCacheEntry,
|
|
205
|
+
} from '../../../render/src/instance-buffer-cache';
|
|
206
|
+
import { standardPipeline as urpPipeline } from '../../../render/src/pipeline/standard-pipeline';
|
|
207
|
+
import { ZERO_CAMERA_CLEAR_FALLBACK } from '../../../render/src/record/frame-snapshot';
|
|
208
|
+
import {
|
|
209
|
+
warnMultiLightDirectional,
|
|
210
|
+
warnMultiLightPoint,
|
|
211
|
+
warnMultiLightSpot,
|
|
212
|
+
} from '../../../render/src/record/helpers';
|
|
213
|
+
import type { CameraSnapshot } from '../../../render/src/render-contract';
|
|
214
|
+
import {
|
|
215
|
+
type ExtractedLights,
|
|
216
|
+
extractFrame,
|
|
217
|
+
extractFrames,
|
|
218
|
+
prepareExtractContext,
|
|
219
|
+
} from '../../../render/src/render-system-extract';
|
|
220
|
+
import {
|
|
221
|
+
getTransparentSortConfig,
|
|
222
|
+
setTransparentSortConfig,
|
|
223
|
+
TRANSPARENT_SORT_CONFIG_KEY,
|
|
224
|
+
TRANSPARENT_SORT_MODE_LAYER_Y,
|
|
225
|
+
TRANSPARENT_SORT_MODE_LAYER_YZ,
|
|
226
|
+
TRANSPARENT_SORT_MODE_LAYER_Z,
|
|
227
|
+
} from '../../../render/src/systems/transparent-sort-config';
|
|
228
|
+
import { spriteAnimationTickSystem } from '../systems/sprite-animation-tick';
|
|
229
|
+
import { REC709_LUMA_WEIGHTS, tonemapReinhardLuminance } from '../systems/tonemap';
|
|
230
|
+
import { transparentSortEntries } from '../systems/transparent-sort';
|
|
231
|
+
import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
|
|
232
|
+
|
|
233
|
+
void [
|
|
234
|
+
ANTIALIAS_FXAA,
|
|
235
|
+
ANTIALIAS_NONE,
|
|
236
|
+
AnimationPlayer,
|
|
237
|
+
AnimationTargetId,
|
|
238
|
+
AssetRegistry,
|
|
239
|
+
BLOOM_DISABLED,
|
|
240
|
+
BLOOM_ENABLED,
|
|
241
|
+
CAMERA_PROJECTION_ORTHOGRAPHIC,
|
|
242
|
+
CAMERA_PROJECTION_PERSPECTIVE,
|
|
243
|
+
Camera,
|
|
244
|
+
ChildOf,
|
|
245
|
+
DeviceScope,
|
|
246
|
+
ENTITY_NULL_RAW,
|
|
247
|
+
GpuBuffer,
|
|
248
|
+
INSTANCE_STORAGE_STRIDE_FLOATS,
|
|
249
|
+
MeshFilter,
|
|
250
|
+
MeshRenderer,
|
|
251
|
+
Name,
|
|
252
|
+
REC709_LUMA_WEIGHTS,
|
|
253
|
+
SPRITE_PLAYBACK_MODE_CLAMP,
|
|
254
|
+
SPRITE_PLAYBACK_MODE_LOOP,
|
|
255
|
+
Skin,
|
|
256
|
+
SkinInstancesCoexistForbiddenError,
|
|
257
|
+
SkinJointCountExceededError,
|
|
258
|
+
SkinJointDespawnedError,
|
|
259
|
+
SkinJointPathUnresolvedError,
|
|
260
|
+
SkyboxBackground,
|
|
261
|
+
Skylight,
|
|
262
|
+
SpriteAnimation,
|
|
263
|
+
SpriteAnimationInvalidError,
|
|
264
|
+
SpriteRegionOverride,
|
|
265
|
+
TONEMAP_LUMINANCE_EPSILON,
|
|
266
|
+
TRANSPARENT_SORT_CONFIG_KEY,
|
|
267
|
+
TRANSPARENT_SORT_MODE_LAYER_Y,
|
|
268
|
+
TRANSPARENT_SORT_MODE_LAYER_YZ,
|
|
269
|
+
TRANSPARENT_SORT_MODE_LAYER_Z,
|
|
270
|
+
Transform,
|
|
271
|
+
World,
|
|
272
|
+
ZERO_CAMERA_CLEAR_FALLBACK,
|
|
273
|
+
afterEach,
|
|
274
|
+
assembleMaterialWithSkylightEntries,
|
|
275
|
+
beforeAll,
|
|
276
|
+
beforeEach,
|
|
277
|
+
bindAnimationTargets,
|
|
278
|
+
buildPbrPipelineLayouts,
|
|
279
|
+
buildUnlitMaterialBgl,
|
|
280
|
+
cameraProjectionFromF32,
|
|
281
|
+
canonicalAdvanceAnimationPlayer,
|
|
282
|
+
componentFieldDefault,
|
|
283
|
+
componentFieldType,
|
|
284
|
+
componentSchemaTypes,
|
|
285
|
+
createSkinPaletteAllocator,
|
|
286
|
+
createSkylightFallback,
|
|
287
|
+
deriveAnimationTargetId,
|
|
288
|
+
describe,
|
|
289
|
+
disposeInstanceBuffers,
|
|
290
|
+
drawPublished,
|
|
291
|
+
drawWithOwners,
|
|
292
|
+
expect,
|
|
293
|
+
extractFrame,
|
|
294
|
+
extractFrames,
|
|
295
|
+
fileURLToPath,
|
|
296
|
+
getOrCreateIblCache,
|
|
297
|
+
getTransparentSortConfig,
|
|
298
|
+
hasIblCache,
|
|
299
|
+
it,
|
|
300
|
+
makeMockShaderRegistry,
|
|
301
|
+
mat4,
|
|
302
|
+
mergeSkylightIntoMaterialBgl,
|
|
303
|
+
prepareExtractContext,
|
|
304
|
+
propagateTransforms,
|
|
305
|
+
readFileSync,
|
|
306
|
+
resolve,
|
|
307
|
+
rhiOk,
|
|
308
|
+
selectSwapChainFormat,
|
|
309
|
+
setTransparentSortConfig,
|
|
310
|
+
spriteAnimationTickSystem,
|
|
311
|
+
standardMaterialShaderVariants,
|
|
312
|
+
subscribeRendererErrors,
|
|
313
|
+
toShared,
|
|
314
|
+
tonemapReinhardLuminance,
|
|
315
|
+
transparentSortEntries,
|
|
316
|
+
unwrapRendererError,
|
|
317
|
+
urpPipeline,
|
|
318
|
+
vec3,
|
|
319
|
+
vi,
|
|
320
|
+
warnMultiLightDirectional,
|
|
321
|
+
warnMultiLightPoint,
|
|
322
|
+
warnMultiLightSpot,
|
|
323
|
+
worldInternal,
|
|
324
|
+
];
|
|
325
|
+
type __MergedKeep =
|
|
326
|
+
| AssetRuntimeErrorCode
|
|
327
|
+
| BindGroupEntry
|
|
328
|
+
| Buffer
|
|
329
|
+
| CameraProjection
|
|
330
|
+
| CameraSnapshot
|
|
331
|
+
| EntityHandle
|
|
332
|
+
| ExtractedLights
|
|
333
|
+
| Handle
|
|
334
|
+
| InstanceBufferCacheEntry
|
|
335
|
+
| MaterialAsset
|
|
336
|
+
| MeshAsset
|
|
337
|
+
| RenderErrorCode
|
|
338
|
+
| RendererErrorObservation
|
|
339
|
+
| RendererType
|
|
340
|
+
| RuntimeLayerErrorCode
|
|
341
|
+
| Sampler
|
|
342
|
+
| SkeletonAsset
|
|
343
|
+
| SkinErrorCode
|
|
344
|
+
| Texture
|
|
345
|
+
| TextureFormat
|
|
346
|
+
| TextureView
|
|
347
|
+
| TransparentEntry
|
|
348
|
+
| WorldType;
|
|
349
|
+
|
|
350
|
+
{
|
|
351
|
+
// --- from skin-palette-extract.test.ts ---
|
|
352
|
+
|
|
353
|
+
// We test the allocator logic directly by mocking the RhiDevice.
|
|
354
|
+
// The createSkinPaletteAllocator function takes a real RhiDevice,
|
|
355
|
+
// but we can test allocateSlice and writeJointPalette through the
|
|
356
|
+
// public API after a real device is provided.
|
|
357
|
+
// For unit-testing grow/overflow logic, we test the allocator helper
|
|
358
|
+
// functions extracted from the implementation.
|
|
359
|
+
|
|
360
|
+
const MAX_BINDING = 128 * 1024 * 1024; // 128 MiB
|
|
361
|
+
|
|
362
|
+
describe('skin palette allocator', () => {
|
|
363
|
+
function mockDevice(capacity: number = MAX_BINDING) {
|
|
364
|
+
const buffers: Array<{ size: number }> = [];
|
|
365
|
+
const written: Array<{ offset: number; data: Float32Array }> = [];
|
|
366
|
+
return {
|
|
367
|
+
device: {
|
|
368
|
+
createBuffer: (desc: { size: number; usage: number; mappedAtCreation: boolean }) => {
|
|
369
|
+
if (desc.size > capacity) {
|
|
370
|
+
return { ok: false, error: new Error('limit-exceeded') };
|
|
371
|
+
}
|
|
372
|
+
const buf = { size: desc.size, _id: buffers.length };
|
|
373
|
+
buffers.push(buf);
|
|
374
|
+
return { ok: true, value: buf };
|
|
375
|
+
},
|
|
376
|
+
queue: {
|
|
377
|
+
writeBuffer: (_buf: unknown, offset: number, data: Float32Array) => {
|
|
378
|
+
written.push({ offset, data });
|
|
379
|
+
return { ok: true };
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
} as unknown as Parameters<typeof createSkinPaletteAllocator>[0],
|
|
383
|
+
buffers,
|
|
384
|
+
written,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
it('allocateSlice returns correct byteOffset and jointCount', () => {
|
|
389
|
+
const { device } = mockDevice();
|
|
390
|
+
const alloc = createSkinPaletteAllocator(device, MAX_BINDING);
|
|
391
|
+
const slice = alloc.allocateSlice(5);
|
|
392
|
+
expect(slice.jointCount).toBe(5);
|
|
393
|
+
expect(slice.byteOffset).toBe(0);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
it('consecutive allocations stack offsets rounded up to 256-byte alignment', () => {
|
|
397
|
+
const { device } = mockDevice();
|
|
398
|
+
const alloc = createSkinPaletteAllocator(device, MAX_BINDING);
|
|
399
|
+
const s1 = alloc.allocateSlice(3);
|
|
400
|
+
expect(s1.jointCount).toBe(3);
|
|
401
|
+
expect(s1.byteOffset).toBe(0);
|
|
402
|
+
const s2 = alloc.allocateSlice(2);
|
|
403
|
+
expect(s2.jointCount).toBe(2);
|
|
404
|
+
// 3 joints * 64 = 192, rounded up to the 256-byte dynamic-offset
|
|
405
|
+
// alignment (WebGPU minStorageBufferOffsetAlignment) -> 256, NOT 192.
|
|
406
|
+
expect(s2.byteOffset).toBe(256);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// Regression for the hellforge crash: a skinned char with 33 joints made
|
|
410
|
+
// the 1st slice's tight footprint 33*64 = 2112, which is not a multiple of
|
|
411
|
+
// 256 (2112 = 256 * 8.25). The 2nd slice then bound at dynOffset 2112 and
|
|
412
|
+
// tripped `Dynamic Offset[1] (2112) is not 256 byte aligned` at draw time.
|
|
413
|
+
// Every slice's byteOffset must be 256-aligned regardless of joint count.
|
|
414
|
+
it('every slice byteOffset stays 256-aligned even for non-aligned joint counts', () => {
|
|
415
|
+
const { device } = mockDevice();
|
|
416
|
+
const alloc = createSkinPaletteAllocator(device, 262144);
|
|
417
|
+
// Joint counts whose *64 footprint is NOT a multiple of 256:
|
|
418
|
+
// 33*64=2112, 17*64=1088, 5*64=320 — all misaligned pre-fix.
|
|
419
|
+
const offsets = [33, 17, 5, 40].map((jc) => alloc.allocateSlice(jc).byteOffset);
|
|
420
|
+
expect(offsets[0]).toBe(0);
|
|
421
|
+
for (const off of offsets) {
|
|
422
|
+
expect(off % 256).toBe(0);
|
|
423
|
+
}
|
|
424
|
+
// Offsets must also be strictly increasing (no overlap after rounding).
|
|
425
|
+
for (let i = 1; i < offsets.length; i++) {
|
|
426
|
+
// biome-ignore lint/style/noNonNullAssertion: fixed-length map above
|
|
427
|
+
expect(offsets[i]!).toBeGreaterThan(offsets[i - 1]!);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('resetForFrame rewinds cursor', () => {
|
|
432
|
+
const { device } = mockDevice();
|
|
433
|
+
const alloc = createSkinPaletteAllocator(device, MAX_BINDING);
|
|
434
|
+
alloc.allocateSlice(10);
|
|
435
|
+
alloc.resetForFrame();
|
|
436
|
+
const s = alloc.allocateSlice(1);
|
|
437
|
+
expect(s.byteOffset).toBe(0);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it('grow allocates buffer lazily on first request', () => {
|
|
441
|
+
const { device, buffers } = mockDevice();
|
|
442
|
+
const alloc = createSkinPaletteAllocator(device, MAX_BINDING);
|
|
443
|
+
// M6: allocator.buffer field retired in favour of per-slice
|
|
444
|
+
// `slice.buffer` (uniform fallback path needs per-entity buffers).
|
|
445
|
+
// Lazy allocation surface is now: 0 buffers before first
|
|
446
|
+
// allocateSlice, >=1 buffer after.
|
|
447
|
+
expect(buffers.length).toBe(0);
|
|
448
|
+
const slice = alloc.allocateSlice(1);
|
|
449
|
+
expect(slice.buffer).toBeDefined();
|
|
450
|
+
expect(buffers.length).toBe(1);
|
|
451
|
+
// Initial capacity = MAX_JOINTS * 64 = 255 * 64 = 16320 (storage
|
|
452
|
+
// path's first grow step; uniform fallback would also start at
|
|
453
|
+
// exactly 16320 since each pool entry equals one binding window).
|
|
454
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
455
|
+
expect(buffers[0]!.size).toBe(255 * 64);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it('grow at 1.5x when binding window exceeds capacity', () => {
|
|
459
|
+
const { device, buffers } = mockDevice();
|
|
460
|
+
const alloc = createSkinPaletteAllocator(device, MAX_BINDING);
|
|
461
|
+
// First alloc (offset=0): needed = 0 + bindingWindowBytes (16320)
|
|
462
|
+
// -> grow to 16320 exactly (initial = 255 * 64).
|
|
463
|
+
alloc.allocateSlice(255);
|
|
464
|
+
expect(buffers.length).toBe(1);
|
|
465
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
466
|
+
expect(buffers[0]!.size).toBe(16320);
|
|
467
|
+
// Second alloc (offset=255*64=16320): needed = 16320 + 16320 = 32640.
|
|
468
|
+
// 1.5x grow: 16320 -> 24576 -> 36864 (smallest aligned >= 32640).
|
|
469
|
+
alloc.allocateSlice(100);
|
|
470
|
+
expect(buffers.length).toBe(2);
|
|
471
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
472
|
+
expect(buffers[1]!.size).toBe(36864);
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// M6 regression gate: the bug that this fix repairs reproduces here as
|
|
476
|
+
// a SkinPaletteOverflowError under the old allocator (cap=16320, grow
|
|
477
|
+
// gated on `cursor + jointCount * 64`). Under the new allocator the
|
|
478
|
+
// 2nd entity would need `offset=1536 + window=16320 = 17856 B`, so a
|
|
479
|
+
// cap of 16320 must reject during grow -- but a realistic device cap
|
|
480
|
+
// (storage limit / uniform spec floor 64 KiB) must accept it.
|
|
481
|
+
it('two skin entities at byteOffset 0 and 1536 stay within buffer (M6)', () => {
|
|
482
|
+
const { device, buffers } = mockDevice();
|
|
483
|
+
// 64 KiB == WebGPU spec floor for maxUniformBufferBindingSize.
|
|
484
|
+
const alloc = createSkinPaletteAllocator(device, 65536);
|
|
485
|
+
const s0 = alloc.allocateSlice(24); // Fox: 24 joints
|
|
486
|
+
const s1 = alloc.allocateSlice(24);
|
|
487
|
+
expect(s0.byteOffset).toBe(0);
|
|
488
|
+
expect(s1.byteOffset).toBe(24 * 64); // 1536, matches the WebGPU error
|
|
489
|
+
// The allocator must satisfy `buffer.size >= byteOffset + window`
|
|
490
|
+
// for every slice so `setBindGroup(_, _, [_, dynOffset=1536])` with
|
|
491
|
+
// an `entry.size = 16320` BG passes `dynOffset + entry.size <=
|
|
492
|
+
// buffer.size` validation.
|
|
493
|
+
const lastBuf = buffers[buffers.length - 1];
|
|
494
|
+
expect(lastBuf?.size).toBeGreaterThanOrEqual(s1.byteOffset + 255 * 64);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it('overflow fails-fast with SkinPaletteOverflowError', () => {
|
|
498
|
+
// Cap below one binding window (16320) -> first allocateSlice grows
|
|
499
|
+
// and overflows.
|
|
500
|
+
const { device } = mockDevice(1000);
|
|
501
|
+
const alloc = createSkinPaletteAllocator(device, 1000);
|
|
502
|
+
expect(() => alloc.allocateSlice(20)).toThrow();
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it('overflow fails-fast when 2nd entity would breach cap (M6)', () => {
|
|
506
|
+
// Cap == one binding window. First entity (offset=0) fits, second
|
|
507
|
+
// entity (offset=1536) would need 17856 B and must throw.
|
|
508
|
+
const { device } = mockDevice(16320);
|
|
509
|
+
const alloc = createSkinPaletteAllocator(device, 16320);
|
|
510
|
+
alloc.allocateSlice(24); // offset=0, fits in 16320
|
|
511
|
+
expect(() => alloc.allocateSlice(24)).toThrow(); // offset=1536, needs 17856 > 16320
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
// M6 uniform fallback path: each slice gets its OWN 16320 B UBO
|
|
515
|
+
// (the cap=16384 storage-buffer-disabled browser case). Slice
|
|
516
|
+
// byteOffset is always 0; slice.buffer is path-specific.
|
|
517
|
+
it('uniform fallback: each entity gets its own buffer + byteOffset 0 (M6)', () => {
|
|
518
|
+
const { device, buffers } = mockDevice();
|
|
519
|
+
const alloc = createSkinPaletteAllocator(device, 16384, /* useStorageBuffer */ false);
|
|
520
|
+
expect(alloc.useStorageBuffer).toBe(false);
|
|
521
|
+
const s0 = alloc.allocateSlice(24);
|
|
522
|
+
const s1 = alloc.allocateSlice(24);
|
|
523
|
+
const s2 = alloc.allocateSlice(24);
|
|
524
|
+
expect(s0.byteOffset).toBe(0);
|
|
525
|
+
expect(s1.byteOffset).toBe(0);
|
|
526
|
+
expect(s2.byteOffset).toBe(0);
|
|
527
|
+
expect(s0.buffer).not.toBe(s1.buffer);
|
|
528
|
+
expect(s1.buffer).not.toBe(s2.buffer);
|
|
529
|
+
expect(s0.buffer).not.toBe(s2.buffer);
|
|
530
|
+
// Three entities -> three distinct UBOs of size = bindingWindowBytes.
|
|
531
|
+
expect(buffers.length).toBe(3);
|
|
532
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
533
|
+
expect(buffers[0]!.size).toBe(16320);
|
|
534
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
535
|
+
expect(buffers[1]!.size).toBe(16320);
|
|
536
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
537
|
+
expect(buffers[2]!.size).toBe(16320);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
it('uniform fallback: pool reuses buffers across frames (M6)', () => {
|
|
541
|
+
const { device, buffers } = mockDevice();
|
|
542
|
+
const alloc = createSkinPaletteAllocator(device, 16384, false);
|
|
543
|
+
// Frame 1: 3 entities -> 3 buffers minted.
|
|
544
|
+
const f1s0 = alloc.allocateSlice(10);
|
|
545
|
+
const f1s1 = alloc.allocateSlice(10);
|
|
546
|
+
const f1s2 = alloc.allocateSlice(10);
|
|
547
|
+
expect(buffers.length).toBe(3);
|
|
548
|
+
// Frame 2: reset + same-shape walk -> pool round-robin, no new
|
|
549
|
+
// createBuffer calls. Slices reuse the exact same buffer objects.
|
|
550
|
+
alloc.resetForFrame();
|
|
551
|
+
const f2s0 = alloc.allocateSlice(10);
|
|
552
|
+
const f2s1 = alloc.allocateSlice(10);
|
|
553
|
+
const f2s2 = alloc.allocateSlice(10);
|
|
554
|
+
expect(buffers.length).toBe(3); // unchanged
|
|
555
|
+
expect(f2s0.buffer).toBe(f1s0.buffer);
|
|
556
|
+
expect(f2s1.buffer).toBe(f1s1.buffer);
|
|
557
|
+
expect(f2s2.buffer).toBe(f1s2.buffer);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it('CPU premul writes correct mat4 values', () => {
|
|
561
|
+
const { device, written } = mockDevice();
|
|
562
|
+
const alloc = createSkinPaletteAllocator(device, MAX_BINDING);
|
|
563
|
+
// Identity joint_world * identity IBM = identity
|
|
564
|
+
const jw = mat4.create();
|
|
565
|
+
mat4.identity(jw);
|
|
566
|
+
// IBM: identity matrix
|
|
567
|
+
const ibm = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
568
|
+
const slice = alloc.allocateSlice(1);
|
|
569
|
+
alloc.writeJointPalette(slice, [ibm], [jw]);
|
|
570
|
+
expect(written.length).toBe(1);
|
|
571
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
572
|
+
expect(written[0]!.offset).toBe(slice.byteOffset);
|
|
573
|
+
// Expected: identity mat4 in column-major order
|
|
574
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
575
|
+
const payload = written[0]!.data;
|
|
576
|
+
expect(payload[0]).toBeCloseTo(1); // col 0 row 0
|
|
577
|
+
expect(payload[1]).toBeCloseTo(0);
|
|
578
|
+
expect(payload[2]).toBeCloseTo(0);
|
|
579
|
+
expect(payload[3]).toBeCloseTo(0);
|
|
580
|
+
expect(payload[4]).toBeCloseTo(0); // col 1 row 0
|
|
581
|
+
expect(payload[5]).toBeCloseTo(1);
|
|
582
|
+
expect(payload[15]).toBeCloseTo(1); // col 3 row 3
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
it('CPU premul: joint_world * IBM multiplication is correct', () => {
|
|
586
|
+
const { device, written } = mockDevice();
|
|
587
|
+
const alloc = createSkinPaletteAllocator(device, MAX_BINDING);
|
|
588
|
+
// joint_world: translate (2, 0, 0)
|
|
589
|
+
const jw = mat4.create();
|
|
590
|
+
mat4.translate(jw, mat4.identity(mat4.create()), [2, 0, 0]);
|
|
591
|
+
// IBM: identity
|
|
592
|
+
const ibm = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
593
|
+
const slice = alloc.allocateSlice(1);
|
|
594
|
+
alloc.writeJointPalette(slice, [ibm], [jw]);
|
|
595
|
+
|
|
596
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
597
|
+
const payload = written[0]!.data;
|
|
598
|
+
// Column 3 should have translation (2, 0, 0, 1)
|
|
599
|
+
// Column-major: element 12 = col 3 row 0 = tx
|
|
600
|
+
expect(payload[12]).toBeCloseTo(2);
|
|
601
|
+
expect(payload[13]).toBeCloseTo(0);
|
|
602
|
+
expect(payload[14]).toBeCloseTo(0);
|
|
603
|
+
expect(payload[15]).toBeCloseTo(1);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
// feat-20260601 w12/w13: skin joint world matrices now flow from the resolved
|
|
607
|
+
// `Transform.world` column array view (a raw 16-float `Float32Array`, written
|
|
608
|
+
// by propagateTransforms) straight into the allocator's `readonly Mat4[]`
|
|
609
|
+
// jointWorlds parameter -- zero recompose from decomposed TRS. The allocator
|
|
610
|
+
// contract is unchanged; this guards that a bare Transform.world-shaped
|
|
611
|
+
// Float32Array premultiplies against the IBM exactly like a `mat4.create()`.
|
|
612
|
+
it('accepts a Transform.world-shaped Float32Array as a joint world matrix', () => {
|
|
613
|
+
const { device, written } = mockDevice();
|
|
614
|
+
const alloc = createSkinPaletteAllocator(device, MAX_BINDING);
|
|
615
|
+
// A Transform.world view is a plain 16-float column-major Float32Array.
|
|
616
|
+
// Here: translation (0, 3, 0) -- the shape a `world._getArrayView(joint,
|
|
617
|
+
// Transform, 'world')` read returns after propagate.
|
|
618
|
+
const jointWorldView = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 3, 0, 1]);
|
|
619
|
+
const ibm = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
620
|
+
const slice = alloc.allocateSlice(1);
|
|
621
|
+
alloc.writeJointPalette(
|
|
622
|
+
slice,
|
|
623
|
+
[ibm],
|
|
624
|
+
[jointWorldView as unknown as Parameters<typeof alloc.writeJointPalette>[2][number]],
|
|
625
|
+
);
|
|
626
|
+
|
|
627
|
+
// biome-ignore lint/style/noNonNullAssertion: controlled test context
|
|
628
|
+
const payload = written[0]!.data;
|
|
629
|
+
expect(payload[12]).toBeCloseTo(0);
|
|
630
|
+
expect(payload[13]).toBeCloseTo(3);
|
|
631
|
+
expect(payload[14]).toBeCloseTo(0);
|
|
632
|
+
expect(payload[15]).toBeCloseTo(1);
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
}
|