@woosh/meep-engine 3.60.4 → 3.60.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 (419) hide show
  1. package/CHANGELOG.md +2621 -0
  2. package/CONTRIBUTING.md +7 -0
  3. package/MIGRATION_2_TO_3.md +136 -0
  4. package/SECURITY.md +4 -0
  5. package/editor/EditorCameraNavigation.d.ts +2 -1
  6. package/editor/EditorCameraNavigation.d.ts.map +1 -1
  7. package/editor/EditorCameraNavigation.js +51 -57
  8. package/package.json +6 -2
  9. package/src/engine/EngineHarness.d.ts +3 -9
  10. package/src/engine/EngineHarness.d.ts.map +1 -1
  11. package/src/engine/EngineHarness.js +6 -8
  12. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts +9 -6
  13. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts.map +1 -1
  14. package/src/engine/graphics/camera/makeOrbitalCameraController.js +44 -71
  15. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts +64 -0
  16. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts.map +1 -0
  17. package/src/engine/graphics/camera/orbital/MomentumAxis.js +187 -0
  18. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts +86 -0
  19. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts.map +1 -0
  20. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.js +319 -0
  21. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +34 -10
  22. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  23. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +116 -30
  24. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +1 -7
  25. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  26. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +1 -37
  27. package/src/engine/graphics/ecs/water/Water.d.ts +8 -0
  28. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  29. package/src/engine/graphics/ecs/water/Water.js +8 -0
  30. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  31. package/src/engine/graphics3/WaterSystem.js +731 -734
  32. package/src/engine/graphics3/decal/DecalTileShader.d.ts +61 -0
  33. package/src/engine/graphics3/decal/DecalTileShader.d.ts.map +1 -0
  34. package/src/engine/graphics3/decal/DecalTileShader.js +138 -0
  35. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts +10 -4
  36. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  37. package/src/engine/graphics3/decal/GPUDecalRenderer.js +149 -44
  38. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts +25 -0
  39. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts.map +1 -0
  40. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.js +55 -0
  41. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts +22 -0
  42. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts.map +1 -0
  43. package/src/engine/graphics3/decal/graph_gather_decal_tiles.js +70 -0
  44. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +7 -5
  45. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  46. package/src/engine/graphics3/decal/shader_decal_composite.js +48 -44
  47. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts +12 -0
  48. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts.map +1 -0
  49. package/src/engine/graphics3/decal/shader_decal_tile_copy.js +78 -0
  50. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts +11 -0
  51. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts.map +1 -0
  52. package/src/engine/graphics3/decal/shader_gather_decal_tiles.js +80 -0
  53. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts +13 -0
  54. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts.map +1 -0
  55. package/src/engine/input/devices/mouse/MouseEventButtons.js +23 -0
  56. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts +4 -0
  57. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts.map +1 -1
  58. package/src/engine/input/ecs/controllers/KeyboardCameraController.js +9 -45
  59. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  60. package/src/shade/playground/water_refraction/README.md +5 -6
  61. package/src/shade/playground/water_refraction/index.html +1 -1
  62. package/src/shade/renderer/Renderer.d.ts +11 -0
  63. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  64. package/src/shade/renderer/Renderer.js +50 -6
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  67. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  68. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  69. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  70. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  71. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  72. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +28 -45
  74. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  75. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +111 -119
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +22 -3
  77. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +84 -3
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts +19 -0
  80. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts.map +1 -0
  81. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js +25 -0
  82. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  83. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  84. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  85. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +15 -0
  86. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +38 -0
  88. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  89. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  90. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  91. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  92. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  93. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +28 -59
  94. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +84 -789
  96. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  98. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +7 -6
  99. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  100. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +12 -11
  101. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -2
  102. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -2
  103. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  104. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  105. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  106. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  107. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  108. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  109. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  110. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  111. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  112. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  113. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  114. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  115. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  116. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  117. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  118. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  119. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  120. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  121. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  122. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  123. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  124. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  125. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  126. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  127. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  128. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  129. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  130. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  131. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  132. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  133. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  134. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  135. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  136. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  137. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  138. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  139. package/src/shade/renderer/material/GPUMaterialManager.d.ts +11 -1
  140. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  141. package/src/shade/renderer/material/GPUMaterialManager.js +16 -8
  142. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  143. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  144. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  145. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +7 -3
  146. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  147. package/src/shade/renderer/postprocess/gtao/GTAO.js +26 -13
  148. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts +14 -0
  149. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  150. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +196 -68
  151. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  152. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +42 -28
  153. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
  154. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +429 -414
  155. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts +16 -0
  156. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts.map +1 -0
  157. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.js +156 -0
  158. package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -2
  159. package/src/shade/renderer/scene/GPUSceneContext.js +5 -5
  160. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  161. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  162. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  163. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  164. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  165. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  166. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  167. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  168. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  169. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  170. package/src/shade/renderer/water/shader_water.js +22 -13
  171. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  172. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  173. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  174. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  175. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  176. package/editor/REWORK_PLAN_2026_08.md +0 -692
  177. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  178. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  179. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  180. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  181. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  182. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  183. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  184. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  185. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  186. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  187. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  188. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  189. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  190. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  191. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  192. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  193. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  194. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  195. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  196. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  197. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  198. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  199. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  200. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  201. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  202. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  203. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  204. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  205. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  206. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  207. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  208. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  209. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  210. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  211. package/src/REVIEW_2026_08_06/generation.md +0 -176
  212. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  213. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  214. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  215. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  216. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  217. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  218. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  219. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  220. package/src/REVIEW_2026_08_06/view.md +0 -667
  221. package/src/REVIEW_2026_08_06.md +0 -610
  222. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  223. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  224. package/src/core/bvh8/NOTES.md +0 -63
  225. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  226. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  227. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  228. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  229. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  230. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  231. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  232. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  233. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  234. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  235. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  236. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  237. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  238. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  239. package/src/engine/REVIEW_2026_07_03.md +0 -211
  240. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  241. package/src/engine/control/first-person/DESIGN.md +0 -658
  242. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  243. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  244. package/src/engine/control/first-person/TODO.md +0 -160
  245. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  246. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  247. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  248. package/src/engine/ecs/ik/PLAN.md +0 -179
  249. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  250. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  251. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  252. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  253. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  254. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  255. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  256. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  257. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  258. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  259. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  260. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  261. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  262. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  263. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  264. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  265. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  266. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  267. package/src/engine/physics/cloth/PLAN.md +0 -3056
  268. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  269. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  270. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  271. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  272. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  273. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  274. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  275. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  276. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  277. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  278. package/src/format/image/avif/DECISIONS.md +0 -545
  279. package/src/format/image/jpeg/NOTES.md +0 -3
  280. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  281. package/src/generation/COORDINATES.md +0 -54
  282. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  283. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  284. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  285. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  286. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  287. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  288. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  289. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  290. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  291. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  292. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  293. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  294. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  295. package/src/shade/RENDERER_CONTRACT.md +0 -697
  296. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  297. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  298. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  299. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  300. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  301. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  302. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  303. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  304. package/src/shade/renderer/NOTES.md +0 -78
  305. package/src/shade/renderer/PLAN.md +0 -8
  306. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  307. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  308. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  309. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  310. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  311. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  312. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  313. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  314. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  315. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  316. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  317. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  318. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  319. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  320. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  321. package/src/shade/renderer/camera/orbital/README.md +0 -81
  322. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  323. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  324. package/src/shade/renderer/camera/orbital/index.js +0 -9
  325. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  326. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  327. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  328. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  329. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  330. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  331. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  332. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  333. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  334. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  335. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  336. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  337. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  338. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  339. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  340. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  341. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  342. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  343. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +0 -47
  344. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +0 -1
  345. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +0 -80
  346. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +0 -16
  347. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +0 -1
  348. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +0 -67
  349. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +0 -17
  350. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +0 -1
  351. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +0 -145
  352. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +0 -12
  353. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +0 -1
  354. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +0 -105
  355. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  356. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  357. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  358. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  359. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  360. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  361. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  362. package/src/shade/renderer/hiz/NOTES.md +0 -3
  363. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  364. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  365. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  366. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  367. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  368. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  369. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  370. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  371. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  372. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  373. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  374. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  375. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  376. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  377. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  378. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  379. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  380. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  381. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  382. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  383. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  384. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  385. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  386. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  387. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  388. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  389. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  390. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  391. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  392. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  393. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  394. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  395. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  396. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  397. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  398. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  399. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  400. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  401. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  402. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  403. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  404. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  405. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  406. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  407. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  408. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  409. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  410. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  411. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  412. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  413. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  414. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  415. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  416. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  417. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  418. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  419. package/src/shade/wgsl/NOTES.md +0 -4
@@ -1,181 +1,46 @@
1
1
  import { assert } from "../../../../../core/assert.js";
2
- import { BufferDescriptor } from "../../../../descriptor/buffer/BufferDescriptor.js";
3
- import { BufferResourceDescriptor } from "../../../../device/graph/BufferResourceDescriptor.js";
4
- import { graph_read_buffer } from "../../../buffer/graph_read_buffer.js";
5
- import { graph_build_indirect_dispatch_command } from "../../../gpu_primitive/indirect/IndirectComputeCommandBuildPass.js";
6
- import {
7
- graph_prefix_scan_csdldf,
8
- prefix_scan_csdldf_output_descriptor
9
- } from "../../../gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js";
10
- import { graph_create_buffer } from "../../../shader/graph/graph_create_buffer.js";
11
- import { Attribute } from "../../Attribute.js";
12
- import { Geometry } from "../../Geometry.js";
13
- import { MeshoptClusterizer } from "../../meshlet/build/meshoptimizer/meshopt_clusterizer.js";
14
- import { meshlet_geometry_build_from_geometry } from "../../meshlet_geometry_build_from_geometry.js";
15
- import { MeshSDFState } from "../../sdf/MESH_SDF.js";
16
- import { MeshSDFLayout } from "../../sdf/MeshSDFLayout.js";
17
- import { StandardAttributes } from "../../StandardAttributes.js";
18
- import { vgeo_feedback_slot_stats } from "../runtime/cut/vgeo_cut_feedback_layout.js";
19
- import { graph_vgeo_cut_descent } from "../runtime/graph_vgeo_cut_descent.js";
20
- import { VGEO_CUT_STAT } from "../runtime/layout/VGEO_CUT_STAT.js";
21
- import { VGEO_CUT_STAT_COUNT } from "../runtime/layout/VGEO_CUT_STAT_COUNT.js";
22
- import { VGEO_GEOMETRY_ROW_NONE } from "../runtime/layout/VGEO_GEOMETRY_ROW_NONE.js";
23
- import { VGEO_INSTANCE_WORDS } from "../runtime/layout/VGEO_INSTANCE_WORDS.js";
24
- import { VGeoViewCut } from "../runtime/VGeoViewCut.js";
25
- import { shader_vgeo_sdf_collect, VGEO_SDF_COLLECT_WORKGROUP_SIZE } from "./shader_vgeo_sdf_collect.js";
26
- import { shader_vgeo_sdf_decode } from "./shader_vgeo_sdf_decode.js";
27
- import { shader_vgeo_sdf_traverse } from "./shader_vgeo_sdf_traverse.js";
28
- import {
29
- VGEO_SDF_CLUSTER_WORDS,
30
- VGEO_SDF_COUNTER,
31
- VGEO_SDF_COUNTER_WORDS,
32
- VGEO_SDF_JOB_STRUCT,
33
- vgeo_sdf_header_words
34
- } from "./VGEO_SDF.js";
35
2
 
36
3
  /**
37
- * @typedef {import("../../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} FrameGraph
38
4
  * @typedef {import("../../GPUGeometryManager.js").GPUGeometryManager} GPUGeometryManager
39
5
  * @typedef {import("../../GPUGeometryMetadata.js").GPUGeometryMetadata} GPUGeometryMetadata
40
6
  * @typedef {import("../../MeshletGeometry.js").MeshletGeometry} MeshletGeometry
41
- * @typedef {import("../runtime/GPUVirtualGeometryRuntime.js").GPUVirtualGeometryRuntime} GPUVirtualGeometryRuntime
42
7
  */
43
8
 
44
- /** The slot holds no geometry. */
45
- const JOB_FREE = 0;
46
- /** Cut each frame, its counters read back. */
47
- const JOB_CUT = 1;
48
- /** Its last cut read back stood nothing in: the next frame it is cut, its mesh is written out too. */
49
- const JOB_READY = 2;
50
- /** Written out in a frame whose readback has not landed. */
51
- const JOB_DECODING = 3;
52
- /** Its mesh is read back: its proxy is built on the host. */
53
- const JOB_BUILD = 4;
54
- /** Its proxy is baked by the mesh path. */
55
- const JOB_BAKING = 5;
56
- /** Its proxy's cache is resident: given to the geometry at the next update. */
57
- const JOB_BAKED = 6;
58
-
59
- /**
60
- * Frames whose readback may be in flight before a frame's cut is skipped, as the bake's log: a mapping lands a frame or
61
- * two after its copy, and past this the device is behind.
62
- * @type {number}
63
- */
64
- const MAX_FRAMES_IN_FLIGHT = 3;
65
-
66
- /**
67
- * Geometries extracted at once: the jobs cut each frame until their cut stands nothing in. One whose proxy is built,
68
- * baking or waiting to be given its cache keeps its slot until then.
69
- * @type {number}
70
- */
71
- const DEFAULT_JOB_CAPACITY = 32;
72
-
73
- /**
74
- * Entries the cluster list starts with: a cut of a typical geometry at half its cache's voxel is under 128 clusters
75
- * (S8, step 0), for each of {@link DEFAULT_JOB_CAPACITY} jobs. It doubles past what a frame's cut took.
76
- * @type {number}
77
- */
78
- const INITIAL_CLUSTER_CAPACITY = DEFAULT_JOB_CAPACITY * 128;
79
-
80
- /**
81
- * One geometry being extracted.
82
- */
83
- class VGeoSDFJob {
84
- /**
85
- * Bumped each time the slot takes a geometry: a readback of a frame cut for an earlier one is not this one's.
86
- * @type {number}
87
- */
88
- generation = 0;
89
-
90
- phase = JOB_FREE;
91
-
92
- /**
93
- * The geometry, whose cache is asked for.
94
- * @type {GPUGeometryMetadata|null}
95
- */
96
- record = null;
97
-
98
- /**
99
- * What puts its error against a τ of 1: one over half its cache's level-0 voxel, in its own units.
100
- * @type {number}
101
- */
102
- projection_k = 0;
103
-
104
- /** What its last complete cut held. */
105
- vertex_count = 0;
106
- triangle_count = 0;
107
-
108
- /** @type {Float32Array|null} */
109
- positions = null;
110
-
111
- /** @type {Uint32Array|null} */
112
- indices = null;
113
-
114
- /** @type {MeshletGeometry|null} */
115
- proxy = null;
116
-
117
- /** @type {GPUGeometryMetadata|null} */
118
- proxy_record = null;
119
- }
120
-
121
9
  /**
122
- * The jobs one recorded frame cut, for its readback.
10
+ * A virtual geometry's stand-in, once applied.
123
11
  */
124
- class VGeoSDFFrame {
125
- busy = false;
126
-
127
- count = 0;
128
-
129
- /** @type {VGeoSDFJob[]} */
130
- jobs = [];
131
-
12
+ class VGeoProxyEntry {
132
13
  /**
133
- * @param {number} capacity
14
+ * @param {GPUGeometryMetadata} record the virtual geometry's
15
+ * @param {MeshletGeometry} proxy
134
16
  */
135
- constructor(capacity) {
136
- this.generations = new Uint32Array(capacity);
137
- this.decoding = new Uint8Array(capacity);
138
- this.vertex_bases = new Uint32Array(capacity);
139
- this.triangle_bases = new Uint32Array(capacity);
17
+ constructor(record, proxy) {
18
+ this.record = record;
19
+ this.proxy = proxy;
140
20
  }
141
-
142
- vertex_offset = 0;
143
- index_offset = 0;
144
21
  }
145
22
 
146
23
  /**
147
- * The geometry caches of virtual geometry (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §7.8, as S8 built it): a
148
- * {@link MeshSDFSource} of {@link GPUGeometrySDFManager}, which bakes a geometry's field from its tree, and a virtual
149
- * geometry has none. Each virtual geometry whose cache is asked for gets a proxy, the triangles of a cut of it, baked by
150
- * the mesh path as any geometry is, and its resident cache adopted into the geometry. Its instances are then composed
151
- * from it as a mesh's are.
24
+ * The geometry caches and cards of virtual geometry (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §7.8, §17).
25
+ * {@link GPUGeometrySDFManager} bakes a geometry's field from its tree and captures its cards through its meshlets, and
26
+ * a virtual geometry has neither.
152
27
  *
153
- * **The cut.** A geometry is cut whole by the camera cut's own descent (`shader_vgeo_sdf_traverse`), at an error under
154
- * half its cache's level-0 voxel, in its own space, under a feedback slot of the extraction's own: a cluster's page not
155
- * resident is wanted there, as a view's are, and since a want lasts one reading the job is cut again each frame until
156
- * its cut stands nothing in. Its counters are read back each frame.
28
+ * Each virtual geometry whose cache is asked for gets its proxy ({@link VirtualGeometry#get_proxy}): an ordinary
29
+ * geometry in the same local space, with its attributes. The proxy is added to the geometry manager and the virtual
30
+ * geometry aliased to it ({@link GPUGeometrySDFManager#alias}). From there the proxy is any geometry: the virtual
31
+ * geometry's holders hold its cache, baked from its tree, and the virtual geometry's card sets capture its layout,
32
+ * drawn through its meshlets with the virtual geometry's own materials.
157
33
  *
158
- * **The mesh.** The frame after a cut that stood nothing in, the job's clusters are written out too, its vertices as
159
- * stored and its triangles as indices into them (`shader_vgeo_sdf_decode`), in room the last cut's counts made, and
160
- * read back with that frame's counters. A frame that cut it otherwise (a page evicted since, the cut grown) is not
161
- * taken, and the job is cut again.
34
+ * **The proxy's detail is its own**, not the cache's voxel's: a proxy coarser than the voxel bakes a coarser field and
35
+ * coarser cards than the asset would. A known discrepancy, kept: a hit on virtual geometry has a material at all.
162
36
  *
163
- * **The proxy.** One a frame, on the host: an ordinary geometry built from the mesh
164
- * (`meshlet_geometry_build_from_geometry`, which costs 2.2 to 4.1 µs a triangle, measured), added to the geometry
165
- * manager, its cache held with the side the geometry's holders draw. When its bake turns resident the next update gives
166
- * it to the geometry ({@link GPUGeometrySDFManager#adopt}) and removes the proxy.
167
- *
168
- * A geometry no longer asked for when its turn comes is let go, and one whose holders ask again is extracted again.
169
- * Settings that change the caches' voxel restart every job.
37
+ * A proxy is applied as it arrives, which is between frames: adding a geometry grows the geometry manager's buffers,
38
+ * which a frame's passes must not find replaced under them. A virtual geometry the geometry manager lets go takes its
39
+ * proxy with it; one let go before its proxy arrives has none applied. A proxy that cannot be had leaves its geometry
40
+ * waiting, black.
170
41
  */
171
42
  export class VGeoSDFProxies {
172
43
 
173
- /** @type {GPUDevice} */
174
- #device;
175
-
176
- /** @type {GPUVirtualGeometryRuntime} */
177
- #runtime;
178
-
179
44
  /** @type {GPUGeometryManager} */
180
45
  #geometries;
181
46
 
@@ -183,700 +48,137 @@ export class VGeoSDFProxies {
183
48
  #sdf;
184
49
 
185
50
  /**
186
- * The extraction's cut: its slot, its params and its wavefront bound.
187
- * @type {VGeoViewCut}
51
+ * Virtual geometries whose proxy is asked for and has not arrived, by id.
52
+ * @type {Map<number, GPUGeometryMetadata>}
188
53
  */
189
- #cut;
190
-
191
- /** @type {VGeoSDFJob[]} */
192
- #jobs = [];
54
+ #asked = new Map();
193
55
 
194
56
  /**
195
- * Geometries asked for and not yet a job's, in the order asked; a geometry asked for again or let go since may be
196
- * here, and is passed over.
197
- * @type {GPUGeometryMetadata[]}
57
+ * Proxies applied, by the virtual geometry's id.
58
+ * @type {Map<number, VGeoProxyEntry>}
198
59
  */
199
- #requested = [];
200
-
201
- /** @type {VGeoSDFFrame[]} */
202
- #frames = [];
203
-
204
- #cluster_capacity = INITIAL_CLUSTER_CAPACITY;
205
-
206
- /**
207
- * The frame's jobs as the passes read them, `VGEO_SDF_JOB_STRUCT` each.
208
- * @type {GPUBuffer}
209
- */
210
- #jobs_buffer;
211
-
212
- #jobs_scratch;
213
-
214
- #settings = { job_count: 0, cluster_capacity: 0, vertex_offset: 0, index_offset: 0 };
215
-
216
- #collect_data = { instances: -1, claim_widths: -1 };
217
- #collect_bindings = {};
218
- #decode_data = { command: -1, clusters: -1, counters: -1, payload: -1 };
219
- #decode_bindings = {};
220
- #header_data = { counters: -1, feedback: -1, payload: -1 };
221
-
222
- /** Where the extraction's slot keeps its counters in the frame's feedback, for the frame being recorded. */
223
- #stats_base = 0;
60
+ #applied = new Map();
224
61
 
225
- #voxel_size;
226
- #max_bricks;
227
-
228
- #layout = new MeshSDFLayout();
229
-
230
- #clusterizer_ready = false;
231
-
232
- #extracted_count = 0;
233
- #adopted_count = 0;
234
- #triangles_extracted = 0;
62
+ #failed_count = 0;
235
63
 
236
64
  #destroyed = false;
237
65
 
238
66
  /**
239
67
  * @param {Object} options
240
- * @param {GPUDevice} options.device
241
- * @param {GPUVirtualGeometryRuntime} options.runtime whose geometries' caches this makes
242
68
  * @param {GPUGeometryManager} options.geometries the scene's, whose caches the virtual geometries' are
243
- * @param {number} [options.job_capacity] geometries extracted at once
244
69
  */
245
- constructor({ device, runtime, geometries, job_capacity = DEFAULT_JOB_CAPACITY }) {
246
- assert.defined(device, 'device');
247
- assert.defined(runtime, 'runtime');
70
+ constructor({ geometries }) {
248
71
  assert.defined(geometries, 'geometries');
249
- assert.isPositiveInteger(job_capacity, 'job_capacity');
250
72
 
251
- this.#device = device;
252
- this.#runtime = runtime;
253
73
  this.#geometries = geometries;
254
74
  this.#sdf = geometries.sdf;
255
- this.#cut = new VGeoViewCut({ device, label: 'vgeo sdf proxies' });
256
-
257
- this.#voxel_size = this.#sdf.voxel_size;
258
- this.#max_bricks = this.#sdf.max_bricks;
259
-
260
- for (let i = 0; i < job_capacity; i++) {
261
- this.#jobs.push(new VGeoSDFJob());
262
- }
263
-
264
- for (let i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
265
- this.#frames.push(new VGeoSDFFrame(job_capacity));
266
- }
267
-
268
- this.#jobs_buffer = device.createBuffer(BufferDescriptor.fromJSON({
269
- label: 'VGeoSDFProxies/jobs',
270
- size: job_capacity * VGEO_SDF_JOB_STRUCT.size,
271
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
272
- }));
273
-
274
- this.#jobs_scratch = new DataView(new ArrayBuffer(job_capacity * VGEO_SDF_JOB_STRUCT.size));
275
-
276
- const ready = MeshoptClusterizer.ready;
277
-
278
- if (ready === undefined) {
279
- this.#clusterizer_ready = true;
280
- } else {
281
- ready.then(() => {
282
- this.#clusterizer_ready = true;
283
- });
284
- }
285
-
286
- this.#sdf.onRequested.add(this.#requested_one, this);
287
- this.#sdf.onBaked.add(this.#baked, this);
288
- this.#sdf.add_source(this);
289
- }
290
75
 
291
- /**
292
- * The extraction's cut, whose `stats` say what the last reading of its slot counted.
293
- * @returns {VGeoViewCut}
294
- */
295
- get cut() {
296
- return this.#cut;
297
- }
298
-
299
- /**
300
- * Geometries being extracted.
301
- * @returns {number}
302
- */
303
- get job_count() {
304
- let count = 0;
305
-
306
- for (const job of this.#jobs) {
307
- if (job.phase !== JOB_FREE) {
308
- count++;
309
- }
310
- }
311
-
312
- return count;
313
- }
314
-
315
- /**
316
- * Geometries asked for that wait for a job, those let go since included.
317
- * @returns {number}
318
- */
319
- get requested_count() {
320
- return this.#requested.length;
321
- }
322
-
323
- /**
324
- * Proxies built so far.
325
- * @returns {number}
326
- */
327
- get extracted_count() {
328
- return this.#extracted_count;
76
+ this.#sdf.onRequested.add(this.#requested, this);
77
+ this.#sdf.onForgotten.add(this.#forgotten, this);
329
78
  }
330
79
 
331
80
  /**
332
- * Caches given to their geometries so far.
81
+ * Virtual geometries whose proxy is asked for and has not arrived.
333
82
  * @returns {number}
334
83
  */
335
- get adopted_count() {
336
- return this.#adopted_count;
84
+ get pending_count() {
85
+ return this.#asked.size;
337
86
  }
338
87
 
339
88
  /**
340
- * Triangles of the proxies built so far.
89
+ * Virtual geometries standing in through their proxy.
341
90
  * @returns {number}
342
91
  */
343
- get triangles_extracted() {
344
- return this.#triangles_extracted;
92
+ get applied_count() {
93
+ return this.#applied.size;
345
94
  }
346
95
 
347
96
  /**
348
- * Entries the cluster list holds.
97
+ * Proxies that could not be had.
349
98
  * @returns {number}
350
99
  */
351
- get cluster_capacity() {
352
- return this.#cluster_capacity;
353
- }
354
-
355
- /**
356
- * @param {GPUGeometryMetadata} record
357
- */
358
- #requested_one(record) {
359
- if (record.vg_row !== VGEO_GEOMETRY_ROW_NONE) {
360
- this.#requested.push(record);
361
- }
362
- }
363
-
364
- /**
365
- * @param {number} id
366
- */
367
- #baked(id) {
368
- for (const job of this.#jobs) {
369
- if (job.phase === JOB_BAKING && job.proxy_record.index === id) {
370
- job.phase = JOB_BAKED;
371
- }
372
- }
100
+ get failed_count() {
101
+ return this.#failed_count;
373
102
  }
374
103
 
375
104
  /**
376
- * The frame's work, ahead of the caches' bake: the caches baked given to their geometries, a proxy built, jobs
377
- * started, and the jobs' cut recorded into `graph` while the runtime's frame is open.
105
+ * The proxy a virtual geometry stands in through, once applied.
378
106
  *
379
- * @param {FrameGraph} graph
380
- */
381
- graph_update(graph) {
382
- assert.notOk(this.#destroyed, 'destroyed');
383
-
384
- const sdf = this.#sdf;
385
-
386
- if (sdf.voxel_size !== this.#voxel_size || sdf.max_bricks !== this.#max_bricks) {
387
- // a cut for the old voxel bakes a proxy finer or coarser than the cache it is for
388
- this.#restart();
389
-
390
- this.#voxel_size = sdf.voxel_size;
391
- this.#max_bricks = sdf.max_bricks;
392
- }
393
-
394
- this.#adopt();
395
- this.#build();
396
- this.#start();
397
-
398
- if (this.#runtime.frame_open) {
399
- this.#record(graph);
400
- }
401
- }
402
-
403
- /**
404
- * Give each geometry whose proxy is baked its cache, and remove the proxy.
107
+ * @param {GPUGeometryMetadata} record the virtual geometry's
108
+ * @returns {MeshletGeometry|undefined}
405
109
  */
406
- #adopt() {
407
- const sdf = this.#sdf;
408
-
409
- for (const job of this.#jobs) {
410
- if (job.phase !== JOB_BAKED) {
411
- continue;
412
- }
413
-
414
- if (sdf.adopt(job.record, job.proxy_record)) {
415
- this.#adopted_count++;
416
- } else if (sdf.is_requested(job.record)) {
417
- // the proxy's cache is not the one it was baked to: a proxy equal to another's is that one's record
418
- this.#requested.push(job.record);
419
- }
110
+ proxy_of(record) {
111
+ const entry = this.#applied.get(record.index);
420
112
 
421
- this.#free(job);
422
- }
113
+ return entry !== undefined && entry.record === record ? entry.proxy : undefined;
423
114
  }
424
115
 
425
116
  /**
426
- * Build the proxy of the first job whose mesh is read back, and hold its cache.
117
+ * @param {GPUGeometryMetadata} record
427
118
  */
428
- #build() {
429
- if (!this.#clusterizer_ready) {
430
- return;
431
- }
432
-
433
- const sdf = this.#sdf;
434
-
435
- for (const job of this.#jobs) {
436
- if (job.phase !== JOB_BUILD) {
437
- continue;
438
- }
439
-
440
- if (!sdf.is_requested(job.record)) {
441
- // let go since its cut was taken
442
- this.#free(job);
443
- continue;
444
- }
445
-
446
- const mesh = new Geometry();
447
-
448
- mesh.name = 'vgeo sdf proxy';
449
- mesh.index = Attribute.from(job.indices, 1, StandardAttributes.Index);
450
- mesh.addAttribute(Attribute.from(job.positions, 3, StandardAttributes.Position));
451
-
452
- const proxy = meshlet_geometry_build_from_geometry(mesh);
453
-
454
- this.#geometries.add(proxy);
455
-
456
- job.proxy = proxy;
457
- job.proxy_record = this.#geometries.get_metadata(proxy);
458
- job.positions = null;
459
- job.indices = null;
460
- job.phase = JOB_BAKING;
461
-
462
- this.#extracted_count++;
463
- this.#triangles_extracted += job.triangle_count;
464
-
465
- sdf.acquire(job.proxy_record, sdf.holds_two_sided(job.record));
466
-
467
- if (sdf.state_of(job.proxy_record) === MeshSDFState.Resident) {
468
- // a record a resident proxy of the same mesh already had
469
- job.phase = JOB_BAKED;
470
- }
119
+ #requested(record) {
120
+ const geometry = record.geometry;
471
121
 
122
+ if (geometry?.isVirtualGeometry !== true) {
472
123
  return;
473
124
  }
474
- }
475
-
476
- /**
477
- * Give the free slots the geometries asked for, in the order asked.
478
- */
479
- #start() {
480
- const sdf = this.#sdf;
481
- const requested = this.#requested;
482
- const layout = this.#layout;
483
-
484
- let taken = 0;
485
125
 
486
- for (const job of this.#jobs) {
487
- if (job.phase !== JOB_FREE) {
488
- continue;
489
- }
126
+ // asked again before it arrives, the proxy is the same promise's, and arrives twice: the second finds it applied
127
+ this.#asked.set(record.index, record);
490
128
 
491
- while (taken < requested.length) {
492
- const record = requested[taken++];
129
+ geometry.get_proxy().then(
130
+ proxy => this.#arrived(record, proxy),
131
+ error => {
132
+ if (this.#asked.get(record.index) === record) {
133
+ this.#asked.delete(record.index);
134
+ this.#failed_count++;
493
135
 
494
- if (!sdf.is_requested(record) || this.#extracting(record)) {
495
- continue;
136
+ console.warn('vgeo: no proxy, the geometry has no cache or cards', error);
496
137
  }
497
-
498
- layout.compute(record.geometry.bounding_box, sdf.voxel_size, sdf.max_bricks);
499
-
500
- job.generation++;
501
- job.record = record;
502
- job.projection_k = 1 / (0.5 * layout.voxel);
503
- job.phase = JOB_CUT;
504
-
505
- break;
506
138
  }
507
- }
508
-
509
- requested.copyWithin(0, taken);
510
- requested.length -= taken;
139
+ );
511
140
  }
512
141
 
513
142
  /**
514
143
  * @param {GPUGeometryMetadata} record
515
- * @returns {boolean} whether a job holds it
516
- */
517
- #extracting(record) {
518
- for (const job of this.#jobs) {
519
- if (job.phase !== JOB_FREE && job.record === record) {
520
- return true;
521
- }
522
- }
523
-
524
- return false;
525
- }
526
-
527
- /**
528
- * Let every job go, and ask again for the geometries still asked for.
529
- */
530
- #restart() {
531
- for (const job of this.#jobs) {
532
- if (job.phase === JOB_FREE) {
533
- continue;
534
- }
535
-
536
- if (this.#sdf.is_requested(job.record)) {
537
- this.#requested.push(job.record);
538
- }
539
-
540
- this.#free(job);
541
- }
542
- }
543
-
544
- /**
545
- * @param {VGeoSDFJob} job
546
- */
547
- #free(job) {
548
- if (job.proxy !== null) {
549
- this.#geometries.remove(job.proxy);
550
- }
551
-
552
- job.phase = JOB_FREE;
553
- job.record = null;
554
- job.positions = null;
555
- job.indices = null;
556
- job.proxy = null;
557
- job.proxy_record = null;
558
- }
559
-
560
- /**
561
- * @returns {VGeoSDFFrame|null}
562
- */
563
- #take_frame() {
564
- for (const frame of this.#frames) {
565
- if (!frame.busy) {
566
- return frame;
567
- }
568
- }
569
-
570
- return null;
571
- }
572
-
573
- /**
574
- * Record the cut of the jobs that cut, and the write-out of those whose last cut stood nothing in.
575
- *
576
- * @param {FrameGraph} graph
144
+ * @param {MeshletGeometry} proxy
577
145
  */
578
- #record(graph) {
579
- const frame = this.#take_frame();
580
-
581
- if (frame === null) {
582
- return;
583
- }
584
-
585
- const runtime = this.#runtime;
586
- const view = this.#jobs_scratch;
587
- const stride = VGEO_SDF_JOB_STRUCT.size;
588
-
589
- let count = 0;
590
- let vertices = 0;
591
- let triangles = 0;
592
-
593
- for (const job of this.#jobs) {
594
- if (job.phase !== JOB_CUT && job.phase !== JOB_READY) {
595
- continue;
596
- }
597
-
598
- if (!this.#sdf.is_requested(job.record)) {
599
- // let go since it was asked for: dropped, or forgotten
600
- this.#free(job);
601
- continue;
602
- }
603
-
604
- const decode = job.phase === JOB_READY;
605
- const at = count * stride;
606
-
607
- frame.jobs[count] = job;
608
- frame.generations[count] = job.generation;
609
- frame.decoding[count] = decode ? 1 : 0;
610
- frame.vertex_bases[count] = vertices;
611
- frame.triangle_bases[count] = triangles;
612
-
613
- view.setUint32(at + VGEO_SDF_JOB_STRUCT.get("vg_row").offset, job.record.vg_row, true);
614
- view.setFloat32(at + VGEO_SDF_JOB_STRUCT.get("projection_k").offset, job.projection_k, true);
615
- view.setUint32(at + VGEO_SDF_JOB_STRUCT.get("decode").offset, decode ? 1 : 0, true);
616
- view.setUint32(at + VGEO_SDF_JOB_STRUCT.get("vertex_base").offset, vertices, true);
617
- view.setUint32(at + VGEO_SDF_JOB_STRUCT.get("triangle_base").offset, triangles, true);
618
- view.setUint32(at + VGEO_SDF_JOB_STRUCT.get("vertex_count").offset, decode ? job.vertex_count : 0, true);
619
- view.setUint32(at + VGEO_SDF_JOB_STRUCT.get("triangle_count").offset, decode ? job.triangle_count : 0, true);
620
-
621
- if (decode) {
622
- vertices += job.vertex_count;
623
- triangles += job.triangle_count;
624
- job.phase = JOB_DECODING;
625
- }
626
-
627
- count++;
628
- }
629
-
630
- if (count === 0) {
146
+ #arrived(record, proxy) {
147
+ if (this.#asked.get(record.index) !== record) {
148
+ // let go since it was asked for, or applied already
631
149
  return;
632
150
  }
633
151
 
634
- frame.busy = true;
635
- frame.count = count;
636
-
637
- const header_words = vgeo_sdf_header_words(count);
638
-
639
- frame.vertex_offset = header_words;
640
- frame.index_offset = header_words + 3 * vertices;
641
-
642
- const payload_bytes = 4 * (frame.index_offset + 3 * triangles);
643
-
644
- this.#device.queue.writeBuffer(this.#jobs_buffer, 0, view.buffer, 0, count * stride);
645
-
646
- const settings = this.#settings;
647
-
648
- settings.job_count = count;
649
- settings.cluster_capacity = this.#cluster_capacity;
650
- settings.vertex_offset = frame.vertex_offset;
651
- settings.index_offset = frame.index_offset;
652
-
653
- // this frame's slot for the cut, and its params: a τ of 1, since its records carry the error's own scale
654
- const slot = runtime.slot_of(this.#cut);
655
-
656
- this.#cut.write_params({ runtime, slot, tau: 1 });
657
- this.#stats_base = vgeo_feedback_slot_stats(slot);
658
-
659
- // ----- the records: a job's geometry whole, then their claim widths scanned -----
660
-
661
- const collect_data = this.#collect_data;
662
- const collect = graph.add("VGeo SDF Collect", collect_data, this.#execute_collect);
152
+ this.#asked.delete(record.index);
663
153
 
664
- collect_data.instances = collect.create("vgeo sdf instances", BufferResourceDescriptor.from(
665
- count * VGEO_INSTANCE_WORDS * 4, GPUBufferUsage.STORAGE
666
- ));
667
- collect_data.claim_widths = collect.create("vgeo sdf claim widths", BufferResourceDescriptor.from(
668
- 16 + count * 4, GPUBufferUsage.STORAGE, 0, 16
669
- ));
154
+ this.#geometries.add(proxy);
155
+ this.#applied.set(record.index, new VGeoProxyEntry(record, proxy));
670
156
 
671
- const prefix_sums = graph_prefix_scan_csdldf({
672
- graph,
673
- input: collect_data.claim_widths,
674
- output: graph_create_buffer(graph, "vgeo sdf claim offsets", prefix_scan_csdldf_output_descriptor(count)),
675
- element_max_count: count,
676
- });
677
-
678
- // ----- the cut: the camera cut's own descent, its clusters onto the list -----
679
-
680
- const counters = graph_create_buffer(graph, "vgeo sdf counters", BufferResourceDescriptor.empty(
681
- count * VGEO_SDF_COUNTER_WORDS * 4, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
682
- ));
683
- const clusters = graph_create_buffer(graph, "vgeo sdf clusters", BufferResourceDescriptor.from(
684
- 16 + this.#cluster_capacity * VGEO_SDF_CLUSTER_WORDS * 4, GPUBufferUsage.STORAGE, 0, 16
685
- ));
686
-
687
- const descent = graph_vgeo_cut_descent({
688
- graph,
689
- runtime,
690
- cut: this.#cut,
691
- instances: collect_data.instances,
692
- prefix_sums,
693
- feedback: runtime.feedback_in(graph),
694
- traverse: shader_vgeo_sdf_traverse,
695
- bindings: { settings },
696
- outputs: { vgeo_sdf_counters: counters, vgeo_sdf_clusters: clusters },
697
- });
698
-
699
- runtime.publish_feedback(graph, descent.feedback);
700
-
701
- // ----- the write-out: a workgroup a listed cluster, every job's sizes and the ready jobs' meshes -----
702
-
703
- const command = graph_build_indirect_dispatch_command(graph, descent.outputs.vgeo_sdf_clusters, 1, true);
704
-
705
- const decode_data = this.#decode_data;
706
- const decode = graph.add("VGeo SDF Decode", decode_data, this.#execute_decode);
707
-
708
- decode_data.command = decode.read(command);
709
- decode_data.clusters = decode.read(descent.outputs.vgeo_sdf_clusters);
710
- decode_data.counters = decode.write(descent.outputs.vgeo_sdf_counters);
711
- decode_data.payload = decode.create("vgeo sdf payload", BufferResourceDescriptor.from(
712
- payload_bytes, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST
713
- ));
714
-
715
- // ----- the header: the jobs' counters and the cut's own, ahead of the meshes, then read back -----
716
-
717
- const header_data = this.#header_data;
718
- const header = graph.add("VGeo SDF Header", header_data, this.#execute_header);
719
-
720
- header_data.counters = header.read(decode_data.counters);
721
- header_data.feedback = header.read(descent.feedback);
722
- header_data.payload = header.write(decode_data.payload);
723
-
724
- graph_read_buffer({ graph, buffer: header_data.payload, offset: 0, size: payload_bytes })
725
- .then(reference => {
726
- try {
727
- if (!this.#destroyed) {
728
- this.#apply(new Uint32Array(reference.getValue()), frame);
729
- }
730
- } finally {
731
- reference.release();
732
- }
733
- })
734
- .catch(error => {
735
- if (!this.#destroyed) {
736
- console.warn('VGeoSDFProxies: readback failed', error);
737
- this.#lose(frame);
738
- }
739
- })
740
- .finally(() => {
741
- frame.busy = false;
742
- });
157
+ this.#sdf.alias(record, this.#geometries.get_metadata(proxy));
743
158
  }
744
159
 
745
- #execute_collect = (data, resources, execution) => {
746
- const b = this.#collect_bindings;
747
-
748
- b.settings = this.#settings;
749
- b.vgeo_sdf_jobs = this.#jobs_buffer;
750
- b.vg_geometries = this.#runtime.pool.buffer_geometries;
751
- b.instances = resources.get(data.instances);
752
- b.claim_widths = resources.get(data.claim_widths);
753
-
754
- shader_vgeo_sdf_collect.dispatch({
755
- encoder: execution.encoder,
756
- group_count_x: Math.ceil(this.#settings.job_count / VGEO_SDF_COLLECT_WORKGROUP_SIZE),
757
- bindings: b,
758
- });
759
- };
760
-
761
- #execute_decode = (data, resources, execution) => {
762
- const meshlets = this.#geometries.meshlets;
763
- const b = this.#decode_bindings;
764
-
765
- b.settings = this.#settings;
766
- b.vgeo_sdf_jobs = this.#jobs_buffer;
767
- b.vgeo_sdf_counters = resources.get(data.counters);
768
- b.vgeo_sdf_clusters = resources.get(data.clusters);
769
- b.meshlet_metadata = meshlets.buffer_metadata;
770
- b.meshlet_data = meshlets.buffer_data;
771
- b.vgeo_sdf_payload = resources.get(data.payload);
772
-
773
- shader_vgeo_sdf_decode.dispatchIndirect({
774
- encoder: execution.encoder,
775
- command: resources.get(data.command),
776
- command_offset: 0,
777
- bindings: b,
778
- });
779
- };
780
-
781
- #execute_header = (data, resources, execution) => {
782
- const encoder = execution.encoder;
783
- const payload = resources.get(data.payload);
784
- const counter_bytes = 4 * this.#settings.job_count * VGEO_SDF_COUNTER_WORDS;
785
-
786
- encoder.copyBufferToBuffer(resources.get(data.counters), 0, payload, 0, counter_bytes);
787
- encoder.copyBufferToBuffer(resources.get(data.feedback), 4 * this.#stats_base, payload, counter_bytes, 4 * VGEO_CUT_STAT_COUNT);
788
- };
789
-
790
160
  /**
791
- * A recorded frame's readback: each job's cut taken, its mesh too where the frame wrote it out.
792
- *
793
- * @param {Uint32Array} words
794
- * @param {VGeoSDFFrame} frame
161
+ * @param {GPUGeometryMetadata} record
795
162
  */
796
- #apply(words, frame) {
797
- const stats = frame.count * VGEO_SDF_COUNTER_WORDS;
798
-
799
- // a subtree the cut left undescended is missing from every job's list, and no counter of a job says which
800
- const holes = words[stats + VGEO_CUT_STAT.QUEUE_DROPPED] > 0
801
- || words[stats + VGEO_CUT_STAT.QUEUE_REMAINING] > 0
802
- || words[stats + VGEO_CUT_STAT.INSTANCES_DROPPED] > 0;
803
-
804
- let taken = 0;
805
- let dropped = false;
806
-
807
- for (let i = 0; i < frame.count; i++) {
808
- const job = frame.jobs[i];
809
- const c = i * VGEO_SDF_COUNTER_WORDS;
810
-
811
- taken += words[c + VGEO_SDF_COUNTER.TAKEN];
812
- dropped ||= words[c + VGEO_SDF_COUNTER.DROPPED] > 0;
813
-
814
- if (job.generation !== frame.generations[i]) {
815
- // the slot holds another geometry now
816
- continue;
817
- }
818
-
819
- const complete = !holes
820
- && words[c + VGEO_SDF_COUNTER.TAKEN] > 0
821
- && words[c + VGEO_SDF_COUNTER.STAND_INS] === 0
822
- && words[c + VGEO_SDF_COUNTER.DROPPED] === 0;
823
-
824
- if (frame.decoding[i] === 0) {
825
- if (job.phase === JOB_CUT && complete) {
826
- job.vertex_count = words[c + VGEO_SDF_COUNTER.VERTICES];
827
- job.triangle_count = words[c + VGEO_SDF_COUNTER.TRIANGLES];
828
- job.phase = JOB_READY;
829
- }
830
-
831
- continue;
832
- }
833
-
834
- if (job.phase !== JOB_DECODING) {
835
- continue;
836
- }
163
+ #forgotten(record) {
164
+ const id = record.index;
837
165
 
838
- const whole = complete
839
- && words[c + VGEO_SDF_COUNTER.VERTICES] === job.vertex_count
840
- && words[c + VGEO_SDF_COUNTER.TRIANGLES] === job.triangle_count
841
- && words[c + VGEO_SDF_COUNTER.VERTICES_WRITTEN] === job.vertex_count
842
- && words[c + VGEO_SDF_COUNTER.TRIANGLES_WRITTEN] === job.triangle_count;
843
-
844
- if (!whole) {
845
- // cut otherwise than the cut its room was made for
846
- job.phase = JOB_CUT;
847
- continue;
848
- }
849
-
850
- const first_vertex = frame.vertex_offset + 3 * frame.vertex_bases[i];
851
- const first_index = frame.index_offset + 3 * frame.triangle_bases[i];
852
-
853
- job.positions = new Float32Array(words.buffer, words.byteOffset + 4 * first_vertex, 3 * job.vertex_count).slice();
854
- job.indices = words.slice(first_index, first_index + 3 * job.triangle_count);
855
- job.phase = JOB_BUILD;
166
+ if (this.#asked.get(id) === record) {
167
+ this.#asked.delete(id);
856
168
  }
857
169
 
858
- if (dropped) {
859
- while (this.#cluster_capacity < taken) {
860
- this.#cluster_capacity *= 2;
861
- }
170
+ const entry = this.#applied.get(id);
171
+
172
+ if (entry !== undefined && entry.record === record) {
173
+ this.#applied.delete(id);
174
+ this.#geometries.remove(entry.proxy);
862
175
  }
863
176
  }
864
177
 
865
178
  /**
866
- * A frame whose readback was lost: the jobs it wrote out are cut again.
867
- *
868
- * @param {VGeoSDFFrame} frame
179
+ * Hear no more of the caches. The proxies applied stay with the geometry manager, as stand-ins their geometries
180
+ * are aliased to: removing one under its alias would leave its geometry's holders holding a geometry let go.
869
181
  */
870
- #lose(frame) {
871
- for (let i = 0; i < frame.count; i++) {
872
- const job = frame.jobs[i];
873
-
874
- if (frame.decoding[i] === 1 && job.generation === frame.generations[i] && job.phase === JOB_DECODING) {
875
- job.phase = JOB_CUT;
876
- }
877
- }
878
- }
879
-
880
182
  destroy() {
881
183
  if (this.#destroyed) {
882
184
  return;
@@ -886,17 +188,10 @@ export class VGeoSDFProxies {
886
188
 
887
189
  const sdf = this.#sdf;
888
190
 
889
- sdf.remove_source(this);
890
- sdf.onRequested.remove(this.#requested_one, this);
891
- sdf.onBaked.remove(this.#baked, this);
892
-
893
- for (const job of this.#jobs) {
894
- this.#free(job);
895
- }
896
-
897
- this.#requested.length = 0;
191
+ sdf.onRequested.remove(this.#requested, this);
192
+ sdf.onForgotten.remove(this.#forgotten, this);
898
193
 
899
- this.#cut.destroy();
900
- this.#jobs_buffer.destroy();
194
+ this.#applied.clear();
195
+ this.#asked.clear();
901
196
  }
902
197
  }