@woosh/meep-engine 3.16.0 → 3.17.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 (410) hide show
  1. package/editor/particles/effect/ParticleEffectDocument.d.ts +21 -6
  2. package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
  3. package/editor/particles/effect/ParticleEffectDocument.js +38 -17
  4. package/editor/view/node-graph/NodeGraphClipboard.d.ts +186 -0
  5. package/editor/view/node-graph/NodeGraphClipboard.d.ts.map +1 -0
  6. package/editor/view/node-graph/NodeGraphClipboard.js +231 -0
  7. package/editor/view/node-graph/NodeGraphEditorView.d.ts +59 -1
  8. package/editor/view/node-graph/NodeGraphEditorView.d.ts.map +1 -1
  9. package/editor/view/node-graph/NodeGraphEditorView.js +248 -5
  10. package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
  11. package/editor/view/node-graph/NodeGraphView.js +84 -8
  12. package/editor/view/node-graph/actions/connection_bind_actions.d.ts +23 -0
  13. package/editor/view/node-graph/actions/connection_bind_actions.d.ts.map +1 -0
  14. package/editor/view/node-graph/actions/connection_bind_actions.js +39 -0
  15. package/editor/view/particles/effect/ParticleCodeEditorView.d.ts.map +1 -1
  16. package/editor/view/particles/effect/ParticleCodeEditorView.js +4 -3
  17. package/editor/view/particles/effect/ParticleCurveEditorView.d.ts +20 -0
  18. package/editor/view/particles/effect/ParticleCurveEditorView.d.ts.map +1 -0
  19. package/editor/view/particles/effect/ParticleCurveEditorView.js +574 -0
  20. package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -1
  21. package/editor/view/particles/effect/ParticleEmitterInspectorView.js +27 -1
  22. package/editor/view/particles/effect/ParticleGradientEditorView.d.ts +24 -0
  23. package/editor/view/particles/effect/ParticleGradientEditorView.d.ts.map +1 -0
  24. package/editor/view/particles/effect/ParticleGradientEditorView.js +472 -0
  25. package/editor/view/particles/effect/ParticleGraphEditorView.d.ts +5 -0
  26. package/editor/view/particles/effect/ParticleGraphEditorView.d.ts.map +1 -1
  27. package/editor/view/particles/effect/ParticleGraphEditorView.js +61 -31
  28. package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
  29. package/editor/view/particles/effect/ParticleNodeParametersView.js +33 -0
  30. package/editor/view/particles/effect/particle-editor.css +123 -35
  31. package/package.json +1 -1
  32. package/src/core/binary/allocator/OffsetAllocator.d.ts +25 -16
  33. package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
  34. package/src/core/binary/allocator/OffsetAllocator.js +10 -1
  35. package/src/core/collection/array/typed/float32_array_hash.d.ts +21 -0
  36. package/src/core/collection/array/typed/float32_array_hash.d.ts.map +1 -0
  37. package/src/core/collection/array/typed/float32_array_hash.js +38 -0
  38. package/src/core/graph/csr/CSRGraph.d.ts +8 -1
  39. package/src/core/graph/csr/CSRGraph.d.ts.map +1 -1
  40. package/src/core/graph/csr/CSRGraph.js +14 -6
  41. package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts +24 -0
  42. package/src/core/model/node-graph/visual/layout/LayoutProblem.d.ts.map +1 -1
  43. package/src/core/model/node-graph/visual/layout/LayoutProblem.js +27 -0
  44. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts +26 -0
  45. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts.map +1 -1
  46. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.js +28 -0
  47. package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts +92 -3
  48. package/src/core/model/node-graph/visual/layout/RouteGrid.d.ts.map +1 -1
  49. package/src/core/model/node-graph/visual/layout/RouteGrid.js +405 -242
  50. package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts +50 -5
  51. package/src/core/model/node-graph/visual/layout/RouteSearch.d.ts.map +1 -1
  52. package/src/core/model/node-graph/visual/layout/RouteSearch.js +160 -24
  53. package/src/core/model/node-graph/visual/layout/RouteSet.d.ts +7 -0
  54. package/src/core/model/node-graph/visual/layout/RouteSet.d.ts.map +1 -1
  55. package/src/core/model/node-graph/visual/layout/RouteSet.js +8 -0
  56. package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.js +9 -3
  57. package/src/core/model/node-graph/visual/layout/layout_build_problem.d.ts.map +1 -1
  58. package/src/core/model/node-graph/visual/layout/layout_build_problem.js +7 -0
  59. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts +9 -3
  60. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts.map +1 -1
  61. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.js +17 -3
  62. package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts +9 -6
  63. package/src/core/model/node-graph/visual/layout/layout_node_graph.d.ts.map +1 -1
  64. package/src/core/model/node-graph/visual/layout/layout_node_graph.js +49 -7
  65. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts +11 -1
  66. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts.map +1 -1
  67. package/src/core/model/node-graph/visual/layout/layout_order_layers.js +135 -16
  68. package/src/core/model/node-graph/visual/layout/route_connections.d.ts +29 -0
  69. package/src/core/model/node-graph/visual/layout/route_connections.d.ts.map +1 -1
  70. package/src/core/model/node-graph/visual/layout/route_connections.js +716 -309
  71. package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts +3 -2
  72. package/src/core/model/node-graph/visual/layout/route_grid_build.d.ts.map +1 -1
  73. package/src/core/model/node-graph/visual/layout/route_grid_build.js +7 -15
  74. package/src/core/model/node-graph/visual/layout/route_nudge.d.ts +6 -0
  75. package/src/core/model/node-graph/visual/layout/route_nudge.d.ts.map +1 -1
  76. package/src/core/model/node-graph/visual/layout/route_nudge.js +42 -13
  77. package/src/engine/animation/AnimationUtils.js +246 -246
  78. package/src/engine/animation/Animations.js +74 -74
  79. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2078 -2078
  80. package/src/engine/ecs/EventType.d.ts +0 -1
  81. package/src/engine/ecs/EventType.js +1 -26
  82. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts +1 -1
  83. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +1 -1
  84. package/src/engine/ecs/ik/ik_write_local_rotation.js +3 -7
  85. package/src/engine/ecs/parent/EntityNode.d.ts.map +1 -1
  86. package/src/engine/ecs/parent/EntityNode.js +4 -9
  87. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
  88. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +360 -364
  89. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts +41 -0
  90. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.d.ts.map +1 -0
  91. package/src/engine/ecs/transform/TRANSFORM64_EVENT_CHANGE.js +40 -0
  92. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +8 -0
  93. package/src/engine/ecs/transform/t64_announce_change.d.ts +10 -7
  94. package/src/engine/ecs/transform/t64_announce_change.d.ts.map +1 -1
  95. package/src/engine/ecs/transform/t64_announce_change.js +12 -12
  96. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts +30 -0
  97. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.d.ts.map +1 -0
  98. package/src/engine/ecs/transform-attachment/TRANSFORM_ATTACHMENT_EVENT_CHANGE.js +29 -0
  99. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
  100. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +13 -21
  101. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
  102. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +4 -8
  103. package/src/engine/graphics3/LightSystem.d.ts.map +1 -1
  104. package/src/engine/graphics3/LightSystem.js +4 -8
  105. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  106. package/src/engine/graphics3/MeshSystem.js +9 -19
  107. package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -1
  108. package/src/engine/graphics3/ParticleEmitterSystem.js +4 -8
  109. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  110. package/src/engine/graphics3/ShadedGeometrySystem.js +4 -10
  111. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts +1 -1
  112. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts.map +1 -1
  113. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +4 -8
  114. package/src/engine/intelligence/behavior/ecs/OrbitingBehavior.js +218 -218
  115. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  116. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  117. package/src/engine/sound/ecs/SoundListenerSystem.d.ts.map +1 -1
  118. package/src/engine/sound/ecs/SoundListenerSystem.js +6 -8
  119. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts +0 -4
  120. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.d.ts.map +1 -1
  121. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.js +5 -11
  122. package/src/shade/playground/particle_editor/README.md +43 -2
  123. package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
  124. package/src/shade/playground/particle_system/particle_prototype.js +4 -5
  125. package/src/shade/playground/particle_system/particle_scene.js +4 -4
  126. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  127. package/src/shade/renderer/Renderer.js +13 -1
  128. package/src/shade/renderer/particles/DESIGN.md +104 -19
  129. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +64 -50
  130. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  131. package/src/shade/renderer/particles/GPUParticleSystem.js +176 -78
  132. package/src/shade/renderer/particles/ParticleConstants.d.ts +59 -23
  133. package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
  134. package/src/shade/renderer/particles/ParticleConstants.js +66 -23
  135. package/src/shade/renderer/particles/ParticleRenderMode.d.ts +19 -0
  136. package/src/shade/renderer/particles/ParticleRenderMode.d.ts.map +1 -0
  137. package/src/shade/renderer/particles/ParticleRenderMode.js +33 -0
  138. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
  139. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +167 -166
  140. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts +37 -0
  141. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -0
  142. package/src/shade/renderer/particles/data/particle_emitter_record.js +109 -0
  143. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +3 -3
  144. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +303 -303
  145. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +18 -0
  146. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -1
  147. package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +152 -133
  148. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +0 -11
  149. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
  150. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +720 -621
  151. package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
  152. package/src/shade/renderer/particles/graph/compile_particle_graph.js +8 -3
  153. package/src/shade/renderer/particles/graph/flatten_particle_graph.d.ts.map +1 -1
  154. package/src/shade/renderer/particles/graph/flatten_particle_graph.js +244 -213
  155. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.d.ts.map +1 -1
  156. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.js +6 -0
  157. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts.map +1 -1
  158. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.js +294 -319
  159. package/src/shade/renderer/particles/graph/groups/particle_groups_noise.d.ts.map +1 -1
  160. package/src/shade/renderer/particles/graph/groups/particle_groups_noise.js +524 -517
  161. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts +22 -0
  162. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.d.ts.map +1 -0
  163. package/src/shade/renderer/particles/graph/groups/particle_groups_psrdnoise.js +517 -0
  164. package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
  165. package/src/shade/renderer/particles/graph/groups/simplex_reference.js +185 -159
  166. package/src/shade/renderer/particles/graph/make_particle_group.d.ts.map +1 -1
  167. package/src/shade/renderer/particles/graph/make_particle_group.js +2 -20
  168. package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts +17 -0
  169. package/src/shade/renderer/particles/graph/particle_compare_ops.d.ts.map +1 -0
  170. package/src/shade/renderer/particles/graph/particle_compare_ops.js +22 -0
  171. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts +28 -8
  172. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.d.ts.map +1 -1
  173. package/src/shade/renderer/particles/graph/particle_graph_diagnostic.js +49 -25
  174. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +40 -0
  175. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -1
  176. package/src/shade/renderer/particles/graph/particle_node_parameters.js +312 -234
  177. package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -1
  178. package/src/shade/renderer/particles/graph/particle_node_presentation.js +59 -3
  179. package/src/shade/renderer/particles/graph/particle_ramp.d.ts +230 -0
  180. package/src/shade/renderer/particles/graph/particle_ramp.d.ts.map +1 -0
  181. package/src/shade/renderer/particles/graph/particle_ramp.js +403 -0
  182. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts +7 -1
  183. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts.map +1 -1
  184. package/src/shade/renderer/particles/graph/validate_particle_graph.js +66 -10
  185. package/src/shade/renderer/particles/graph_particles.d.ts +23 -69
  186. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  187. package/src/shade/renderer/particles/graph_particles.js +105 -262
  188. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  189. package/src/shade/renderer/particles/graph_particles_avboit.js +3 -2
  190. package/src/shade/renderer/particles/graph_particles_billboard.d.ts +37 -0
  191. package/src/shade/renderer/particles/graph_particles_billboard.d.ts.map +1 -0
  192. package/src/shade/renderer/particles/graph_particles_billboard.js +93 -0
  193. package/src/shade/renderer/particles/isa/InstructionStream.d.ts +51 -22
  194. package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
  195. package/src/shade/renderer/particles/isa/InstructionStream.js +98 -38
  196. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts +49 -8
  197. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts.map +1 -1
  198. package/src/shade/renderer/particles/isa/ParticleProgram.js +95 -150
  199. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +306 -64
  200. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
  201. package/src/shade/renderer/particles/isa/ParticleVMISA.js +505 -136
  202. package/src/shade/renderer/particles/isa/particle_assembly.d.ts +36 -12
  203. package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -1
  204. package/src/shade/renderer/particles/isa/particle_assembly.js +354 -139
  205. package/src/shade/renderer/particles/isa/validate_particle_program.d.ts +9 -0
  206. package/src/shade/renderer/particles/isa/validate_particle_program.d.ts.map +1 -0
  207. package/src/shade/renderer/particles/isa/validate_particle_program.js +128 -0
  208. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts +23 -0
  209. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts.map +1 -1
  210. package/src/shade/renderer/particles/layout/ParticleLayout.js +68 -0
  211. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts +77 -0
  212. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts.map +1 -0
  213. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js +219 -0
  214. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts +83 -0
  215. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -0
  216. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +283 -0
  217. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts +133 -0
  218. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts.map +1 -0
  219. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.js +334 -0
  220. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts +117 -0
  221. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.d.ts.map +1 -0
  222. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.js +70 -0
  223. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts +97 -0
  224. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.d.ts.map +1 -0
  225. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +462 -0
  226. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts +116 -0
  227. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.d.ts.map +1 -0
  228. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.js +687 -0
  229. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts +57 -0
  230. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts.map +1 -0
  231. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +860 -0
  232. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts +115 -0
  233. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.d.ts.map +1 -0
  234. package/src/shade/renderer/particles/optimizer/dag/particle_vector_rules.js +264 -0
  235. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts +81 -42
  236. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts.map +1 -1
  237. package/src/shade/renderer/particles/optimizer/optimize_particle_program.js +477 -478
  238. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts +100 -0
  239. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts.map +1 -0
  240. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.js +236 -0
  241. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts +139 -59
  242. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
  243. package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +764 -647
  244. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts +40 -7
  245. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -1
  246. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +376 -213
  247. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts +30 -3
  248. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts.map +1 -1
  249. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +337 -223
  250. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +24 -38
  251. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
  252. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +166 -206
  253. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts +99 -0
  254. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts.map +1 -0
  255. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.js +313 -0
  256. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts +3 -2
  257. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts.map +1 -1
  258. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.js +198 -197
  259. package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.d.ts.map +1 -1
  260. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts +19 -0
  261. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
  262. package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +678 -561
  263. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts +22 -0
  264. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -0
  265. package/src/shade/renderer/particles/optimizer/pass_inline_constants.js +221 -0
  266. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
  267. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.js +63 -72
  268. package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
  269. package/src/shade/renderer/particles/optimizer/pass_pack_registers.js +87 -86
  270. package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
  271. package/src/shade/renderer/particles/optimizer/pass_peephole.js +392 -271
  272. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
  273. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.js +361 -268
  274. package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts +4 -0
  275. package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts.map +1 -0
  276. package/src/shade/renderer/particles/optimizer/pass_schedule.js +244 -0
  277. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
  278. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +154 -151
  279. package/src/shade/renderer/particles/particle_test_fixtures.d.ts +20 -0
  280. package/src/shade/renderer/particles/particle_test_fixtures.d.ts.map +1 -1
  281. package/src/shade/renderer/particles/particle_test_fixtures.js +229 -203
  282. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +99 -25
  283. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
  284. package/src/shade/renderer/particles/runtime/EmitterRegistry.js +438 -286
  285. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +109 -0
  286. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -0
  287. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +127 -0
  288. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +87 -102
  289. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  290. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +184 -163
  291. package/src/shade/renderer/particles/runtime/ProgramArena.d.ts +26 -0
  292. package/src/shade/renderer/particles/runtime/ProgramArena.d.ts.map +1 -1
  293. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts +130 -0
  294. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts.map +1 -0
  295. package/src/shade/renderer/particles/runtime/ProgramHeap.js +595 -0
  296. package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts +91 -0
  297. package/src/shade/renderer/particles/runtime/ProgramPlacement.d.ts.map +1 -0
  298. package/src/shade/renderer/particles/runtime/ProgramPlacement.js +106 -0
  299. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +5 -2
  300. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
  301. package/src/shade/renderer/particles/runtime/create_particle_effect.js +22 -19
  302. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts +28 -0
  303. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.d.ts.map +1 -0
  304. package/src/shade/renderer/particles/shaders/chunk_particle_emit_step.js +136 -0
  305. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts +35 -0
  306. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.d.ts.map +1 -0
  307. package/src/shade/renderer/particles/shaders/chunk_particle_simulate_step.js +133 -0
  308. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts +18 -9
  309. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  310. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +20 -80
  311. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts +33 -0
  312. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts.map +1 -0
  313. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.js +114 -0
  314. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts +8 -0
  315. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  316. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +33 -101
  317. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts +45 -0
  318. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts.map +1 -0
  319. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js +123 -0
  320. package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts +51 -0
  321. package/src/shade/renderer/particles/sort/graph_particle_sort.d.ts.map +1 -0
  322. package/src/shade/renderer/particles/sort/graph_particle_sort.js +120 -0
  323. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts +6 -0
  324. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts.map +1 -0
  325. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.js +16 -0
  326. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +4 -1
  327. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  328. package/src/shade/renderer/particles/vm/ParticleVMReference.js +261 -140
  329. package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
  330. package/src/shade/renderer/particles/vm/chunk_particle_vm.js +217 -255
  331. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts +43 -0
  332. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.d.ts.map +1 -0
  333. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_fast.js +55 -0
  334. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts +62 -0
  335. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.d.ts.map +1 -0
  336. package/src/shade/renderer/particles/vm/chunk_particle_vm_registers_wide.js +86 -0
  337. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts +22 -0
  338. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.d.ts.map +1 -0
  339. package/src/shade/renderer/shader/chunk/math/chunk_mod_v3f.js +32 -0
  340. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts +9 -0
  341. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.d.ts.map +1 -0
  342. package/src/shade/renderer/shader/chunk/math/chunk_mod_v4f.js +19 -0
  343. package/src/shade/renderer/shader/chunk/noise/psrdnoise/README.md +65 -0
  344. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts +24 -0
  345. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.d.ts.map +1 -0
  346. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2.js +83 -0
  347. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts +25 -0
  348. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.d.ts.map +1 -0
  349. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_hash.js +42 -0
  350. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts +31 -0
  351. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.d.ts.map +1 -0
  352. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise2_kernel.js +80 -0
  353. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts +26 -0
  354. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.d.ts.map +1 -0
  355. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3.js +109 -0
  356. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts +38 -0
  357. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.d.ts.map +1 -0
  358. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_kernel.js +129 -0
  359. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts +21 -0
  360. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.d.ts.map +1 -0
  361. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_permute.js +35 -0
  362. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts +19 -0
  363. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.d.ts.map +1 -0
  364. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_skew.js +28 -0
  365. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts +13 -0
  366. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.d.ts.map +1 -0
  367. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_psrdnoise3_unskew.js +22 -0
  368. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts +22 -0
  369. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.d.ts.map +1 -0
  370. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise2.js +59 -0
  371. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts +23 -0
  372. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.d.ts.map +1 -0
  373. package/src/shade/renderer/shader/chunk/noise/psrdnoise/chunk_srdnoise3.js +74 -0
  374. package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts +34 -1
  375. package/src/shade/wgsl/emulator/ComputeShaderEmulator.d.ts.map +1 -1
  376. package/src/shade/wgsl/emulator/ComputeShaderEmulator.js +41 -1
  377. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +3 -2
  378. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  379. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +49 -10
  380. package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
  381. package/src/view/minimap/dom/MinimapCameraView.js +4 -9
  382. package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts +0 -15
  383. package/src/core/model/node-graph/visual/layout/BoxLayoutSpec.d.ts.map +0 -1
  384. package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts +0 -45
  385. package/src/core/model/node-graph/visual/layout/ConnectedBoxLayouter.d.ts.map +0 -1
  386. package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts +0 -24
  387. package/src/core/model/node-graph/visual/layout/ConnectionEndpointLayoutSpec.d.ts.map +0 -1
  388. package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts +0 -19
  389. package/src/core/model/node-graph/visual/layout/ConnectionLayoutSpec.d.ts.map +0 -1
  390. package/src/engine/ecs/transform/__probe.d.ts +0 -4
  391. package/src/engine/ecs/transform/__probe.d.ts.map +0 -1
  392. package/src/engine/ecs/util/hideEntityGracefully.d.ts +0 -9
  393. package/src/engine/ecs/util/hideEntityGracefully.d.ts.map +0 -1
  394. package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts +0 -27
  395. package/src/shade/renderer/buffer/table/gpu_database_emulator_image.d.ts.map +0 -1
  396. package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts +0 -14
  397. package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts.map +0 -1
  398. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts +0 -156
  399. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_LAYOUT.d.ts.map +0 -1
  400. package/src/shade/renderer/particles/runtime/Emitter.d.ts +0 -219
  401. package/src/shade/renderer/particles/runtime/Emitter.d.ts.map +0 -1
  402. package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts +0 -77
  403. package/src/shade/renderer/particles/runtime/ParticleSpawnScheduler.d.ts.map +0 -1
  404. package/src/shade/renderer/particles/runtime/ProgramArena.js +0 -155
  405. package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts +0 -15
  406. package/src/shade/renderer/particles/runtime/emitter_database_image.d.ts.map +0 -1
  407. package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts +0 -34
  408. package/src/shade/renderer/particles/runtime/spawn_request_encoding.d.ts.map +0 -1
  409. package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts +0 -32
  410. package/src/shade/renderer/particles/shaders/chunk_particle_context.d.ts.map +0 -1
@@ -0,0 +1,595 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { Allocation, ALLOCATOR_NO_SPACE, OffsetAllocator } from "../../../../core/binary/allocator/OffsetAllocator.js";
3
+ import { HashMap } from "../../../../core/collection/map/HashMap.js";
4
+ import {
5
+ PARTICLE_PROGRAM_CODE_BASE_WORD,
6
+ PARTICLE_PROGRAM_HEADER_WORDS,
7
+ PARTICLE_VM_INSTRUCTION_WORDS,
8
+ } from "../ParticleConstants.js";
9
+ import { ProgramPlacement } from "./ProgramPlacement.js";
10
+
11
+ /**
12
+ * Instructions the code section starts out able to hold. It doubles from here as programs are
13
+ * registered; a handful of typical effects fit without ever growing.
14
+ * @type {number}
15
+ */
16
+ const INITIAL_CODE_CAPACITY = 128;
17
+
18
+ /**
19
+ * Words the constant section starts out able to hold.
20
+ * @type {number}
21
+ */
22
+ const INITIAL_CONSTANT_CAPACITY = 128;
23
+
24
+ /**
25
+ * Ranges an allocator can describe at once, to begin with. Each live program costs one, plus one for
26
+ * the free remainder, and this grows with the set — it is a floor, not a ceiling.
27
+ * @type {number}
28
+ */
29
+ const INITIAL_ALLOCATION_CAPACITY = 32;
30
+
31
+ /**
32
+ * @type {Uint32Array}
33
+ */
34
+ const EMPTY_WORDS = new Uint32Array(0);
35
+
36
+ /**
37
+ * What a zero-length request gets: offset zero, and a metadata handle the allocator will refuse, so
38
+ * {@link ProgramRegion#free} can tell it from a range that has to be given back.
39
+ *
40
+ * A program with no INIT section, or with no constants at all, is ordinary — it reads nothing from
41
+ * the range it does not have — and asking the allocator for zero elements is not.
42
+ *
43
+ * @type {Allocation}
44
+ */
45
+ const EMPTY_ALLOCATION = Object.freeze(Allocation.from(0, ALLOCATOR_NO_SPACE));
46
+
47
+ /**
48
+ * One of the two sections of the packed buffer: a flat word array, and the
49
+ * {@link ../../../../core/binary/allocator/OffsetAllocator.js OffsetAllocator} that says which parts
50
+ * of it are in use.
51
+ *
52
+ * The unit is the ELEMENT, not the word — instructions for the code section, words for the constant
53
+ * pool — because that is the unit the emitter record's offsets are in. `stride` is what converts.
54
+ */
55
+ class ProgramRegion {
56
+
57
+ /**
58
+ * Words per element: {@link PARTICLE_VM_INSTRUCTION_WORDS} for code, 1 for constants.
59
+ * @type {number}
60
+ */
61
+ stride;
62
+
63
+ /**
64
+ * @type {OffsetAllocator|null}
65
+ */
66
+ allocator = null;
67
+
68
+ /**
69
+ * The section's words, `capacity * stride` of them. Words outside a live allocation hold
70
+ * whatever the program that used to be there left — nothing addresses them.
71
+ * @type {Uint32Array}
72
+ */
73
+ words = EMPTY_WORDS;
74
+
75
+ /**
76
+ * Elements this section can hold.
77
+ * @type {number}
78
+ */
79
+ capacity = 0;
80
+
81
+ /**
82
+ * @param {number} stride words per element
83
+ */
84
+ constructor(stride) {
85
+ assert.isNonNegativeInteger(stride, 'stride');
86
+
87
+ this.stride = stride;
88
+ }
89
+
90
+ /**
91
+ * Throw away every allocation and start again at `capacity` elements. The words go with them —
92
+ * the caller is expected to write each surviving program back into its new range.
93
+ *
94
+ * @param {number} capacity elements
95
+ * @param {number} max_allocations ranges the allocator can describe at once
96
+ */
97
+ reset(capacity, max_allocations) {
98
+ assert.greaterThan(capacity, 0, 'capacity');
99
+ assert.greaterThan(max_allocations, 0, 'max_allocations');
100
+
101
+ this.capacity = capacity;
102
+ this.allocator = new OffsetAllocator(capacity, max_allocations);
103
+ this.words = new Uint32Array(capacity * this.stride);
104
+ }
105
+
106
+ /**
107
+ * @param {number} count elements
108
+ * @returns {Allocation|null} `null` when the section has no contiguous run that long, or no node
109
+ * left to describe one with — both of which a repack fixes
110
+ */
111
+ allocate(count) {
112
+ assert.isNonNegativeInteger(count, 'count');
113
+
114
+ if (count === 0) {
115
+ return EMPTY_ALLOCATION;
116
+ }
117
+
118
+ const allocation = this.allocator.allocate(count);
119
+
120
+ if (allocation.offset === ALLOCATOR_NO_SPACE) {
121
+ return null;
122
+ }
123
+
124
+ return allocation;
125
+ }
126
+
127
+ /**
128
+ * @param {Allocation|null} allocation
129
+ */
130
+ free(allocation) {
131
+ if (allocation === null || allocation.metadata === ALLOCATOR_NO_SPACE) {
132
+ // never held a range of its own
133
+ return;
134
+ }
135
+
136
+ this.allocator.free(allocation);
137
+ }
138
+
139
+ /**
140
+ * @param {number} offset in elements
141
+ * @param {Uint32Array} words
142
+ */
143
+ write(offset, words) {
144
+ this.words.set(words, offset * this.stride);
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Holds every distinct compiled {@link ../isa/ParticleProgram.js ParticleProgram} the emitter set
150
+ * runs, packs them into one buffer — a header, every constant pool, then every instruction stream —
151
+ * and hands back the {@link ./ProgramPlacement.js placement} each emitter records.
152
+ *
153
+ * Data before code, behind a four-word header whose first word says where the code starts: the VM
154
+ * reads both sections through one binding (a storage buffer per stage is not free, and code and
155
+ * constants are read together), and an emitter's constant pool sits next to the pools of the
156
+ * programs it shares a wave with.
157
+ *
158
+ * **Programs are placed, not appended.** Each section is a range allocator
159
+ * ({@link ../../../../core/binary/allocator/OffsetAllocator.js}) over a flat word array, so a
160
+ * program that is no longer wanted gives its space back and the next one takes it. This is what the
161
+ * emitter table has always been able to do, and what the packed buffer could not: an authoring
162
+ * session that adds, edits and drops effects for an hour no longer grows the buffer for an hour.
163
+ *
164
+ * Because VM instructions carry no absolute code addresses (control flow is branchless) and constant
165
+ * references are program-local (the VM adds the emitter's `constant_offset`), a program is
166
+ * relocatable — it can be placed at any offset, and moved to another one by copying its words and
167
+ * rewriting the placement. INIT and UPDATE are one allocation, laid out back-to-back, because they
168
+ * are always wanted together.
169
+ *
170
+ * **Deduplication is by CONTENT, not object identity**, and it is the {@link HashMap} that does it:
171
+ * two emitters that authored the same graph separately compile to distinct `ParticleProgram` objects
172
+ * holding the same bytecode, and `ParticleProgram` already answers `equals`/`hash` over exactly
173
+ * that. They land on one placement, one bucket, and one copy of the code. Keying on the emitter
174
+ * instead would be simpler and strictly worse: N emitters running one shared effect would become N
175
+ * buckets, each padded out to a whole workgroup, which both wastes lanes and splits a run that was
176
+ * already program-coherent.
177
+ *
178
+ * **Sharing is what makes {@link ProgramHeap#release} a reference count** rather than a delete: the
179
+ * last emitter of an effect frees it, and the ones before it do not.
180
+ */
181
+ export class ProgramHeap {
182
+
183
+ /**
184
+ * Bumped whenever the packed buffer would come out different from the last one
185
+ * {@link ProgramHeap#build_buffer} produced — a program was placed, or the sections were
186
+ * repacked. A holder that uploads the buffer re-uploads when this moves.
187
+ *
188
+ * Releasing a program does NOT move it. The words it occupied are dead rather than changed, and
189
+ * re-uploading the buffer to remove bytes nothing addresses would be a rebuild for nothing; the
190
+ * next program placed there is what makes the buffer differ, and that bumps this.
191
+ *
192
+ * @type {number}
193
+ */
194
+ version = 0;
195
+
196
+ /**
197
+ * Bumped when a repack moved programs that were already placed — every existing placement now
198
+ * holds different offsets, so every emitter record built from one is out of date.
199
+ *
200
+ * Separate from {@link ProgramHeap#version} because the two ask for different work: that one
201
+ * says "upload the buffer again", this one says "restage every row". A repack moves both; an
202
+ * ordinary placement moves only the first.
203
+ *
204
+ * @type {number}
205
+ */
206
+ placement_version = 0;
207
+
208
+ /**
209
+ * The set, keyed by the bytecode itself. The default key functions are `equals`/`hash` on the
210
+ * key object, which is exactly what {@link ../isa/ParticleProgram.js} implements.
211
+ *
212
+ * @type {HashMap<import("../isa/ParticleProgram.js").ParticleProgram, ProgramPlacement>}
213
+ */
214
+ #programs = new HashMap();
215
+
216
+ /**
217
+ * @type {ProgramRegion}
218
+ */
219
+ #code = new ProgramRegion(PARTICLE_VM_INSTRUCTION_WORDS);
220
+
221
+ /**
222
+ * @type {ProgramRegion}
223
+ */
224
+ #constants = new ProgramRegion(1);
225
+
226
+ /**
227
+ * Id the next program gets when {@link ProgramHeap##free_program_ids} is empty. Also the number
228
+ * of id slots that have ever been in use at once, which is what
229
+ * {@link ProgramHeap#program_id_capacity} reports.
230
+ *
231
+ * @type {number}
232
+ */
233
+ #next_program_id = 0;
234
+
235
+ /**
236
+ * Ids of released programs, waiting to be handed out again. Keeping ids dense is not cosmetic:
237
+ * the id indexes a histogram bin in the simulation-order pass, so a set that churned through a
238
+ * thousand effects would otherwise histogram into a thousand bins to serve three.
239
+ *
240
+ * @type {number[]}
241
+ */
242
+ #free_program_ids = [];
243
+
244
+ /**
245
+ * @type {number}
246
+ */
247
+ #max_register_count = 0;
248
+
249
+ constructor() {
250
+ this.#code.reset(INITIAL_CODE_CAPACITY, INITIAL_ALLOCATION_CAPACITY);
251
+ this.#constants.reset(INITIAL_CONSTANT_CAPACITY, INITIAL_ALLOCATION_CAPACITY);
252
+ }
253
+
254
+ /**
255
+ * Distinct programs currently held — and therefore effects, not emitters.
256
+ * @returns {number}
257
+ */
258
+ get program_count() {
259
+ return this.#programs.size;
260
+ }
261
+
262
+ /**
263
+ * How many program ids the heap has had in play at once, which is the number of bins the
264
+ * simulation-order pass has to histogram into: live ids are all below it.
265
+ *
266
+ * It rises to the set's peak and stays there, because released ids are reused rather than
267
+ * renumbered. That costs an empty bin per id the set is currently below its peak by, and an
268
+ * empty bin is free — it rounds up to zero workgroups and shifts nothing after it — whereas
269
+ * renumbering would mean rewriting every emitter record that carries an id, and resizing the
270
+ * coherence buffers every time an effect came or went.
271
+ *
272
+ * @returns {number}
273
+ */
274
+ get program_id_capacity() {
275
+ return this.#next_program_id;
276
+ }
277
+
278
+ /**
279
+ * Register slots the hungriest program currently held needs — the maximum of every live
280
+ * program's `register_count`, and `0` for an empty heap.
281
+ *
282
+ * The heap has no opinion about what that number means; it is the caller that compares it
283
+ * against {@link ../ParticleConstants.js PARTICLE_VM_FAST_REGISTER_SLOTS} and picks an
284
+ * interpreter, because which register backing a pass is compiled against is the VM's business
285
+ * and not the store's. What matters here is that the number is a property of the SET: there is
286
+ * one pipeline per pass and it is chosen once, so one hungry effect decides for every emitter in
287
+ * the system, including the ones whose programs would have fit.
288
+ *
289
+ * It falls again when that effect is released. The heap knows exactly what it holds, so there is
290
+ * no reason for the answer to be a high-water mark that only a full rebuild could bring down.
291
+ *
292
+ * @returns {number}
293
+ */
294
+ get max_register_count() {
295
+ return this.#max_register_count;
296
+ }
297
+
298
+ /**
299
+ * Take a reference on `program`, placing it if the heap does not already hold an identical one.
300
+ *
301
+ * The placement it returns is what the emitter record carries and what the coherence pass
302
+ * buckets on. It is SHARED with every other holder of the same bytecode, and the heap mutates it
303
+ * in place when it repacks, so a caller keeps the object rather than copying its fields —
304
+ * copies go stale, the object does not.
305
+ *
306
+ * @param {import("../isa/ParticleProgram.js").ParticleProgram} program
307
+ * @returns {ProgramPlacement}
308
+ */
309
+ acquire(program) {
310
+ assert.defined(program, 'program');
311
+
312
+ const existing = this.#programs.get(program);
313
+
314
+ if (existing !== undefined) {
315
+ existing.references++;
316
+
317
+ return existing;
318
+ }
319
+
320
+ // The heap keeps its own copy, because this is about to become a hash table key and hash
321
+ // table keys have to be immutable. A compiled program is treated as immutable everywhere,
322
+ // but nothing enforces it — the optimizer's passes rewrite these arrays in place — and a
323
+ // caller that rewrote one it had handed over would leave its own entry unfindable.
324
+ const owned = program.clone();
325
+
326
+ const placement = new ProgramPlacement();
327
+
328
+ placement.program = owned;
329
+ placement.program_id = this.#claim_program_id();
330
+ placement.references = 1;
331
+ placement.init_count = owned.init_instruction_count;
332
+ placement.update_count = owned.update_instruction_count;
333
+
334
+ // before the map: a repack walks what is already placed, and this is not yet one of them
335
+ this.#place(placement);
336
+
337
+ this.#programs.set(owned, placement);
338
+
339
+ if (owned.register_count > this.#max_register_count) {
340
+ this.#max_register_count = owned.register_count;
341
+ }
342
+
343
+ this.version++;
344
+
345
+ return placement;
346
+ }
347
+
348
+ /**
349
+ * Give back a reference taken by {@link ProgramHeap#acquire}. The program's ranges and its id are
350
+ * released when the last one goes.
351
+ *
352
+ * @param {ProgramPlacement} placement
353
+ * @returns {boolean} whether that was the last reference, and the program is now gone
354
+ */
355
+ release(placement) {
356
+ assert.defined(placement, 'placement');
357
+ assert.greaterThan(placement.references, 0, 'placement.references — this placement has already been released');
358
+
359
+ placement.references--;
360
+
361
+ // `!== 0` rather than `> 0`, so that a release too many walks past the freeing branch
362
+ // instead of back into it. The assert above is the real answer to that mistake, but asserts
363
+ // are stripped from a shipped build and this is not a mistake to be quiet about: a second
364
+ // free would push the program id onto the free list twice, and the two effects that later
365
+ // took it would histogram into one bucket and run each other's code.
366
+ if (placement.references !== 0) {
367
+ return false;
368
+ }
369
+
370
+ const program = placement.program;
371
+
372
+ this.#code.free(placement.code_allocation);
373
+ this.#constants.free(placement.constant_allocation);
374
+
375
+ placement.code_allocation = null;
376
+ placement.constant_allocation = null;
377
+
378
+ this.#programs.delete(program);
379
+ this.#free_program_ids.push(placement.program_id);
380
+
381
+ if (program.register_count >= this.#max_register_count) {
382
+ this.#max_register_count = this.#find_max_register_count();
383
+ }
384
+
385
+ return true;
386
+ }
387
+
388
+ /**
389
+ * The packed buffer: `[header][constants][code]`. Word
390
+ * {@link ../ParticleConstants.js PARTICLE_PROGRAM_CODE_BASE_WORD} of the header is the word index
391
+ * the code starts at — the only absolute address in the buffer, and the reason a placement can
392
+ * hold section-relative offsets and survive the sections being resized.
393
+ *
394
+ * Both sections come out at their full capacity rather than trimmed to what is live: the offsets
395
+ * a placement holds are offsets into the capacity, and trimming would mean moving programs to
396
+ * close the holes, which is what a repack is for and what a buffer rebuild should not silently
397
+ * become.
398
+ *
399
+ * @returns {Uint32Array}
400
+ */
401
+ build_buffer() {
402
+ const constants = this.#constants.words;
403
+ const code = this.#code.words;
404
+
405
+ const code_base = PARTICLE_PROGRAM_HEADER_WORDS + constants.length;
406
+ const buffer = new Uint32Array(code_base + code.length);
407
+
408
+ buffer[PARTICLE_PROGRAM_CODE_BASE_WORD] = code_base;
409
+ buffer.set(constants, PARTICLE_PROGRAM_HEADER_WORDS);
410
+ buffer.set(code, code_base);
411
+
412
+ return buffer;
413
+ }
414
+
415
+ /**
416
+ * @returns {number}
417
+ */
418
+ #claim_program_id() {
419
+ if (this.#free_program_ids.length > 0) {
420
+ return this.#free_program_ids.pop();
421
+ }
422
+
423
+ return this.#next_program_id++;
424
+ }
425
+
426
+ /**
427
+ * @returns {number} the largest `register_count` among the programs still held
428
+ */
429
+ #find_max_register_count() {
430
+ let result = 0;
431
+
432
+ this.#programs.forEach((placement) => {
433
+ const count = placement.program.register_count;
434
+
435
+ if (count > result) {
436
+ result = count;
437
+ }
438
+ });
439
+
440
+ return result;
441
+ }
442
+
443
+ /**
444
+ * Find room for `placement` and write its words there, repacking the sections first if there is
445
+ * none to be found.
446
+ *
447
+ * @param {ProgramPlacement} placement
448
+ */
449
+ #place(placement) {
450
+ if (this.#try_place(placement)) {
451
+ return;
452
+ }
453
+
454
+ this.#repack(placement.instruction_count, placement.constant_word_count, 1);
455
+
456
+ if (this.#try_place(placement)) {
457
+ return;
458
+ }
459
+
460
+ // Meant to be unreachable — {@link grown_capacity} sizes a section with slack for exactly
461
+ // this reason — and not left to the assert alone all the same. The sizing rests on an
462
+ // argument about how the allocator rounds its bins, and the cost of that argument being
463
+ // wrong is not an exception: it is a program placed nowhere, which is a shader reading
464
+ // whatever the words at offset zero happen to be. Doubling both sections is cheaper than
465
+ // being right.
466
+ this.#repack(placement.instruction_count, placement.constant_word_count, 2);
467
+
468
+ const placed = this.#try_place(placement);
469
+
470
+ assert.ok(placed, 'two repacks sized for this program still had no room for it');
471
+ }
472
+
473
+ /**
474
+ * Allocate both ranges, or neither, and on success write the program into them.
475
+ *
476
+ * Both or neither matters: a half-placed program would leak the half that succeeded through the
477
+ * repack that follows, which walks the programs the heap holds and this is not yet one of them.
478
+ *
479
+ * @param {ProgramPlacement} placement
480
+ * @returns {boolean} whether it fit
481
+ */
482
+ #try_place(placement) {
483
+ const program = placement.program;
484
+
485
+ const code = this.#code.allocate(placement.instruction_count);
486
+ const constants = this.#constants.allocate(program.constant_word_count);
487
+
488
+ if (code === null || constants === null) {
489
+ this.#code.free(code);
490
+ this.#constants.free(constants);
491
+
492
+ return false;
493
+ }
494
+
495
+ placement.code_allocation = code;
496
+ placement.constant_allocation = constants;
497
+
498
+ placement.init_offset = code.offset;
499
+ placement.update_offset = code.offset + placement.init_count;
500
+ placement.constant_offset = constants.offset;
501
+
502
+ this.#code.write(placement.init_offset, program.init);
503
+ this.#code.write(placement.update_offset, program.update);
504
+ this.#constants.write(placement.constant_offset, program.constant_words);
505
+
506
+ return true;
507
+ }
508
+
509
+ /**
510
+ * Lay both sections out again from scratch, with room for the programs already held plus one
511
+ * more of the given size.
512
+ *
513
+ * This is the only thing that moves a program, and it happens for one of two reasons: a section
514
+ * has no contiguous run long enough (its free space is there but scattered), or its allocator has
515
+ * no node left to describe another range with. Compaction answers both, and a section that is
516
+ * genuinely full grows on the way — the capacities are only ever raised here, never lowered, so
517
+ * a set that peaked at a hundred effects does not pay for a resize every time it returns to
518
+ * three.
519
+ *
520
+ * Ids survive: the offsets move, the `program_id` an emitter record carries does not.
521
+ *
522
+ * @param {number} extra_instructions
523
+ * @param {number} extra_constant_words
524
+ * @param {number} growth multiplier on the capacity a section is allowed to keep — `1` to let it
525
+ * stay where it is if compacting was enough, `2` to insist that it at least doubles
526
+ */
527
+ #repack(extra_instructions, extra_constant_words, growth) {
528
+ /**
529
+ * @type {ProgramPlacement[]}
530
+ */
531
+ const placements = [];
532
+
533
+ let instructions = extra_instructions;
534
+ let constant_words = extra_constant_words;
535
+
536
+ this.#programs.forEach((placement) => {
537
+ placements.push(placement);
538
+
539
+ instructions += placement.instruction_count;
540
+ constant_words += placement.constant_word_count;
541
+ });
542
+
543
+ // one node per live range plus one for the free remainder, doubled so the allocator is not
544
+ // rebuilt again on the very next program
545
+ const max_allocations = Math.max(INITIAL_ALLOCATION_CAPACITY, (placements.length + 2) * 2);
546
+
547
+ this.#code.reset(
548
+ grown_capacity(this.#code.capacity * growth, instructions, INITIAL_CODE_CAPACITY),
549
+ max_allocations
550
+ );
551
+ this.#constants.reset(
552
+ grown_capacity(this.#constants.capacity * growth, constant_words, INITIAL_CONSTANT_CAPACITY),
553
+ max_allocations
554
+ );
555
+
556
+ for (let i = 0; i < placements.length; i++) {
557
+ const placed = this.#try_place(placements[i]);
558
+
559
+ assert.ok(placed, 'a freshly reset section had no room for a program it already held');
560
+ }
561
+
562
+ this.placement_version++;
563
+ this.version++;
564
+ }
565
+ }
566
+
567
+ /**
568
+ * A capacity that holds `required` elements with room to spare: the one it has, doubled until it
569
+ * does.
570
+ *
571
+ * Doubling rather than fitting exactly is what keeps the number of repacks logarithmic in the size
572
+ * of the set — a section grown to exactly what the newest program needed would be repacked again by
573
+ * the one after it.
574
+ *
575
+ * The room to spare is not tidiness, it is correctness. The allocator files a free run under the
576
+ * largest BIN that fits INSIDE it, and its bins are 3-bit floats, so consecutive bins are up to a
577
+ * ninth apart: a free run of 68 is filed under 64, while a request for 68 is looked up from 72 and
578
+ * never finds it. A section sized to exactly what it holds therefore refuses the last program that
579
+ * fits in it. An eighth of slack — `capacity * 8 >= required * 9` — is what makes "it fits" mean it
580
+ * fits, for every allocation in the sequence a repack replays.
581
+ *
582
+ * @param {number} current
583
+ * @param {number} required
584
+ * @param {number} minimum
585
+ * @returns {number}
586
+ */
587
+ function grown_capacity(current, required, minimum) {
588
+ let capacity = Math.max(current, minimum);
589
+
590
+ while (capacity * 8 < required * 9) {
591
+ capacity *= 2;
592
+ }
593
+
594
+ return capacity;
595
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Where one program sits in the {@link ./ProgramHeap.js ProgramHeap}, and what an emitter record
3
+ * carries to find it.
4
+ *
5
+ * A placement is the heap's, not the caller's: {@link ./ProgramHeap.js#acquire} hands one out and
6
+ * {@link ./ProgramHeap.js#release} takes it back, and every field here is written by the heap. It is
7
+ * shared — every emitter running the same bytecode holds the same placement object, which is what
8
+ * puts them in one simulation bucket — and it is MUTATED IN PLACE when the heap repacks. Holders
9
+ * therefore see the new offsets without being handed a new object, and only have to restage the
10
+ * record they wrote the old ones into.
11
+ *
12
+ * The offsets are section-relative, which is what lets the heap move a program without the shader
13
+ * knowing: instruction offsets count instructions from the code section's base, and
14
+ * {@link ProgramPlacement#constant_offset} counts words from the constant section's base. The one
15
+ * absolute address in the whole buffer is the header word saying where the code section starts.
16
+ */
17
+ export class ProgramPlacement {
18
+ /**
19
+ * Dense-ish id of this program: the value the emitter record carries and the simulation-order
20
+ * pass histograms on. Stable for the life of the placement, repacks included — the offsets move,
21
+ * the id does not.
22
+ *
23
+ * Ids are handed out lowest-free-first and a released one is reused, so they stay inside
24
+ * `[0, ProgramHeap#program_id_capacity)` however many programs come and go.
25
+ *
26
+ * @type {number}
27
+ */
28
+ program_id: number;
29
+ /**
30
+ * First instruction of the INIT section, counted in instructions from the code base.
31
+ * @type {number}
32
+ */
33
+ init_offset: number;
34
+ /**
35
+ * Instructions in the INIT section.
36
+ * @type {number}
37
+ */
38
+ init_count: number;
39
+ /**
40
+ * First instruction of the UPDATE section, counted in instructions from the code base. Directly
41
+ * after INIT — the two sections of a program are allocated as one contiguous range.
42
+ * @type {number}
43
+ */
44
+ update_offset: number;
45
+ /**
46
+ * Instructions in the UPDATE section.
47
+ * @type {number}
48
+ */
49
+ update_count: number;
50
+ /**
51
+ * First word of this program's constant pool, counted in words from the constant base. The VM
52
+ * adds it to every program-local constant reference.
53
+ * @type {number}
54
+ */
55
+ constant_offset: number;
56
+ /**
57
+ * The heap's own copy of the bytecode — the key it is filed under, and what a repack rewrites
58
+ * into the moved range.
59
+ *
60
+ * @type {import("../isa/ParticleProgram.js").ParticleProgram|null}
61
+ */
62
+ program: import("../isa/ParticleProgram.js").ParticleProgram | null;
63
+ /**
64
+ * How many emitters hold this placement. The heap frees the ranges and releases the id when it
65
+ * reaches zero, so one emitter of a shared effect going away does not take the effect with it.
66
+ *
67
+ * @type {number}
68
+ */
69
+ references: number;
70
+ /**
71
+ * The code range, in instructions, as {@link ../../../../core/binary/allocator/OffsetAllocator.js}
72
+ * handed it out. `null` for a program with no instructions at all.
73
+ *
74
+ * @type {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation|null}
75
+ */
76
+ code_allocation: import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation | null;
77
+ /**
78
+ * The constant-pool range, in words. `null` for a program with an empty pool.
79
+ * @type {import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation|null}
80
+ */
81
+ constant_allocation: import("../../../../core/binary/allocator/OffsetAllocator.js").Allocation | null;
82
+ /**
83
+ * @returns {number} instructions this program occupies in the code section, both sections summed
84
+ */
85
+ get instruction_count(): number;
86
+ /**
87
+ * @returns {number} words this program occupies in the constant section
88
+ */
89
+ get constant_word_count(): number;
90
+ }
91
+ //# sourceMappingURL=ProgramPlacement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgramPlacement.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/ProgramPlacement.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH;IAEI;;;;;;;;;OASG;IACH,YAFU,MAAM,CAEA;IAEhB;;;OAGG;IACH,aAFU,MAAM,CAEA;IAEhB;;;OAGG;IACH,YAFU,MAAM,CAED;IAEf;;;;OAIG;IACH,eAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,cAFU,MAAM,CAEC;IAEjB;;;;OAIG;IACH,iBAFU,MAAM,CAEI;IAEpB;;;;;OAKG;IACH,SAFU,OAAO,2BAA2B,EAAE,eAAe,GAAC,IAAI,CAEnD;IAEf;;;;;OAKG;IACH,YAFU,MAAM,CAED;IAEf;;;;;OAKG;IACH,iBAFU,OAAO,sDAAsD,EAAE,UAAU,GAAC,IAAI,CAEjE;IAEvB;;;OAGG;IACH,qBAFU,OAAO,sDAAsD,EAAE,UAAU,GAAC,IAAI,CAE7D;IAE3B;;OAEG;IACH,gCAEC;IAED;;OAEG;IACH,kCAEC;CACJ"}