@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,70 @@
1
+ import { assert } from "../../../core/assert.js";
2
+ import { BufferResourceDescriptor } from "../../../shade/device/graph/BufferResourceDescriptor.js";
3
+ import { STRUCT_UNINDEXED_DRAW_COMMAND } from "../../../shade/renderer/gpu_primitive/indirect/STRUCT_UNINDEXED_DRAW_COMMAND.js";
4
+ import { build_indirect_draw_command } from "../../../shade/renderer/gpu_primitive/indirect/build_indirect_draw_command.js";
5
+ import { u32 } from "../../../shade/renderer/shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
6
+ import { DECAL_CLUSTER_TILE_RESOLUTION } from "./DECAL_CLUSTER.js";
7
+ import { shader_gather_decal_tiles } from "./shader_gather_decal_tiles.js";
8
+
9
+ /**
10
+ * Two triangles per tile, one instance per tile, the instance count read off the tile list's head.
11
+ *
12
+ * @type {string}
13
+ */
14
+ const DRAW_COMMAND_PATTERN = "6u, input, 0u, 0u";
15
+
16
+ /**
17
+ * List the screen tiles that hold a decal, and the draw command a `DecalTileShader` draws them with.
18
+ *
19
+ * The list holds every tile of the screen at worst, so it never drops one; what it costs to draw
20
+ * follows the count the gather wrote, through the command. The command has a buffer of its own, as
21
+ * an indirect argument may not be bound writable in the scope it is used in.
22
+ *
23
+ * @param {object} args
24
+ * @param {FrameGraph} args.graph
25
+ * @param {number} args.cluster_lookup handle of the decal froxels' lookup
26
+ * @param {number[]} args.resolution
27
+ * @returns {{tiles: number, command: number}}
28
+ */
29
+ export function graph_gather_decal_tiles({ graph, cluster_lookup, resolution }) {
30
+ assert.isNonNegativeInteger(cluster_lookup, 'cluster_lookup');
31
+ assert.isArrayLike(resolution, 'resolution');
32
+
33
+ const tile_count_x = Math.ceil(resolution[0] / DECAL_CLUSTER_TILE_RESOLUTION);
34
+ const tile_count_y = Math.ceil(resolution[1] / DECAL_CLUSTER_TILE_RESOLUTION);
35
+
36
+ const data = {};
37
+
38
+ const pass = graph.add("decal tiles / gather", data, (data, resources, context) => {
39
+ const encoder = context.encoder;
40
+ const tiles = resources.get(data.tiles);
41
+
42
+ shader_gather_decal_tiles.dispatchThreads({
43
+ encoder,
44
+ bindings: {
45
+ settings: { screen_resolution: resolution },
46
+ cluster_lookup: resources.get(data.cluster_lookup),
47
+ decal_tiles: tiles,
48
+ },
49
+ thread_count_x: tile_count_x,
50
+ thread_count_y: tile_count_y,
51
+ });
52
+
53
+ build_indirect_draw_command(encoder.device, DRAW_COMMAND_PATTERN, encoder, tiles, resources.get(data.command));
54
+ });
55
+
56
+ data.cluster_lookup = pass.read(cluster_lookup);
57
+
58
+ data.tiles = pass.create("decal tiles", BufferResourceDescriptor.from(
59
+ u32.size * (1 + tile_count_x * tile_count_y),
60
+ GPUBufferUsage.STORAGE,
61
+ 0, u32.size, // clear the count
62
+ ));
63
+
64
+ data.command = pass.create("decal tiles / draw command", BufferResourceDescriptor.from(
65
+ STRUCT_UNINDEXED_DRAW_COMMAND.aligned_size,
66
+ GPUBufferUsage.STORAGE | GPUBufferUsage.INDIRECT,
67
+ ));
68
+
69
+ return { tiles: data.tiles, command: data.command };
70
+ }
@@ -1,18 +1,20 @@
1
1
  export const DECAL_COMPOSITE_SETTINGS: WebGPUStruct;
2
2
  /**
3
- * Reads the G-buffer, paints this frame's decals into it, and writes a new one.
3
+ * Paints this frame's decals into the G-buffer, in place, over the screen tiles that hold one.
4
4
  *
5
5
  * **Every channel is composited exactly, in registers.** Nothing is blended by hardware and nothing
6
6
  * is approximated: two of the four targets are integer formats that cannot blend at all, and the
7
7
  * previous shading normal and the ambient in the albedo's alpha both have to survive — which they
8
- * only can if the pass reads one texture and writes another (D23).
8
+ * only can if the pass reads one texture and writes another (D23). The one it reads is
9
+ * `shader_decal_tile_copy`'s copy of the same tiles, so only the covered part of the screen
10
+ * is read and written twice, rather than all of it once.
9
11
  *
10
12
  * The face normal is carried through untouched. A decal changes what a surface looks like, not which
11
13
  * way it is turned, and the face normal is what the fade and everything downstream reason about.
12
14
  *
13
- * @type {ImageShader}
15
+ * @type {DecalTileShader}
14
16
  */
15
- export const shader_decal_composite: ImageShader;
17
+ export const shader_decal_composite: DecalTileShader;
16
18
  import { WebGPUStruct } from "../../../shade/renderer/shader/type/WebGPUStruct.js";
17
- import { ImageShader } from "../../../shade/renderer/shader/ImageShader.js";
19
+ import { DecalTileShader } from "./DecalTileShader.js";
18
20
  //# sourceMappingURL=shader_decal_composite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shader_decal_composite.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/shader_decal_composite.js"],"names":[],"mappings":"AAgEA,oDAKG;AAySH;;;;;;;;;;;;GAYG;AACH,qCAFU,WAAW,CAclB;6BA1V0B,qDAAqD;4BAPtD,+CAA+C"}
1
+ {"version":3,"file":"shader_decal_composite.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/shader_decal_composite.js"],"names":[],"mappings":"AAgEA,oDAKG;AA2SH;;;;;;;;;;;;;;GAcG;AACH,qCAFU,eAAe,CActB;6BA9V0B,qDAAqD;gCARlD,sBAAsB"}
@@ -1,5 +1,5 @@
1
- import { CAMERA_UNIFORM_STRUCT } from "../../../shade/renderer/camera/CAMERA_UNIFORM_STRUCT.js";
2
- import { VIEW_UNIFORM_STRUCT } from "../../../shade/renderer/view/VIEW_UNIFORM_STRUCT.js";
1
+ import { CAMERA_UNIFORM_STRUCT } from "../../../shade/renderer/camera/CAMERA_UNIFORM_STRUCT.js";
2
+ import { VIEW_UNIFORM_STRUCT } from "../../../shade/renderer/view/VIEW_UNIFORM_STRUCT.js";
3
3
  import { chunk_view_mip_bias } from "../../../shade/renderer/view/chunk_view_mip_bias.js";
4
4
  import { G_BUFFER_ALBEDO_FORMAT } from "../../../shade/renderer/gbuffer/G_BUFFER_ALBEDO_FORMAT.js";
5
5
  import {
@@ -35,8 +35,8 @@ import {
35
35
  } from "../../../shade/renderer/shader/chunk/texture/GRADIENT_SAMPLING_INFO_STRUCT.js";
36
36
  import { chunk_decal_sampling_info } from "./chunk_decal_sampling_info.js";
37
37
  import { chunk_decal_surface_frame } from "./chunk_decal_surface_frame.js";
38
+ import { DecalTileShader } from "./DecalTileShader.js";
38
39
  import { CodeChunk } from "../../../shade/renderer/shader/compiler/CodeChunk.js";
39
- import { ImageShader } from "../../../shade/renderer/shader/ImageShader.js";
40
40
  import {
41
41
  ShaderResourceSetDescriptor
42
42
  } from "../../../shade/renderer/shader/resource/ShaderResourceSetDescriptor.js";
@@ -75,7 +75,7 @@ const resources = new ShaderResourceSetDescriptor();
75
75
  resources.setImmediate("settings", DECAL_COMPOSITE_SETTINGS);
76
76
 
77
77
  resources.createGroup()
78
- .addUniform("camera", CAMERA_UNIFORM_STRUCT)
78
+ .addUniform("camera", CAMERA_UNIFORM_STRUCT)
79
79
  .addUniform("view", VIEW_UNIFORM_STRUCT);
80
80
 
81
81
  /*
@@ -93,7 +93,8 @@ resources.createGroup()
93
93
  resources.createGroup()
94
94
  .addStorageBuffer("decal_data", WebGPUArray.f32)
95
95
  .addStorageBuffer("cluster_lookup", WebGPUArray.from(DECAL_CLUSTER_METADATA))
96
- .addStorageBuffer("cluster_data", WebGPUArray.u32);
96
+ .addStorageBuffer("cluster_data", WebGPUArray.u32)
97
+ .addStorageBuffer("decal_tiles", WebGPUArray.u32);
97
98
 
98
99
  /*
99
100
  The three atlases are **filterable**, which is not the default a texture binding gets. Every one of
@@ -153,10 +154,11 @@ fn main(
153
154
  let old_emissive = textureLoad(gBufferEmissive, i_coord, 0).r;
154
155
 
155
156
  /*
156
- Every pixel is written, covered or not. The targets are fresh textures this pass hands
157
- downstream in place of the ones it read, so a pixel left alone here is not "unchanged" — it is
158
- undefined. Reading and writing the whole frame is the price of being able to composite exactly
159
- rather than through a blend the integer targets cannot do.
157
+ Every pixel this pass is drawn over is written, covered or not: the draw replaces what the
158
+ target held, and what it held is exactly what was read, so a pixel no decal touches is written
159
+ back unchanged. The inputs are a copy of the same texels taken by the pass before — one texture
160
+ cannot be attached and sampled at once — which is what lets the composite be exact rather than
161
+ a blend the integer targets cannot do.
160
162
  */
161
163
  var out : DecalCompositeOut;
162
164
 
@@ -179,34 +181,6 @@ fn main(
179
181
 
180
182
  let position = project_position_from_depth(uv, depth, camera.view_projection_matrix_inverse);
181
183
 
182
- let shading_normal = decode_g_buffer_normal(old_normal.xy);
183
- let face_normal = decode_g_buffer_normal(old_normal.zw);
184
-
185
- /*
186
- Screen-space world gradients, taken analytically off the surface rather than from 'dpdx'.
187
-
188
- Two reasons, and the first is that there is no choice: sampling inside a loop over a per-pixel
189
- decal list is non-uniform control flow, where WGSL forbids implicit derivatives — the same
190
- constraint that made the material pass interpolate its own from barycentrics. The second is
191
- that it is better anyway. A hardware derivative reads whatever the neighbouring pixel hit, so
192
- it lies across every silhouette; intersecting the neighbouring pixel's ray with *this* surface's
193
- plane answers the question actually being asked, which is how fast the decal's texture moves
194
- across the surface it is painted on.
195
- */
196
- let ray_here = normalize(project_position_from_depth(uv, 0.5, camera.view_projection_matrix_inverse) - camera_position);
197
- let ray_x = normalize(project_position_from_depth(uv + vec2<f32>(1.0 / resolution.x, 0.0), 0.5, camera.view_projection_matrix_inverse) - camera_position);
198
- let ray_y = normalize(project_position_from_depth(uv + vec2<f32>(0.0, 1.0 / resolution.y), 0.5, camera.view_projection_matrix_inverse) - camera_position);
199
-
200
- let plane_distance = dot(position - camera_position, face_normal);
201
-
202
- let denominator_x = dot(ray_x, face_normal);
203
- let denominator_y = dot(ray_y, face_normal);
204
-
205
- // grazing angles send these toward zero and the gradient toward infinity; the per-decal LOD
206
- // clamp is what keeps that finite, so nothing here needs to guard it
207
- let position_x = camera_position + ray_x * (plane_distance / denominator_x);
208
- let position_y = camera_position + ray_y * (plane_distance / denominator_y);
209
-
210
184
  let view_forward = -normalize(camera.view_matrix_inverse[2].xyz);
211
185
  let view_depth = dot(position - camera_position, view_forward);
212
186
 
@@ -232,10 +206,38 @@ fn main(
232
206
 
233
207
  let metadata = cluster_lookup[cluster_index];
234
208
 
209
+ // most pixels of a tile sit in a slice with no decal; they leave before any of the work below
235
210
  if (metadata.count == 0u) {
236
211
  return out;
237
212
  }
238
213
 
214
+ let shading_normal = decode_g_buffer_normal(old_normal.xy);
215
+ let face_normal = decode_g_buffer_normal(old_normal.zw);
216
+
217
+ /*
218
+ Screen-space world gradients, taken analytically off the surface rather than from 'dpdx'.
219
+
220
+ Two reasons, and the first is that there is no choice: sampling inside a loop over a per-pixel
221
+ decal list is non-uniform control flow, where WGSL forbids implicit derivatives — the same
222
+ constraint that made the material pass interpolate its own from barycentrics. The second is
223
+ that it is better anyway. A hardware derivative reads whatever the neighbouring pixel hit, so
224
+ it lies across every silhouette; intersecting the neighbouring pixel's ray with *this* surface's
225
+ plane answers the question actually being asked, which is how fast the decal's texture moves
226
+ across the surface it is painted on.
227
+ */
228
+ let ray_x = normalize(project_position_from_depth(uv + vec2<f32>(1.0 / resolution.x, 0.0), 0.5, camera.view_projection_matrix_inverse) - camera_position);
229
+ let ray_y = normalize(project_position_from_depth(uv + vec2<f32>(0.0, 1.0 / resolution.y), 0.5, camera.view_projection_matrix_inverse) - camera_position);
230
+
231
+ let plane_distance = dot(position - camera_position, face_normal);
232
+
233
+ let denominator_x = dot(ray_x, face_normal);
234
+ let denominator_y = dot(ray_y, face_normal);
235
+
236
+ // grazing angles send these toward zero and the gradient toward infinity; the per-decal LOD
237
+ // clamp is what keeps that finite, so nothing here needs to guard it
238
+ let position_x = camera_position + ray_x * (plane_distance / denominator_x);
239
+ let position_y = camera_position + ray_y * (plane_distance / denominator_y);
240
+
239
241
  let atlas_albedo_size = vec2<f32>(textureDimensions(atlas_albedo, 0));
240
242
  let atlas_normal_size = vec2<f32>(textureDimensions(atlas_normal, 0));
241
243
  let atlas_orm_size = vec2<f32>(textureDimensions(atlas_orm, 0));
@@ -246,8 +248,8 @@ fn main(
246
248
  var normal = shading_normal;
247
249
  var emissive = rgbe9995_decode(old_emissive);
248
250
 
249
- let uv_bias = view_uv_derivative_bias(view.upscale_ratio);
250
-
251
+ let uv_bias = view_uv_derivative_bias(view.upscale_ratio);
252
+
251
253
  for (var i = 0u; i < metadata.count; i++) {
252
254
  let decal_index = cluster_data[metadata.offset + i];
253
255
 
@@ -359,25 +361,27 @@ fn main(
359
361
  chunk_rgbe9995_encode,
360
362
  chunk_light_cluster_resolution_xy_from_screen,
361
363
  chunk_cluster_depth_to_z_slice,
362
- chunk_grid3d_to_index,
364
+ chunk_grid3d_to_index,
363
365
  chunk_view_mip_bias
364
366
  ]
365
367
  );
366
368
 
367
369
  /**
368
- * Reads the G-buffer, paints this frame's decals into it, and writes a new one.
370
+ * Paints this frame's decals into the G-buffer, in place, over the screen tiles that hold one.
369
371
  *
370
372
  * **Every channel is composited exactly, in registers.** Nothing is blended by hardware and nothing
371
373
  * is approximated: two of the four targets are integer formats that cannot blend at all, and the
372
374
  * previous shading normal and the ambient in the albedo's alpha both have to survive — which they
373
- * only can if the pass reads one texture and writes another (D23).
375
+ * only can if the pass reads one texture and writes another (D23). The one it reads is
376
+ * `shader_decal_tile_copy`'s copy of the same tiles, so only the covered part of the screen
377
+ * is read and written twice, rather than all of it once.
374
378
  *
375
379
  * The face normal is carried through untouched. A decal changes what a surface looks like, not which
376
380
  * way it is turned, and the face normal is what the fade and everything downstream reason about.
377
381
  *
378
- * @type {ImageShader}
382
+ * @type {DecalTileShader}
379
383
  */
380
- export const shader_decal_composite = ImageShader.from({
384
+ export const shader_decal_composite = new DecalTileShader({
381
385
  descriptor: ShaderDescriptor.from({
382
386
  label: "Decal composite",
383
387
  resources,
@@ -0,0 +1,12 @@
1
+ export const DECAL_TILE_COPY_SETTINGS: WebGPUStruct;
2
+ /**
3
+ * Copies the G-buffer under the tiles that hold a decal, so the composite can read a surface as it
4
+ * was while writing the same texels in place — one texture cannot be a render attachment and a
5
+ * sampled source in one pass, and two of the four targets are integers that cannot blend.
6
+ *
7
+ * @type {DecalTileShader}
8
+ */
9
+ export const shader_decal_tile_copy: DecalTileShader;
10
+ import { WebGPUStruct } from "../../../shade/renderer/shader/type/WebGPUStruct.js";
11
+ import { DecalTileShader } from "./DecalTileShader.js";
12
+ //# sourceMappingURL=shader_decal_tile_copy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_decal_tile_copy.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/shader_decal_tile_copy.js"],"names":[],"mappings":"AAWA,oDAEG;AA6CH;;;;;;GAMG;AACH,qCAFU,eAAe,CActB;6BArE0B,qDAAqD;gCAClD,sBAAsB"}
@@ -0,0 +1,78 @@
1
+ import { G_BUFFER_ALBEDO_FORMAT } from "../../../shade/renderer/gbuffer/G_BUFFER_ALBEDO_FORMAT.js";
2
+ import { CodeChunk } from "../../../shade/renderer/shader/compiler/CodeChunk.js";
3
+ import {
4
+ ShaderResourceSetDescriptor
5
+ } from "../../../shade/renderer/shader/resource/ShaderResourceSetDescriptor.js";
6
+ import { ShaderDescriptor } from "../../../shade/renderer/shader/ShaderDescriptor.js";
7
+ import { vec2u } from "../../../shade/renderer/shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
8
+ import { WebGPUArray } from "../../../shade/renderer/shader/type/WebGPUArray.js";
9
+ import { WebGPUStruct } from "../../../shade/renderer/shader/type/WebGPUStruct.js";
10
+ import { DecalTileShader } from "./DecalTileShader.js";
11
+
12
+ export const DECAL_TILE_COPY_SETTINGS = WebGPUStruct.from({
13
+ screen_resolution: vec2u,
14
+ });
15
+
16
+ const resources = new ShaderResourceSetDescriptor();
17
+
18
+ resources.setImmediate("settings", DECAL_TILE_COPY_SETTINGS);
19
+
20
+ resources.createGroup()
21
+ .addStorageBuffer("decal_tiles", WebGPUArray.u32);
22
+
23
+ // integer targets are read as integer textures, as the composite reads them — see its note
24
+ resources.createGroup()
25
+ .addTexture("gBufferPBR")
26
+ .addTexture("gBufferNormal", "uint")
27
+ .addTexture("gBufferAlbedo")
28
+ .addTexture("gBufferEmissive", "uint");
29
+
30
+ const body = CodeChunk.from(
31
+ //language=WGSL
32
+ `
33
+ struct DecalTileCopyOut {
34
+ @location(0) pbr : vec2<f32>,
35
+ @location(1) normal : vec4<u32>,
36
+ @location(2) albedo : vec4<f32>,
37
+ @location(3) emissive : u32,
38
+ }
39
+
40
+ @fragment
41
+ fn main(
42
+ @builtin(position) coord : vec4<f32>,
43
+ ) -> DecalTileCopyOut {
44
+ let i_coord = vec2<i32>(coord.xy);
45
+
46
+ var out : DecalTileCopyOut;
47
+
48
+ // the two unorm targets round-trip exactly: k/255 written back is k
49
+ out.pbr = textureLoad(gBufferPBR, i_coord, 0).rg;
50
+ out.normal = textureLoad(gBufferNormal, i_coord, 0);
51
+ out.albedo = textureLoad(gBufferAlbedo, i_coord, 0);
52
+ out.emissive = textureLoad(gBufferEmissive, i_coord, 0).r;
53
+
54
+ return out;
55
+ }
56
+ `
57
+ );
58
+
59
+ /**
60
+ * Copies the G-buffer under the tiles that hold a decal, so the composite can read a surface as it
61
+ * was while writing the same texels in place — one texture cannot be a render attachment and a
62
+ * sampled source in one pass, and two of the four targets are integers that cannot blend.
63
+ *
64
+ * @type {DecalTileShader}
65
+ */
66
+ export const shader_decal_tile_copy = new DecalTileShader({
67
+ descriptor: ShaderDescriptor.from({
68
+ label: "Decal tiles / copy",
69
+ resources,
70
+ body
71
+ }),
72
+ targets: [
73
+ { format: "rg8unorm" },
74
+ { format: "rgba16uint" },
75
+ { format: G_BUFFER_ALBEDO_FORMAT },
76
+ { format: "r32uint" },
77
+ ]
78
+ });
@@ -0,0 +1,11 @@
1
+ export const DECAL_TILE_GATHER_SETTINGS: WebGPUStruct;
2
+ /**
3
+ * Lists the screen tiles whose froxel column holds at least one decal — the only part of the screen
4
+ * the decal passes draw. The list's first word is its length, and is zero when the pass starts.
5
+ *
6
+ * @type {ComputeShader}
7
+ */
8
+ export const shader_gather_decal_tiles: ComputeShader;
9
+ import { WebGPUStruct } from "../../../shade/renderer/shader/type/WebGPUStruct.js";
10
+ import { ComputeShader } from "../../../shade/renderer/shader/ComputeShader.js";
11
+ //# sourceMappingURL=shader_gather_decal_tiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_gather_decal_tiles.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/shader_gather_decal_tiles.js"],"names":[],"mappings":"AAcA,sDAEG;AAqDH;;;;;GAKG;AACH,wCAFU,aAAa,CAMpB;6BApE0B,qDAAqD;8BANpD,iDAAiD"}
@@ -0,0 +1,80 @@
1
+ import {
2
+ chunk_light_cluster_resolution_xy_from_screen
3
+ } from "../../../shade/renderer/light/cluster/chunk_light_cluster_resolution_xy_from_screen.js";
4
+ import { chunk_grid3d_to_index } from "../../../shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.js";
5
+ import { CodeChunk } from "../../../shade/renderer/shader/compiler/CodeChunk.js";
6
+ import { ComputeShader } from "../../../shade/renderer/shader/ComputeShader.js";
7
+ import {
8
+ ShaderResourceSetDescriptor
9
+ } from "../../../shade/renderer/shader/resource/ShaderResourceSetDescriptor.js";
10
+ import { atomic_u32, vec2u } from "../../../shade/renderer/shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
11
+ import { WebGPUArray } from "../../../shade/renderer/shader/type/WebGPUArray.js";
12
+ import { WebGPUStruct } from "../../../shade/renderer/shader/type/WebGPUStruct.js";
13
+ import { DECAL_CLUSTER_METADATA, DECAL_CLUSTER_RESOLUTION_Z } from "./DECAL_CLUSTER.js";
14
+
15
+ export const DECAL_TILE_GATHER_SETTINGS = WebGPUStruct.from({
16
+ screen_resolution: vec2u,
17
+ });
18
+
19
+ const resources = new ShaderResourceSetDescriptor();
20
+
21
+ resources.setImmediate("settings", DECAL_TILE_GATHER_SETTINGS);
22
+
23
+ resources.createGroup()
24
+ .addStorageBuffer("cluster_lookup", WebGPUArray.from(DECAL_CLUSTER_METADATA))
25
+ .addStorageBuffer("decal_tiles", WebGPUArray.from(atomic_u32), true);
26
+
27
+ const body = CodeChunk.from(
28
+ //language=WGSL
29
+ `
30
+ @compute @workgroup_size(8, 8, 1)
31
+ fn main(
32
+ @builtin(global_invocation_id) tile : vec3<u32>
33
+ ) {
34
+ let resolution = light_cluster_resolution_xy_from_screen(settings.screen_resolution);
35
+
36
+ if (any(tile.xy >= resolution)) {
37
+ return;
38
+ }
39
+
40
+ /*
41
+ Gathered per tile, down its own column, rather than scattered by the froxels that hold a decal:
42
+ a tile is listed once however many of its slices are occupied, with no flag to clear and no
43
+ second pass to compact one.
44
+ */
45
+ var occupied = false;
46
+
47
+ for (var z = 0u; z < ${DECAL_CLUSTER_RESOLUTION_Z}u; z++) {
48
+ if (cluster_lookup[grid3d_to_index(vec3<u32>(tile.xy, z), resolution)].count > 0u) {
49
+ occupied = true;
50
+ break;
51
+ }
52
+ }
53
+
54
+ if (!occupied) {
55
+ return;
56
+ }
57
+
58
+ // the count leads the list; the list is sized for every tile, so the append cannot overrun
59
+ let slot = atomicAdd(&decal_tiles[0], 1u);
60
+
61
+ atomicStore(&decal_tiles[1u + slot], tile.x | (tile.y << 16u));
62
+ }
63
+ `,
64
+ [
65
+ chunk_light_cluster_resolution_xy_from_screen,
66
+ chunk_grid3d_to_index,
67
+ ]
68
+ );
69
+
70
+ /**
71
+ * Lists the screen tiles whose froxel column holds at least one decal — the only part of the screen
72
+ * the decal passes draw. The list's first word is its length, and is zero when the pass starts.
73
+ *
74
+ * @type {ComputeShader}
75
+ */
76
+ export const shader_gather_decal_tiles = ComputeShader.from({
77
+ label: "decal tiles / gather",
78
+ resources,
79
+ body
80
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Bits of {@link MouseEvent.buttons }, the set of buttons held during an event.
3
+ *
4
+ * NOTE: not the {@link MouseButtons } ordinals, which index a single button by {@link MouseEvent.button }
5
+ * and put the middle button before the right one. Here the right button is 2 and the middle one 4.
6
+ */
7
+ export type MouseEventButtons = number;
8
+ export namespace MouseEventButtons {
9
+ let primary: number;
10
+ let secondary: number;
11
+ let auxiliary: number;
12
+ }
13
+ //# sourceMappingURL=MouseEventButtons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MouseEventButtons.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/input/devices/mouse/MouseEventButtons.js"],"names":[],"mappings":";;;;;;gCAOU,MAAM"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Bits of {@link MouseEvent.buttons}, the set of buttons held during an event.
3
+ *
4
+ * NOTE: not the {@link MouseButtons} ordinals, which index a single button by {@link MouseEvent.button}
5
+ * and put the middle button before the right one. Here the right button is 2 and the middle one 4.
6
+ *
7
+ * @readonly
8
+ * @enum {number}
9
+ */
10
+ export const MouseEventButtons = {
11
+ /**
12
+ * usually the left button, and a touch or pen in contact
13
+ */
14
+ primary: 1,
15
+ /**
16
+ * usually the right button
17
+ */
18
+ secondary: 2,
19
+ /**
20
+ * usually the middle button or the wheel
21
+ */
22
+ auxiliary: 4,
23
+ };
@@ -1,4 +1,8 @@
1
1
  export default KeyboardCameraController;
2
+ /**
3
+ * WASD and the arrow keys move a top-down camera's orbit target across the ground, along the way the
4
+ * view is turned, at a fixed speed in world units a second.
5
+ */
2
6
  declare class KeyboardCameraController {
3
7
  /**
4
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"KeyboardCameraController.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/input/ecs/controllers/KeyboardCameraController.js"],"names":[],"mappings":";AAaA;IACI;;;;;OAKG;IACH,8BAHW;QAAC,SAAS,0BAAyB;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,+BAqG7D;IALG,gBAIgB;IAGpB;;OAEG;IACH,0CAEC;CACJ;mBAvHkB,wBAAwB"}
1
+ {"version":3,"file":"KeyboardCameraController.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/input/ecs/controllers/KeyboardCameraController.js"],"names":[],"mappings":";AAQA;;;GAGG;AACH;IACI;;;;;OAKG;IACH,8BAHW;QAAC,SAAS,0BAAyB;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,+BAkE7D;IALG,gBAIgB;IAGpB;;OAEG;IACH,0CAEC;CACJ;mBAtFkB,wBAAwB"}
@@ -1,16 +1,15 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
- import Vector2 from '../../../../core/geom/Vector2.js';
3
- import Vector3 from "../../../../core/geom/Vector3.js";
4
- import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
5
2
  import Script from '../../../ecs/components/Script.js';
6
3
  import { SerializationMetadata } from "../../../ecs/components/SerializationMetadata.js";
7
4
  import { Tag } from "../../../ecs/components/Tag.js";
8
5
  import Entity from '../../../ecs/Entity.js';
9
- import { Transform64 } from "../../../ecs/transform/Transform64.js";
6
+ import { top_down_truck_on_ground } from "../../../graphics/ecs/camera/topdown/TopDownCameraController.js";
10
7
  import InputController from '../components/InputController.js';
11
8
 
12
- const v3 = new Vector3();
13
-
9
+ /**
10
+ * WASD and the arrow keys move a top-down camera's orbit target across the ground, along the way the
11
+ * view is turned, at a fixed speed in world units a second.
12
+ */
14
13
  class KeyboardCameraController {
15
14
  /**
16
15
  *
@@ -23,8 +22,6 @@ class KeyboardCameraController {
23
22
 
24
23
  assert.notEqual(controller, undefined, 'controller is undefined');
25
24
 
26
- const cameraPanSpeed = new Vector2(0, 0);
27
-
28
25
  const controls = {
29
26
  panUp: false,
30
27
  panDown: false,
@@ -70,43 +67,10 @@ class KeyboardCameraController {
70
67
  inputController.on.unlinked.add(clearControls);
71
68
 
72
69
  const script = new Script(function (timeDelta) {
73
- cameraPanSpeed.set(0, 0);
74
-
75
- if (controls.panDown) {
76
- cameraPanSpeed.y += 1;
77
- }
78
- if (controls.panUp) {
79
- cameraPanSpeed.y -= 1;
80
- }
81
- if (controls.panLeft) {
82
- cameraPanSpeed.x -= 1;
83
- }
84
- if (controls.panRight) {
85
- cameraPanSpeed.x += 1;
86
- }
87
-
88
- if (cameraPanSpeed.isZero()) {
89
- // not panning
90
- return;
91
- }
92
-
93
- const displacement = cameraPanSpeed.clone().multiplyScalar(keyboardPanSpeed * timeDelta);
94
-
95
- const camera_transform = ecd.getComponent(cameraController.entity, Transform64);
96
-
97
- // by component: a Transform64's `rotation` is four numbers in an array, and
98
- // `applyQuaternion` reads `.x` off what it is given
99
- v3_quaternion_apply(
100
- v3, 0,
101
- -displacement.x, 0, -displacement.y,
102
- camera_transform.rotation_x,
103
- camera_transform.rotation_y,
104
- camera_transform.rotation_z,
105
- camera_transform.rotation_w
106
- );
107
-
108
-
109
- controller.target.add(v3);
70
+ const right = (controls.panRight ? 1 : 0) - (controls.panLeft ? 1 : 0);
71
+ const forward = (controls.panUp ? 1 : 0) - (controls.panDown ? 1 : 0);
72
+
73
+ top_down_truck_on_ground(controller, right, forward, keyboardPanSpeed * timeDelta);
110
74
  });
111
75
 
112
76
  const builder = new Entity();
@@ -66,11 +66,11 @@ export class FluidObstacleSystem extends System<any> {
66
66
  /**
67
67
  * @param {FluidComponent} fluid
68
68
  */
69
- static "__#478@#refresh_masks"(fluid: FluidComponent): void;
69
+ static "__#481@#refresh_masks"(fluid: FluidComponent): void;
70
70
  /**
71
71
  * @param {FluidComponent} fluid
72
72
  */
73
- static "__#478@#clear_field"(fluid: FluidComponent): void;
73
+ static "__#481@#clear_field"(fluid: FluidComponent): void;
74
74
  /**
75
75
  * Mark every cell of `fluid` whose centre lies within `inflation` of the
76
76
  * posed shape as solid. Iteration is clipped to the shape's world AABB
@@ -82,7 +82,7 @@ export class FluidObstacleSystem extends System<any> {
82
82
  * @param {number} inflation world-units SDF threshold
83
83
  * @param {Float64Array} point length-3 scratch
84
84
  */
85
- static "__#478@#voxelize"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array): void;
85
+ static "__#481@#voxelize"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array): void;
86
86
  /**
87
87
  * Write the obstacle's translation velocity onto every face of every cell
88
88
  * it voxelized — the moving-wall boundary condition. Runs AFTER the mask
@@ -102,7 +102,7 @@ export class FluidObstacleSystem extends System<any> {
102
102
  * @param {number} wvy
103
103
  * @param {number} wvz
104
104
  */
105
- static "__#478@#stamp_wall_velocity"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array, wvx: number, wvy: number, wvz: number): void;
105
+ static "__#481@#stamp_wall_velocity"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array, wvx: number, wvy: number, wvz: number): void;
106
106
  constructor();
107
107
  dependencies: (typeof FluidObstacle)[];
108
108
  components_used: (ResourceAccessSpecification<typeof Transform64> | ResourceAccessSpecification<typeof FluidObstacle> | ResourceAccessSpecification<typeof Collider> | ResourceAccessSpecification<typeof RigidBody> | ResourceAccessSpecification<typeof FluidComponent>)[];