@forgeax/engine-render 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.
Files changed (918) hide show
  1. package/README.md +130 -641
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts +2 -0
  4. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts.map +1 -0
  5. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts +2 -0
  6. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts.map +1 -0
  7. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts +2 -0
  8. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts.map +1 -0
  9. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts.map +1 -1
  10. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts +6 -0
  11. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts.map +1 -1
  12. package/dist/{gpu-driven/view-reference.d.ts → __tests__/gpu-driven-view-reference.d.ts} +4 -4
  13. package/dist/__tests__/gpu-driven-view-reference.d.ts.map +1 -0
  14. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts.map +1 -1
  15. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts +2 -0
  16. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts.map +1 -0
  17. package/dist/__tests__/morph-feature-plan.unit.test.d.ts +2 -0
  18. package/dist/__tests__/morph-feature-plan.unit.test.d.ts.map +1 -0
  19. package/dist/__tests__/render-feature-plan.test-d.d.ts +2 -0
  20. package/dist/__tests__/render-feature-plan.test-d.d.ts.map +1 -0
  21. package/dist/__tests__/render-feature-plan.unit.test.d.ts +2 -0
  22. package/dist/__tests__/render-feature-plan.unit.test.d.ts.map +1 -0
  23. package/dist/__tests__/ssao-config.unit.test.d.ts +2 -0
  24. package/dist/__tests__/ssao-config.unit.test.d.ts.map +1 -0
  25. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts +2 -0
  26. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts.map +1 -0
  27. package/dist/__tests__/standard-descriptors.test-d.d.ts +2 -0
  28. package/dist/__tests__/standard-descriptors.test-d.d.ts.map +1 -0
  29. package/dist/__tests__/standard-pipeline.dawn.test.d.ts +2 -0
  30. package/dist/__tests__/standard-pipeline.dawn.test.d.ts.map +1 -0
  31. package/dist/__tests__/standard-pipeline.integration.test.d.ts +2 -0
  32. package/dist/__tests__/standard-pipeline.integration.test.d.ts.map +1 -0
  33. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts +2 -0
  34. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts.map +1 -0
  35. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts +2 -0
  36. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts.map +1 -0
  37. package/dist/{renderer/backend-selection.d.ts → assembly/backend-contract.d.ts} +15 -4
  38. package/dist/assembly/backend-contract.d.ts.map +1 -0
  39. package/dist/assembly/factory.d.ts +207 -0
  40. package/dist/assembly/factory.d.ts.map +1 -0
  41. package/dist/assembly/host-contract.d.ts +84 -0
  42. package/dist/assembly/host-contract.d.ts.map +1 -0
  43. package/dist/{renderer → assembly}/material/assembly.d.ts +0 -1
  44. package/dist/{renderer → assembly}/material/assembly.d.ts.map +1 -1
  45. package/dist/assembly/material/pipeline-projection.d.ts +30 -0
  46. package/dist/assembly/material/pipeline-projection.d.ts.map +1 -0
  47. package/dist/authoring.d.ts +10 -11
  48. package/dist/authoring.d.ts.map +1 -1
  49. package/dist/authoring.mjs +25 -3
  50. package/dist/authoring.mjs.map +1 -1
  51. package/dist/chunk-CQXZC5XI.mjs +182 -0
  52. package/dist/chunk-CQXZC5XI.mjs.map +1 -0
  53. package/dist/chunk-QC4VW3XJ.mjs +79 -0
  54. package/dist/chunk-QC4VW3XJ.mjs.map +1 -0
  55. package/dist/chunk-SCRSAK5B.mjs +480 -0
  56. package/dist/chunk-SCRSAK5B.mjs.map +1 -0
  57. package/dist/components/__tests__/schema-contract.unit.test.d.ts +2 -0
  58. package/dist/components/__tests__/schema-contract.unit.test.d.ts.map +1 -0
  59. package/dist/components/glyph-text.d.ts +1 -1
  60. package/dist/components/glyph-text.d.ts.map +1 -1
  61. package/dist/components/index.d.ts +2 -2
  62. package/dist/components/index.d.ts.map +1 -1
  63. package/dist/components/instances.d.ts +1 -1
  64. package/dist/components/instances.d.ts.map +1 -1
  65. package/dist/components/light-helpers.d.ts +1 -1
  66. package/dist/components/light-helpers.d.ts.map +1 -1
  67. package/dist/components/mesh-filter.d.ts +7 -7
  68. package/dist/components/mesh-filter.d.ts.map +1 -1
  69. package/dist/components/scene-instance.d.ts +11 -11
  70. package/dist/components/skybox-background.d.ts +56 -0
  71. package/dist/components/skybox-background.d.ts.map +1 -0
  72. package/dist/components/skylight.d.ts +55 -0
  73. package/dist/components/skylight.d.ts.map +1 -0
  74. package/dist/components/sprite-animation.d.ts +2 -3
  75. package/dist/components/sprite-animation.d.ts.map +1 -1
  76. package/dist/components/sprite-instances.d.ts +1 -1
  77. package/dist/components/sprite-playback-mode.d.ts +6 -1
  78. package/dist/components/sprite-playback-mode.d.ts.map +1 -1
  79. package/dist/components/sprite-region-override.d.ts +2 -3
  80. package/dist/components/sprite-region-override.d.ts.map +1 -1
  81. package/dist/components/tile-layer.d.ts +5 -0
  82. package/dist/components/tile-layer.d.ts.map +1 -1
  83. package/dist/construct-renderer.d.ts +18 -1
  84. package/dist/construct-renderer.d.ts.map +1 -1
  85. package/dist/construct-renderer.mjs +27008 -4
  86. package/dist/construct-renderer.mjs.map +1 -1
  87. package/dist/debug-draw-glue.d.ts +2 -53
  88. package/dist/debug-draw-glue.d.ts.map +1 -1
  89. package/dist/device/device-scope.d.ts +83 -0
  90. package/dist/device/device-scope.d.ts.map +1 -0
  91. package/dist/{gpu-resource-store.d.ts → device/gpu-residency.d.ts} +91 -48
  92. package/dist/device/gpu-residency.d.ts.map +1 -0
  93. package/dist/device/resource-types.d.ts +8 -0
  94. package/dist/device/resource-types.d.ts.map +1 -0
  95. package/dist/engine-metrics.d.ts +2 -2
  96. package/dist/engine-metrics.d.ts.map +1 -1
  97. package/dist/errors/recover.d.ts +28 -1
  98. package/dist/errors/recover.d.ts.map +1 -1
  99. package/dist/errors/render.d.ts +249 -258
  100. package/dist/errors/render.d.ts.map +1 -1
  101. package/dist/features/fullscreen.d.ts +19 -0
  102. package/dist/features/fullscreen.d.ts.map +1 -0
  103. package/dist/features/host.d.ts +32 -26
  104. package/dist/features/host.d.ts.map +1 -1
  105. package/dist/features/morph/morph-feature.d.ts +39 -5
  106. package/dist/features/morph/morph-feature.d.ts.map +1 -1
  107. package/dist/features/plan.d.ts +182 -0
  108. package/dist/features/plan.d.ts.map +1 -0
  109. package/dist/features/prepared-gpu-work.d.ts +21 -17
  110. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  111. package/dist/features/prepared-graphics-store.d.ts +2 -1
  112. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  113. package/dist/features/prepared-graphics.d.ts +11 -21
  114. package/dist/features/prepared-graphics.d.ts.map +1 -1
  115. package/dist/features/render-graph-compute.d.ts +2 -2
  116. package/dist/features/render-graph-compute.d.ts.map +1 -1
  117. package/dist/features/render-graph-contribution.d.ts +4 -7
  118. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  119. package/dist/features/render-graph-raster.d.ts +2 -2
  120. package/dist/features/render-graph-raster.d.ts.map +1 -1
  121. package/dist/features/render-graph-resources.d.ts +6 -6
  122. package/dist/features/render-graph-resources.d.ts.map +1 -1
  123. package/dist/features/targets.d.ts +5 -5
  124. package/dist/features/targets.d.ts.map +1 -1
  125. package/dist/features/types.d.ts +11 -190
  126. package/dist/features/types.d.ts.map +1 -1
  127. package/dist/features/vocabulary.d.ts +14 -0
  128. package/dist/features/vocabulary.d.ts.map +1 -0
  129. package/dist/fullscreen-post-process-pass.d.ts +4 -25
  130. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  131. package/dist/glyph-text-layout-system.d.ts +3 -2
  132. package/dist/glyph-text-layout-system.d.ts.map +1 -1
  133. package/dist/gpu-driven/batch-topology.d.ts +6 -75
  134. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  135. package/dist/gpu-driven/production-raster.d.ts +13 -112
  136. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  137. package/dist/gpu-driven/view-gpu.d.ts +10 -66
  138. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  139. package/dist/gpu-resource.d.ts +3 -3
  140. package/dist/gpu-scene-schema.d.ts +1 -94
  141. package/dist/gpu-scene-schema.d.ts.map +1 -1
  142. package/dist/gpu-scene.d.ts +7 -33
  143. package/dist/gpu-scene.d.ts.map +1 -1
  144. package/dist/hdrp-buffers.d.ts +3 -53
  145. package/dist/hdrp-buffers.d.ts.map +1 -1
  146. package/dist/ibl/IblPipelineCache.d.ts +74 -180
  147. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  148. package/dist/ibl/skylight-bind-group.d.ts +1 -1
  149. package/dist/index.d.ts +13 -43
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.mjs +165 -3
  152. package/dist/index.mjs.map +1 -1
  153. package/dist/inspection-types.d.ts +69 -0
  154. package/dist/inspection-types.d.ts.map +1 -0
  155. package/dist/instance-buffer-cache.d.ts +1 -4
  156. package/dist/instance-buffer-cache.d.ts.map +1 -1
  157. package/dist/internal.d.ts +1 -73
  158. package/dist/internal.d.ts.map +1 -1
  159. package/dist/internal.mjs +1 -43
  160. package/dist/internal.mjs.map +1 -1
  161. package/dist/lifecycle.d.ts +36 -2
  162. package/dist/lifecycle.d.ts.map +1 -1
  163. package/dist/materials.d.ts +0 -3
  164. package/dist/materials.d.ts.map +1 -1
  165. package/dist/mesh-material-bindings.d.ts +0 -1
  166. package/dist/mesh-material-bindings.d.ts.map +1 -1
  167. package/dist/pbr-pipeline.d.ts +75 -29
  168. package/dist/pbr-pipeline.d.ts.map +1 -1
  169. package/dist/pipeline/standard-forward-lane.d.ts +5 -0
  170. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -0
  171. package/dist/pipeline/standard-pipeline.d.ts +31 -0
  172. package/dist/pipeline/standard-pipeline.d.ts.map +1 -0
  173. package/dist/pipeline/standard-profile.d.ts +40 -0
  174. package/dist/pipeline/standard-profile.d.ts.map +1 -0
  175. package/dist/pipeline-builder.d.ts +3 -3
  176. package/dist/pipeline-builder.d.ts.map +1 -1
  177. package/dist/pipeline-spec-types.d.ts +24 -0
  178. package/dist/pipeline-spec-types.d.ts.map +1 -0
  179. package/dist/pipeline-spec.d.ts +16 -155
  180. package/dist/pipeline-spec.d.ts.map +1 -1
  181. package/dist/plugin.d.ts +1 -14
  182. package/dist/plugin.d.ts.map +1 -1
  183. package/dist/post-process-errors.d.ts +18 -18
  184. package/dist/post-process-errors.d.ts.map +1 -1
  185. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -5
  186. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  187. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts +2 -0
  188. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts.map +1 -0
  189. package/dist/record/frame-lighting.d.ts +7 -73
  190. package/dist/record/frame-lighting.d.ts.map +1 -1
  191. package/dist/record/frame-snapshot.d.ts +44 -44
  192. package/dist/record/frame-snapshot.d.ts.map +1 -1
  193. package/dist/record/frame-targets.d.ts +5 -38
  194. package/dist/record/frame-targets.d.ts.map +1 -1
  195. package/dist/record/frame.d.ts +64 -52
  196. package/dist/record/frame.d.ts.map +1 -1
  197. package/dist/record/helpers.d.ts +3 -2
  198. package/dist/record/helpers.d.ts.map +1 -1
  199. package/dist/record/main-pass-geometry.d.ts +5 -4
  200. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  201. package/dist/record/main-pass-material.d.ts +90 -59
  202. package/dist/record/main-pass-material.d.ts.map +1 -1
  203. package/dist/record/main-pass-sprite-draws.d.ts +28 -3
  204. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  205. package/dist/record/main-pass.d.ts +1 -1
  206. package/dist/record/main-pass.d.ts.map +1 -1
  207. package/dist/record/mesh-ssbo.d.ts +276 -3
  208. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  209. package/dist/record/render-context.d.ts +235 -0
  210. package/dist/record/render-context.d.ts.map +1 -0
  211. package/dist/record/shadow-pass.d.ts +15 -88
  212. package/dist/record/shadow-pass.d.ts.map +1 -1
  213. package/dist/record/skybox-post-pass.d.ts +1 -1
  214. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  215. package/dist/record/typed-frame-graph.d.ts +29 -7
  216. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  217. package/dist/record/view-ubo.d.ts +3 -3
  218. package/dist/record/view-ubo.d.ts.map +1 -1
  219. package/dist/render-contract.d.ts +416 -0
  220. package/dist/render-contract.d.ts.map +1 -0
  221. package/dist/render-data.d.ts.map +1 -1
  222. package/dist/render-graph-primitives.d.ts +14 -362
  223. package/dist/render-graph-primitives.d.ts.map +1 -1
  224. package/dist/render-pipeline.d.ts +25 -64
  225. package/dist/render-pipeline.d.ts.map +1 -1
  226. package/dist/render-system-extract.d.ts +107 -338
  227. package/dist/render-system-extract.d.ts.map +1 -1
  228. package/dist/render-system.d.ts +21 -713
  229. package/dist/render-system.d.ts.map +1 -1
  230. package/dist/scene/render-scene-types.d.ts +58 -0
  231. package/dist/scene/render-scene-types.d.ts.map +1 -0
  232. package/dist/scene/render-scene.d.ts +105 -0
  233. package/dist/scene/render-scene.d.ts.map +1 -0
  234. package/dist/scene-instances/post-spawn-resolve-joints.d.ts +2 -5
  235. package/dist/scene-instances/post-spawn-resolve-joints.d.ts.map +1 -1
  236. package/dist/ssao-buffers.d.ts +22 -3
  237. package/dist/ssao-buffers.d.ts.map +1 -1
  238. package/dist/systems/skin-palette-allocator.d.ts +2 -4
  239. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  240. package/dist/systems/skin-palette-types.d.ts +14 -0
  241. package/dist/systems/skin-palette-types.d.ts.map +1 -0
  242. package/dist/systems/transparent-sort-config.d.ts +23 -2
  243. package/dist/systems/transparent-sort-config.d.ts.map +1 -1
  244. package/dist/tilemap-chunk-extract-system.d.ts +4 -3
  245. package/dist/tilemap-chunk-extract-system.d.ts.map +1 -1
  246. package/dist/typed-render-graph-primitives.d.ts +2 -4
  247. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  248. package/dist/typed-shadow-passes.d.ts +3 -3
  249. package/dist/typed-shadow-passes.d.ts.map +1 -1
  250. package/package.json +23 -23
  251. package/src/__tests__/backend-selection-rhi-capture.test-d.ts +1 -1
  252. package/src/__tests__/callback-inference.test-d.ts +6 -3
  253. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -4
  254. package/src/__tests__/construct-renderer-identity.unit.test.ts +15 -2
  255. package/src/__tests__/device-scope-lifecycle.unit.test.ts +151 -0
  256. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +42 -0
  257. package/src/__tests__/direct-extract-consumer-contract.test-d.ts +8 -19
  258. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -13
  259. package/src/__tests__/factory-contract.integration.test.ts +158 -209
  260. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +1 -4
  261. package/src/__tests__/frame-observation.contract.test.ts +17 -8
  262. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +32 -0
  263. package/src/__tests__/glyph-text-layout-recovery.unit.test.ts +6 -11
  264. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +9 -16
  265. package/src/__tests__/gpu-driven-production.integration.test.ts +32 -205
  266. package/src/__tests__/gpu-driven-scaling.unit.test.ts +4 -7
  267. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +87 -8
  268. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +170 -8
  269. package/src/{gpu-driven/view-reference.ts → __tests__/gpu-driven-view-reference.ts} +4 -3
  270. package/src/__tests__/gpu-driven-view.browser.test.ts +12 -1
  271. package/src/__tests__/gpu-driven-view.dawn.test.ts +12 -1
  272. package/src/__tests__/gpu-driven-view.unit.test.ts +11 -267
  273. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +3 -3
  274. package/src/__tests__/gpu-scene-render-graph-gpu.ts +2 -3
  275. package/src/__tests__/gpu-scene.dawn.test.ts +2 -6
  276. package/src/__tests__/gpu-scene.unit.test.ts +10 -24
  277. package/src/__tests__/ibl/face-uniforms.unit.test.ts +46 -0
  278. package/src/__tests__/infinite-grid-no-vertex-probe.unit.test.ts +34 -66
  279. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -5
  280. package/src/__tests__/light-buffer-layout.unit.test.ts +4 -49
  281. package/src/__tests__/material-cooked-projection.unit.test.ts +2 -51
  282. package/src/__tests__/material-snapshot-mutation.integration.test.ts +10 -15
  283. package/src/__tests__/material-static-dynamic-route.unit.test.ts +4 -23
  284. package/src/__tests__/material-stride-surface.unit.test.ts +2 -2
  285. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +7 -8
  286. package/src/__tests__/morph-culling-reentry.dawn.test.ts +29 -38
  287. package/src/__tests__/morph-feature-gpu-work.integration.test.ts +45 -43
  288. package/src/__tests__/morph-feature-plan.unit.test.ts +53 -0
  289. package/src/__tests__/morph-visual-evidence.integration.test.ts +47 -33
  290. package/src/__tests__/nineslice-handle-surface.unit.test.ts +11 -6
  291. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -13
  292. package/src/__tests__/prepared-graphics-capability.unit.test.ts +6 -81
  293. package/src/__tests__/prepared-graphics-generation.unit.test.ts +3 -17
  294. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +6 -74
  295. package/src/__tests__/prepared-graphics-resolver.unit.test.ts +1 -3
  296. package/src/__tests__/prepared-graphics-snapshot.unit.test.ts +2 -2
  297. package/src/__tests__/profiler-default-off.test.ts +1 -1
  298. package/src/__tests__/profiler-phase-catalog.test.ts +2 -2
  299. package/src/__tests__/profiler-phase-integration.test.ts +5 -13
  300. package/src/__tests__/profiler-phase-token.test.ts +3 -8
  301. package/src/__tests__/public-surface.test-d.ts +65 -3
  302. package/src/__tests__/recover-error-policy-owner.unit.test.ts +1 -21
  303. package/src/__tests__/render-error-code-owner.test-d.ts +18 -23
  304. package/src/__tests__/render-error-detail-ssot.test-d.ts +0 -95
  305. package/src/__tests__/render-error-exhaustive.test-d.ts +8 -1
  306. package/src/__tests__/render-feature-assembly.test-d.ts +8 -16
  307. package/src/__tests__/render-feature-context.test-d.ts +16 -40
  308. package/src/__tests__/render-feature-contract.test-d.ts +9 -18
  309. package/src/__tests__/render-feature-diagnostics.unit.test.ts +6 -8
  310. package/src/__tests__/render-feature-docs.unit.test.ts +8 -7
  311. package/src/__tests__/render-feature-gpu-work.integration.test.ts +14 -75
  312. package/src/__tests__/render-feature-plan.test-d.ts +161 -0
  313. package/src/__tests__/render-feature-plan.unit.test.ts +170 -0
  314. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +8 -19
  315. package/src/__tests__/render-feature-prepared-errors.test-d.ts +3 -6
  316. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +10 -71
  317. package/src/__tests__/render-feature-prepared-graphics-isolation.unit.test.ts +11 -61
  318. package/src/__tests__/render-feature-prepared-graphics-negative.test-d.ts +20 -43
  319. package/src/__tests__/render-feature-prepared-graphics.test-d.ts +56 -78
  320. package/src/__tests__/render-feature-public-surface.test-d.ts +6 -24
  321. package/src/__tests__/render-feature-retry.unit.test.ts +7 -48
  322. package/src/__tests__/render-feature-scheduling.unit.test.ts +15 -27
  323. package/src/__tests__/render-feature-stage-failed-policy-owner.unit.test.ts +0 -9
  324. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +19 -109
  325. package/src/__tests__/render-feature-visibility-context.test-d.ts +1 -6
  326. package/src/__tests__/render-feature-visibility-context.unit.test.ts +1 -2
  327. package/src/__tests__/render-feature-zero-work.unit.test.ts +14 -20
  328. package/src/__tests__/render-scene-projection.unit.test.ts +73 -111
  329. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +44 -95
  330. package/src/__tests__/renderer-lifecycle.integration.test.ts +49 -1
  331. package/src/__tests__/shader-stage-surface.unit.test.ts +14 -9
  332. package/src/__tests__/ssao-config.unit.test.ts +36 -0
  333. package/src/__tests__/ssao-kernel-surface.unit.test.ts +4 -5
  334. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +28 -0
  335. package/src/__tests__/standard-descriptors.test-d.ts +22 -0
  336. package/src/__tests__/standard-pipeline.dawn.test.ts +61 -0
  337. package/src/__tests__/standard-pipeline.integration.test.ts +124 -0
  338. package/src/__tests__/standard-profile-oracle.unit.test.ts +62 -0
  339. package/src/__tests__/surface-configuration.unit.test.ts +1 -2
  340. package/src/__tests__/texture-usage-surface.unit.test.ts +3 -6
  341. package/src/__tests__/typed-pipeline-topology.unit.test.ts +40 -206
  342. package/src/__tests__/urp-pipeline-targets.unit.test.ts +1 -11
  343. package/src/__tests__/urp-pipeline.unit.test.ts +2 -2
  344. package/src/__tests__/vertex-color-pipeline.unit.test.ts +10 -2
  345. package/src/__tests__/vertex-layout-consumer.unit.test.ts +1 -1
  346. package/src/__tests__/visibility-diagnostics.integration.test.ts +7 -11
  347. package/src/__tests__/visibility-extract.integration.test.ts +20 -11
  348. package/src/__tests__/visibility-extract.perf.test.ts +66 -32
  349. package/src/__tests__/visibility-feature-dedup.integration.test.ts +2 -4
  350. package/src/__tests__/visibility-hidden-report.unit.test.ts +1 -2
  351. package/src/__tests__/visibility-instances.integration.test.ts +7 -11
  352. package/src/__tests__/visibility-multi-world.integration.test.ts +38 -6
  353. package/src/__tests__/visibility-producer-matrix.integration.test.ts +18 -41
  354. package/src/__tests__/visibility-public-surface.test-d.ts +10 -9
  355. package/src/__tests__/visibility-resolver.unit.test.ts +2 -1
  356. package/src/__tests__/visibility-resource-short-circuit.unit.test.ts +80 -0
  357. package/src/__tests__/visibility-snapshot-contract.unit.test.ts +2 -1
  358. package/src/__tests__/vocabulary.unit.test.ts +1 -1
  359. package/src/assembly/backend-contract.ts +57 -0
  360. package/src/{renderer/renderer-factory.ts → assembly/factory.ts} +1663 -2690
  361. package/src/assembly/host-contract.ts +101 -0
  362. package/src/{renderer → assembly}/material/assembly.ts +0 -2
  363. package/src/assembly/material/pipeline-projection.ts +63 -0
  364. package/src/authoring.ts +14 -22
  365. package/src/components/__tests__/schema-contract.unit.test.ts +10 -0
  366. package/src/components/glyph-text.ts +3 -2
  367. package/src/components/index.ts +7 -9
  368. package/src/components/instances.ts +4 -5
  369. package/src/components/light-helpers.ts +1 -1
  370. package/src/components/mesh-filter.ts +11 -10
  371. package/src/components/post-process-params.ts +3 -3
  372. package/src/components/scene-instance.ts +12 -12
  373. package/src/components/skybox-background.ts +103 -0
  374. package/src/components/{environment.ts → skylight.ts} +2 -110
  375. package/src/components/sprite-animation.ts +3 -4
  376. package/src/components/sprite-instances.ts +2 -2
  377. package/src/components/sprite-playback-mode.ts +7 -1
  378. package/src/components/sprite-region-override.ts +2 -3
  379. package/src/components/tile-layer.ts +8 -2
  380. package/src/construct-renderer.ts +67 -4
  381. package/src/debug-draw-glue.ts +8 -129
  382. package/src/device/device-scope.ts +306 -0
  383. package/src/{gpu-resource-store.ts → device/gpu-residency.ts} +540 -639
  384. package/src/device/resource-types.ts +20 -0
  385. package/src/engine-metrics.ts +12 -19
  386. package/src/errors/recover.ts +45 -3
  387. package/src/errors/render.ts +357 -460
  388. package/src/features/fullscreen.ts +46 -0
  389. package/src/features/host.ts +575 -309
  390. package/src/features/morph/morph-feature.ts +195 -105
  391. package/src/features/plan.ts +447 -0
  392. package/src/features/prepared-gpu-work.ts +72 -15
  393. package/src/features/prepared-graphics-store.ts +20 -6
  394. package/src/features/prepared-graphics.ts +12 -71
  395. package/src/features/render-graph-compute.ts +14 -5
  396. package/src/features/render-graph-contribution.ts +43 -63
  397. package/src/features/render-graph-raster.ts +11 -6
  398. package/src/features/render-graph-resources.ts +25 -23
  399. package/src/features/targets.ts +8 -21
  400. package/src/features/types.ts +39 -227
  401. package/src/features/vocabulary.ts +24 -0
  402. package/src/fullscreen-post-process-pass.ts +14 -57
  403. package/src/glyph-text-layout-system.ts +70 -96
  404. package/src/gpu-driven/batch-topology.ts +24 -202
  405. package/src/gpu-driven/production-raster.ts +93 -1108
  406. package/src/gpu-driven/view-gpu.ts +46 -192
  407. package/src/gpu-resource.ts +4 -4
  408. package/src/gpu-scene-schema.ts +11 -99
  409. package/src/gpu-scene.ts +231 -364
  410. package/src/hdrp-buffers.ts +12 -221
  411. package/src/ibl/IblPipelineCache.ts +471 -711
  412. package/src/ibl/skylight-bind-group.ts +4 -4
  413. package/src/index.ts +58 -217
  414. package/src/inspection-types.ts +76 -0
  415. package/src/instance-buffer-cache.ts +1 -29
  416. package/src/internal.ts +6 -85
  417. package/src/lifecycle.ts +64 -19
  418. package/src/materials.ts +7 -29
  419. package/src/mesh-material-bindings.ts +0 -1
  420. package/src/pbr-pipeline.ts +434 -53
  421. package/src/{urp-pipeline.ts → pipeline/standard-forward-lane.ts} +38 -149
  422. package/src/{hdrp-pipeline.ts → pipeline/standard-pipeline.ts} +221 -191
  423. package/src/pipeline/standard-profile.ts +65 -0
  424. package/src/pipeline-builder.ts +60 -64
  425. package/src/pipeline-spec-types.ts +28 -0
  426. package/src/pipeline-spec.ts +72 -609
  427. package/src/plugin.ts +3 -75
  428. package/src/post-process-errors.ts +31 -33
  429. package/src/prepare/prepared-graphics-resolver.ts +5 -4
  430. package/src/record/__tests__/material-slot-plan.unit.test.ts +1 -33
  431. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +41 -0
  432. package/src/record/__tests__/video-texture-view.unit.test.ts +1 -1
  433. package/src/record/frame-lighting.ts +74 -195
  434. package/src/record/frame-snapshot.ts +45 -60
  435. package/src/record/frame-targets.ts +8 -243
  436. package/src/record/frame.ts +509 -796
  437. package/src/record/helpers.ts +6 -11
  438. package/src/record/main-pass-geometry.ts +106 -147
  439. package/src/record/main-pass-material.ts +517 -190
  440. package/src/record/main-pass-sprite-draws.ts +198 -117
  441. package/src/record/main-pass.ts +162 -143
  442. package/src/record/mesh-ssbo.ts +517 -38
  443. package/src/record/render-context.ts +364 -0
  444. package/src/record/shadow-pass.ts +138 -1838
  445. package/src/record/skybox-post-pass.ts +12 -14
  446. package/src/record/typed-frame-graph.ts +215 -254
  447. package/src/record/view-ubo.ts +6 -37
  448. package/src/render-contract.ts +571 -0
  449. package/src/render-data.ts +3 -3
  450. package/src/render-graph-primitives.ts +76 -851
  451. package/src/render-pipeline.ts +104 -188
  452. package/src/render-system-extract.ts +1048 -1729
  453. package/src/render-system.ts +330 -1957
  454. package/src/scene/render-scene-types.ts +64 -0
  455. package/src/scene/render-scene.ts +1032 -0
  456. package/src/scene-instances/post-spawn-resolve-joints.ts +4 -7
  457. package/src/ssao-buffers.ts +167 -8
  458. package/src/systems/skin-palette-allocator.ts +21 -64
  459. package/src/systems/skin-palette-types.ts +14 -0
  460. package/src/systems/transparent-sort-config.ts +25 -3
  461. package/src/tilemap-chunk-extract-system.ts +53 -70
  462. package/src/typed-render-graph-primitives.ts +35 -24
  463. package/src/typed-shadow-passes.ts +26 -56
  464. package/dist/__tests__/analytic-sky-contract.test.d.ts +0 -2
  465. package/dist/__tests__/analytic-sky-contract.test.d.ts.map +0 -1
  466. package/dist/__tests__/analytic-sky-falsify.test.d.ts +0 -2
  467. package/dist/__tests__/analytic-sky-falsify.test.d.ts.map +0 -1
  468. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts +0 -2
  469. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts.map +0 -1
  470. package/dist/__tests__/backend-selection.integration.test.d.ts +0 -2
  471. package/dist/__tests__/backend-selection.integration.test.d.ts.map +0 -1
  472. package/dist/__tests__/camera-temporal.test-d.d.ts +0 -2
  473. package/dist/__tests__/camera-temporal.test-d.d.ts.map +0 -1
  474. package/dist/__tests__/camera-temporal.test.d.ts +0 -2
  475. package/dist/__tests__/camera-temporal.test.d.ts.map +0 -1
  476. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts +0 -2
  477. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts.map +0 -1
  478. package/dist/__tests__/environment-inspection.test.d.ts +0 -2
  479. package/dist/__tests__/environment-inspection.test.d.ts.map +0 -1
  480. package/dist/__tests__/fog-ai-user.fixture.d.ts +0 -2
  481. package/dist/__tests__/fog-ai-user.fixture.d.ts.map +0 -1
  482. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts +0 -16
  483. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts.map +0 -1
  484. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts +0 -2
  485. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts.map +0 -1
  486. package/dist/__tests__/fog-inspection.integration.test.d.ts +0 -2
  487. package/dist/__tests__/fog-inspection.integration.test.d.ts.map +0 -1
  488. package/dist/__tests__/fog-owner-state.integration.test.d.ts +0 -2
  489. package/dist/__tests__/fog-owner-state.integration.test.d.ts.map +0 -1
  490. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts +0 -2
  491. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts.map +0 -1
  492. package/dist/__tests__/fog-public-surface.integration.test.d.ts +0 -2
  493. package/dist/__tests__/fog-public-surface.integration.test.d.ts.map +0 -1
  494. package/dist/__tests__/fog-ray-contract.integration.test.d.ts +0 -2
  495. package/dist/__tests__/fog-ray-contract.integration.test.d.ts.map +0 -1
  496. package/dist/__tests__/fog-source-absence.integration.test.d.ts +0 -2
  497. package/dist/__tests__/fog-source-absence.integration.test.d.ts.map +0 -1
  498. package/dist/__tests__/fog-temporal.integration.test.d.ts +0 -2
  499. package/dist/__tests__/fog-temporal.integration.test.d.ts.map +0 -1
  500. package/dist/__tests__/frame-chain.unit.test.d.ts +0 -2
  501. package/dist/__tests__/frame-chain.unit.test.d.ts.map +0 -1
  502. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts +0 -2
  503. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts.map +0 -1
  504. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts +0 -2
  505. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts.map +0 -1
  506. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts +0 -2
  507. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts.map +0 -1
  508. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts +0 -2
  509. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts.map +0 -1
  510. package/dist/__tests__/material-derived-payload.integration.test.d.ts +0 -2
  511. package/dist/__tests__/material-derived-payload.integration.test.d.ts.map +0 -1
  512. package/dist/__tests__/materials.unit.test.d.ts +0 -2
  513. package/dist/__tests__/materials.unit.test.d.ts.map +0 -1
  514. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts +0 -2
  515. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts.map +0 -1
  516. package/dist/__tests__/persistent-render-scene.unit.test.d.ts +0 -2
  517. package/dist/__tests__/persistent-render-scene.unit.test.d.ts.map +0 -1
  518. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts +0 -2
  519. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts.map +0 -1
  520. package/dist/__tests__/pipeline-pass-trace.test.d.ts +0 -2
  521. package/dist/__tests__/pipeline-pass-trace.test.d.ts.map +0 -1
  522. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts +0 -2
  523. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts.map +0 -1
  524. package/dist/__tests__/plugin.test.d.ts +0 -2
  525. package/dist/__tests__/plugin.test.d.ts.map +0 -1
  526. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts +0 -2
  527. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts.map +0 -1
  528. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts +0 -2
  529. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts.map +0 -1
  530. package/dist/__tests__/public-pipeline-id.test-d.d.ts +0 -2
  531. package/dist/__tests__/public-pipeline-id.test-d.d.ts.map +0 -1
  532. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts +0 -2
  533. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts.map +0 -1
  534. package/dist/__tests__/render-feature-construction.unit.test.d.ts +0 -2
  535. package/dist/__tests__/render-feature-construction.unit.test.d.ts.map +0 -1
  536. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts +0 -2
  537. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts.map +0 -1
  538. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts +0 -2
  539. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts.map +0 -1
  540. package/dist/__tests__/render-feature-graph.integration.test.d.ts +0 -2
  541. package/dist/__tests__/render-feature-graph.integration.test.d.ts.map +0 -1
  542. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts +0 -2
  543. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts.map +0 -1
  544. package/dist/__tests__/render-feature-order.unit.test.d.ts +0 -2
  545. package/dist/__tests__/render-feature-order.unit.test.d.ts.map +0 -1
  546. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts +0 -2
  547. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts.map +0 -1
  548. package/dist/__tests__/render-feature-staging.unit.test.d.ts +0 -2
  549. package/dist/__tests__/render-feature-staging.unit.test.d.ts.map +0 -1
  550. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts +0 -2
  551. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts.map +0 -1
  552. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts +0 -2
  553. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts.map +0 -1
  554. package/dist/__tests__/sun-snapshot-consumers.test.d.ts +0 -2
  555. package/dist/__tests__/sun-snapshot-consumers.test.d.ts.map +0 -1
  556. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts +0 -2
  557. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts.map +0 -1
  558. package/dist/__tests__/taa-history-store.unit.test.d.ts +0 -2
  559. package/dist/__tests__/taa-history-store.unit.test.d.ts.map +0 -1
  560. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts +0 -2
  561. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts.map +0 -1
  562. package/dist/__tests__/temporal-inspection.unit.test.d.ts +0 -2
  563. package/dist/__tests__/temporal-inspection.unit.test.d.ts.map +0 -1
  564. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts +0 -2
  565. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts.map +0 -1
  566. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts +0 -2
  567. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts.map +0 -1
  568. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts +0 -2
  569. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts.map +0 -1
  570. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts +0 -2
  571. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts.map +0 -1
  572. package/dist/chunk-DJIMFYX6.mjs +0 -1439
  573. package/dist/chunk-DJIMFYX6.mjs.map +0 -1
  574. package/dist/chunk-F2SIOCRM.mjs +0 -7423
  575. package/dist/chunk-F2SIOCRM.mjs.map +0 -1
  576. package/dist/chunk-JMSB7AR4.mjs +0 -3
  577. package/dist/chunk-JMSB7AR4.mjs.map +0 -1
  578. package/dist/chunk-KHI6K4C6.mjs +0 -659
  579. package/dist/chunk-KHI6K4C6.mjs.map +0 -1
  580. package/dist/chunk-PORZOL2V.mjs +0 -569
  581. package/dist/chunk-PORZOL2V.mjs.map +0 -1
  582. package/dist/chunk-UOJGMDGP.mjs +0 -29913
  583. package/dist/chunk-UOJGMDGP.mjs.map +0 -1
  584. package/dist/components/__tests__/atmosphere-red.test.d.ts +0 -2
  585. package/dist/components/__tests__/atmosphere-red.test.d.ts.map +0 -1
  586. package/dist/components/__tests__/atmosphere.test.d.ts +0 -2
  587. package/dist/components/__tests__/atmosphere.test.d.ts.map +0 -1
  588. package/dist/components/__tests__/fog.test-d.d.ts +0 -2
  589. package/dist/components/__tests__/fog.test-d.d.ts.map +0 -1
  590. package/dist/components/__tests__/fog.test.d.ts +0 -2
  591. package/dist/components/__tests__/fog.test.d.ts.map +0 -1
  592. package/dist/components/atmosphere.d.ts +0 -18
  593. package/dist/components/atmosphere.d.ts.map +0 -1
  594. package/dist/components/environment.d.ts +0 -115
  595. package/dist/components/environment.d.ts.map +0 -1
  596. package/dist/deferred-lighting.d.ts +0 -13
  597. package/dist/deferred-lighting.d.ts.map +0 -1
  598. package/dist/dynamic-texture-store.d.ts +0 -42
  599. package/dist/dynamic-texture-store.d.ts.map +0 -1
  600. package/dist/environment/__tests__/failure-injection.test.d.ts +0 -2
  601. package/dist/environment/__tests__/failure-injection.test.d.ts.map +0 -1
  602. package/dist/environment/__tests__/generation-red.test.d.ts +0 -2
  603. package/dist/environment/__tests__/generation-red.test.d.ts.map +0 -1
  604. package/dist/environment/__tests__/generation.test.d.ts +0 -2
  605. package/dist/environment/__tests__/generation.test.d.ts.map +0 -1
  606. package/dist/environment/__tests__/graph-transaction.test.d.ts +0 -2
  607. package/dist/environment/__tests__/graph-transaction.test.d.ts.map +0 -1
  608. package/dist/environment/__tests__/inspection-red.test.d.ts +0 -2
  609. package/dist/environment/__tests__/inspection-red.test.d.ts.map +0 -1
  610. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts +0 -2
  611. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts.map +0 -1
  612. package/dist/environment/__tests__/pipeline-topology.test.d.ts +0 -2
  613. package/dist/environment/__tests__/pipeline-topology.test.d.ts.map +0 -1
  614. package/dist/environment/__tests__/readiness.test.d.ts +0 -2
  615. package/dist/environment/__tests__/readiness.test.d.ts.map +0 -1
  616. package/dist/environment/__tests__/recovery.test.d.ts +0 -2
  617. package/dist/environment/__tests__/recovery.test.d.ts.map +0 -1
  618. package/dist/environment/__tests__/resize-dispose.test.d.ts +0 -2
  619. package/dist/environment/__tests__/resize-dispose.test.d.ts.map +0 -1
  620. package/dist/environment/__tests__/signature-red.test.d.ts +0 -2
  621. package/dist/environment/__tests__/signature-red.test.d.ts.map +0 -1
  622. package/dist/environment/__tests__/signature.test.d.ts +0 -2
  623. package/dist/environment/__tests__/signature.test.d.ts.map +0 -1
  624. package/dist/environment/descriptors.d.ts +0 -2
  625. package/dist/environment/descriptors.d.ts.map +0 -1
  626. package/dist/environment/extracted-environment.d.ts +0 -53
  627. package/dist/environment/extracted-environment.d.ts.map +0 -1
  628. package/dist/environment/generation.d.ts +0 -62
  629. package/dist/environment/generation.d.ts.map +0 -1
  630. package/dist/environment/gpu-bundle.d.ts +0 -23
  631. package/dist/environment/gpu-bundle.d.ts.map +0 -1
  632. package/dist/environment/graph.d.ts +0 -108
  633. package/dist/environment/graph.d.ts.map +0 -1
  634. package/dist/environment/inspection.d.ts +0 -48
  635. package/dist/environment/inspection.d.ts.map +0 -1
  636. package/dist/environment/lifecycle.d.ts +0 -22
  637. package/dist/environment/lifecycle.d.ts.map +0 -1
  638. package/dist/environment/readiness.d.ts +0 -29
  639. package/dist/environment/readiness.d.ts.map +0 -1
  640. package/dist/environment/signature.d.ts +0 -70
  641. package/dist/environment/signature.d.ts.map +0 -1
  642. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts +0 -2
  643. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts.map +0 -1
  644. package/dist/extract/__tests__/environment-source.test.d.ts +0 -2
  645. package/dist/extract/__tests__/environment-source.test.d.ts.map +0 -1
  646. package/dist/extract/__tests__/schema-readers.unit.test.d.ts +0 -2
  647. package/dist/extract/__tests__/schema-readers.unit.test.d.ts.map +0 -1
  648. package/dist/extract/directional-csm.d.ts +0 -129
  649. package/dist/extract/directional-csm.d.ts.map +0 -1
  650. package/dist/extract/index.d.ts +0 -5
  651. package/dist/extract/index.d.ts.map +0 -1
  652. package/dist/extract/material-interface.d.ts +0 -56
  653. package/dist/extract/material-interface.d.ts.map +0 -1
  654. package/dist/extract/schema-readers.d.ts +0 -20
  655. package/dist/extract/schema-readers.d.ts.map +0 -1
  656. package/dist/features/graph-contribution.d.ts +0 -64
  657. package/dist/features/graph-contribution.d.ts.map +0 -1
  658. package/dist/features/index.d.ts +0 -21
  659. package/dist/features/index.d.ts.map +0 -1
  660. package/dist/features/morph/index.d.ts +0 -3
  661. package/dist/features/morph/index.d.ts.map +0 -1
  662. package/dist/features/morph/morph-bounds.d.ts +0 -42
  663. package/dist/features/morph/morph-bounds.d.ts.map +0 -1
  664. package/dist/features/scene-temporal.d.ts +0 -45
  665. package/dist/features/scene-temporal.d.ts.map +0 -1
  666. package/dist/features/taa-resolve.d.ts +0 -21
  667. package/dist/features/taa-resolve.d.ts.map +0 -1
  668. package/dist/frame-chain.d.ts +0 -14
  669. package/dist/frame-chain.d.ts.map +0 -1
  670. package/dist/gpu-driven/view-reference.d.ts.map +0 -1
  671. package/dist/gpu-resource-store.d.ts.map +0 -1
  672. package/dist/hdrp-cluster-membership.d.ts +0 -2
  673. package/dist/hdrp-cluster-membership.d.ts.map +0 -1
  674. package/dist/hdrp-pipeline.d.ts +0 -36
  675. package/dist/hdrp-pipeline.d.ts.map +0 -1
  676. package/dist/ibl/cubemap-projection.d.ts +0 -23
  677. package/dist/ibl/cubemap-projection.d.ts.map +0 -1
  678. package/dist/ibl/face-uniforms.d.ts +0 -65
  679. package/dist/ibl/face-uniforms.d.ts.map +0 -1
  680. package/dist/mesh-update-errors.d.ts +0 -71
  681. package/dist/mesh-update-errors.d.ts.map +0 -1
  682. package/dist/mipmap-generator.d.ts +0 -39
  683. package/dist/mipmap-generator.d.ts.map +0 -1
  684. package/dist/param-schema-projection-census.d.ts +0 -18
  685. package/dist/param-schema-projection-census.d.ts.map +0 -1
  686. package/dist/persistent-render-scene.d.ts +0 -158
  687. package/dist/persistent-render-scene.d.ts.map +0 -1
  688. package/dist/pipeline/index.d.ts +0 -11
  689. package/dist/pipeline/index.d.ts.map +0 -1
  690. package/dist/pipeline-errors.d.ts +0 -110
  691. package/dist/pipeline-errors.d.ts.map +0 -1
  692. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts +0 -2
  693. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts.map +0 -1
  694. package/dist/prepare/index.d.ts +0 -4
  695. package/dist/prepare/index.d.ts.map +0 -1
  696. package/dist/prepare/schema-readers.d.ts +0 -11
  697. package/dist/prepare/schema-readers.d.ts.map +0 -1
  698. package/dist/record/__tests__/environment-record.test.d.ts +0 -2
  699. package/dist/record/__tests__/environment-record.test.d.ts.map +0 -1
  700. package/dist/record/__tests__/frame-targets.unit.test.d.ts +0 -2
  701. package/dist/record/__tests__/frame-targets.unit.test.d.ts.map +0 -1
  702. package/dist/record/__tests__/membership-timing.unit.test.d.ts +0 -2
  703. package/dist/record/__tests__/membership-timing.unit.test.d.ts.map +0 -1
  704. package/dist/record/__tests__/render-submission.integration.test.d.ts +0 -2
  705. package/dist/record/__tests__/render-submission.integration.test.d.ts.map +0 -1
  706. package/dist/record/__tests__/render-submission.perf.test.d.ts +0 -2
  707. package/dist/record/__tests__/render-submission.perf.test.d.ts.map +0 -1
  708. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts +0 -2
  709. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts.map +0 -1
  710. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts +0 -2
  711. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts.map +0 -1
  712. package/dist/record/frame-observation.d.ts +0 -38
  713. package/dist/record/frame-observation.d.ts.map +0 -1
  714. package/dist/record/index.d.ts +0 -15
  715. package/dist/record/index.d.ts.map +0 -1
  716. package/dist/record/main-pass-skin.d.ts +0 -46
  717. package/dist/record/main-pass-skin.d.ts.map +0 -1
  718. package/dist/record/main-pass-sprite.d.ts +0 -69
  719. package/dist/record/main-pass-sprite.d.ts.map +0 -1
  720. package/dist/record/material-payload.d.ts +0 -43
  721. package/dist/record/material-payload.d.ts.map +0 -1
  722. package/dist/record/material-slot-plan.d.ts +0 -26
  723. package/dist/record/material-slot-plan.d.ts.map +0 -1
  724. package/dist/record/membership-timing.d.ts +0 -232
  725. package/dist/record/membership-timing.d.ts.map +0 -1
  726. package/dist/record/shadow-caster-uniform.d.ts +0 -8
  727. package/dist/record/shadow-caster-uniform.d.ts.map +0 -1
  728. package/dist/record/shadow-submit-mode.d.ts +0 -66
  729. package/dist/record/shadow-submit-mode.d.ts.map +0 -1
  730. package/dist/render-dispatch-membership.d.ts +0 -47
  731. package/dist/render-dispatch-membership.d.ts.map +0 -1
  732. package/dist/render-pipeline-context.d.ts +0 -289
  733. package/dist/render-pipeline-context.d.ts.map +0 -1
  734. package/dist/render-pipeline-target.d.ts +0 -16
  735. package/dist/render-pipeline-target.d.ts.map +0 -1
  736. package/dist/render-scene-projection.d.ts +0 -174
  737. package/dist/render-scene-projection.d.ts.map +0 -1
  738. package/dist/render-system-fold.d.ts +0 -266
  739. package/dist/render-system-fold.d.ts.map +0 -1
  740. package/dist/renderer/asset-service.d.ts +0 -10
  741. package/dist/renderer/asset-service.d.ts.map +0 -1
  742. package/dist/renderer/backend-selection.d.ts.map +0 -1
  743. package/dist/renderer/environment-classify.d.ts +0 -6
  744. package/dist/renderer/environment-classify.d.ts.map +0 -1
  745. package/dist/renderer/environment-error.d.ts +0 -13
  746. package/dist/renderer/environment-error.d.ts.map +0 -1
  747. package/dist/renderer/material/pipeline-projection.d.ts +0 -91
  748. package/dist/renderer/material/pipeline-projection.d.ts.map +0 -1
  749. package/dist/renderer/renderer-factory.d.ts +0 -289
  750. package/dist/renderer/renderer-factory.d.ts.map +0 -1
  751. package/dist/renderer.d.ts +0 -771
  752. package/dist/renderer.d.ts.map +0 -1
  753. package/dist/scene-utils/collect-subtree.d.ts +0 -11
  754. package/dist/scene-utils/collect-subtree.d.ts.map +0 -1
  755. package/dist/ssao-data.d.ts +0 -34
  756. package/dist/ssao-data.d.ts.map +0 -1
  757. package/dist/surface-format.d.ts +0 -10
  758. package/dist/surface-format.d.ts.map +0 -1
  759. package/dist/taa-history-store.d.ts +0 -88
  760. package/dist/taa-history-store.d.ts.map +0 -1
  761. package/dist/temporal-coverage.d.ts +0 -35
  762. package/dist/temporal-coverage.d.ts.map +0 -1
  763. package/dist/temporal-frame-transaction.d.ts +0 -92
  764. package/dist/temporal-frame-transaction.d.ts.map +0 -1
  765. package/dist/temporal-inspection.d.ts +0 -57
  766. package/dist/temporal-inspection.d.ts.map +0 -1
  767. package/dist/temporal-view.d.ts +0 -43
  768. package/dist/temporal-view.d.ts.map +0 -1
  769. package/dist/tilemap/resolve-tileset-runtime.d.ts +0 -23
  770. package/dist/tilemap/resolve-tileset-runtime.d.ts.map +0 -1
  771. package/dist/urp-pipeline.d.ts +0 -4
  772. package/dist/urp-pipeline.d.ts.map +0 -1
  773. package/src/__tests__/analytic-sky-contract.test.ts +0 -27
  774. package/src/__tests__/analytic-sky-falsify-carriers.mjs +0 -43
  775. package/src/__tests__/analytic-sky-falsify.test.ts +0 -94
  776. package/src/__tests__/assets-runtime-handoff.integration.test.ts +0 -36
  777. package/src/__tests__/backend-selection.integration.test.ts +0 -11
  778. package/src/__tests__/camera-temporal.test-d.ts +0 -8
  779. package/src/__tests__/camera-temporal.test.ts +0 -188
  780. package/src/__tests__/directional-shadow-probe-atlas-layout.unit.test.ts +0 -18
  781. package/src/__tests__/environment-inspection.test.ts +0 -45
  782. package/src/__tests__/fog-ai-user.fixture.ts +0 -350
  783. package/src/__tests__/fog-custom-render-feature.fixture.ts +0 -33
  784. package/src/__tests__/fog-custom-render-feature.integration.test.ts +0 -76
  785. package/src/__tests__/fog-inspection.integration.test.ts +0 -127
  786. package/src/__tests__/fog-owner-state.integration.test.ts +0 -112
  787. package/src/__tests__/fog-pipeline-topology.integration.test.ts +0 -93
  788. package/src/__tests__/fog-public-surface.integration.test.ts +0 -60
  789. package/src/__tests__/fog-ray-contract.integration.test.ts +0 -73
  790. package/src/__tests__/fog-source-absence.integration.test.ts +0 -51
  791. package/src/__tests__/fog-temporal.integration.test.ts +0 -115
  792. package/src/__tests__/frame-chain.unit.test.ts +0 -26
  793. package/src/__tests__/gpu-scene-field-type-owner.test-d.ts +0 -27
  794. package/src/__tests__/hdrp-pipeline.unit.test.ts +0 -100
  795. package/src/__tests__/ibl/ibl-fallback.unit.test.ts +0 -23
  796. package/src/__tests__/material-derived-error-stop-draw.integration.test.ts +0 -69
  797. package/src/__tests__/material-derived-payload.integration.test.ts +0 -164
  798. package/src/__tests__/materials.unit.test.ts +0 -25
  799. package/src/__tests__/param-schema-projection-census.unit.test.ts +0 -40
  800. package/src/__tests__/persistent-render-scene.unit.test.ts +0 -1311
  801. package/src/__tests__/pipeline-error-policy-owner.unit.test.ts +0 -167
  802. package/src/__tests__/pipeline-pass-trace.test.ts +0 -92
  803. package/src/__tests__/pipeline-stage-owner.test-d.ts +0 -13
  804. package/src/__tests__/plugin.test.ts +0 -25
  805. package/src/__tests__/prepared-graphics-backend-matrix.unit.test.ts +0 -129
  806. package/src/__tests__/prepared-graphics-resolver-recording.unit.test.ts +0 -180
  807. package/src/__tests__/public-pipeline-id.test-d.ts +0 -6
  808. package/src/__tests__/render-dispatch-membership.unit.test.ts +0 -117
  809. package/src/__tests__/render-feature-construction.unit.test.ts +0 -124
  810. package/src/__tests__/render-feature-error-code-owner.test-d.ts +0 -27
  811. package/src/__tests__/render-feature-gpu-buffer-usage-owner.test-d.ts +0 -46
  812. package/src/__tests__/render-feature-graph.integration.test.ts +0 -205
  813. package/src/__tests__/render-feature-graphics-staging.unit.test.ts +0 -200
  814. package/src/__tests__/render-feature-order.unit.test.ts +0 -66
  815. package/src/__tests__/render-feature-prepared-graphics-recording.unit.test.ts +0 -107
  816. package/src/__tests__/render-feature-staging.unit.test.ts +0 -94
  817. package/src/__tests__/renderer-render-scene-public.test-d.ts +0 -27
  818. package/src/__tests__/scene-temporal-coverage.unit.test.ts +0 -259
  819. package/src/__tests__/sun-snapshot-consumers.test.ts +0 -35
  820. package/src/__tests__/surface-backend-kind-owner.test-d.ts +0 -42
  821. package/src/__tests__/taa-history-store.unit.test.ts +0 -196
  822. package/src/__tests__/temporal-frame-transaction.integration.test.ts +0 -537
  823. package/src/__tests__/temporal-inspection.unit.test.ts +0 -138
  824. package/src/assets/__tests__/asset-decoders.unit.test.ts +0 -92
  825. package/src/assets/__tests__/mipmap-generator.unit.test.ts +0 -52
  826. package/src/assets/__tests__/render-asset-port.unit.test.ts +0 -54
  827. package/src/assets/__tests__/resolve-render-asset.unit.test.ts +0 -47
  828. package/src/components/__tests__/atmosphere-red.test.ts +0 -51
  829. package/src/components/__tests__/atmosphere.test.ts +0 -79
  830. package/src/components/__tests__/fog.test-d.ts +0 -49
  831. package/src/components/__tests__/fog.test.ts +0 -60
  832. package/src/components/atmosphere.ts +0 -64
  833. package/src/deferred-lighting.ts +0 -92
  834. package/src/dynamic-texture-store.ts +0 -111
  835. package/src/environment/README.md +0 -76
  836. package/src/environment/__tests__/failure-injection.test.ts +0 -50
  837. package/src/environment/__tests__/generation-red.test.ts +0 -64
  838. package/src/environment/__tests__/generation.test.ts +0 -37
  839. package/src/environment/__tests__/graph-transaction.test.ts +0 -85
  840. package/src/environment/__tests__/inspection-red.test.ts +0 -53
  841. package/src/environment/__tests__/lifecycle-evidence.test.ts +0 -40
  842. package/src/environment/__tests__/pipeline-topology.test.ts +0 -33
  843. package/src/environment/__tests__/readiness.test.ts +0 -42
  844. package/src/environment/__tests__/recovery.test.ts +0 -62
  845. package/src/environment/__tests__/resize-dispose.test.ts +0 -30
  846. package/src/environment/__tests__/signature-red.test.ts +0 -45
  847. package/src/environment/__tests__/signature.test.ts +0 -60
  848. package/src/environment/descriptors.ts +0 -7
  849. package/src/environment/extracted-environment.ts +0 -239
  850. package/src/environment/generation.ts +0 -158
  851. package/src/environment/gpu-bundle.ts +0 -144
  852. package/src/environment/graph.ts +0 -588
  853. package/src/environment/inspection.ts +0 -107
  854. package/src/environment/lifecycle.ts +0 -124
  855. package/src/environment/readiness.ts +0 -76
  856. package/src/environment/signature.ts +0 -185
  857. package/src/extract/__tests__/directional-csm-domain.unit.test.ts +0 -391
  858. package/src/extract/__tests__/environment-source.test.ts +0 -105
  859. package/src/extract/__tests__/schema-readers.unit.test.ts +0 -16
  860. package/src/extract/directional-csm.ts +0 -959
  861. package/src/extract/index.ts +0 -10
  862. package/src/extract/material-interface.ts +0 -604
  863. package/src/extract/schema-readers.ts +0 -27
  864. package/src/features/graph-contribution.ts +0 -577
  865. package/src/features/index.ts +0 -100
  866. package/src/features/morph/index.ts +0 -24
  867. package/src/features/morph/morph-bounds.ts +0 -123
  868. package/src/features/scene-temporal.ts +0 -274
  869. package/src/features/taa-resolve.ts +0 -244
  870. package/src/frame-chain.ts +0 -21
  871. package/src/hdrp-cluster-membership.ts +0 -70
  872. package/src/ibl/cubemap-projection.ts +0 -60
  873. package/src/ibl/face-uniforms.ts +0 -150
  874. package/src/mesh-update-errors.ts +0 -113
  875. package/src/mipmap-generator.ts +0 -244
  876. package/src/param-schema-projection-census.ts +0 -73
  877. package/src/persistent-render-scene.ts +0 -1752
  878. package/src/pipeline/index.ts +0 -40
  879. package/src/pipeline-errors.ts +0 -172
  880. package/src/prepare/__tests__/schema-readers.unit.test.ts +0 -16
  881. package/src/prepare/index.ts +0 -8
  882. package/src/prepare/schema-readers.ts +0 -20
  883. package/src/record/__tests__/environment-record.test.ts +0 -35
  884. package/src/record/__tests__/frame-targets.unit.test.ts +0 -54
  885. package/src/record/__tests__/membership-timing.unit.test.ts +0 -524
  886. package/src/record/__tests__/render-submission.integration.test.ts +0 -76
  887. package/src/record/__tests__/render-submission.perf.test.ts +0 -141
  888. package/src/record/__tests__/shadow-submit-mode.unit.test.ts +0 -88
  889. package/src/record/__tests__/view-ubo-layout.unit.test.ts +0 -101
  890. package/src/record/frame-observation.ts +0 -122
  891. package/src/record/index.ts +0 -15
  892. package/src/record/main-pass-skin.ts +0 -51
  893. package/src/record/main-pass-sprite.ts +0 -166
  894. package/src/record/material-payload.ts +0 -292
  895. package/src/record/material-slot-plan.ts +0 -68
  896. package/src/record/membership-timing.ts +0 -1012
  897. package/src/record/shadow-caster-uniform.ts +0 -37
  898. package/src/record/shadow-submit-mode.ts +0 -277
  899. package/src/render-dispatch-membership.ts +0 -155
  900. package/src/render-pipeline-context.ts +0 -332
  901. package/src/render-pipeline-target.ts +0 -96
  902. package/src/render-scene-projection.ts +0 -1738
  903. package/src/render-system-fold.ts +0 -531
  904. package/src/renderer/asset-service.ts +0 -32
  905. package/src/renderer/backend-selection.ts +0 -121
  906. package/src/renderer/environment-classify.ts +0 -30
  907. package/src/renderer/environment-error.ts +0 -19
  908. package/src/renderer/material/pipeline-projection.ts +0 -140
  909. package/src/renderer.ts +0 -940
  910. package/src/scene-utils/collect-subtree.ts +0 -40
  911. package/src/ssao-data.ts +0 -106
  912. package/src/surface-format.ts +0 -37
  913. package/src/taa-history-store.ts +0 -429
  914. package/src/temporal-coverage.ts +0 -106
  915. package/src/temporal-frame-transaction.ts +0 -301
  916. package/src/temporal-inspection.ts +0 -194
  917. package/src/temporal-view.ts +0 -174
  918. package/src/tilemap/resolve-tileset-runtime.ts +0 -72
@@ -1,1738 +0,0 @@
1
- import type {
2
- RenderSceneFact,
3
- RenderSceneFactInput,
4
- SceneCasterEligibility,
5
- SceneFactDiagnostic,
6
- SceneFactRevisionDomain,
7
- SceneFactRevisions,
8
- SceneMobility,
9
- } from './gpu-scene-schema';
10
- import type {
11
- RenderableReactiveReason,
12
- RenderableSnapshot,
13
- RenderableTemporalSnapshot,
14
- } from './render-system-extract';
15
-
16
- interface RenderSceneIdentity {
17
- readonly worldId: number;
18
- readonly entityKey: number;
19
- /** Generation observed by the producer when the operation was authored. */
20
- readonly expectedGeneration?: number;
21
- }
22
-
23
- export type RenderSceneOperation =
24
- | {
25
- readonly kind: 'create';
26
- readonly snapshot: RenderableSnapshot;
27
- readonly expectedGeneration?: number;
28
- }
29
- | (RenderSceneIdentity & {
30
- readonly kind: 'update-transform';
31
- readonly world: Float32Array;
32
- })
33
- | (RenderSceneIdentity & { readonly kind: 'remove' });
34
-
35
- export interface RenderSceneFactDelta {
36
- readonly slot: number;
37
- readonly generation: number;
38
- readonly changedDomains: readonly SceneFactRevisionDomain[];
39
- readonly previous: RenderSceneFact | undefined;
40
- readonly current: RenderSceneFact;
41
- }
42
-
43
- export interface RenderSceneApplyResult {
44
- readonly created: number;
45
- readonly updated: number;
46
- readonly removed: number;
47
- readonly recreated: number;
48
- readonly ignoredLateUpdates: number;
49
- readonly createdSlots: readonly RenderSceneProjectionSlot[];
50
- readonly updatedSlots: readonly RenderSceneProjectionSlot[];
51
- readonly removedSlots: readonly RenderSceneProjectionRecord[];
52
- readonly recreatedSlots: readonly RenderSceneProjectionSlot[];
53
- /** Fine-grained Scene Fact updates consumed by GPU tables and later views. */
54
- readonly factDeltas: readonly RenderSceneFactDelta[];
55
- /** Non-fatal diagnostics; malformed facts never become implicit casters. */
56
- readonly diagnostics: readonly SceneFactDiagnostic[];
57
- /** Spatial owner revisions produced by this projection update. */
58
- readonly spatialIndex?: SpatialIndexUpdate;
59
- }
60
-
61
- export interface RenderSceneProjectionRecord
62
- extends Omit<RenderSceneIdentity, 'expectedGeneration'> {
63
- readonly slot: number;
64
- readonly generation: number;
65
- }
66
-
67
- export interface RenderSceneProjectionInspection {
68
- readonly current: readonly RenderSceneProjectionRecord[];
69
- readonly lastSubmitted: {
70
- readonly epoch: number;
71
- readonly records: readonly RenderSceneProjectionRecord[];
72
- };
73
- readonly slotCapacity: number;
74
- readonly freeSlots: number;
75
- readonly factDiagnostics: readonly SceneFactDiagnostic[];
76
- readonly spatialIndex: SpatialIndexInspection;
77
- }
78
-
79
- export interface RenderSceneProjectionSlot extends RenderSceneProjectionRecord {
80
- readonly snapshot: RenderableSnapshot;
81
- readonly fact: RenderSceneFact;
82
- }
83
-
84
- type ProjectionSlot = RenderSceneProjectionSlot;
85
-
86
- function submittedIdentity(slot: number, generation: number): string {
87
- return `${slot}:${generation}`;
88
- }
89
-
90
- export interface RenderSceneSubmissionCapture {
91
- readonly revision: number;
92
- readonly slots: readonly {
93
- readonly slot: number;
94
- readonly current: RenderSceneProjectionSlot | undefined;
95
- }[];
96
- readonly visible: ReadonlySet<string>;
97
- }
98
-
99
- export interface RenderSceneSubmissionDelta {
100
- readonly epoch: number;
101
- readonly slots: readonly number[];
102
- }
103
-
104
- export type SpatialIndexOwnerKind = 'static-bvh' | 'dynamic-loose-tree';
105
-
106
- export interface SpatialQueryHit extends RenderSceneProjectionRecord {
107
- readonly owner: SpatialIndexOwnerKind;
108
- readonly mobility: SceneMobility;
109
- readonly worldAabb: Float32Array | undefined;
110
- }
111
-
112
- export interface SpatialQueryResult {
113
- readonly hits: readonly SpatialQueryHit[];
114
- readonly staticRevision: number;
115
- readonly dynamicRevision: number;
116
- readonly visitedNodes: number;
117
- readonly testedEntries: number;
118
- readonly falseNegativeSlots: readonly number[];
119
- }
120
-
121
- export interface SpatialIndexOwnerInspection {
122
- readonly revision: number;
123
- readonly entries: number;
124
- readonly boundedEntries: number;
125
- readonly unboundedEntries: number;
126
- readonly nodes: number;
127
- readonly rebuilds: number;
128
- readonly patches: number;
129
- readonly queries: number;
130
- readonly visitedNodes: number;
131
- readonly testedEntries: number;
132
- readonly returnedEntries: number;
133
- }
134
-
135
- export interface SpatialIndexInspection {
136
- readonly revision: number;
137
- readonly static: SpatialIndexOwnerInspection;
138
- readonly dynamic: SpatialIndexOwnerInspection & {
139
- readonly dynamicEntries: number;
140
- readonly unknownEntries: number;
141
- readonly reinserts: number;
142
- };
143
- readonly broadphaseQueries: number;
144
- readonly bruteForceComparisons: number;
145
- readonly falseNegatives: number;
146
- }
147
-
148
- export interface SpatialIndexUpdate {
149
- readonly revision: number;
150
- readonly staticRevision: number;
151
- readonly dynamicRevision: number;
152
- readonly staticChanged: boolean;
153
- readonly dynamicChanged: boolean;
154
- readonly inspection: SpatialIndexInspection;
155
- }
156
-
157
- interface SpatialRecord {
158
- readonly slot: number;
159
- readonly generation: number;
160
- readonly worldId: number;
161
- readonly entityKey: number;
162
- readonly mobility: SceneMobility;
163
- readonly worldAabb: Float32Array | undefined;
164
- }
165
-
166
- interface SpatialQueryOwnerResult {
167
- readonly records: readonly SpatialRecord[];
168
- readonly visitedNodes: number;
169
- readonly testedEntries: number;
170
- }
171
-
172
- interface ConservativeSpatialIndexOwner {
173
- query(bounds: Float32Array): SpatialQueryOwnerResult;
174
- }
175
-
176
- interface StaticBvhNode {
177
- readonly bounds: Float32Array;
178
- readonly left: StaticBvhNode | undefined;
179
- readonly right: StaticBvhNode | undefined;
180
- readonly record: SpatialRecord | undefined;
181
- }
182
-
183
- interface DynamicLooseNode {
184
- parent: DynamicLooseNode | undefined;
185
- left: DynamicLooseNode | undefined;
186
- right: DynamicLooseNode | undefined;
187
- bounds: Float32Array;
188
- record: SpatialRecord | undefined;
189
- }
190
-
191
- function spatialRecord(slot: RenderSceneProjectionSlot): SpatialRecord {
192
- return {
193
- slot: slot.slot,
194
- generation: slot.generation,
195
- worldId: slot.worldId,
196
- entityKey: slot.entityKey,
197
- mobility: slot.fact.mobility,
198
- worldAabb:
199
- slot.fact.bounds.status === 'present'
200
- ? new Float32Array(slot.fact.bounds.worldAabb)
201
- : undefined,
202
- };
203
- }
204
-
205
- function sameSpatialRecord(left: SpatialRecord | undefined, right: SpatialRecord): boolean {
206
- return (
207
- left !== undefined &&
208
- left.generation === right.generation &&
209
- left.worldId === right.worldId &&
210
- left.entityKey === right.entityKey &&
211
- left.mobility === right.mobility &&
212
- sameFloatArray(left.worldAabb, right.worldAabb)
213
- );
214
- }
215
-
216
- function mergeAabbInto(target: Float32Array, left: Float32Array, right: Float32Array): void {
217
- target[0] = Math.min(left[0] ?? 0, right[0] ?? 0);
218
- target[1] = Math.min(left[1] ?? 0, right[1] ?? 0);
219
- target[2] = Math.min(left[2] ?? 0, right[2] ?? 0);
220
- target[3] = Math.max(left[3] ?? 0, right[3] ?? 0);
221
- target[4] = Math.max(left[4] ?? 0, right[4] ?? 0);
222
- target[5] = Math.max(left[5] ?? 0, right[5] ?? 0);
223
- }
224
-
225
- function mergeAabb(left: Float32Array, right: Float32Array): Float32Array {
226
- const merged = new Float32Array(6);
227
- mergeAabbInto(merged, left, right);
228
- return merged;
229
- }
230
-
231
- function overlapsAabb(left: Float32Array, right: Float32Array): boolean {
232
- return (
233
- (left[3] ?? -Infinity) >= (right[0] ?? Infinity) &&
234
- (left[0] ?? Infinity) <= (right[3] ?? -Infinity) &&
235
- (left[4] ?? -Infinity) >= (right[1] ?? Infinity) &&
236
- (left[1] ?? Infinity) <= (right[4] ?? -Infinity) &&
237
- (left[5] ?? -Infinity) >= (right[2] ?? Infinity) &&
238
- (left[2] ?? Infinity) <= (right[5] ?? -Infinity)
239
- );
240
- }
241
-
242
- function containsAabb(outer: Float32Array, inner: Float32Array): boolean {
243
- return (
244
- (outer[0] ?? Infinity) <= (inner[0] ?? -Infinity) &&
245
- (outer[1] ?? Infinity) <= (inner[1] ?? -Infinity) &&
246
- (outer[2] ?? Infinity) <= (inner[2] ?? -Infinity) &&
247
- (outer[3] ?? -Infinity) >= (inner[3] ?? Infinity) &&
248
- (outer[4] ?? -Infinity) >= (inner[4] ?? Infinity) &&
249
- (outer[5] ?? -Infinity) >= (inner[5] ?? Infinity)
250
- );
251
- }
252
-
253
- function aabbCost(bounds: Float32Array): number {
254
- const x = Math.max(0, (bounds[3] ?? 0) - (bounds[0] ?? 0));
255
- const y = Math.max(0, (bounds[4] ?? 0) - (bounds[1] ?? 0));
256
- const z = Math.max(0, (bounds[5] ?? 0) - (bounds[2] ?? 0));
257
- return 2 * (x * y + x * z + y * z);
258
- }
259
-
260
- /** Compute the union surface area without allocating a temporary AABB. */
261
- function mergedAabbCost(left: Float32Array, right: Float32Array): number {
262
- const x = Math.max(
263
- 0,
264
- Math.max(left[3] ?? 0, right[3] ?? 0) - Math.min(left[0] ?? 0, right[0] ?? 0),
265
- );
266
- const y = Math.max(
267
- 0,
268
- Math.max(left[4] ?? 0, right[4] ?? 0) - Math.min(left[1] ?? 0, right[1] ?? 0),
269
- );
270
- const z = Math.max(
271
- 0,
272
- Math.max(left[5] ?? 0, right[5] ?? 0) - Math.min(left[2] ?? 0, right[2] ?? 0),
273
- );
274
- return 2 * (x * y + x * z + y * z);
275
- }
276
-
277
- function looseBounds(bounds: Float32Array): Float32Array {
278
- const extent = Math.max(
279
- (bounds[3] ?? 0) - (bounds[0] ?? 0),
280
- (bounds[4] ?? 0) - (bounds[1] ?? 0),
281
- (bounds[5] ?? 0) - (bounds[2] ?? 0),
282
- );
283
- const margin = Math.max(0.01, extent * 0.125);
284
- return new Float32Array([
285
- (bounds[0] ?? 0) - margin,
286
- (bounds[1] ?? 0) - margin,
287
- (bounds[2] ?? 0) - margin,
288
- (bounds[3] ?? 0) + margin,
289
- (bounds[4] ?? 0) + margin,
290
- (bounds[5] ?? 0) + margin,
291
- ]);
292
- }
293
-
294
- function buildStaticBvh(records: readonly SpatialRecord[]): StaticBvhNode | undefined {
295
- if (records.length === 0) return undefined;
296
- if (records.length === 1) {
297
- const record = records[0];
298
- if (record?.worldAabb === undefined) return undefined;
299
- return { bounds: record.worldAabb, left: undefined, right: undefined, record };
300
- }
301
- let bounds = records[0]?.worldAabb;
302
- if (bounds === undefined) return undefined;
303
- bounds = new Float32Array(bounds);
304
- for (let index = 1; index < records.length; index += 1) {
305
- const next = records[index]?.worldAabb;
306
- if (next !== undefined) bounds = mergeAabb(bounds, next);
307
- }
308
- const extents = [
309
- (bounds[3] ?? 0) - (bounds[0] ?? 0),
310
- (bounds[4] ?? 0) - (bounds[1] ?? 0),
311
- (bounds[5] ?? 0) - (bounds[2] ?? 0),
312
- ];
313
- let axis = 0;
314
- if ((extents[1] ?? 0) > (extents[axis] ?? 0)) axis = 1;
315
- if ((extents[2] ?? 0) > (extents[axis] ?? 0)) axis = 2;
316
- const ordered = [...records].sort((left, right) => {
317
- const leftBounds = left.worldAabb;
318
- const rightBounds = right.worldAabb;
319
- return (
320
- ((leftBounds?.[axis] ?? 0) + (leftBounds?.[axis + 3] ?? 0)) * 0.5 -
321
- ((rightBounds?.[axis] ?? 0) + (rightBounds?.[axis + 3] ?? 0)) * 0.5
322
- );
323
- });
324
- const middle = Math.floor(ordered.length / 2);
325
- const left = buildStaticBvh(ordered.slice(0, middle));
326
- const right = buildStaticBvh(ordered.slice(middle));
327
- if (left === undefined) return right;
328
- if (right === undefined) return left;
329
- return { bounds: mergeAabb(left.bounds, right.bounds), left, right, record: undefined };
330
- }
331
-
332
- function countStaticNodes(node: StaticBvhNode | undefined): number {
333
- return node === undefined ? 0 : 1 + countStaticNodes(node.left) + countStaticNodes(node.right);
334
- }
335
-
336
- class StaticBvhOwner implements ConservativeSpatialIndexOwner {
337
- private readonly records = new Map<number, SpatialRecord>();
338
- private readonly unbounded = new Map<number, SpatialRecord>();
339
- private root: StaticBvhNode | undefined;
340
- private nodeCount = 0;
341
- private revision = 0;
342
- private rebuilds = 0;
343
- private queries = 0;
344
- private visitedNodes = 0;
345
- private testedEntries = 0;
346
- private returnedEntries = 0;
347
-
348
- replace(records: readonly SpatialRecord[]): boolean {
349
- const next = new Map(records.map((record) => [record.slot, record]));
350
- const changed =
351
- next.size !== this.records.size ||
352
- [...next].some(([slot, record]) => !sameSpatialRecord(this.records.get(slot), record));
353
- if (!changed) return false;
354
- this.records.clear();
355
- this.unbounded.clear();
356
- for (const record of records) {
357
- this.records.set(record.slot, record);
358
- if (record.worldAabb === undefined) this.unbounded.set(record.slot, record);
359
- }
360
- this.rebuild();
361
- this.revision += 1;
362
- this.rebuilds += 1;
363
- return true;
364
- }
365
-
366
- patch(records: readonly SpatialRecord[], removedSlots: readonly number[]): boolean {
367
- let changed = false;
368
- for (const slot of removedSlots) {
369
- if (!this.records.delete(slot)) continue;
370
- this.unbounded.delete(slot);
371
- changed = true;
372
- }
373
- for (const record of records) {
374
- if (record.mobility !== 'static') {
375
- if (!this.records.delete(record.slot)) continue;
376
- this.unbounded.delete(record.slot);
377
- changed = true;
378
- continue;
379
- }
380
- if (sameSpatialRecord(this.records.get(record.slot), record)) continue;
381
- this.records.set(record.slot, record);
382
- if (record.worldAabb === undefined) this.unbounded.set(record.slot, record);
383
- else this.unbounded.delete(record.slot);
384
- changed = true;
385
- }
386
- if (!changed) return false;
387
- this.rebuild();
388
- this.revision += 1;
389
- this.rebuilds += 1;
390
- return true;
391
- }
392
-
393
- query(bounds: Float32Array): SpatialQueryOwnerResult {
394
- const records = [...this.unbounded.values()];
395
- let visitedNodes = 0;
396
- let testedEntries = this.unbounded.size;
397
- const stack = this.root === undefined ? [] : [this.root];
398
- while (stack.length > 0) {
399
- const node = stack.pop();
400
- if (node === undefined) continue;
401
- visitedNodes += 1;
402
- if (!overlapsAabb(node.bounds, bounds)) continue;
403
- if (node.record !== undefined) {
404
- testedEntries += 1;
405
- records.push(node.record);
406
- } else {
407
- if (node.left !== undefined) stack.push(node.left);
408
- if (node.right !== undefined) stack.push(node.right);
409
- }
410
- }
411
- this.queries += 1;
412
- this.visitedNodes += visitedNodes;
413
- this.testedEntries += testedEntries;
414
- this.returnedEntries += records.length;
415
- return { records, visitedNodes, testedEntries };
416
- }
417
-
418
- snapshot(): readonly SpatialRecord[] {
419
- return [...this.records.values()];
420
- }
421
-
422
- inspect(): SpatialIndexOwnerInspection {
423
- return {
424
- revision: this.revision,
425
- entries: this.records.size,
426
- boundedEntries: this.records.size - this.unbounded.size,
427
- unboundedEntries: this.unbounded.size,
428
- nodes: this.nodeCount,
429
- rebuilds: this.rebuilds,
430
- patches: 0,
431
- queries: this.queries,
432
- visitedNodes: this.visitedNodes,
433
- testedEntries: this.testedEntries,
434
- returnedEntries: this.returnedEntries,
435
- };
436
- }
437
-
438
- private rebuild(): void {
439
- this.root = buildStaticBvh(
440
- [...this.records.values()].filter((record) => record.worldAabb !== undefined),
441
- );
442
- this.nodeCount = countStaticNodes(this.root);
443
- }
444
- }
445
-
446
- class DynamicLooseTreeOwner implements ConservativeSpatialIndexOwner {
447
- private readonly records = new Map<number, SpatialRecord>();
448
- private readonly leaves = new Map<number, DynamicLooseNode>();
449
- private readonly unbounded = new Map<number, SpatialRecord>();
450
- private root: DynamicLooseNode | undefined;
451
- private nodeCount = 0;
452
- private dynamicEntries = 0;
453
- private unknownEntries = 0;
454
- private revision = 0;
455
- private patches = 0;
456
- private reinserts = 0;
457
- private queries = 0;
458
- private visitedNodes = 0;
459
- private testedEntries = 0;
460
- private returnedEntries = 0;
461
-
462
- replace(records: readonly SpatialRecord[]): boolean {
463
- const next = new Map(records.map((record) => [record.slot, record]));
464
- let changed = false;
465
- for (const slot of this.records.keys()) {
466
- if (!next.has(slot)) {
467
- this.remove(slot);
468
- changed = true;
469
- }
470
- }
471
- if (
472
- !changed &&
473
- [...next].every(([slot, record]) => sameSpatialRecord(this.records.get(slot), record))
474
- ) {
475
- return false;
476
- }
477
- this.records.clear();
478
- this.leaves.clear();
479
- this.unbounded.clear();
480
- this.root = undefined;
481
- this.nodeCount = 0;
482
- this.dynamicEntries = 0;
483
- this.unknownEntries = 0;
484
- for (const record of records) {
485
- this.records.set(record.slot, record);
486
- this.addCategory(record);
487
- if (record.worldAabb === undefined) this.unbounded.set(record.slot, record);
488
- }
489
- this.rebuild(records);
490
- this.patches += records.length;
491
- this.revision += 1;
492
- return true;
493
- }
494
-
495
- patch(records: readonly SpatialRecord[], removedSlots: readonly number[]): boolean {
496
- let changed = false;
497
- for (const slot of removedSlots) {
498
- if (!this.records.has(slot)) continue;
499
- this.remove(slot);
500
- changed = true;
501
- }
502
- for (const record of records) {
503
- if (record.mobility === 'static') {
504
- if (!this.records.has(record.slot)) continue;
505
- this.remove(record.slot);
506
- changed = true;
507
- continue;
508
- }
509
- if (sameSpatialRecord(this.records.get(record.slot), record)) continue;
510
- this.upsert(record);
511
- changed = true;
512
- }
513
- if (changed) this.revision += 1;
514
- return changed;
515
- }
516
-
517
- query(bounds: Float32Array): SpatialQueryOwnerResult {
518
- const records = [...this.unbounded.values()];
519
- let visitedNodes = 0;
520
- let testedEntries = this.unbounded.size;
521
- const stack = this.root === undefined ? [] : [this.root];
522
- while (stack.length > 0) {
523
- const node = stack.pop();
524
- if (node === undefined) continue;
525
- visitedNodes += 1;
526
- if (!overlapsAabb(node.bounds, bounds)) continue;
527
- if (node.record !== undefined) {
528
- testedEntries += 1;
529
- if (node.record.worldAabb === undefined || overlapsAabb(node.record.worldAabb, bounds)) {
530
- records.push(node.record);
531
- }
532
- } else {
533
- if (node.left !== undefined) stack.push(node.left);
534
- if (node.right !== undefined) stack.push(node.right);
535
- }
536
- }
537
- this.queries += 1;
538
- this.visitedNodes += visitedNodes;
539
- this.testedEntries += testedEntries;
540
- this.returnedEntries += records.length;
541
- return { records, visitedNodes, testedEntries };
542
- }
543
-
544
- snapshot(): readonly SpatialRecord[] {
545
- return [...this.records.values()];
546
- }
547
-
548
- inspect(): SpatialIndexInspection['dynamic'] {
549
- return {
550
- revision: this.revision,
551
- entries: this.records.size,
552
- boundedEntries: this.records.size - this.unbounded.size,
553
- unboundedEntries: this.unbounded.size,
554
- nodes: this.nodeCount,
555
- rebuilds: 0,
556
- patches: this.patches,
557
- queries: this.queries,
558
- visitedNodes: this.visitedNodes,
559
- testedEntries: this.testedEntries,
560
- returnedEntries: this.returnedEntries,
561
- dynamicEntries: this.dynamicEntries,
562
- unknownEntries: this.unknownEntries,
563
- reinserts: this.reinserts,
564
- };
565
- }
566
-
567
- private upsert(record: SpatialRecord): void {
568
- const previous = this.records.get(record.slot);
569
- if (previous !== undefined) this.removeCategory(previous);
570
- this.records.set(record.slot, record);
571
- this.addCategory(record);
572
- this.patches += 1;
573
- if (record.worldAabb === undefined) {
574
- this.removeLeaf(record.slot);
575
- this.unbounded.set(record.slot, record);
576
- return;
577
- }
578
- this.unbounded.delete(record.slot);
579
- const leaf = this.leaves.get(record.slot);
580
- if (
581
- leaf !== undefined &&
582
- previous?.generation === record.generation &&
583
- containsAabb(leaf.bounds, record.worldAabb)
584
- ) {
585
- leaf.record = record;
586
- return;
587
- }
588
- this.removeLeaf(record.slot);
589
- this.insertLeaf({
590
- parent: undefined,
591
- left: undefined,
592
- right: undefined,
593
- bounds: looseBounds(record.worldAabb),
594
- record,
595
- });
596
- if (leaf !== undefined) this.reinserts += 1;
597
- }
598
-
599
- private remove(slot: number): void {
600
- const previous = this.records.get(slot);
601
- if (previous === undefined) return;
602
- this.records.delete(slot);
603
- this.removeCategory(previous);
604
- this.unbounded.delete(slot);
605
- this.removeLeaf(slot);
606
- this.patches += 1;
607
- }
608
-
609
- private addCategory(record: SpatialRecord): void {
610
- if (record.mobility === 'dynamic') this.dynamicEntries += 1;
611
- else this.unknownEntries += 1;
612
- }
613
-
614
- private removeCategory(record: SpatialRecord): void {
615
- if (record.mobility === 'dynamic') this.dynamicEntries -= 1;
616
- else this.unknownEntries -= 1;
617
- }
618
-
619
- private rebuild(records: readonly SpatialRecord[]): void {
620
- const ordered = records
621
- .filter((record) => record.worldAabb !== undefined)
622
- .slice()
623
- .sort(
624
- (left, right) =>
625
- ((left.worldAabb?.[0] ?? 0) + (left.worldAabb?.[3] ?? 0)) * 0.5 -
626
- ((right.worldAabb?.[0] ?? 0) + (right.worldAabb?.[3] ?? 0)) * 0.5,
627
- );
628
- const build = (start: number, end: number): DynamicLooseNode | undefined => {
629
- if (start >= end) return undefined;
630
- if (end - start === 1) {
631
- const record = ordered[start];
632
- if (record === undefined || record.worldAabb === undefined) return undefined;
633
- const leaf: DynamicLooseNode = {
634
- parent: undefined,
635
- left: undefined,
636
- right: undefined,
637
- bounds: looseBounds(record.worldAabb),
638
- record,
639
- };
640
- this.leaves.set(record.slot, leaf);
641
- this.nodeCount += 1;
642
- return leaf;
643
- }
644
- const middle = start + Math.floor((end - start) / 2);
645
- const left = build(start, middle);
646
- const right = build(middle, end);
647
- if (left === undefined) return right;
648
- if (right === undefined) return left;
649
- const parent: DynamicLooseNode = {
650
- parent: undefined,
651
- left,
652
- right,
653
- bounds: mergeAabb(left.bounds, right.bounds),
654
- record: undefined,
655
- };
656
- left.parent = parent;
657
- right.parent = parent;
658
- this.nodeCount += 1;
659
- return parent;
660
- };
661
- this.root = build(0, ordered.length);
662
- }
663
-
664
- private insertLeaf(leaf: DynamicLooseNode): void {
665
- const slot = leaf.record?.slot;
666
- if (slot === undefined) return;
667
- this.leaves.set(slot, leaf);
668
- if (this.root === undefined) {
669
- this.root = leaf;
670
- this.nodeCount += 1;
671
- return;
672
- }
673
- let sibling = this.root;
674
- while (sibling.record === undefined) {
675
- const left = sibling.left;
676
- const right = sibling.right;
677
- if (left === undefined || right === undefined) break;
678
- const leftCost = mergedAabbCost(left.bounds, leaf.bounds) - aabbCost(left.bounds);
679
- const rightCost = mergedAabbCost(right.bounds, leaf.bounds) - aabbCost(right.bounds);
680
- sibling = leftCost <= rightCost ? left : right;
681
- }
682
- const previousParent = sibling.parent;
683
- const parent: DynamicLooseNode = {
684
- parent: previousParent,
685
- left: sibling,
686
- right: leaf,
687
- bounds: mergeAabb(sibling.bounds, leaf.bounds),
688
- record: undefined,
689
- };
690
- sibling.parent = parent;
691
- leaf.parent = parent;
692
- if (previousParent === undefined) this.root = parent;
693
- else if (previousParent.left === sibling) previousParent.left = parent;
694
- else previousParent.right = parent;
695
- this.nodeCount += 2;
696
- this.refit(parent);
697
- }
698
-
699
- private removeLeaf(slot: number): void {
700
- const leaf = this.leaves.get(slot);
701
- if (leaf === undefined) return;
702
- this.leaves.delete(slot);
703
- if (leaf === this.root) {
704
- this.root = undefined;
705
- this.nodeCount -= 1;
706
- return;
707
- }
708
- const parent = leaf.parent;
709
- const sibling = parent?.left === leaf ? parent.right : parent?.left;
710
- const grandparent = parent?.parent;
711
- if (sibling === undefined) return;
712
- sibling.parent = grandparent;
713
- if (grandparent === undefined) this.root = sibling;
714
- else if (grandparent.left === parent) grandparent.left = sibling;
715
- else grandparent.right = sibling;
716
- this.nodeCount -= 2;
717
- this.refit(grandparent);
718
- }
719
-
720
- private refit(start: DynamicLooseNode | undefined): void {
721
- let node = start;
722
- while (node !== undefined) {
723
- if (node.left !== undefined && node.right !== undefined) {
724
- // Parent nodes own their bounds, so update in place. Dynamic
725
- // transform/topology patches can refit thousands of ancestors per
726
- // frame; allocating a Float32Array at every ancestor turns an
727
- // O(delta log N) spatial update into a GC-heavy hot path.
728
- mergeAabbInto(node.bounds, node.left.bounds, node.right.bounds);
729
- }
730
- node = node.parent;
731
- }
732
- }
733
- }
734
-
735
- class RenderSceneSpatialIndex {
736
- private readonly staticOwner = new StaticBvhOwner();
737
- private readonly dynamicOwner = new DynamicLooseTreeOwner();
738
- private revision = 0;
739
- private broadphaseQueries = 0;
740
- private bruteForceComparisons = 0;
741
- private falseNegatives = 0;
742
-
743
- replace(slots: readonly RenderSceneProjectionSlot[]): SpatialIndexUpdate {
744
- const records = slots.map(spatialRecord);
745
- const staticChanged = this.staticOwner.replace(
746
- records.filter((record) => record.mobility === 'static'),
747
- );
748
- const dynamicChanged = this.dynamicOwner.replace(
749
- records.filter((record) => record.mobility !== 'static'),
750
- );
751
- if (staticChanged || dynamicChanged) this.revision += 1;
752
- const inspection = this.inspect();
753
- return {
754
- revision: this.revision,
755
- staticRevision: inspection.static.revision,
756
- dynamicRevision: inspection.dynamic.revision,
757
- staticChanged,
758
- dynamicChanged,
759
- inspection,
760
- };
761
- }
762
-
763
- patch(
764
- slots: readonly RenderSceneProjectionSlot[],
765
- removedSlots: readonly RenderSceneProjectionRecord[],
766
- ): SpatialIndexUpdate {
767
- const records = slots.map(spatialRecord);
768
- const removed = removedSlots.map((record) => record.slot);
769
- const staticChanged = this.staticOwner.patch(records, removed);
770
- const dynamicChanged = this.dynamicOwner.patch(records, removed);
771
- if (staticChanged || dynamicChanged) this.revision += 1;
772
- const inspection = this.inspect();
773
- return {
774
- revision: this.revision,
775
- staticRevision: inspection.static.revision,
776
- dynamicRevision: inspection.dynamic.revision,
777
- staticChanged,
778
- dynamicChanged,
779
- inspection,
780
- };
781
- }
782
-
783
- query(bounds: Float32Array, verifyAgainstBruteForce: boolean): SpatialQueryResult {
784
- if (bounds.length < 6 || ![...bounds.slice(0, 6)].every(Number.isFinite)) {
785
- throw new RangeError('spatial query requires a finite world AABB');
786
- }
787
- const fromStatic = this.staticOwner.query(bounds);
788
- const fromDynamic = this.dynamicOwner.query(bounds);
789
- const records = [...fromStatic.records, ...fromDynamic.records].sort(
790
- (left, right) => left.slot - right.slot,
791
- );
792
- const falseNegativeSlots: number[] = [];
793
- if (verifyAgainstBruteForce) {
794
- this.bruteForceComparisons += 1;
795
- const actual = new Set(records.map((record) => record.slot));
796
- for (const reference of this.bruteForce(bounds)) {
797
- if (!actual.has(reference.slot)) falseNegativeSlots.push(reference.slot);
798
- }
799
- this.falseNegatives += falseNegativeSlots.length;
800
- }
801
- this.broadphaseQueries += 1;
802
- const inspection = this.inspect();
803
- return {
804
- hits: records.map((record) => ({
805
- slot: record.slot,
806
- generation: record.generation,
807
- worldId: record.worldId,
808
- entityKey: record.entityKey,
809
- owner: record.mobility === 'static' ? 'static-bvh' : 'dynamic-loose-tree',
810
- mobility: record.mobility,
811
- worldAabb: record.worldAabb === undefined ? undefined : new Float32Array(record.worldAabb),
812
- })),
813
- staticRevision: inspection.static.revision,
814
- dynamicRevision: inspection.dynamic.revision,
815
- visitedNodes: fromStatic.visitedNodes + fromDynamic.visitedNodes,
816
- testedEntries: fromStatic.testedEntries + fromDynamic.testedEntries,
817
- falseNegativeSlots,
818
- };
819
- }
820
-
821
- inspect(): SpatialIndexInspection {
822
- return {
823
- revision: this.revision,
824
- static: this.staticOwner.inspect(),
825
- dynamic: this.dynamicOwner.inspect(),
826
- broadphaseQueries: this.broadphaseQueries,
827
- bruteForceComparisons: this.bruteForceComparisons,
828
- falseNegatives: this.falseNegatives,
829
- };
830
- }
831
-
832
- private bruteForce(bounds: Float32Array): readonly SpatialRecord[] {
833
- return [...this.staticOwner.snapshot(), ...this.dynamicOwner.snapshot()].filter(
834
- (record) => record.worldAabb === undefined || overlapsAabb(record.worldAabb, bounds),
835
- );
836
- }
837
- }
838
-
839
- interface PendingIdentity {
840
- readonly worldId: number;
841
- readonly entityKey: number;
842
- readonly initial: ProjectionSlot | undefined;
843
- current: RenderableSnapshot | undefined;
844
- removed: boolean;
845
- touched: boolean;
846
- }
847
-
848
- const FACT_DOMAINS: readonly SceneFactRevisionDomain[] = [
849
- 'transform',
850
- 'geometry',
851
- 'material',
852
- 'eligibility',
853
- 'space',
854
- 'batch',
855
- 'resource',
856
- ];
857
-
858
- const ZERO_REVISIONS: SceneFactRevisions = Object.freeze({
859
- transform: 0,
860
- geometry: 0,
861
- material: 0,
862
- eligibility: 0,
863
- space: 0,
864
- batch: 0,
865
- resource: 0,
866
- });
867
-
868
- function ownSnapshot(snapshot: RenderableSnapshot): RenderableSnapshot {
869
- const { temporal: _temporal, ...current } = snapshot;
870
- return {
871
- ...current,
872
- transform: { ...snapshot.transform, world: new Float32Array(snapshot.transform.world) },
873
- ...(snapshot.boundsWorld !== undefined && {
874
- boundsWorld: new Float32Array(snapshot.boundsWorld),
875
- }),
876
- ...(snapshot.candidateInstanceTransforms !== undefined && {
877
- candidateInstanceTransforms: new Float32Array(snapshot.candidateInstanceTransforms),
878
- }),
879
- ...(snapshot.localAabb !== undefined && { localAabb: new Float32Array(snapshot.localAabb) }),
880
- ...(snapshot.instances !== undefined && {
881
- instances: {
882
- ...snapshot.instances,
883
- transforms: new Float32Array(snapshot.instances.transforms),
884
- },
885
- }),
886
- ...(snapshot.spriteInstances !== undefined && {
887
- spriteInstances: {
888
- ...snapshot.spriteInstances,
889
- transforms: new Float32Array(snapshot.spriteInstances.transforms),
890
- regions: new Float32Array(snapshot.spriteInstances.regions),
891
- },
892
- }),
893
- ...(snapshot.skin !== undefined && {
894
- skin: {
895
- ...snapshot.skin,
896
- jointMatrices: new Float32Array(snapshot.skin.jointMatrices),
897
- },
898
- }),
899
- ...(snapshot.gpuDrivenDraws !== undefined && {
900
- gpuDrivenDraws: snapshot.gpuDrivenDraws.map((draw) => ({ ...draw })),
901
- }),
902
- ...(snapshot.morphWeights !== undefined && {
903
- morphWeights: new Float32Array(snapshot.morphWeights),
904
- }),
905
- materials: [...snapshot.materials],
906
- materialBindingSources: [...snapshot.materialBindingSources],
907
- };
908
- }
909
-
910
- function withWorld(snapshot: RenderableSnapshot, world: Float32Array): RenderableSnapshot {
911
- return ownSnapshot({
912
- ...snapshot,
913
- transform: { ...snapshot.transform, world: new Float32Array(world) },
914
- });
915
- }
916
-
917
- function sameFloatArray(left: Float32Array | undefined, right: Float32Array | undefined): boolean {
918
- if (left === right) return true;
919
- if (left === undefined || right === undefined || left.length !== right.length) return false;
920
- for (let index = 0; index < left.length; index += 1) {
921
- if (left[index] !== right[index]) return false;
922
- }
923
- return true;
924
- }
925
-
926
- interface ComparedObjectPairs {
927
- readonly leftToRight: Map<object, object>;
928
- readonly rightToLeft: Map<object, object>;
929
- }
930
-
931
- function sameValue(
932
- left: unknown,
933
- right: unknown,
934
- seen: ComparedObjectPairs = { leftToRight: new Map(), rightToLeft: new Map() },
935
- ): boolean {
936
- if (Object.is(left, right)) return true;
937
- if (left === null || right === null || typeof left !== 'object' || typeof right !== 'object') {
938
- return false;
939
- }
940
- const previousRight = seen.leftToRight.get(left);
941
- if (previousRight !== undefined || seen.leftToRight.has(left)) return previousRight === right;
942
- const previousLeft = seen.rightToLeft.get(right);
943
- if (previousLeft !== undefined || seen.rightToLeft.has(right)) return previousLeft === left;
944
- seen.leftToRight.set(left, right);
945
- seen.rightToLeft.set(right, left);
946
- if (ArrayBuffer.isView(left) && ArrayBuffer.isView(right)) {
947
- if (left.byteLength !== right.byteLength) return false;
948
- const leftBytes = new Uint8Array(left.buffer, left.byteOffset, left.byteLength);
949
- const rightBytes = new Uint8Array(right.buffer, right.byteOffset, right.byteLength);
950
- for (let index = 0; index < leftBytes.length; index += 1) {
951
- if (leftBytes[index] !== rightBytes[index]) return false;
952
- }
953
- return true;
954
- }
955
- if (left instanceof Map && right instanceof Map) {
956
- if (left.size !== right.size) return false;
957
- for (const [key, value] of left) {
958
- if (!right.has(key) || !sameValue(value, right.get(key), seen)) return false;
959
- }
960
- return true;
961
- }
962
- if (Array.isArray(left) && Array.isArray(right)) {
963
- if (left.length !== right.length) return false;
964
- return left.every((value, index) => sameValue(value, right[index], seen));
965
- }
966
- const leftKeys = Object.keys(left).sort();
967
- const rightKeys = Object.keys(right).sort();
968
- if (
969
- leftKeys.length !== rightKeys.length ||
970
- leftKeys.some((key, index) => key !== rightKeys[index])
971
- ) {
972
- return false;
973
- }
974
- return leftKeys.every((key) =>
975
- sameValue(
976
- (left as Record<string, unknown>)[key],
977
- (right as Record<string, unknown>)[key],
978
- seen,
979
- ),
980
- );
981
- }
982
-
983
- function validMobility(value: unknown): SceneMobility {
984
- return value === 'static' || value === 'dynamic' || value === 'unknown' ? value : 'unknown';
985
- }
986
-
987
- function validCasterEligibility(value: unknown): SceneCasterEligibility {
988
- return value === 'eligible' || value === 'ineligible' || value === 'unknown' ? value : 'unknown';
989
- }
990
-
991
- function localBoundsFact(snapshot: RenderableSnapshot): RenderSceneFact['bounds'] {
992
- const local = snapshot.localAabb;
993
- if (local === undefined) return { status: 'missing', reason: 'missing-local-aabb' };
994
- const minX = local[0] ?? Number.NaN;
995
- const minY = local[1] ?? Number.NaN;
996
- const minZ = local[2] ?? Number.NaN;
997
- const maxX = local[3] ?? Number.NaN;
998
- const maxY = local[4] ?? Number.NaN;
999
- const maxZ = local[5] ?? Number.NaN;
1000
- if (
1001
- local.length < 6 ||
1002
- ![minX, minY, minZ, maxX, maxY, maxZ].every(Number.isFinite) ||
1003
- minX > maxX ||
1004
- minY > maxY ||
1005
- minZ > maxZ
1006
- ) {
1007
- return { status: 'missing', reason: 'invalid-local-aabb' };
1008
- }
1009
- const world = snapshot.transform.world;
1010
- if (world.length < 16 || !world.slice(0, 16).every(Number.isFinite)) {
1011
- return { status: 'missing', reason: 'invalid-world-transform' };
1012
- }
1013
- const m00 = world[0] ?? 0;
1014
- const m01 = world[1] ?? 0;
1015
- const m02 = world[2] ?? 0;
1016
- const m10 = world[4] ?? 0;
1017
- const m11 = world[5] ?? 0;
1018
- const m12 = world[6] ?? 0;
1019
- const m20 = world[8] ?? 0;
1020
- const m21 = world[9] ?? 0;
1021
- const m22 = world[10] ?? 0;
1022
- const tx = world[12] ?? 0;
1023
- const ty = world[13] ?? 0;
1024
- const tz = world[14] ?? 0;
1025
- const minimum = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];
1026
- const maximum = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];
1027
- for (const x of [minX, maxX]) {
1028
- for (const y of [minY, maxY]) {
1029
- for (const z of [minZ, maxZ]) {
1030
- const worldX = m00 * x + m10 * y + m20 * z + tx;
1031
- const worldY = m01 * x + m11 * y + m21 * z + ty;
1032
- const worldZ = m02 * x + m12 * y + m22 * z + tz;
1033
- minimum[0] = Math.min(minimum[0] as number, worldX);
1034
- minimum[1] = Math.min(minimum[1] as number, worldY);
1035
- minimum[2] = Math.min(minimum[2] as number, worldZ);
1036
- maximum[0] = Math.max(maximum[0] as number, worldX);
1037
- maximum[1] = Math.max(maximum[1] as number, worldY);
1038
- maximum[2] = Math.max(maximum[2] as number, worldZ);
1039
- }
1040
- }
1041
- }
1042
- return {
1043
- status: 'present',
1044
- localAabb: new Float32Array([minX, minY, minZ, maxX, maxY, maxZ]),
1045
- worldAabb: new Float32Array([
1046
- minimum[0] as number,
1047
- minimum[1] as number,
1048
- minimum[2] as number,
1049
- maximum[0] as number,
1050
- maximum[1] as number,
1051
- maximum[2] as number,
1052
- ]),
1053
- };
1054
- }
1055
-
1056
- function sameMaterials(left: RenderableSnapshot, right: RenderableSnapshot): boolean {
1057
- return sameValue(left.materials, right.materials) && sameValue(left.material, right.material);
1058
- }
1059
-
1060
- function diagnosticForBounds(
1061
- snapshot: RenderableSnapshot,
1062
- slot: number,
1063
- generation: number,
1064
- bounds: RenderSceneFact['bounds'],
1065
- ): SceneFactDiagnostic | undefined {
1066
- if (bounds.status === 'present') return undefined;
1067
- return {
1068
- code: 'missing-bounds',
1069
- slot,
1070
- generation,
1071
- worldId: snapshot.worldId,
1072
- entityKey: snapshot.entityKey,
1073
- reason: bounds.reason,
1074
- };
1075
- }
1076
-
1077
- function normalizeRevision(
1078
- value: number | undefined,
1079
- previous: number,
1080
- domain: SceneFactRevisionDomain,
1081
- snapshot: RenderableSnapshot,
1082
- slot: number,
1083
- generation: number,
1084
- diagnostics: SceneFactDiagnostic[],
1085
- ): number {
1086
- if (value === undefined) return previous;
1087
- if (!Number.isInteger(value) || value < 0 || value < previous) {
1088
- diagnostics.push({
1089
- code: 'invalid-revision',
1090
- slot,
1091
- generation,
1092
- worldId: snapshot.worldId,
1093
- entityKey: snapshot.entityKey,
1094
- domain,
1095
- reason: value < previous ? 'non-monotonic' : 'expected-non-negative-integer',
1096
- });
1097
- return previous;
1098
- }
1099
- return value;
1100
- }
1101
-
1102
- function factFor(
1103
- snapshot: RenderableSnapshot,
1104
- slot: number,
1105
- generation: number,
1106
- previous: RenderSceneFact | undefined,
1107
- changedDomains: ReadonlySet<SceneFactRevisionDomain>,
1108
- diagnostics: SceneFactDiagnostic[],
1109
- emitBoundsDiagnostic: boolean,
1110
- ): RenderSceneFact {
1111
- const bounds = localBoundsFact(snapshot);
1112
- if (emitBoundsDiagnostic) {
1113
- const boundsDiagnostic = diagnosticForBounds(snapshot, slot, generation, bounds);
1114
- if (boundsDiagnostic !== undefined) diagnostics.push(boundsDiagnostic);
1115
- }
1116
- const input: RenderSceneFactInput | undefined = snapshot.sceneFact;
1117
- const previousRevisions = previous?.revisions ?? ZERO_REVISIONS;
1118
- const revisions = Object.fromEntries(
1119
- FACT_DOMAINS.map((domain) => {
1120
- const explicit = input?.revisions?.[domain];
1121
- let value = normalizeRevision(
1122
- explicit,
1123
- previousRevisions[domain],
1124
- domain,
1125
- snapshot,
1126
- slot,
1127
- generation,
1128
- diagnostics,
1129
- );
1130
- if (explicit === undefined && changedDomains.has(domain)) value += 1;
1131
- if (
1132
- explicit !== undefined &&
1133
- changedDomains.has(domain) &&
1134
- value === previousRevisions[domain]
1135
- ) {
1136
- value += 1;
1137
- }
1138
- return [domain, value];
1139
- }),
1140
- ) as unknown as SceneFactRevisions;
1141
- return {
1142
- slot,
1143
- generation,
1144
- worldId: snapshot.worldId,
1145
- entityKey: snapshot.entityKey,
1146
- bounds,
1147
- mobility: validMobility(input?.mobility),
1148
- casterEligibility:
1149
- bounds.status === 'present' ? validCasterEligibility(input?.casterEligibility) : 'unknown',
1150
- revisions,
1151
- };
1152
- }
1153
-
1154
- function changedFactDomains(
1155
- previous: RenderSceneProjectionSlot,
1156
- next: RenderableSnapshot,
1157
- ): Set<SceneFactRevisionDomain> {
1158
- const changed = new Set<SceneFactRevisionDomain>();
1159
- if (!sameFloatArray(previous.snapshot.transform.world, next.transform.world)) {
1160
- changed.add('transform');
1161
- changed.add('space');
1162
- }
1163
- if (
1164
- previous.snapshot.assetHandle !== next.assetHandle ||
1165
- !sameFloatArray(previous.snapshot.localAabb, next.localAabb)
1166
- ) {
1167
- changed.add('geometry');
1168
- changed.add('space');
1169
- }
1170
- if (
1171
- !sameFloatArray(
1172
- previous.snapshot.candidateInstanceTransforms,
1173
- next.candidateInstanceTransforms,
1174
- ) ||
1175
- !sameFloatArray(previous.snapshot.boundsWorld, next.boundsWorld) ||
1176
- !sameValue(previous.snapshot.instances, next.instances) ||
1177
- !sameValue(previous.snapshot.spriteInstances, next.spriteInstances)
1178
- ) {
1179
- changed.add('space');
1180
- }
1181
- if (!sameValue(previous.snapshot.gpuDrivenDraws, next.gpuDrivenDraws)) {
1182
- changed.add('geometry');
1183
- changed.add('batch');
1184
- }
1185
- if (!sameMaterials(previous.snapshot, next)) {
1186
- changed.add('material');
1187
- changed.add('resource');
1188
- changed.add('batch');
1189
- }
1190
- if (
1191
- !sameValue(previous.snapshot.materialBindingSources, next.materialBindingSources) ||
1192
- !sameValue(previous.snapshot.materialBindingDiagnostics, next.materialBindingDiagnostics)
1193
- ) {
1194
- changed.add('resource');
1195
- }
1196
- const previousInput = previous.snapshot.sceneFact;
1197
- const nextInput = next.sceneFact;
1198
- if (validMobility(previousInput?.mobility) !== validMobility(nextInput?.mobility)) {
1199
- changed.add('space');
1200
- changed.add('eligibility');
1201
- }
1202
- if (
1203
- validCasterEligibility(previousInput?.casterEligibility) !==
1204
- validCasterEligibility(nextInput?.casterEligibility)
1205
- ) {
1206
- changed.add('eligibility');
1207
- }
1208
- for (const domain of FACT_DOMAINS) {
1209
- const nextRevision = nextInput?.revisions?.[domain];
1210
- if (nextRevision !== undefined && nextRevision !== previous.fact.revisions[domain]) {
1211
- changed.add(domain);
1212
- }
1213
- }
1214
- return changed;
1215
- }
1216
-
1217
- function temporalProducerChanged(previous: RenderableSnapshot, next: RenderableSnapshot): boolean {
1218
- return (
1219
- !sameValue(previous.skin?.jointMatrices, next.skin?.jointMatrices) ||
1220
- !sameFloatArray(previous.morphWeights, next.morphWeights)
1221
- );
1222
- }
1223
-
1224
- /**
1225
- * Renderer-owned persistent CPU scene projection.
1226
- *
1227
- * Operations are coalesced per `(worldId, entityKey)` before stable slots are
1228
- * touched. Slots carry generations so downstream GPU residency can reject
1229
- * stale work after removal and reuse. Each slot also owns the Scene Fact used
1230
- * by later spatial, visibility, batch, and upload owners.
1231
- */
1232
- export class RenderSceneProjection {
1233
- private readonly slots: Array<ProjectionSlot | undefined> = [];
1234
- private readonly lastSubmittedSlots: Array<ProjectionSlot | undefined> = [];
1235
- private readonly generations: number[] = [];
1236
- private readonly freeSlots: number[] = [];
1237
- private readonly slotsByWorld = new Map<number, Map<number, number>>();
1238
- private readonly slotsByMaterial = new Map<number, Set<number>>();
1239
- private materialized: readonly RenderableSnapshot[] | undefined;
1240
- private slotSnapshot: readonly RenderSceneProjectionSlot[] | undefined;
1241
- private factDiagnostics: readonly SceneFactDiagnostic[] = [];
1242
- private readonly spatialIndex = new RenderSceneSpatialIndex();
1243
- private readonly dirtySinceSubmitted = new Set<number>();
1244
- private lastSubmittedVisible = new Set<string>();
1245
- private revision = 0;
1246
- private submittedEpoch = 0;
1247
-
1248
- apply(operations: readonly RenderSceneOperation[]): RenderSceneApplyResult {
1249
- const pendingByWorld = new Map<number, Map<number, PendingIdentity>>();
1250
- const pendingOrder: PendingIdentity[] = [];
1251
- const diagnostics: SceneFactDiagnostic[] = [];
1252
- let ignoredLateUpdates = 0;
1253
-
1254
- const pendingFor = (worldId: number, entityKey: number): PendingIdentity => {
1255
- let entities = pendingByWorld.get(worldId);
1256
- if (entities === undefined) {
1257
- entities = new Map<number, PendingIdentity>();
1258
- pendingByWorld.set(worldId, entities);
1259
- }
1260
- let pending = entities.get(entityKey);
1261
- if (pending !== undefined) return pending;
1262
- const initial = this.lookup(worldId, entityKey);
1263
- pending = {
1264
- worldId,
1265
- entityKey,
1266
- initial,
1267
- current: initial?.snapshot,
1268
- removed: false,
1269
- touched: false,
1270
- };
1271
- entities.set(entityKey, pending);
1272
- pendingOrder.push(pending);
1273
- return pending;
1274
- };
1275
-
1276
- const acceptsGeneration = (
1277
- operation: RenderSceneOperation,
1278
- pending: PendingIdentity,
1279
- ): boolean => {
1280
- if (operation.expectedGeneration === undefined) return true;
1281
- const actualGeneration = pending.initial?.generation;
1282
- if (actualGeneration === operation.expectedGeneration) return true;
1283
- const diagnostic = {
1284
- code: 'stale-generation',
1285
- worldId: operation.kind === 'create' ? operation.snapshot.worldId : operation.worldId,
1286
- entityKey: operation.kind === 'create' ? operation.snapshot.entityKey : operation.entityKey,
1287
- expectedGeneration: operation.expectedGeneration,
1288
- reason: 'operation-generation-does-not-match-live-slot',
1289
- ...(actualGeneration === undefined ? {} : { actualGeneration }),
1290
- ...(pending.initial === undefined
1291
- ? {}
1292
- : { slot: pending.initial.slot, generation: pending.initial.generation }),
1293
- } satisfies SceneFactDiagnostic;
1294
- diagnostics.push(diagnostic);
1295
- return false;
1296
- };
1297
-
1298
- for (const operation of operations) {
1299
- if (operation.kind === 'create') {
1300
- const { worldId, entityKey } = operation.snapshot;
1301
- const pending = pendingFor(worldId, entityKey);
1302
- if (!acceptsGeneration(operation, pending)) continue;
1303
- pending.current = ownSnapshot(operation.snapshot);
1304
- pending.touched = true;
1305
- continue;
1306
- }
1307
- const pending = pendingFor(operation.worldId, operation.entityKey);
1308
- if (!acceptsGeneration(operation, pending)) {
1309
- if (operation.kind === 'update-transform') ignoredLateUpdates += 1;
1310
- continue;
1311
- }
1312
- if (operation.kind === 'remove') {
1313
- pending.current = undefined;
1314
- pending.removed = true;
1315
- pending.touched = true;
1316
- continue;
1317
- }
1318
- if (pending.current === undefined) {
1319
- ignoredLateUpdates += 1;
1320
- continue;
1321
- }
1322
- pending.touched = true;
1323
- pending.current = withWorld(pending.current, operation.world);
1324
- }
1325
-
1326
- let created = 0;
1327
- let updated = 0;
1328
- let removed = 0;
1329
- let recreated = 0;
1330
- const createdSlots: RenderSceneProjectionSlot[] = [];
1331
- const updatedSlots: RenderSceneProjectionSlot[] = [];
1332
- const removedSlots: RenderSceneProjectionRecord[] = [];
1333
- const recreatedSlots: RenderSceneProjectionSlot[] = [];
1334
- const factDeltas: RenderSceneFactDelta[] = [];
1335
- for (const pending of pendingOrder) {
1336
- if (!pending.touched) continue;
1337
- if (pending.initial === undefined) {
1338
- if (pending.current === undefined) continue;
1339
- const createdSlot = this.allocate(pending.current, diagnostics);
1340
- createdSlots.push(createdSlot);
1341
- factDeltas.push({
1342
- slot: createdSlot.slot,
1343
- generation: createdSlot.generation,
1344
- changedDomains: FACT_DOMAINS,
1345
- previous: undefined,
1346
- current: createdSlot.fact,
1347
- });
1348
- this.dirtySinceSubmitted.add(createdSlot.slot);
1349
- created += 1;
1350
- continue;
1351
- }
1352
- if (pending.current === undefined) {
1353
- this.release(pending.initial);
1354
- this.dirtySinceSubmitted.add(pending.initial.slot);
1355
- removedSlots.push(pending.initial);
1356
- removed += 1;
1357
- continue;
1358
- }
1359
- if (pending.removed) {
1360
- this.release(pending.initial);
1361
- const recreatedSlot = this.allocate(pending.current, diagnostics);
1362
- recreatedSlots.push(recreatedSlot);
1363
- factDeltas.push({
1364
- slot: recreatedSlot.slot,
1365
- generation: recreatedSlot.generation,
1366
- changedDomains: FACT_DOMAINS,
1367
- previous: pending.initial.fact,
1368
- current: recreatedSlot.fact,
1369
- });
1370
- this.dirtySinceSubmitted.add(recreatedSlot.slot);
1371
- recreated += 1;
1372
- continue;
1373
- }
1374
- const domains = changedFactDomains(pending.initial, pending.current);
1375
- const currentFact = factFor(
1376
- pending.current,
1377
- pending.initial.slot,
1378
- pending.initial.generation,
1379
- pending.initial.fact,
1380
- domains,
1381
- diagnostics,
1382
- domains.size > 0,
1383
- );
1384
- const updatedSlot: ProjectionSlot = {
1385
- ...pending.initial,
1386
- snapshot: pending.current,
1387
- fact: currentFact,
1388
- };
1389
- this.unindexMaterials(pending.initial);
1390
- this.slots[pending.initial.slot] = updatedSlot;
1391
- this.indexMaterials(updatedSlot);
1392
- updatedSlots.push(updatedSlot);
1393
- if (domains.size > 0) {
1394
- factDeltas.push({
1395
- slot: updatedSlot.slot,
1396
- generation: updatedSlot.generation,
1397
- changedDomains: FACT_DOMAINS.filter((domain) => domains.has(domain)),
1398
- previous: pending.initial.fact,
1399
- current: currentFact,
1400
- });
1401
- }
1402
- if (domains.size > 0 || temporalProducerChanged(pending.initial.snapshot, pending.current)) {
1403
- this.dirtySinceSubmitted.add(updatedSlot.slot);
1404
- }
1405
- updated += 1;
1406
- }
1407
-
1408
- this.factDiagnostics = diagnostics;
1409
- const changed = created + updated + removed + recreated > 0;
1410
- const result: RenderSceneApplyResult = {
1411
- created,
1412
- updated,
1413
- removed,
1414
- recreated,
1415
- ignoredLateUpdates,
1416
- createdSlots,
1417
- updatedSlots,
1418
- removedSlots,
1419
- recreatedSlots,
1420
- factDeltas,
1421
- diagnostics,
1422
- };
1423
- if (!changed) return result;
1424
- this.revision += 1;
1425
- this.invalidateSnapshots();
1426
- return {
1427
- ...result,
1428
- spatialIndex: this.spatialIndex.patch(
1429
- [...createdSlots, ...updatedSlots, ...recreatedSlots],
1430
- removedSlots,
1431
- ),
1432
- };
1433
- }
1434
-
1435
- materialize(): readonly RenderableSnapshot[] {
1436
- if (this.materialized !== undefined) return this.materialized;
1437
- const snapshots: RenderableSnapshot[] = [];
1438
- for (const slot of this.slots) {
1439
- if (slot !== undefined) snapshots.push(slot.snapshot);
1440
- }
1441
- this.materialized = Object.freeze(snapshots);
1442
- return this.materialized;
1443
- }
1444
-
1445
- slotsSnapshot(): readonly RenderSceneProjectionSlot[] {
1446
- if (this.slotSnapshot !== undefined) return this.slotSnapshot;
1447
- const records: RenderSceneProjectionSlot[] = [];
1448
- for (const slot of this.slots) {
1449
- if (slot !== undefined) records.push(slot);
1450
- }
1451
- this.slotSnapshot = Object.freeze(records);
1452
- return this.slotSnapshot;
1453
- }
1454
-
1455
- lastSubmittedSlotByIndex(slot: number): RenderSceneProjectionSlot | undefined {
1456
- return this.lastSubmittedSlots[slot];
1457
- }
1458
-
1459
- temporalSnapshotBySlot(slot: number): RenderableTemporalSnapshot | undefined {
1460
- const current = this.slots[slot];
1461
- return current === undefined ? undefined : this.temporalSnapshot(current);
1462
- }
1463
-
1464
- withTemporal(snapshot: RenderableSnapshot): RenderableSnapshot {
1465
- const slot = this.lookup(snapshot.worldId, snapshot.entityKey);
1466
- return slot === undefined ? snapshot : { ...snapshot, temporal: this.temporalSnapshot(slot) };
1467
- }
1468
-
1469
- wasLastSubmittedVisible(slot: number, generation: number): boolean {
1470
- return this.lastSubmittedVisible.has(submittedIdentity(slot, generation));
1471
- }
1472
-
1473
- captureSubmission(
1474
- visible: readonly Pick<RenderableSnapshot, 'worldId' | 'entityKey'>[],
1475
- ): RenderSceneSubmissionCapture {
1476
- const visibleSlots = new Set<string>();
1477
- for (const snapshot of visible) {
1478
- const slot = this.lookup(snapshot.worldId, snapshot.entityKey);
1479
- if (slot !== undefined) visibleSlots.add(submittedIdentity(slot.slot, slot.generation));
1480
- }
1481
- return {
1482
- revision: this.revision,
1483
- slots: [...this.dirtySinceSubmitted].map((slot) => ({ slot, current: this.slots[slot] })),
1484
- visible: visibleSlots,
1485
- };
1486
- }
1487
-
1488
- commitSubmission(capture: RenderSceneSubmissionCapture): RenderSceneSubmissionDelta {
1489
- if (capture.revision !== this.revision) {
1490
- throw new RangeError('render scene changed while its temporal submission was active');
1491
- }
1492
- for (const update of capture.slots) {
1493
- this.lastSubmittedSlots[update.slot] = update.current;
1494
- this.dirtySinceSubmitted.delete(update.slot);
1495
- }
1496
- this.lastSubmittedVisible = new Set(capture.visible);
1497
- this.submittedEpoch += 1;
1498
- this.invalidateSnapshots();
1499
- return {
1500
- epoch: this.submittedEpoch,
1501
- slots: capture.slots.map((update) => update.slot),
1502
- };
1503
- }
1504
-
1505
- /** O(1) stable-slot lookup for delta owners; avoids rescanning slotsSnapshot. */
1506
- slotByIndex(slot: number): RenderSceneProjectionSlot | undefined {
1507
- return this.slots[slot];
1508
- }
1509
-
1510
- has(worldId: number, entityKey: number): boolean {
1511
- return this.lookup(worldId, entityKey) !== undefined;
1512
- }
1513
-
1514
- record(worldId: number, entityKey: number): RenderSceneProjectionRecord | undefined {
1515
- const slot = this.lookup(worldId, entityKey);
1516
- if (slot === undefined) return undefined;
1517
- return { slot: slot.slot, generation: slot.generation, worldId, entityKey };
1518
- }
1519
-
1520
- snapshot(worldId: number, entityKey: number): RenderableSnapshot | undefined {
1521
- return this.lookup(worldId, entityKey)?.snapshot;
1522
- }
1523
-
1524
- slotsForMaterial(materialHandle: number): readonly RenderSceneProjectionSlot[] {
1525
- const slots = this.slotsByMaterial.get(materialHandle);
1526
- if (slots === undefined) return [];
1527
- const records: RenderSceneProjectionSlot[] = [];
1528
- for (const slot of slots) {
1529
- const record = this.slots[slot];
1530
- if (record !== undefined) records.push(record);
1531
- }
1532
- return records;
1533
- }
1534
-
1535
- querySpatialIndex(
1536
- worldAabb: Float32Array,
1537
- options: { readonly verifyAgainstBruteForce?: boolean } = {},
1538
- ): SpatialQueryResult {
1539
- return this.spatialIndex.query(worldAabb, options.verifyAgainstBruteForce === true);
1540
- }
1541
-
1542
- replaceCurrent(snapshots: readonly RenderableSnapshot[]): RenderSceneApplyResult {
1543
- const incoming = new Set(
1544
- snapshots.map((snapshot) => `${snapshot.worldId}:${snapshot.entityKey}`),
1545
- );
1546
- const operations: RenderSceneOperation[] = [];
1547
- for (const slot of this.slots) {
1548
- if (slot === undefined || incoming.has(`${slot.worldId}:${slot.entityKey}`)) continue;
1549
- operations.push({
1550
- kind: 'remove',
1551
- worldId: slot.worldId,
1552
- entityKey: slot.entityKey,
1553
- expectedGeneration: slot.generation,
1554
- });
1555
- }
1556
- for (const snapshot of snapshots) {
1557
- const live = this.lookup(snapshot.worldId, snapshot.entityKey);
1558
- operations.push({
1559
- kind: 'create',
1560
- snapshot,
1561
- ...(live === undefined ? {} : { expectedGeneration: live.generation }),
1562
- });
1563
- }
1564
- return this.apply(operations);
1565
- }
1566
-
1567
- reset(snapshots: readonly RenderableSnapshot[]): void {
1568
- this.slots.length = 0;
1569
- this.generations.length = 0;
1570
- this.freeSlots.length = 0;
1571
- this.slotsByWorld.clear();
1572
- this.slotsByMaterial.clear();
1573
- this.lastSubmittedSlots.length = 0;
1574
- this.lastSubmittedVisible.clear();
1575
- this.dirtySinceSubmitted.clear();
1576
- this.submittedEpoch = 0;
1577
- const diagnostics: SceneFactDiagnostic[] = [];
1578
- for (const snapshot of snapshots) this.allocate(ownSnapshot(snapshot), diagnostics);
1579
- for (const slot of this.slots) {
1580
- if (slot !== undefined) this.dirtySinceSubmitted.add(slot.slot);
1581
- }
1582
- this.factDiagnostics = diagnostics;
1583
- this.invalidateSnapshots();
1584
- this.spatialIndex.replace(this.slotsSnapshot());
1585
- this.revision += 1;
1586
- }
1587
-
1588
- inspect(): RenderSceneProjectionInspection {
1589
- const current: RenderSceneProjectionRecord[] = [];
1590
- const lastSubmitted: RenderSceneProjectionRecord[] = [];
1591
- for (const slot of this.slots) {
1592
- if (slot === undefined) continue;
1593
- current.push({
1594
- slot: slot.slot,
1595
- generation: slot.generation,
1596
- worldId: slot.worldId,
1597
- entityKey: slot.entityKey,
1598
- });
1599
- }
1600
- for (const slot of this.lastSubmittedSlots) {
1601
- if (slot === undefined) continue;
1602
- lastSubmitted.push({
1603
- slot: slot.slot,
1604
- generation: slot.generation,
1605
- worldId: slot.worldId,
1606
- entityKey: slot.entityKey,
1607
- });
1608
- }
1609
- return {
1610
- current,
1611
- lastSubmitted: { epoch: this.submittedEpoch, records: lastSubmitted },
1612
- slotCapacity: this.slots.length,
1613
- freeSlots: this.freeSlots.length,
1614
- factDiagnostics: this.factDiagnostics,
1615
- spatialIndex: this.spatialIndex.inspect(),
1616
- };
1617
- }
1618
-
1619
- private lookup(worldId: number, entityKey: number): ProjectionSlot | undefined {
1620
- const slot = this.slotsByWorld.get(worldId)?.get(entityKey);
1621
- return slot === undefined ? undefined : this.slots[slot];
1622
- }
1623
-
1624
- private temporalSnapshot(slot: ProjectionSlot): RenderableTemporalSnapshot {
1625
- const submitted = this.lastSubmittedSlots[slot.slot];
1626
- const sameGeneration = submitted?.generation === slot.generation;
1627
- const wasVisible =
1628
- sameGeneration &&
1629
- this.lastSubmittedVisible.has(submittedIdentity(slot.slot, slot.generation));
1630
- const changed =
1631
- sameGeneration && submitted !== undefined
1632
- ? changedFactDomains(submitted, slot.snapshot)
1633
- : new Set<SceneFactRevisionDomain>();
1634
- const reasons: RenderableReactiveReason[] = [];
1635
- if (!sameGeneration) {
1636
- reasons.push(submitted === undefined ? 'new-slot' : 'generation-reuse');
1637
- } else if (!wasVisible) {
1638
- reasons.push('reentered');
1639
- }
1640
- if (changed.has('geometry')) reasons.push('geometry-revision');
1641
- if (changed.has('material') || changed.has('resource')) reasons.push('material-revision');
1642
- const exactSkin =
1643
- slot.snapshot.skin === undefined ||
1644
- (sameGeneration &&
1645
- submitted?.snapshot.skin !== undefined &&
1646
- submitted.snapshot.skin.jointCount === slot.snapshot.skin.jointCount &&
1647
- submitted.snapshot.skin.jointMatrices.length === slot.snapshot.skin.jointMatrices.length);
1648
- const exactMorph =
1649
- slot.snapshot.morphWeights === undefined ||
1650
- (sameGeneration &&
1651
- submitted?.snapshot.morphWeights !== undefined &&
1652
- submitted.snapshot.morphWeights.length === slot.snapshot.morphWeights.length);
1653
- if (!exactSkin) reasons.push('skinning-deformation');
1654
- if (!exactMorph) reasons.push('morph-deformation');
1655
- const seedCurrent =
1656
- !sameGeneration ||
1657
- !wasVisible ||
1658
- changed.has('geometry') ||
1659
- changed.has('material') ||
1660
- changed.has('resource') ||
1661
- !exactSkin ||
1662
- !exactMorph;
1663
- const previous = seedCurrent || submitted === undefined ? slot.snapshot : submitted.snapshot;
1664
- return {
1665
- previousEpoch: seedCurrent ? undefined : this.submittedEpoch,
1666
- previousSource: seedCurrent ? 'current-seed' : 'last-submitted',
1667
- reactive: reasons.length > 0,
1668
- reactiveReasons: reasons,
1669
- previousTransform: previous.transform,
1670
- previousInstances: previous.instances,
1671
- previousSkin: previous.skin,
1672
- previousMorphWeights: previous.morphWeights,
1673
- };
1674
- }
1675
-
1676
- private allocate(
1677
- snapshot: RenderableSnapshot,
1678
- diagnostics: SceneFactDiagnostic[],
1679
- ): ProjectionSlot {
1680
- const reused = this.freeSlots.pop();
1681
- const slot = reused ?? this.slots.length;
1682
- const generation = reused === undefined ? 0 : (this.generations[slot] ?? -1) + 1;
1683
- const fact = factFor(snapshot, slot, generation, undefined, new Set(), diagnostics, true);
1684
- const record: ProjectionSlot = {
1685
- slot,
1686
- generation,
1687
- worldId: snapshot.worldId,
1688
- entityKey: snapshot.entityKey,
1689
- snapshot,
1690
- fact,
1691
- };
1692
- this.generations[slot] = generation;
1693
- this.slots[slot] = record;
1694
- let entities = this.slotsByWorld.get(snapshot.worldId);
1695
- if (entities === undefined) {
1696
- entities = new Map<number, number>();
1697
- this.slotsByWorld.set(snapshot.worldId, entities);
1698
- }
1699
- entities.set(snapshot.entityKey, slot);
1700
- this.indexMaterials(record);
1701
- return record;
1702
- }
1703
-
1704
- private release(record: ProjectionSlot): void {
1705
- this.slots[record.slot] = undefined;
1706
- this.unindexMaterials(record);
1707
- const entities = this.slotsByWorld.get(record.worldId);
1708
- entities?.delete(record.entityKey);
1709
- if (entities?.size === 0) this.slotsByWorld.delete(record.worldId);
1710
- this.freeSlots.push(record.slot);
1711
- }
1712
-
1713
- private indexMaterials(record: ProjectionSlot): void {
1714
- for (const material of record.snapshot.materials) {
1715
- const handle = material.materialHandle ?? 0;
1716
- let slots = this.slotsByMaterial.get(handle);
1717
- if (slots === undefined) {
1718
- slots = new Set();
1719
- this.slotsByMaterial.set(handle, slots);
1720
- }
1721
- slots.add(record.slot);
1722
- }
1723
- }
1724
-
1725
- private unindexMaterials(record: ProjectionSlot): void {
1726
- for (const material of record.snapshot.materials) {
1727
- const handle = material.materialHandle ?? 0;
1728
- const slots = this.slotsByMaterial.get(handle);
1729
- slots?.delete(record.slot);
1730
- if (slots?.size === 0) this.slotsByMaterial.delete(handle);
1731
- }
1732
- }
1733
-
1734
- private invalidateSnapshots(): void {
1735
- this.materialized = undefined;
1736
- this.slotSnapshot = undefined;
1737
- }
1738
- }