@woosh/meep-engine 3.43.0 → 3.44.0

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 (287) hide show
  1. package/editor/prototypeEditorShell.d.ts.map +1 -1
  2. package/editor/prototypeEditorShell.js +4 -2
  3. package/package.json +1 -1
  4. package/src/engine/Clock.d.ts +15 -0
  5. package/src/engine/Clock.d.ts.map +1 -1
  6. package/src/engine/Clock.js +29 -5
  7. package/src/engine/Engine.d.ts.map +1 -1
  8. package/src/engine/Engine.js +11 -19
  9. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts +57 -0
  10. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts.map +1 -0
  11. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.js +84 -0
  12. package/src/engine/graphics3/AnimationGraphSystem.d.ts +23 -13
  13. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  14. package/src/engine/graphics3/AnimationGraphSystem.js +61 -64
  15. package/src/engine/graphics3/AnimationSystem.d.ts +24 -15
  16. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  17. package/src/engine/graphics3/AnimationSystem.js +67 -61
  18. package/src/engine/graphics3/MeshSkinSystem.d.ts +56 -0
  19. package/src/engine/graphics3/MeshSkinSystem.d.ts.map +1 -0
  20. package/src/engine/graphics3/MeshSkinSystem.js +317 -0
  21. package/src/engine/graphics3/MeshSystem.d.ts +15 -35
  22. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  23. package/src/engine/graphics3/MeshSystem.js +21 -298
  24. package/src/engine/graphics3/RowChains.d.ts +76 -0
  25. package/src/engine/graphics3/RowChains.d.ts.map +1 -0
  26. package/src/engine/graphics3/RowChains.js +347 -0
  27. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +6 -0
  28. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  29. package/src/engine/graphics3/ShadedGeometrySystem.js +329 -309
  30. package/src/engine/graphics3/animation/AnimationClips.d.ts +56 -0
  31. package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -0
  32. package/src/engine/graphics3/animation/AnimationClips.js +79 -0
  33. package/src/engine/graphics3/animation/ClipListPlayer.d.ts +13 -14
  34. package/src/engine/graphics3/animation/ClipListPlayer.d.ts.map +1 -1
  35. package/src/engine/graphics3/animation/ClipListPlayer.js +262 -263
  36. package/src/engine/graphics3/animation/write_clip_playback.d.ts +3 -3
  37. package/src/engine/graphics3/animation/write_clip_playback.js +4 -4
  38. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +5 -0
  39. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  40. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +80 -75
  41. package/src/engine/graphics3/prefab/PrefabInstance.d.ts +4 -24
  42. package/src/engine/graphics3/prefab/PrefabInstance.d.ts.map +1 -1
  43. package/src/engine/graphics3/prefab/PrefabInstance.js +60 -80
  44. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts +16 -3
  45. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -1
  46. package/src/engine/graphics3/prefab/prefab_instantiate.js +49 -12
  47. package/src/engine/graphics3/prefab/prefab_place.d.ts +31 -17
  48. package/src/engine/graphics3/prefab/prefab_place.d.ts.map +1 -1
  49. package/src/engine/graphics3/prefab/prefab_place.js +175 -130
  50. package/src/engine/graphics3/register_clips.d.ts +64 -0
  51. package/src/engine/graphics3/register_clips.d.ts.map +1 -0
  52. package/src/engine/graphics3/register_clips.js +114 -0
  53. package/src/engine/physics/cloth/MEASUREMENTS.md +795 -0
  54. package/src/engine/physics/cloth/PLAN.md +339 -9
  55. package/src/engine/physics/cloth/build/ClothProxy.d.ts +113 -61
  56. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -1
  57. package/src/engine/physics/cloth/build/ClothProxy.js +142 -77
  58. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +22 -0
  59. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +75 -0
  61. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +43 -30
  62. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  63. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +357 -284
  64. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts +62 -0
  65. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +280 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +1 -1
  68. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +1 -1
  69. package/src/engine/physics/cloth/ecs/Cloth.d.ts +17 -9
  70. package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
  71. package/src/engine/physics/cloth/ecs/Cloth.js +220 -212
  72. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +6 -0
  73. package/src/engine/physics/cloth/ecs/ClothHold.d.ts +91 -0
  74. package/src/engine/physics/cloth/ecs/ClothHold.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/ecs/ClothHold.js +103 -0
  76. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +254 -48
  77. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  78. package/src/engine/physics/cloth/ecs/ClothInstance.js +277 -47
  79. package/src/engine/physics/cloth/ecs/ClothPin.d.ts +73 -0
  80. package/src/engine/physics/cloth/ecs/ClothPin.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothPin.js +92 -0
  82. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts +36 -0
  83. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.js +61 -0
  85. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +23 -17
  86. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -1
  87. package/src/engine/physics/cloth/ecs/ClothRig.js +29 -27
  88. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +12 -14
  89. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  90. package/src/engine/physics/cloth/ecs/ClothSystem.js +20 -15
  91. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +57 -36
  92. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  93. package/src/engine/physics/cloth/ecs/ClothWorld.js +816 -179
  94. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +12 -13
  95. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  96. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +20 -14
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +63 -11
  98. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  99. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +321 -84
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +9 -7
  101. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  102. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +9 -7
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +3 -3
  104. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +30 -30
  105. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +37 -0
  106. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -0
  107. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +142 -0
  108. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts +97 -0
  109. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -0
  110. package/src/engine/physics/cloth/ecs/cloth_holds.js +608 -0
  111. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +2 -2
  112. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
  113. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +160 -9
  114. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +17 -22
  115. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  116. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +55 -117
  117. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -6
  118. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  119. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +44 -15
  120. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +5 -0
  121. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  122. package/src/engine/physics/cloth/ecs/cloth_write_back.js +60 -16
  123. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -1
  124. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +65 -58
  125. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  126. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -1
  127. package/src/engine/physics/cloth/playground/garment_build.js +17 -5
  128. package/src/engine/physics/cloth/playground/garment_main.js +1 -1
  129. package/src/engine/physics/cloth/playground/rig_build.d.ts.map +1 -1
  130. package/src/engine/physics/cloth/playground/rig_build.js +302 -296
  131. package/src/engine/physics/cloth/solver/ClothState.d.ts +45 -7
  132. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  133. package/src/engine/physics/cloth/solver/ClothState.js +63 -7
  134. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +6 -1
  135. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/cloth_contact_find.js +7 -2
  137. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts +114 -0
  138. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_hold_line.js +362 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +6 -2
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +13 -13
  143. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +24 -12
  144. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +24 -12
  146. package/src/engine/physics/cloth/solver/cloth_step.d.ts +16 -0
  147. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_step.js +183 -20
  149. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +1 -0
  150. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step_instance.js +10 -3
  152. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts +1 -1
  153. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts.map +1 -1
  154. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.js +353 -346
  155. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +7 -5
  156. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -1
  157. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +7 -5
  158. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +9 -9
  159. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  160. package/src/engine/physics/cloth/wind/cloth_sample_air.js +26 -26
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/engine/simulation/Ticker.d.ts +13 -0
  163. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  164. package/src/engine/simulation/Ticker.js +43 -8
  165. package/src/shade/RENDERER_CONTRACT.md +8 -2
  166. package/src/shade/playground/mesh_row_ceiling/main.js +2 -1
  167. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  168. package/src/shade/playground/skinned_blas_refit/main.js +11 -19
  169. package/src/shade/playground/skinned_blas_refit/place_character.d.ts +6 -3
  170. package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -1
  171. package/src/shade/playground/skinned_blas_refit/place_character.js +90 -90
  172. package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
  173. package/src/shade/playground/skinned_mesh_soup/main.js +502 -509
  174. package/src/shade/playground/texture_encode/README.md +129 -109
  175. package/src/shade/playground/texture_encode/main.js +1430 -1430
  176. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +45 -14
  177. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  178. package/src/shade/renderer/animation/GPUAnimationManager.js +316 -64
  179. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +5 -0
  180. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  181. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -1
  182. package/src/shade/renderer/geometry/BoxGeometry.d.ts +1 -11
  183. package/src/shade/renderer/geometry/BoxGeometry.d.ts.map +1 -1
  184. package/src/shade/renderer/geometry/BoxGeometry.js +6 -13
  185. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts +19 -0
  186. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts.map +1 -0
  187. package/src/shade/renderer/geometry/CapsuleGeometry.js +24 -0
  188. package/src/shade/renderer/geometry/ConeGeometry.d.ts +20 -0
  189. package/src/shade/renderer/geometry/ConeGeometry.d.ts.map +1 -0
  190. package/src/shade/renderer/geometry/ConeGeometry.js +33 -0
  191. package/src/shade/renderer/geometry/CylinderGeometry.d.ts +21 -0
  192. package/src/shade/renderer/geometry/CylinderGeometry.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/CylinderGeometry.js +35 -0
  194. package/src/shade/renderer/geometry/PlaneGeometry.d.ts +17 -0
  195. package/src/shade/renderer/geometry/PlaneGeometry.d.ts.map +1 -0
  196. package/src/shade/renderer/geometry/PlaneGeometry.js +22 -0
  197. package/src/shade/renderer/geometry/TorusGeometry.d.ts +18 -0
  198. package/src/shade/renderer/geometry/TorusGeometry.d.ts.map +1 -0
  199. package/src/shade/renderer/geometry/TorusGeometry.js +23 -0
  200. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts +21 -0
  201. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts.map +1 -0
  202. package/src/shade/renderer/geometry/UVSphereGeometry.js +34 -0
  203. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts +19 -0
  204. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts.map +1 -0
  205. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.js +205 -0
  206. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts +21 -0
  207. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts.map +1 -0
  208. package/src/shade/renderer/geometry/primitives/make_cone_geometry.js +36 -0
  209. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts +1 -1
  210. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts.map +1 -1
  211. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +44 -9
  212. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts +20 -0
  213. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts.map +1 -0
  214. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.js +190 -0
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -2
  217. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +26 -8
  218. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
  219. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +56 -39
  220. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts +7 -0
  221. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts.map +1 -1
  222. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js +46 -4
  223. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.d.ts.map +1 -1
  224. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.js +4 -2
  225. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +2 -2
  226. package/src/shade/renderer/gpu_primitive/sort/defs.js +79 -79
  227. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +1 -1
  228. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
  229. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +7 -3
  230. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  231. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +4 -3
  232. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
  233. package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +200 -194
  234. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  235. package/src/shade/renderer/particles/graph_particles.js +6 -2
  236. package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -1
  237. package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +334 -329
  238. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  239. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +7 -2
  240. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  241. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +16 -4
  242. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +2444 -2345
  243. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.d.ts.map +1 -1
  244. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.js +312 -310
  245. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts +3 -3
  246. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts.map +1 -1
  247. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.js +383 -375
  248. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.d.ts.map +1 -1
  249. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.js +349 -346
  250. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts +58 -0
  251. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts.map +1 -0
  252. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.js +536 -0
  253. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts +21 -7
  254. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts.map +1 -1
  255. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.js +291 -327
  256. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts +25 -0
  257. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts.map +1 -0
  258. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.js +99 -0
  259. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts +5 -3
  260. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts.map +1 -1
  261. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.js +47 -71
  262. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts +10 -0
  263. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts.map +1 -0
  264. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.js +50 -0
  265. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts +4 -5
  266. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
  267. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +7 -8
  268. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
  269. package/src/shade/renderer/water/chunk_water_transport.js +7 -5
  270. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  271. package/src/shade/renderer/water/medium/GPUWaterBodies.js +8 -2
  272. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts +3 -2
  273. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
  274. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +3 -2
  275. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  276. package/src/shade/renderer/water/shader_water.js +3 -1
  277. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -1
  278. package/src/shade/renderer/water/surface/GPUWaterSurface.js +3 -1
  279. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
  280. package/src/shade/renderer/water/surface/graph_water_tessellation.js +11 -4
  281. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  282. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +37 -20
  283. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  284. package/src/shade/wgsl/validate_wgsl_source.js +74 -3
  285. package/src/engine/graphics3/register_instance_animation.d.ts +0 -114
  286. package/src/engine/graphics3/register_instance_animation.d.ts.map +0 -1
  287. package/src/engine/graphics3/register_instance_animation.js +0 -201
@@ -1,329 +1,334 @@
1
- import { assert } from "../../../../core/assert.js";
2
- import { align_4 } from "../../../../core/binary/align_4.js";
3
- import { BufferResourceDescriptor } from "../../../device/graph/BufferResourceDescriptor.js";
4
- import { INDIRECT_COMPUTE_COMMAND_DESCRIPTOR } from "../../gpu_primitive/indirect/IndirectComputeCommandBuildPass.js";
5
- import { graph_prefix_scan_csdldf } from "../../gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js";
6
- import { PREFIX_SCAN_CSDLDF_HEADER_WORDS } from "../../gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js";
7
- import { shader_prefix_sum_to_command } from "../../rasterize/expand/mesh/shader_prefix_sum_to_command.js";
8
- import { graph_compute_indirect_pass } from "../../shader/graph/compute/graph_compute_indirect_pass.js";
9
- import { graph_compute_pass } from "../../shader/graph/compute/graph_compute_pass.js";
10
- import { graph_create_buffer } from "../../shader/graph/graph_create_buffer.js";
11
- import { graph_import_buffer } from "../../shader/graph/graph_import_buffer.js";
12
- import { PARTICLE_RECORD_WORD_COUNT, PARTICLE_WARMUP_WORKGROUP_SIZE } from "../ParticleConstants.js";
13
- import { PARTICLE_COUNTER_COUNT } from "../data/PARTICLE_COUNTERS.js";
14
- import { shader_particle_emit } from "../shaders/shader_particle_emit.js";
15
- import {
16
- PARTICLE_EMIT_WIDE_WORKGROUP_COUNT,
17
- shader_particle_emit_wide,
18
- } from "../shaders/shader_particle_emit_wide.js";
19
- import {
20
- PARTICLE_WARMUP_WORKGROUP_COUNT,
21
- shader_particle_warmup_init,
22
- shader_particle_warmup_migrate,
23
- shader_particle_warmup_reset,
24
- shader_particle_warmup_tick,
25
- } from "./shader_particle_warmup.js";
26
- import { shader_particle_warmup_advance } from "./shader_particle_warmup_advance.js";
27
- import { shader_particle_warmup_advance_wide } from "./shader_particle_warmup_advance_wide.js";
28
- import { warmup_remaining } from "./warmup_schedule.js";
29
-
30
- /**
31
- * Run a batch of newly added emitters' simulations forward before they are first shown, so that a
32
- * continuous effect arrives at its steady state instead of growing into it in front of the player.
33
- *
34
- * ## What a warm-up is
35
- *
36
- * The ordinary loop — spawn, init, advance — run over a population of its own until every emitter
37
- * in the batch has been running for its `prewarm`. It is not a batch of particles dumped in one
38
- * tick and aged: an emitter keeps spawning throughout, the ones that die are replaced the way they
39
- * are in a live scene, and whatever drives the rate (a curve, `EMITTER_AGE`, the program itself)
40
- * drives it here, because it is the same program being run. What the loop leaves is the population
41
- * the emitter would have had, moved into the main pool.
42
- *
43
- * ## Why it is a pipeline of its own
44
- *
45
- * Because the main one is tuned and it must not pay for this. Emit and simulate are the passes whose
46
- * register pressure sets the system's occupancy, and their waves are kept program-uniform by the
47
- * bucketing; a warm-up folded into either would spend registers on every frame for work that
48
- * happens on one, and a loop inside a lane would break the uniform flow across a wave. So this
49
- * shares code with the main frame and integrates nothing into it: the emit pass is reused unchanged
50
- * over the warm-up's buffers, the advance is a pass of the warm-up's own (`./chunk_particle_warmup_step.js`
51
- * says why), and the main passes' compiled code is byte-identical whether this file exists or not.
52
- *
53
- * ## The population is transient
54
- *
55
- * Pool, alive lists, free list and counters are graph transients that exist for this frame's loop
56
- * and are then moved — record by record — into the main pool by the migrate pass. That is what keeps
57
- * the separation clean: the loop's free-list traffic never touches the main free list, the main
58
- * passes never see a half-warmed particle, and the one point of contact is a pass that pops from the
59
- * main pool and pushes nothing back.
60
- *
61
- * ## Bounded
62
- *
63
- * The tick count is at most `PARTICLE_WARMUP_MAX_TICKS`, with the tick length stretched to cover the
64
- * longest pre-warm in the batch (`./warmup_schedule.js`), so the frame that pays for a warm-up pays
65
- * for a known number of dispatches whatever was asked. Per tick: reset, tick, the scan, the emit
66
- * command, emit, advance — six or seven passes, all sized by constants or by the scan.
67
- *
68
- * ## Where it sits in the frame
69
- *
70
- * After the frame's own emit and simulate, before the bucketing. Migrate appends to the same alive
71
- * list they did, so the bucketing puts the warmed particles in next frame's simulate list, the bounds
72
- * pass measures them into their emitter's box this frame, and the draw draws them this frame. Which
73
- * is also what closes the culling fixed point the bounds passes describe: an emitter that arrives
74
- * with a warmed population is measured on its first frame, whatever the frustum thinks of its origin.
75
- *
76
- * Recorded only on a frame with something queued. The host knows: an emitter is queued when it is
77
- * registered with a `prewarm`, and the queue is consumed by the frame that records it.
78
- *
79
- * @param {object} params
80
- * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} params.graph
81
- * @param {number} params.scene_database graph handle
82
- * @param {number} params.emitter_database graph handle, threaded: the warm-up tick writes ages
83
- * @param {number} params.program graph handle of the packed program buffer
84
- * @param {number} params.pool main pool, threaded
85
- * @param {number} params.alive_out main alive list, threaded
86
- * @param {number} params.dead main free list, threaded
87
- * @param {number} params.counters main counters, threaded
88
- * @param {number} params.vm_registers the wide register file's handle, or -1 when the system is on
89
- * the fast file
90
- * @param {GPUBuffer} params.queue the host's queue buffer, `PARTICLE_WARMUP_QUEUE_WORDS` per entry
91
- * @param {number} params.queue_count entries in the queue
92
- * @param {number} params.warm_capacity slots in the transient pool
93
- * @param {number} params.capacity main pool capacity
94
- * @param {number} params.emitter_capacity element capacity of the emitter table
95
- * @param {import("./warmup_schedule.js").WarmupSchedule} params.schedule
96
- * @param {boolean} params.wide_registers
97
- * @param {object} params.frame
98
- * @param {number} params.frame.time the frame's clock — the loop counts down to it
99
- * @param {number} params.frame.index
100
- * @returns {{pool: number, alive_out: number, dead: number, counters: number, emitter_database: number, vm_registers: number}}
101
- */
102
- export function graph_particle_warmup({
103
- graph,
104
- scene_database,
105
- emitter_database,
106
- program,
107
- pool,
108
- alive_out,
109
- dead,
110
- counters,
111
- vm_registers,
112
- queue,
113
- queue_count,
114
- warm_capacity,
115
- capacity,
116
- emitter_capacity,
117
- schedule,
118
- wide_registers,
119
- frame,
120
- }) {
121
- assert.defined(graph, "graph");
122
- assert.isPositiveInteger(queue_count, "queue_count");
123
- assert.isPositiveInteger(warm_capacity, "warm_capacity");
124
- assert.isPositiveInteger(schedule.ticks, "schedule.ticks");
125
-
126
- const WORD = Uint32Array.BYTES_PER_ELEMENT;
127
- const STORAGE = GPUBufferUsage.STORAGE;
128
-
129
- const gr_queue = graph_import_buffer(graph, queue, "particles/warmup/queue");
130
-
131
- // The transient population. Uncleared where the init pass writes every word that will be read
132
- // (the free list), cleared where a word could be read before it is written (the counters, and
133
- // the alive lists' tails are bounded by counts the passes wrote).
134
- // Threaded like everything a pass writes: emit and advance both rename it, and the next reader
135
- // must take the renamed handle or the graph's validator rejects the frame as reading a stale
136
- // version.
137
- let warm_pool = graph_create_buffer(graph, "particles/warmup/pool", BufferResourceDescriptor.from(
138
- warm_capacity * PARTICLE_RECORD_WORD_COUNT * WORD, STORAGE,
139
- ));
140
- const warm_alive = [
141
- graph_create_buffer(graph, "particles/warmup/alive_a", BufferResourceDescriptor.from(warm_capacity * WORD, STORAGE)),
142
- graph_create_buffer(graph, "particles/warmup/alive_b", BufferResourceDescriptor.from(warm_capacity * WORD, STORAGE)),
143
- ];
144
- let warm_dead = graph_create_buffer(graph, "particles/warmup/dead", BufferResourceDescriptor.from(warm_capacity * WORD, STORAGE));
145
- let warm_counters = graph_create_buffer(graph, "particles/warmup/counters", BufferResourceDescriptor.empty(
146
- PARTICLE_COUNTER_COUNT * WORD, STORAGE | GPUBufferUsage.COPY_DST,
147
- ));
148
-
149
- // Every slot onto the free list.
150
- {
151
- const out = graph_compute_pass({
152
- graph,
153
- shader: shader_particle_warmup_init,
154
- bindings: { dead: warm_dead, counters: warm_counters, u_capacity: warm_capacity },
155
- group_count: [Math.ceil(warm_capacity / PARTICLE_WARMUP_WORKGROUP_SIZE), 1, 1],
156
- });
157
- warm_dead = out.dead;
158
- warm_counters = out.counters;
159
- }
160
-
161
- const count_words = PREFIX_SCAN_CSDLDF_HEADER_WORDS + align_4(Math.max(1, emitter_capacity));
162
- const count_bytes = count_words * WORD;
163
-
164
- let gr_queue_rw = gr_queue;
165
-
166
- for (let tick = 0; tick < schedule.ticks; tick++) {
167
- const remaining = warmup_remaining(schedule, tick);
168
- // The clock at the start of this tick: the frame's, less what is still to run.
169
- const time = frame.time - remaining;
170
- // Distinct per tick, and unlike any frame index the main emit will seed with, so a warmed
171
- // particle's random stream is not a later particle's in the same slot.
172
- const frame_index = (frame.index ^ Math.imul(tick + 1, 0x9e3779b9)) >>> 0;
173
-
174
- // Last tick's survivors are this tick's input; this tick appends to the other list.
175
- const alive_in = warm_alive[(tick + 1) % 2];
176
- let alive_this = warm_alive[tick % 2];
177
-
178
- // 1. Roll the counters: alive -> alive_in, alive = 0, budget = dead.
179
- warm_counters = graph_compute_pass({
180
- graph,
181
- shader: shader_particle_warmup_reset,
182
- bindings: { counters: warm_counters },
183
- group_count: [1, 1, 1],
184
- }).counters;
185
-
186
- // 2. The spawn decision, per queued emitter, into a count list as long as the emitter table.
187
- // Cleared whole: the tick writes only the queued rows.
188
- let spawn_counts = graph_create_buffer(graph, "particles/warmup/spawn_counts", BufferResourceDescriptor.from(
189
- count_bytes, STORAGE, 0, count_bytes,
190
- ));
191
-
192
- {
193
- const out = graph_compute_pass({
194
- graph,
195
- shader: shader_particle_warmup_tick,
196
- bindings: {
197
- queue: gr_queue_rw,
198
- emitter_database,
199
- counters: warm_counters,
200
- spawn_counts,
201
- settings: {
202
- u_dt: schedule.dt,
203
- u_remaining: remaining,
204
- u_capacity: warm_capacity,
205
- u_emitter_capacity: emitter_capacity,
206
- u_count: queue_count,
207
- },
208
- },
209
- group_count: [Math.ceil(queue_count / PARTICLE_WARMUP_WORKGROUP_SIZE), 1, 1],
210
- });
211
- gr_queue_rw = out.queue;
212
- emitter_database = out.emitter_database;
213
- warm_counters = out.counters;
214
- spawn_counts = out.spawn_counts;
215
- }
216
-
217
- // 3. Scan the counts; the last sum is the tick's newborn count.
218
- const spawn_prefix = graph_prefix_scan_csdldf({
219
- graph,
220
- data: spawn_counts,
221
- element_max_count: Math.max(1, emitter_capacity),
222
- });
223
-
224
- // 4. That total as the emit dispatch — for the fast emit; the wide one reads the total as a
225
- // loop bound instead, as it does in the main frame.
226
- const emit_command = graph_compute_pass({
227
- graph,
228
- shader: shader_prefix_sum_to_command,
229
- bindings: {
230
- prefix_sums: spawn_prefix,
231
- command: graph_create_buffer(graph, "particles/warmup/emit_command", INDIRECT_COMPUTE_COMMAND_DESCRIPTOR),
232
- },
233
- group_count: [1, 1, 1],
234
- }).command;
235
-
236
- // 5. Emit — the main pass, unchanged, over the warm-up's buffers. It finds each newborn's
237
- // emitter in the scan, reads the record and the age off the main database, pops the
238
- // transient free list and appends to the transient alive list.
239
- {
240
- const bindings = {
241
- scene_database,
242
- emitter_database,
243
- program,
244
- spawn_prefix,
245
- pool: warm_pool, alive_out: alive_this, dead: warm_dead, counters: warm_counters,
246
- settings: { u_dt: schedule.dt, u_time: time, u_frame: frame_index, u_capacity: warm_capacity },
247
- };
248
-
249
- const out = wide_registers
250
- ? graph_compute_pass({
251
- graph,
252
- shader: shader_particle_emit_wide,
253
- bindings: { ...bindings, vm_registers },
254
- group_count: [PARTICLE_EMIT_WIDE_WORKGROUP_COUNT, 1, 1],
255
- })
256
- : graph_compute_indirect_pass({
257
- graph,
258
- shader: shader_particle_emit,
259
- bindings,
260
- command: emit_command,
261
- });
262
-
263
- warm_pool = out.pool;
264
- alive_this = out.alive_out;
265
- warm_dead = out.dead;
266
- warm_counters = out.counters;
267
-
268
- if (wide_registers) { vm_registers = out.vm_registers; }
269
- }
270
-
271
- // 6. Advance last tick's survivors by one tick, into the same list the newborns went to.
272
- {
273
- const bindings = {
274
- scene_database,
275
- emitter_database,
276
- program,
277
- pool: warm_pool, alive_in, alive_out: alive_this, dead: warm_dead, counters: warm_counters,
278
- settings: { u_dt: schedule.dt, u_time: time, u_frame: frame_index },
279
- };
280
-
281
- const out = wide_registers
282
- ? graph_compute_pass({
283
- graph,
284
- shader: shader_particle_warmup_advance_wide,
285
- bindings: { ...bindings, vm_registers },
286
- group_count: [PARTICLE_WARMUP_WORKGROUP_COUNT, 1, 1],
287
- })
288
- : graph_compute_pass({
289
- graph,
290
- shader: shader_particle_warmup_advance,
291
- bindings,
292
- group_count: [PARTICLE_WARMUP_WORKGROUP_COUNT, 1, 1],
293
- });
294
-
295
- warm_pool = out.pool;
296
- alive_this = out.alive_out;
297
- warm_dead = out.dead;
298
- warm_counters = out.counters;
299
-
300
- if (wide_registers) { vm_registers = out.vm_registers; }
301
- }
302
-
303
- warm_alive[tick % 2] = alive_this;
304
- }
305
-
306
- // 7. The population is the scene's: every survivor into a main-pool slot, onto the main alive
307
- // list.
308
- {
309
- const out = graph_compute_pass({
310
- graph,
311
- shader: shader_particle_warmup_migrate,
312
- bindings: {
313
- warm_pool,
314
- warm_alive: warm_alive[(schedule.ticks - 1) % 2],
315
- warm_counters,
316
- pool, alive_out, dead, counters,
317
- u_capacity: capacity,
318
- },
319
- group_count: [PARTICLE_WARMUP_WORKGROUP_COUNT, 1, 1],
320
- });
321
-
322
- pool = out.pool;
323
- alive_out = out.alive_out;
324
- dead = out.dead;
325
- counters = out.counters;
326
- }
327
-
328
- return { pool, alive_out, dead, counters, emitter_database, vm_registers };
329
- }
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { align_4 } from "../../../../core/binary/align_4.js";
3
+ import { BufferResourceDescriptor } from "../../../device/graph/BufferResourceDescriptor.js";
4
+ import { INDIRECT_COMPUTE_COMMAND_DESCRIPTOR } from "../../gpu_primitive/indirect/IndirectComputeCommandBuildPass.js";
5
+ import {
6
+ graph_prefix_scan_csdldf,
7
+ prefix_scan_csdldf_output_descriptor
8
+ } from "../../gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js";
9
+ import { PREFIX_SCAN_CSDLDF_HEADER_WORDS } from "../../gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js";
10
+ import { shader_prefix_sum_to_command } from "../../rasterize/expand/mesh/shader_prefix_sum_to_command.js";
11
+ import { graph_compute_indirect_pass } from "../../shader/graph/compute/graph_compute_indirect_pass.js";
12
+ import { graph_compute_pass } from "../../shader/graph/compute/graph_compute_pass.js";
13
+ import { graph_create_buffer } from "../../shader/graph/graph_create_buffer.js";
14
+ import { graph_import_buffer } from "../../shader/graph/graph_import_buffer.js";
15
+ import { PARTICLE_RECORD_WORD_COUNT, PARTICLE_WARMUP_WORKGROUP_SIZE } from "../ParticleConstants.js";
16
+ import { PARTICLE_COUNTER_COUNT } from "../data/PARTICLE_COUNTERS.js";
17
+ import { shader_particle_emit } from "../shaders/shader_particle_emit.js";
18
+ import {
19
+ PARTICLE_EMIT_WIDE_WORKGROUP_COUNT,
20
+ shader_particle_emit_wide,
21
+ } from "../shaders/shader_particle_emit_wide.js";
22
+ import {
23
+ PARTICLE_WARMUP_WORKGROUP_COUNT,
24
+ shader_particle_warmup_init,
25
+ shader_particle_warmup_migrate,
26
+ shader_particle_warmup_reset,
27
+ shader_particle_warmup_tick,
28
+ } from "./shader_particle_warmup.js";
29
+ import { shader_particle_warmup_advance } from "./shader_particle_warmup_advance.js";
30
+ import { shader_particle_warmup_advance_wide } from "./shader_particle_warmup_advance_wide.js";
31
+ import { warmup_remaining } from "./warmup_schedule.js";
32
+
33
+ /**
34
+ * Run a batch of newly added emitters' simulations forward before they are first shown, so that a
35
+ * continuous effect arrives at its steady state instead of growing into it in front of the player.
36
+ *
37
+ * ## What a warm-up is
38
+ *
39
+ * The ordinary loop — spawn, init, advance — run over a population of its own until every emitter
40
+ * in the batch has been running for its `prewarm`. It is not a batch of particles dumped in one
41
+ * tick and aged: an emitter keeps spawning throughout, the ones that die are replaced the way they
42
+ * are in a live scene, and whatever drives the rate (a curve, `EMITTER_AGE`, the program itself)
43
+ * drives it here, because it is the same program being run. What the loop leaves is the population
44
+ * the emitter would have had, moved into the main pool.
45
+ *
46
+ * ## Why it is a pipeline of its own
47
+ *
48
+ * Because the main one is tuned and it must not pay for this. Emit and simulate are the passes whose
49
+ * register pressure sets the system's occupancy, and their waves are kept program-uniform by the
50
+ * bucketing; a warm-up folded into either would spend registers on every frame for work that
51
+ * happens on one, and a loop inside a lane would break the uniform flow across a wave. So this
52
+ * shares code with the main frame and integrates nothing into it: the emit pass is reused unchanged
53
+ * over the warm-up's buffers, the advance is a pass of the warm-up's own (`./chunk_particle_warmup_step.js`
54
+ * says why), and the main passes' compiled code is byte-identical whether this file exists or not.
55
+ *
56
+ * ## The population is transient
57
+ *
58
+ * Pool, alive lists, free list and counters are graph transients that exist for this frame's loop
59
+ * and are then moved — record by record — into the main pool by the migrate pass. That is what keeps
60
+ * the separation clean: the loop's free-list traffic never touches the main free list, the main
61
+ * passes never see a half-warmed particle, and the one point of contact is a pass that pops from the
62
+ * main pool and pushes nothing back.
63
+ *
64
+ * ## Bounded
65
+ *
66
+ * The tick count is at most `PARTICLE_WARMUP_MAX_TICKS`, with the tick length stretched to cover the
67
+ * longest pre-warm in the batch (`./warmup_schedule.js`), so the frame that pays for a warm-up pays
68
+ * for a known number of dispatches whatever was asked. Per tick: reset, tick, the scan, the emit
69
+ * command, emit, advance — six or seven passes, all sized by constants or by the scan.
70
+ *
71
+ * ## Where it sits in the frame
72
+ *
73
+ * After the frame's own emit and simulate, before the bucketing. Migrate appends to the same alive
74
+ * list they did, so the bucketing puts the warmed particles in next frame's simulate list, the bounds
75
+ * pass measures them into their emitter's box this frame, and the draw draws them this frame. Which
76
+ * is also what closes the culling fixed point the bounds passes describe: an emitter that arrives
77
+ * with a warmed population is measured on its first frame, whatever the frustum thinks of its origin.
78
+ *
79
+ * Recorded only on a frame with something queued. The host knows: an emitter is queued when it is
80
+ * registered with a `prewarm`, and the queue is consumed by the frame that records it.
81
+ *
82
+ * @param {object} params
83
+ * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} params.graph
84
+ * @param {number} params.scene_database graph handle
85
+ * @param {number} params.emitter_database graph handle, threaded: the warm-up tick writes ages
86
+ * @param {number} params.program graph handle of the packed program buffer
87
+ * @param {number} params.pool main pool, threaded
88
+ * @param {number} params.alive_out main alive list, threaded
89
+ * @param {number} params.dead main free list, threaded
90
+ * @param {number} params.counters main counters, threaded
91
+ * @param {number} params.vm_registers the wide register file's handle, or -1 when the system is on
92
+ * the fast file
93
+ * @param {GPUBuffer} params.queue the host's queue buffer, `PARTICLE_WARMUP_QUEUE_WORDS` per entry
94
+ * @param {number} params.queue_count entries in the queue
95
+ * @param {number} params.warm_capacity slots in the transient pool
96
+ * @param {number} params.capacity main pool capacity
97
+ * @param {number} params.emitter_capacity element capacity of the emitter table
98
+ * @param {import("./warmup_schedule.js").WarmupSchedule} params.schedule
99
+ * @param {boolean} params.wide_registers
100
+ * @param {object} params.frame
101
+ * @param {number} params.frame.time the frame's clock — the loop counts down to it
102
+ * @param {number} params.frame.index
103
+ * @returns {{pool: number, alive_out: number, dead: number, counters: number, emitter_database: number, vm_registers: number}}
104
+ */
105
+ export function graph_particle_warmup({
106
+ graph,
107
+ scene_database,
108
+ emitter_database,
109
+ program,
110
+ pool,
111
+ alive_out,
112
+ dead,
113
+ counters,
114
+ vm_registers,
115
+ queue,
116
+ queue_count,
117
+ warm_capacity,
118
+ capacity,
119
+ emitter_capacity,
120
+ schedule,
121
+ wide_registers,
122
+ frame,
123
+ }) {
124
+ assert.defined(graph, "graph");
125
+ assert.isPositiveInteger(queue_count, "queue_count");
126
+ assert.isPositiveInteger(warm_capacity, "warm_capacity");
127
+ assert.isPositiveInteger(schedule.ticks, "schedule.ticks");
128
+
129
+ const WORD = Uint32Array.BYTES_PER_ELEMENT;
130
+ const STORAGE = GPUBufferUsage.STORAGE;
131
+
132
+ const gr_queue = graph_import_buffer(graph, queue, "particles/warmup/queue");
133
+
134
+ // The transient population. Uncleared where the init pass writes every word that will be read
135
+ // (the free list), cleared where a word could be read before it is written (the counters, and
136
+ // the alive lists' tails are bounded by counts the passes wrote).
137
+ // Threaded like everything a pass writes: emit and advance both rename it, and the next reader
138
+ // must take the renamed handle or the graph's validator rejects the frame as reading a stale
139
+ // version.
140
+ let warm_pool = graph_create_buffer(graph, "particles/warmup/pool", BufferResourceDescriptor.from(
141
+ warm_capacity * PARTICLE_RECORD_WORD_COUNT * WORD, STORAGE,
142
+ ));
143
+ const warm_alive = [
144
+ graph_create_buffer(graph, "particles/warmup/alive_a", BufferResourceDescriptor.from(warm_capacity * WORD, STORAGE)),
145
+ graph_create_buffer(graph, "particles/warmup/alive_b", BufferResourceDescriptor.from(warm_capacity * WORD, STORAGE)),
146
+ ];
147
+ let warm_dead = graph_create_buffer(graph, "particles/warmup/dead", BufferResourceDescriptor.from(warm_capacity * WORD, STORAGE));
148
+ let warm_counters = graph_create_buffer(graph, "particles/warmup/counters", BufferResourceDescriptor.empty(
149
+ PARTICLE_COUNTER_COUNT * WORD, STORAGE | GPUBufferUsage.COPY_DST,
150
+ ));
151
+
152
+ // Every slot onto the free list.
153
+ {
154
+ const out = graph_compute_pass({
155
+ graph,
156
+ shader: shader_particle_warmup_init,
157
+ bindings: { dead: warm_dead, counters: warm_counters, u_capacity: warm_capacity },
158
+ group_count: [Math.ceil(warm_capacity / PARTICLE_WARMUP_WORKGROUP_SIZE), 1, 1],
159
+ });
160
+ warm_dead = out.dead;
161
+ warm_counters = out.counters;
162
+ }
163
+
164
+ const count_words = PREFIX_SCAN_CSDLDF_HEADER_WORDS + align_4(Math.max(1, emitter_capacity));
165
+ const count_bytes = count_words * WORD;
166
+
167
+ let gr_queue_rw = gr_queue;
168
+
169
+ for (let tick = 0; tick < schedule.ticks; tick++) {
170
+ const remaining = warmup_remaining(schedule, tick);
171
+ // The clock at the start of this tick: the frame's, less what is still to run.
172
+ const time = frame.time - remaining;
173
+ // Distinct per tick, and unlike any frame index the main emit will seed with, so a warmed
174
+ // particle's random stream is not a later particle's in the same slot.
175
+ const frame_index = (frame.index ^ Math.imul(tick + 1, 0x9e3779b9)) >>> 0;
176
+
177
+ // Last tick's survivors are this tick's input; this tick appends to the other list.
178
+ const alive_in = warm_alive[(tick + 1) % 2];
179
+ let alive_this = warm_alive[tick % 2];
180
+
181
+ // 1. Roll the counters: alive -> alive_in, alive = 0, budget = dead.
182
+ warm_counters = graph_compute_pass({
183
+ graph,
184
+ shader: shader_particle_warmup_reset,
185
+ bindings: { counters: warm_counters },
186
+ group_count: [1, 1, 1],
187
+ }).counters;
188
+
189
+ // 2. The spawn decision, per queued emitter, into a count list as long as the emitter table.
190
+ // Cleared whole: the tick writes only the queued rows.
191
+ let spawn_counts = graph_create_buffer(graph, "particles/warmup/spawn_counts", BufferResourceDescriptor.from(
192
+ count_bytes, STORAGE, 0, count_bytes,
193
+ ));
194
+
195
+ {
196
+ const out = graph_compute_pass({
197
+ graph,
198
+ shader: shader_particle_warmup_tick,
199
+ bindings: {
200
+ queue: gr_queue_rw,
201
+ emitter_database,
202
+ counters: warm_counters,
203
+ spawn_counts,
204
+ settings: {
205
+ u_dt: schedule.dt,
206
+ u_remaining: remaining,
207
+ u_capacity: warm_capacity,
208
+ u_emitter_capacity: emitter_capacity,
209
+ u_count: queue_count,
210
+ },
211
+ },
212
+ group_count: [Math.ceil(queue_count / PARTICLE_WARMUP_WORKGROUP_SIZE), 1, 1],
213
+ });
214
+ gr_queue_rw = out.queue;
215
+ emitter_database = out.emitter_database;
216
+ warm_counters = out.counters;
217
+ spawn_counts = out.spawn_counts;
218
+ }
219
+
220
+ // 3. Scan the counts; the last sum is the tick's newborn count.
221
+ const spawn_prefix = graph_prefix_scan_csdldf({
222
+ graph,
223
+ input: spawn_counts,
224
+ output: graph_create_buffer(graph, "particles/warmup/spawn_prefix",
225
+ prefix_scan_csdldf_output_descriptor(Math.max(1, emitter_capacity))),
226
+ element_max_count: Math.max(1, emitter_capacity),
227
+ });
228
+
229
+ // 4. That total as the emit dispatch — for the fast emit; the wide one reads the total as a
230
+ // loop bound instead, as it does in the main frame.
231
+ const emit_command = graph_compute_pass({
232
+ graph,
233
+ shader: shader_prefix_sum_to_command,
234
+ bindings: {
235
+ prefix_sums: spawn_prefix,
236
+ command: graph_create_buffer(graph, "particles/warmup/emit_command", INDIRECT_COMPUTE_COMMAND_DESCRIPTOR),
237
+ },
238
+ group_count: [1, 1, 1],
239
+ }).command;
240
+
241
+ // 5. Emit — the main pass, unchanged, over the warm-up's buffers. It finds each newborn's
242
+ // emitter in the scan, reads the record and the age off the main database, pops the
243
+ // transient free list and appends to the transient alive list.
244
+ {
245
+ const bindings = {
246
+ scene_database,
247
+ emitter_database,
248
+ program,
249
+ spawn_prefix,
250
+ pool: warm_pool, alive_out: alive_this, dead: warm_dead, counters: warm_counters,
251
+ settings: { u_dt: schedule.dt, u_time: time, u_frame: frame_index, u_capacity: warm_capacity },
252
+ };
253
+
254
+ const out = wide_registers
255
+ ? graph_compute_pass({
256
+ graph,
257
+ shader: shader_particle_emit_wide,
258
+ bindings: { ...bindings, vm_registers },
259
+ group_count: [PARTICLE_EMIT_WIDE_WORKGROUP_COUNT, 1, 1],
260
+ })
261
+ : graph_compute_indirect_pass({
262
+ graph,
263
+ shader: shader_particle_emit,
264
+ bindings,
265
+ command: emit_command,
266
+ });
267
+
268
+ warm_pool = out.pool;
269
+ alive_this = out.alive_out;
270
+ warm_dead = out.dead;
271
+ warm_counters = out.counters;
272
+
273
+ if (wide_registers) { vm_registers = out.vm_registers; }
274
+ }
275
+
276
+ // 6. Advance last tick's survivors by one tick, into the same list the newborns went to.
277
+ {
278
+ const bindings = {
279
+ scene_database,
280
+ emitter_database,
281
+ program,
282
+ pool: warm_pool, alive_in, alive_out: alive_this, dead: warm_dead, counters: warm_counters,
283
+ settings: { u_dt: schedule.dt, u_time: time, u_frame: frame_index },
284
+ };
285
+
286
+ const out = wide_registers
287
+ ? graph_compute_pass({
288
+ graph,
289
+ shader: shader_particle_warmup_advance_wide,
290
+ bindings: { ...bindings, vm_registers },
291
+ group_count: [PARTICLE_WARMUP_WORKGROUP_COUNT, 1, 1],
292
+ })
293
+ : graph_compute_pass({
294
+ graph,
295
+ shader: shader_particle_warmup_advance,
296
+ bindings,
297
+ group_count: [PARTICLE_WARMUP_WORKGROUP_COUNT, 1, 1],
298
+ });
299
+
300
+ warm_pool = out.pool;
301
+ alive_this = out.alive_out;
302
+ warm_dead = out.dead;
303
+ warm_counters = out.counters;
304
+
305
+ if (wide_registers) { vm_registers = out.vm_registers; }
306
+ }
307
+
308
+ warm_alive[tick % 2] = alive_this;
309
+ }
310
+
311
+ // 7. The population is the scene's: every survivor into a main-pool slot, onto the main alive
312
+ // list.
313
+ {
314
+ const out = graph_compute_pass({
315
+ graph,
316
+ shader: shader_particle_warmup_migrate,
317
+ bindings: {
318
+ warm_pool,
319
+ warm_alive: warm_alive[(schedule.ticks - 1) % 2],
320
+ warm_counters,
321
+ pool, alive_out, dead, counters,
322
+ u_capacity: capacity,
323
+ },
324
+ group_count: [PARTICLE_WARMUP_WORKGROUP_COUNT, 1, 1],
325
+ });
326
+
327
+ pool = out.pool;
328
+ alive_out = out.alive_out;
329
+ dead = out.dead;
330
+ counters = out.counters;
331
+ }
332
+
333
+ return { pool, alive_out, dead, counters, emitter_database, vm_registers };
334
+ }