@woosh/meep-engine 3.60.4 → 3.60.5

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 (379) hide show
  1. package/CHANGELOG.md +2602 -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.map +1 -1
  63. package/src/shade/renderer/Renderer.js +7 -5
  64. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  67. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  68. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  69. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  70. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  71. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  72. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +2 -2
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +2 -2
  74. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +2 -1
  75. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +18 -1
  77. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  78. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  80. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  81. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  82. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  83. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  84. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  85. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  86. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  87. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +5 -5
  88. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  89. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +10 -10
  90. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  91. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  92. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  93. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  94. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  95. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  96. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  98. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  99. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  100. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  101. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  102. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  103. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  104. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  105. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  106. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  107. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  108. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  109. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  110. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  111. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  112. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  113. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  114. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  115. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  116. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  117. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  118. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  119. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  120. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  121. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  122. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  123. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  124. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  125. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  126. package/src/shade/renderer/material/GPUMaterialManager.d.ts +7 -0
  127. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  128. package/src/shade/renderer/material/GPUMaterialManager.js +11 -0
  129. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  130. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  131. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  132. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  133. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  134. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  135. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  136. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  137. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  138. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  139. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  140. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  141. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  142. package/src/shade/renderer/water/shader_water.js +22 -13
  143. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  144. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  145. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  146. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  147. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  148. package/editor/REWORK_PLAN_2026_08.md +0 -692
  149. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  150. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  151. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  152. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  153. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  154. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  155. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  156. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  157. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  158. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  159. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  160. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  161. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  162. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  163. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  164. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  165. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  166. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  167. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  168. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  169. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  170. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  171. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  172. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  173. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  174. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  175. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  176. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  177. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  178. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  179. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  180. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  181. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  182. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  183. package/src/REVIEW_2026_08_06/generation.md +0 -176
  184. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  185. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  186. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  187. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  188. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  189. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  190. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  191. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  192. package/src/REVIEW_2026_08_06/view.md +0 -667
  193. package/src/REVIEW_2026_08_06.md +0 -610
  194. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  195. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  196. package/src/core/bvh8/NOTES.md +0 -63
  197. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  198. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  199. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  200. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  201. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  202. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  203. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  204. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  205. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  206. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  207. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  208. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  209. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  210. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  211. package/src/engine/REVIEW_2026_07_03.md +0 -211
  212. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  213. package/src/engine/control/first-person/DESIGN.md +0 -658
  214. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  215. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  216. package/src/engine/control/first-person/TODO.md +0 -160
  217. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  218. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  219. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  220. package/src/engine/ecs/ik/PLAN.md +0 -179
  221. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  222. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  223. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  224. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  225. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  226. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  227. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  228. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  229. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  230. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  231. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  232. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  233. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  234. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  235. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  236. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  237. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  238. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  239. package/src/engine/physics/cloth/PLAN.md +0 -3056
  240. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  241. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  242. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  243. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  244. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  245. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  246. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  247. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  248. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  249. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  250. package/src/format/image/avif/DECISIONS.md +0 -545
  251. package/src/format/image/jpeg/NOTES.md +0 -3
  252. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  253. package/src/generation/COORDINATES.md +0 -54
  254. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  255. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  256. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  257. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  258. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  259. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  260. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  261. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  262. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  263. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  264. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  265. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  266. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  267. package/src/shade/RENDERER_CONTRACT.md +0 -697
  268. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  269. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  270. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  271. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  272. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  273. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  274. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  275. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  276. package/src/shade/renderer/NOTES.md +0 -78
  277. package/src/shade/renderer/PLAN.md +0 -8
  278. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  279. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  280. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  281. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  282. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  283. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  284. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  285. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  286. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  287. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  288. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  289. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  290. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  291. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  292. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  293. package/src/shade/renderer/camera/orbital/README.md +0 -81
  294. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  295. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  296. package/src/shade/renderer/camera/orbital/index.js +0 -9
  297. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  298. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  299. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  300. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  301. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  302. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  303. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  304. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  305. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  306. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  307. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  308. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  309. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  310. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  311. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  312. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  313. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  314. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  315. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  316. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  317. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  318. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  319. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  320. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  321. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  322. package/src/shade/renderer/hiz/NOTES.md +0 -3
  323. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  324. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  325. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  326. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  327. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  328. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  329. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  330. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  331. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  332. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  333. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  334. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  335. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  336. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  337. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  338. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  339. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  340. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  341. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  342. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  343. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  344. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  345. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  346. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  347. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  348. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  349. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  350. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  351. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  352. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  353. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  354. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  355. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  356. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  357. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  358. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  359. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  360. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  361. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  362. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  363. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  364. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  365. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  366. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  367. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  368. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  369. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  370. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  371. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  372. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  373. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  374. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  375. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  376. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  377. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  378. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  379. package/src/shade/wgsl/NOTES.md +0 -4
@@ -0,0 +1,61 @@
1
+ /**
2
+ * A fragment program drawn over the screen tiles that hold a decal, rather than over the whole
3
+ * screen — what an `ImageShader` is to a full-screen pass, for the decal passes that only need to
4
+ * touch the surfaces a decal could be on.
5
+ *
6
+ * The tiles come from `graph_gather_decal_tiles`, and so does the draw: the instance count is the
7
+ * live tile count, read on the device through an indirect command, so the work follows how much of
8
+ * the screen the decals cover and never the size of the screen.
9
+ *
10
+ * The fragment program is `descriptor`, an ordinary one — it is what the emulator runs and what
11
+ * specs read. The vertex program is {@link chunk_decal_tile_vertex}, compiled against the same
12
+ * resources, so both stages share one layout and the descriptor must declare `decal_tiles` and an
13
+ * immediate `settings` with a `screen_resolution`.
14
+ */
15
+ export class DecalTileShader {
16
+ /**
17
+ * @param {object} options
18
+ * @param {ShaderDescriptor} options.descriptor the fragment program
19
+ * @param {GPUColorTargetState[]} options.targets
20
+ */
21
+ constructor({ descriptor, targets }: {
22
+ descriptor: ShaderDescriptor;
23
+ targets: GPUColorTargetState[];
24
+ });
25
+ /**
26
+ * @returns {ShaderDescriptor}
27
+ */
28
+ get descriptor(): ShaderDescriptor;
29
+ /**
30
+ * @returns {RenderPipelineDescriptor}
31
+ */
32
+ get pipeline(): RenderPipelineDescriptor;
33
+ /**
34
+ * See `ImageShader#pipeline_for`.
35
+ *
36
+ * @param {GPUTextureFormat[]} color_formats
37
+ * @returns {RenderPipelineDescriptor}
38
+ */
39
+ pipeline_for(color_formats: GPUTextureFormat[]): RenderPipelineDescriptor;
40
+ /**
41
+ * Draw over every listed tile.
42
+ *
43
+ * @param {object} options
44
+ * @param {ShadeGPUCommandContext} options.encoder
45
+ * @param {Object} options.bindings
46
+ * @param {GPURenderPassColorAttachment[]} options.colorAttachments
47
+ * @param {GPUTextureFormat[]} options.color_formats
48
+ * @param {GPUBuffer} options.command the tiles' draw command: 6 vertices, one instance per tile
49
+ */
50
+ draw({ encoder, bindings, colorAttachments, color_formats, command }: {
51
+ encoder: ShadeGPUCommandContext;
52
+ bindings: any;
53
+ colorAttachments: GPURenderPassColorAttachment[];
54
+ color_formats: GPUTextureFormat[];
55
+ command: GPUBuffer;
56
+ }): void;
57
+ #private;
58
+ }
59
+ import { ShaderDescriptor } from "../../../shade/renderer/shader/ShaderDescriptor.js";
60
+ import { RenderPipelineDescriptor } from "../../../shade/descriptor/pipeline/render/RenderPipelineDescriptor.js";
61
+ //# sourceMappingURL=DecalTileShader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DecalTileShader.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/DecalTileShader.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;GAaG;AACH;IAkBI;;;;OAIG;IACH;QAHqC,UAAU,EAApC,gBAAgB;QACe,OAAO,EAAtC,qBAAqB;OA8B/B;IAED;;OAEG;IACH,mCAEC;IAED;;OAEG;IACH,yCAEC;IAED;;;;;OAKG;IACH,4BAHW,kBAAkB,GAChB,wBAAwB,CAIpC;IAED;;;;;;;;;OASG;IACH;QAN2C,OAAO;QACvB,QAAQ;QACgB,gBAAgB,EAAxD,8BAA8B;QACF,aAAa,EAAzC,kBAAkB;QACC,OAAO;aA6BpC;;CACJ;iCApIgC,oDAAoD;yCAJ5C,uEAAuE"}
@@ -0,0 +1,138 @@
1
+ import { assert } from "../../../core/assert.js";
2
+ import { RenderPipelineDescriptor } from "../../../shade/descriptor/pipeline/render/RenderPipelineDescriptor.js";
3
+ import {
4
+ rp_validate_and_rewrite_for_color_attachments
5
+ } from "../../../shade/device/pipeline/rp_validate_and_rewrite_for_color_attachments.js";
6
+ import { ShaderDescriptor } from "../../../shade/renderer/shader/ShaderDescriptor.js";
7
+ import { chunk_decal_tile_vertex } from "./chunk_decal_tile_vertex.js";
8
+
9
+ /**
10
+ * A fragment program drawn over the screen tiles that hold a decal, rather than over the whole
11
+ * screen — what an `ImageShader` is to a full-screen pass, for the decal passes that only need to
12
+ * touch the surfaces a decal could be on.
13
+ *
14
+ * The tiles come from `graph_gather_decal_tiles`, and so does the draw: the instance count is the
15
+ * live tile count, read on the device through an indirect command, so the work follows how much of
16
+ * the screen the decals cover and never the size of the screen.
17
+ *
18
+ * The fragment program is `descriptor`, an ordinary one — it is what the emulator runs and what
19
+ * specs read. The vertex program is {@link chunk_decal_tile_vertex}, compiled against the same
20
+ * resources, so both stages share one layout and the descriptor must declare `decal_tiles` and an
21
+ * immediate `settings` with a `screen_resolution`.
22
+ */
23
+ export class DecalTileShader {
24
+ /**
25
+ * @type {ShaderDescriptor}
26
+ */
27
+ #descriptor;
28
+
29
+ /**
30
+ * @type {RenderPipelineDescriptor}
31
+ */
32
+ #pipeline;
33
+
34
+ /**
35
+ * See `ImageShader`'s field of the same name: one device check per device, not one per draw.
36
+ *
37
+ * @type {GPUDevice|null}
38
+ */
39
+ #validated_device = null;
40
+
41
+ /**
42
+ * @param {object} options
43
+ * @param {ShaderDescriptor} options.descriptor the fragment program
44
+ * @param {GPUColorTargetState[]} options.targets
45
+ */
46
+ constructor({ descriptor, targets }) {
47
+ assert.defined(descriptor, 'descriptor');
48
+ assert.isArray(targets, 'targets');
49
+
50
+ this.#descriptor = descriptor;
51
+
52
+ const vertex = ShaderDescriptor.from({
53
+ label: `${descriptor.label} / tiles`,
54
+ resources: descriptor.resources,
55
+ body: chunk_decal_tile_vertex
56
+ });
57
+
58
+ this.#pipeline = RenderPipelineDescriptor.from({
59
+ label: descriptor.label,
60
+ layout: descriptor.resources.generatePipelineLayout(GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT),
61
+ vertex: {
62
+ module: { code: vertex.source },
63
+ entryPoint: 'main',
64
+ },
65
+ fragment: {
66
+ module: { code: descriptor.source },
67
+ targets,
68
+ },
69
+ primitive: {
70
+ topology: 'triangle-list',
71
+ cullMode: 'none',
72
+ },
73
+ });
74
+ }
75
+
76
+ /**
77
+ * @returns {ShaderDescriptor}
78
+ */
79
+ get descriptor() {
80
+ return this.#descriptor;
81
+ }
82
+
83
+ /**
84
+ * @returns {RenderPipelineDescriptor}
85
+ */
86
+ get pipeline() {
87
+ return this.#pipeline;
88
+ }
89
+
90
+ /**
91
+ * See `ImageShader#pipeline_for`.
92
+ *
93
+ * @param {GPUTextureFormat[]} color_formats
94
+ * @returns {RenderPipelineDescriptor}
95
+ */
96
+ pipeline_for(color_formats) {
97
+ return rp_validate_and_rewrite_for_color_attachments(this.#pipeline, color_formats);
98
+ }
99
+
100
+ /**
101
+ * Draw over every listed tile.
102
+ *
103
+ * @param {object} options
104
+ * @param {ShadeGPUCommandContext} options.encoder
105
+ * @param {Object} options.bindings
106
+ * @param {GPURenderPassColorAttachment[]} options.colorAttachments
107
+ * @param {GPUTextureFormat[]} options.color_formats
108
+ * @param {GPUBuffer} options.command the tiles' draw command: 6 vertices, one instance per tile
109
+ */
110
+ draw({ encoder, bindings, colorAttachments, color_formats, command }) {
111
+ assert.defined(encoder, 'encoder');
112
+ assert.defined(command, 'command');
113
+
114
+ const descriptor = this.#descriptor;
115
+ const resources = descriptor.resources;
116
+
117
+ if (encoder.device !== this.#validated_device) {
118
+ descriptor.validate_against_device(encoder.device);
119
+
120
+ this.#validated_device = encoder.device;
121
+ }
122
+
123
+ encoder.pushDebugGroup(descriptor.label);
124
+
125
+ const pass = encoder.constructRenderPass({
126
+ pipeline: this.pipeline_for(color_formats),
127
+ bindings: resources.generateBindings(bindings, encoder),
128
+ colorAttachments,
129
+ immediate: encoder.writeImmediate(resources, bindings),
130
+ });
131
+
132
+ pass.drawIndirect(command, 0);
133
+
134
+ pass.end();
135
+
136
+ encoder.popDebugGroup();
137
+ }
138
+ }
@@ -1,10 +1,16 @@
1
1
  /**
2
2
  * Draws decals into the G-buffer.
3
3
  *
4
- * Four passes, in order: the atlases and this frame's records are uploaded, the decals are culled
5
- * against the camera, they are binned into their own froxels, and the composite reads the G-buffer
6
- * and writes a new one. The last of those is what {@link GBufferTextures} being publishable at
7
- * {@link FramePhase.AfterGBuffer} is for — see D23.
4
+ * Six passes, in order: the atlases and this frame's records are uploaded, the decals are culled
5
+ * against the camera, they are binned into their own froxels, the screen tiles whose froxels hold a
6
+ * decal are listed, the G-buffer under those tiles is copied, and the composite paints the decals
7
+ * into the G-buffer in place over the same tiles, reading the copy. The last of those is what
8
+ * {@link GBufferTextures} being publishable at {@link FramePhase.AfterGBuffer} is for — see D23.
9
+ *
10
+ * **Only the covered part of the screen costs anything.** The composite used to read the whole
11
+ * G-buffer and write a whole new one whenever any decal was on screen; on a 2-CU iGPU at 720p that
12
+ * copy alone was ~385 µs of a 544 µs pass for two small markers (2026-10-31). Now both tile passes
13
+ * are drawn indirectly over the gathered tiles, so their cost follows the area the decals cover.
8
14
  */
9
15
  export class GPUDecalRenderer {
10
16
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"GPUDecalRenderer.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/GPUDecalRenderer.js"],"names":[],"mappings":"AA4CA;;;;;;;GAOG;AACH;IA6BI;;;;;;;;;;;OAWG;IACH;QAP8B,KAAK;QACL,OAAO,EAA1B,YAAY;QACC,YAAY,EAAzB,MAAM;QACU,YAAY;QACZ,YAAY;QACZ,SAAS;aAuBnC;IAkPD,gBAoBC;;CACJ"}
1
+ {"version":3,"file":"GPUDecalRenderer.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/GPUDecalRenderer.js"],"names":[],"mappings":"AA6EA;;;;;;;;;;;;;GAaG;AACH;IA6BI;;;;;;;;;;;OAWG;IACH;QAP8B,KAAK;QACL,OAAO,EAA1B,YAAY;QACC,YAAY,EAAzB,MAAM;QACU,YAAY;QACZ,YAAY;QACZ,SAAS;aA+BnC;IA4SD,gBAoBC;;CACJ"}
@@ -11,6 +11,8 @@ import { SAMPLER_ANISOTROPIC_CLAMP } from "../../../shade/renderer/texture/SAMPL
11
11
  import { graph_build_decal_clusters } from "./graph_build_decal_clusters.js";
12
12
  import { DECAL_RECORD_WORD_COUNT } from "./DECAL_GPU_RECORD.js";
13
13
  import { shader_decal_composite } from "./shader_decal_composite.js";
14
+ import { shader_decal_tile_copy } from "./shader_decal_tile_copy.js";
15
+ import { graph_gather_decal_tiles } from "./graph_gather_decal_tiles.js";
14
16
  import { build_light_cluster_parameters } from "../../../shade/renderer/light/cluster/build_light_cluster_parameters.js";
15
17
  import { DECAL_CLUSTER_RESOLUTION_Z } from "./DECAL_CLUSTER.js";
16
18
 
@@ -22,6 +24,37 @@ import { DECAL_CLUSTER_RESOLUTION_Z } from "./DECAL_CLUSTER.js";
22
24
  */
23
25
  const GROWTH_FACTOR = 1.5;
24
26
 
27
+ /**
28
+ * The G-buffer's four targets, in the order both tile passes write them.
29
+ *
30
+ * @type {GPUTextureFormat[]}
31
+ */
32
+ const G_BUFFER_FORMATS = ["rg8unorm", "rgba16uint", G_BUFFER_ALBEDO_FORMAT, "r32uint"];
33
+
34
+ /**
35
+ * @type {TextureViewDescriptor}
36
+ */
37
+ const MIP_0 = TextureViewDescriptor.from({
38
+ mipLevelCount: 1,
39
+ baseMipLevel: 0
40
+ });
41
+
42
+ /**
43
+ * Mip 0 of a target, kept — a tile pass draws over part of the screen, so whatever lies outside the
44
+ * tiles has to survive it.
45
+ *
46
+ * @param {FramePassResources} resources
47
+ * @param {number} handle
48
+ * @returns {GPURenderPassColorAttachment}
49
+ */
50
+ function attachment(resources, handle) {
51
+ return {
52
+ loadOp: "load",
53
+ storeOp: "store",
54
+ view: resources.get(handle).obtainView(MIP_0)
55
+ };
56
+ }
57
+
25
58
  /**
26
59
  * One atlas as the GPU holds it, with the mip chain its borders exist to make usable.
27
60
  */
@@ -45,10 +78,16 @@ class AtlasResidency {
45
78
  /**
46
79
  * Draws decals into the G-buffer.
47
80
  *
48
- * Four passes, in order: the atlases and this frame's records are uploaded, the decals are culled
49
- * against the camera, they are binned into their own froxels, and the composite reads the G-buffer
50
- * and writes a new one. The last of those is what {@link GBufferTextures} being publishable at
51
- * {@link FramePhase.AfterGBuffer} is for — see D23.
81
+ * Six passes, in order: the atlases and this frame's records are uploaded, the decals are culled
82
+ * against the camera, they are binned into their own froxels, the screen tiles whose froxels hold a
83
+ * decal are listed, the G-buffer under those tiles is copied, and the composite paints the decals
84
+ * into the G-buffer in place over the same tiles, reading the copy. The last of those is what
85
+ * {@link GBufferTextures} being publishable at {@link FramePhase.AfterGBuffer} is for — see D23.
86
+ *
87
+ * **Only the covered part of the screen costs anything.** The composite used to read the whole
88
+ * G-buffer and write a whole new one whenever any decal was on screen; on a 2-CU iGPU at 720p that
89
+ * copy alone was ~385 µs of a 544 µs pass for two small markers (2026-10-31). Now both tile passes
90
+ * are drawn indirectly over the gathered tiles, so their cost follows the area the decals cover.
52
91
  */
53
92
  export class GPUDecalRenderer {
54
93
  /**
@@ -111,15 +150,94 @@ export class GPUDecalRenderer {
111
150
  resolution: frame.resolution
112
151
  });
113
152
 
114
- this.#graph_composite({ frame, clusters });
153
+ const tiles = graph_gather_decal_tiles({
154
+ graph,
155
+ cluster_lookup: clusters.lookup,
156
+ resolution: frame.resolution
157
+ });
158
+
159
+ const copy = this.#graph_copy({ frame, tiles });
160
+
161
+ this.#graph_composite({ frame, clusters, tiles, copy });
162
+ }
163
+
164
+ /**
165
+ * Copy the G-buffer under the listed tiles, for the composite to read while it writes them.
166
+ *
167
+ * The copy's textures are screen-sized, so a tile's texels sit where they are on screen and need
168
+ * no address of their own — only the listed tiles are ever written or read, and the rest of each
169
+ * texture is whatever it last held.
170
+ *
171
+ * @param {object} args
172
+ * @param {FrameContext} args.frame
173
+ * @param {{tiles: number, command: number}} args.tiles
174
+ * @returns {{pbr: number, normal: number, albedo: number, emissive: number}}
175
+ */
176
+ #graph_copy({ frame, tiles }) {
177
+ const graph = frame.graph;
178
+ const resolution = frame.resolution;
179
+
180
+ const gbuffer = frame.get(GBufferTextures);
181
+
182
+ const data = {};
183
+
184
+ const pass = graph.add('decals / copy covered tiles', data, (data, resources, context) => {
185
+ shader_decal_tile_copy.draw({
186
+ encoder: context.encoder,
187
+ bindings: {
188
+ settings: { screen_resolution: resolution },
189
+ decal_tiles: resources.get(data.tiles),
190
+ gBufferPBR: resources.get(data.in_pbr).obtainView(),
191
+ gBufferNormal: resources.get(data.in_normal).obtainView(),
192
+ gBufferAlbedo: resources.get(data.in_albedo).obtainView(),
193
+ gBufferEmissive: resources.get(data.in_emissive).obtainView(),
194
+ },
195
+ colorAttachments: [
196
+ attachment(resources, data.pbr),
197
+ attachment(resources, data.normal),
198
+ attachment(resources, data.albedo),
199
+ attachment(resources, data.emissive),
200
+ ],
201
+ color_formats: G_BUFFER_FORMATS,
202
+ command: resources.get(data.command),
203
+ });
204
+ });
205
+
206
+ data.tiles = pass.read(tiles.tiles);
207
+ data.command = pass.read(tiles.command);
208
+
209
+ data.in_pbr = pass.read(gbuffer.pbr);
210
+ data.in_normal = pass.read(gbuffer.normal);
211
+ data.in_albedo = pass.read(gbuffer.albedo);
212
+ data.in_emissive = pass.read(gbuffer.emissive);
213
+
214
+ /**
215
+ * @param {string} name
216
+ * @param {GPUTextureFormat} format
217
+ * @returns {number}
218
+ */
219
+ const target = (name, format) => pass.create(name, TextureResourceDescriptor.from({
220
+ format,
221
+ resolution,
222
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
223
+ }));
224
+
225
+ data.pbr = target("decals / covered PBR", G_BUFFER_FORMATS[0]);
226
+ data.normal = target("decals / covered normal", G_BUFFER_FORMATS[1]);
227
+ data.albedo = target("decals / covered albedo", G_BUFFER_FORMATS[2]);
228
+ data.emissive = target("decals / covered emissive", G_BUFFER_FORMATS[3]);
229
+
230
+ return { pbr: data.pbr, normal: data.normal, albedo: data.albedo, emissive: data.emissive };
115
231
  }
116
232
 
117
233
  /**
118
234
  * @param {object} args
119
235
  * @param {FrameContext} args.frame
120
236
  * @param {{lookup: number, data: number}} args.clusters
237
+ * @param {{tiles: number, command: number}} args.tiles
238
+ * @param {{pbr: number, normal: number, albedo: number, emissive: number}} args.copy
121
239
  */
122
- #graph_composite({ frame, clusters }) {
240
+ #graph_composite({ frame, clusters, tiles, copy }) {
123
241
  const graph = frame.graph;
124
242
  const resolution = frame.resolution;
125
243
 
@@ -143,35 +261,29 @@ export class GPUDecalRenderer {
143
261
 
144
262
  data.depth = pass.read(frame.get(ViewTextures).depth);
145
263
 
146
- data.in_pbr = pass.read(gbuffer.pbr);
147
- data.in_normal = pass.read(gbuffer.normal);
148
- data.in_albedo = pass.read(gbuffer.albedo);
149
- data.in_emissive = pass.read(gbuffer.emissive);
264
+ data.in_pbr = pass.read(copy.pbr);
265
+ data.in_normal = pass.read(copy.normal);
266
+ data.in_albedo = pass.read(copy.albedo);
267
+ data.in_emissive = pass.read(copy.emissive);
150
268
 
151
269
  data.cluster_lookup = pass.read(clusters.lookup);
152
270
  data.cluster_data = pass.read(clusters.data);
153
271
 
154
- /**
155
- * @param {string} name
156
- * @param {GPUTextureFormat} format
157
- * @returns {number}
158
- */
159
- const target = (name, format) => pass.create(name, TextureResourceDescriptor.from({
160
- format,
161
- resolution,
162
- usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
163
- }));
164
-
165
- data.out_pbr = target("g-buffer / PBR + decals", "rg8unorm");
166
- data.out_normal = target("g-buffer / Normal + decals", "rgba16uint");
167
- data.out_albedo = target("g-buffer / Albedo + decals", G_BUFFER_ALBEDO_FORMAT);
168
- data.out_emissive = target("g-buffer / Emissive + decals", "r32uint");
272
+ data.tiles = pass.read(tiles.tiles);
273
+ data.command = pass.read(tiles.command);
169
274
 
170
275
  /*
171
- The whole reason this pass can composite exactly. Everything downstream — ambient occlusion,
172
- reflections, shading — now reads what the decals wrote, and the graph knows it does, so the
173
- ordering is a real edge rather than an accident of declaration order.
276
+ In place, and still a real edge: a written handle is a new version of the same texture, its
277
+ producer this pass, and it is what the record hands on. Everything downstream — ambient
278
+ occlusion, reflections, shading — reads the version the decals wrote and the graph knows it
279
+ does. Pixels outside the listed tiles are never drawn, so they keep what the G-buffer pass
280
+ left there, which is exactly what they should hold.
174
281
  */
282
+ data.out_pbr = pass.write(gbuffer.pbr);
283
+ data.out_normal = pass.write(gbuffer.normal);
284
+ data.out_albedo = pass.write(gbuffer.albedo);
285
+ data.out_emissive = pass.write(gbuffer.emissive);
286
+
175
287
  gbuffer.pbr = data.out_pbr;
176
288
  gbuffer.normal = data.out_normal;
177
289
  gbuffer.albedo = data.out_albedo;
@@ -186,7 +298,7 @@ export class GPUDecalRenderer {
186
298
  * @param {number[]} cluster_params
187
299
  * @param {number[]} resolution
188
300
  */
189
- #execute(data, resources, context, view_context, cluster_params, resolution) {
301
+ #execute(data, resources, context, view_context, cluster_params, resolution) {
190
302
  const camera = view_context.camera;
191
303
  const encoder = context.encoder;
192
304
  const graphics = context.graphics;
@@ -206,19 +318,10 @@ export class GPUDecalRenderer {
206
318
  */
207
319
  const view = handle => resources.get(handle).obtainView();
208
320
 
209
- const attachment = handle => ({
210
- loadOp: "clear",
211
- storeOp: "store",
212
- view: resources.get(handle).obtainView(TextureViewDescriptor.from({
213
- mipLevelCount: 1,
214
- baseMipLevel: 0
215
- }))
216
- });
217
-
218
321
  shader_decal_composite.draw({
219
322
  encoder,
220
323
  bindings: {
221
- camera: camera.buffer,
324
+ camera: camera.buffer,
222
325
  view: view_context.uniform_buffer.buffer,
223
326
  settings,
224
327
  gBufferPBR: view(data.in_pbr),
@@ -235,14 +338,16 @@ export class GPUDecalRenderer {
235
338
  atlas_normal_sampler: sampler,
236
339
  atlas_orm: this.#orm.texture.obtainView(),
237
340
  atlas_orm_sampler: sampler,
341
+ decal_tiles: resources.get(data.tiles),
238
342
  },
239
343
  colorAttachments: [
240
- attachment(data.out_pbr),
241
- attachment(data.out_normal),
242
- attachment(data.out_albedo),
243
- attachment(data.out_emissive),
344
+ attachment(resources, data.out_pbr),
345
+ attachment(resources, data.out_normal),
346
+ attachment(resources, data.out_albedo),
347
+ attachment(resources, data.out_emissive),
244
348
  ],
245
- color_formats: ["rg8unorm", "rgba16uint", G_BUFFER_ALBEDO_FORMAT, "r32uint"]
349
+ color_formats: G_BUFFER_FORMATS,
350
+ command: resources.get(data.command),
246
351
  });
247
352
  }
248
353
 
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Where corner `vertex_index` of a listed screen tile lands in clip space.
3
+ *
4
+ * A tile is one column of the decal froxel grid, packed `x | y << 16`. Six vertices make two
5
+ * triangles covering it exactly, so a pixel is shaded by a tile draw if and only if its froxel column
6
+ * is that tile — the same column the composite then looks its decals up in.
7
+ *
8
+ * The froxel grid is built over a flipped y, counting rows up from the bottom edge
9
+ * (`cluster_from_fragment_coord`), which is the direction NDC y already runs. So no flip appears here:
10
+ * it is the grid's convention and clip space's agreeing, not an omission.
11
+ *
12
+ * @type {CodeChunk}
13
+ */
14
+ export const chunk_decal_tile_corner: CodeChunk;
15
+ /**
16
+ * The vertex stage of a pass drawn over the screen tiles that hold a decal: instance `i` is the tile
17
+ * at `decal_tiles[1 + i]`, the word before them being their count.
18
+ *
19
+ * Reads `decal_tiles` and `settings.screen_resolution`, which every pass using it declares.
20
+ *
21
+ * @type {CodeChunk}
22
+ */
23
+ export const chunk_decal_tile_vertex: CodeChunk;
24
+ import { CodeChunk } from "../../../shade/renderer/shader/compiler/CodeChunk.js";
25
+ //# sourceMappingURL=chunk_decal_tile_vertex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_decal_tile_vertex.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/chunk_decal_tile_vertex.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,sCAFU,SAAS,CAgBjB;AAEF;;;;;;;GAOG;AACH,sCAFU,SAAS,CAgBjB;0BAtDwB,sDAAsD"}
@@ -0,0 +1,55 @@
1
+ import { CodeChunk } from "../../../shade/renderer/shader/compiler/CodeChunk.js";
2
+ import { DECAL_CLUSTER_TILE_RESOLUTION } from "./DECAL_CLUSTER.js";
3
+
4
+ /**
5
+ * Where corner `vertex_index` of a listed screen tile lands in clip space.
6
+ *
7
+ * A tile is one column of the decal froxel grid, packed `x | y << 16`. Six vertices make two
8
+ * triangles covering it exactly, so a pixel is shaded by a tile draw if and only if its froxel column
9
+ * is that tile — the same column the composite then looks its decals up in.
10
+ *
11
+ * The froxel grid is built over a flipped y, counting rows up from the bottom edge
12
+ * (`cluster_from_fragment_coord`), which is the direction NDC y already runs. So no flip appears here:
13
+ * it is the grid's convention and clip space's agreeing, not an omission.
14
+ *
15
+ * @type {CodeChunk}
16
+ */
17
+ export const chunk_decal_tile_corner = CodeChunk.from(
18
+ //language=WGSL
19
+ `
20
+ fn decal_tile_corner(tile: u32, vertex_index: u32, screen_resolution: vec2<u32>) -> vec2<f32> {
21
+ let cell = vec2<u32>(tile & 0xFFFFu, tile >> 16u);
22
+
23
+ // corners (0,0) (1,0) (0,1) (0,1) (1,0) (1,1), one bit per vertex
24
+ let corner = vec2<u32>((0x32u >> vertex_index) & 1u, (0x2Cu >> vertex_index) & 1u);
25
+
26
+ let pixel = (cell + corner) * ${DECAL_CLUSTER_TILE_RESOLUTION}u;
27
+
28
+ return vec2<f32>(pixel) / vec2<f32>(screen_resolution) * 2.0 - 1.0;
29
+ }
30
+ `
31
+ );
32
+
33
+ /**
34
+ * The vertex stage of a pass drawn over the screen tiles that hold a decal: instance `i` is the tile
35
+ * at `decal_tiles[1 + i]`, the word before them being their count.
36
+ *
37
+ * Reads `decal_tiles` and `settings.screen_resolution`, which every pass using it declares.
38
+ *
39
+ * @type {CodeChunk}
40
+ */
41
+ export const chunk_decal_tile_vertex = CodeChunk.from(
42
+ //language=WGSL
43
+ `
44
+ @vertex
45
+ fn main(
46
+ @builtin(vertex_index) vertex_index : u32,
47
+ @builtin(instance_index) instance_index : u32,
48
+ ) -> @builtin(position) vec4<f32> {
49
+ let ndc = decal_tile_corner(decal_tiles[1u + instance_index], vertex_index, settings.screen_resolution);
50
+
51
+ return vec4<f32>(ndc, 0.0, 1.0);
52
+ }
53
+ `,
54
+ [chunk_decal_tile_corner]
55
+ );
@@ -0,0 +1,22 @@
1
+ /**
2
+ * List the screen tiles that hold a decal, and the draw command a `DecalTileShader` draws them with.
3
+ *
4
+ * The list holds every tile of the screen at worst, so it never drops one; what it costs to draw
5
+ * follows the count the gather wrote, through the command. The command has a buffer of its own, as
6
+ * an indirect argument may not be bound writable in the scope it is used in.
7
+ *
8
+ * @param {object} args
9
+ * @param {FrameGraph} args.graph
10
+ * @param {number} args.cluster_lookup handle of the decal froxels' lookup
11
+ * @param {number[]} args.resolution
12
+ * @returns {{tiles: number, command: number}}
13
+ */
14
+ export function graph_gather_decal_tiles({ graph, cluster_lookup, resolution }: {
15
+ graph: FrameGraph;
16
+ cluster_lookup: number;
17
+ resolution: number[];
18
+ }): {
19
+ tiles: number;
20
+ command: number;
21
+ };
22
+ //# sourceMappingURL=graph_gather_decal_tiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph_gather_decal_tiles.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/graph_gather_decal_tiles.js"],"names":[],"mappings":"AAeA;;;;;;;;;;;;GAYG;AACH;IAL4B,KAAK;IACT,cAAc,EAA3B,MAAM;IACS,UAAU,EAAzB,MAAM,EAAE;IACN;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CA2C5C"}