@woosh/meep-engine 3.23.0 → 3.24.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 (522) hide show
  1. package/editor/entity_world_bounds.d.ts +9 -3
  2. package/editor/entity_world_bounds.d.ts.map +1 -1
  3. package/editor/entity_world_bounds.js +61 -4
  4. package/package.json +1 -1
  5. package/src/core/binary/allocator/OffsetAllocator.d.ts +40 -2
  6. package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
  7. package/src/core/binary/allocator/OffsetAllocator.js +124 -29
  8. package/src/core/collection/map/u32_index.d.ts +83 -0
  9. package/src/core/collection/map/u32_index.d.ts.map +1 -0
  10. package/src/core/collection/map/u32_index.js +247 -0
  11. package/src/engine/asset/loaders/GLTFSceneBundleAssetLoader.d.ts +2 -2
  12. package/src/engine/asset/loaders/GLTFSceneBundleAssetLoader.js +2 -2
  13. package/src/engine/asset/loaders/USDSceneBundleAssetLoader.d.ts +1 -2
  14. package/src/engine/asset/loaders/USDSceneBundleAssetLoader.d.ts.map +1 -1
  15. package/src/engine/asset/loaders/USDSceneBundleAssetLoader.js +4 -12
  16. package/src/engine/ecs/gpu/GPUStateAuthority.d.ts +55 -0
  17. package/src/engine/ecs/gpu/GPUStateAuthority.d.ts.map +1 -0
  18. package/src/engine/ecs/gpu/GPUStateAuthority.js +72 -0
  19. package/src/engine/ecs/gpu/GPUStateAuthorityFlags.d.ts +40 -0
  20. package/src/engine/ecs/gpu/GPUStateAuthorityFlags.d.ts.map +1 -0
  21. package/src/engine/ecs/gpu/GPUStateAuthorityFlags.js +79 -0
  22. package/src/engine/ecs/gpu/gpu_authority_assert_cpu.d.ts +18 -0
  23. package/src/engine/ecs/gpu/gpu_authority_assert_cpu.d.ts.map +1 -0
  24. package/src/engine/ecs/gpu/gpu_authority_assert_cpu.js +27 -0
  25. package/src/engine/ecs/gpu/gpu_authority_declare.d.ts +23 -0
  26. package/src/engine/ecs/gpu/gpu_authority_declare.d.ts.map +1 -0
  27. package/src/engine/ecs/gpu/gpu_authority_declare.js +39 -0
  28. package/src/engine/ecs/gpu/gpu_authority_grant.d.ts +15 -0
  29. package/src/engine/ecs/gpu/gpu_authority_grant.d.ts.map +1 -0
  30. package/src/engine/ecs/gpu/gpu_authority_grant.js +38 -0
  31. package/src/engine/ecs/gpu/gpu_authority_has.d.ts +18 -0
  32. package/src/engine/ecs/gpu/gpu_authority_has.d.ts.map +1 -0
  33. package/src/engine/ecs/gpu/gpu_authority_has.js +28 -0
  34. package/src/engine/ecs/gpu/gpu_authority_revoke.d.ts +24 -0
  35. package/src/engine/ecs/gpu/gpu_authority_revoke.d.ts.map +1 -0
  36. package/src/engine/ecs/gpu/gpu_authority_revoke.js +49 -0
  37. package/src/engine/ecs/ik/IKProblem.d.ts +14 -0
  38. package/src/engine/ecs/ik/IKProblem.d.ts.map +1 -1
  39. package/src/engine/ecs/ik/IKProblem.js +16 -0
  40. package/src/engine/ecs/ik/InverseKinematicsSystem.d.ts.map +1 -1
  41. package/src/engine/ecs/ik/InverseKinematicsSystem.js +19 -0
  42. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +2 -2
  43. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +2 -2
  44. package/src/engine/ecs/ik/ik_bone_chain.d.ts +11 -2
  45. package/src/engine/ecs/ik/ik_bone_chain.d.ts.map +1 -1
  46. package/src/engine/ecs/ik/ik_bone_chain.js +47 -2
  47. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +1 -1
  48. package/src/engine/ecs/ik/ik_write_local_rotation.js +6 -0
  49. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  50. package/src/engine/ecs/speaker/VoiceSystem.js +6 -0
  51. package/src/engine/ecs/transform/T64WorldCache.d.ts +50 -0
  52. package/src/engine/ecs/transform/T64WorldCache.d.ts.map +1 -0
  53. package/src/engine/ecs/transform/T64WorldCache.js +139 -0
  54. package/src/engine/ecs/transform/t64_evaluate_world.d.ts +31 -0
  55. package/src/engine/ecs/transform/t64_evaluate_world.d.ts.map +1 -0
  56. package/src/engine/ecs/transform/t64_evaluate_world.js +126 -0
  57. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts +8 -0
  58. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
  59. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +59 -30
  60. package/src/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.d.ts.map +1 -1
  61. package/src/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.js +4 -11
  62. package/src/engine/graphics/ecs/mesh-v2/SHADED_GEOMETRY_EVENT_CHANGE.d.ts +14 -0
  63. package/src/engine/graphics/ecs/mesh-v2/SHADED_GEOMETRY_EVENT_CHANGE.d.ts.map +1 -0
  64. package/src/engine/graphics/ecs/mesh-v2/SHADED_GEOMETRY_EVENT_CHANGE.js +13 -0
  65. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +2 -14
  66. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts.map +1 -1
  67. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +11 -21
  68. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.d.ts +1 -0
  69. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +7 -0
  70. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.d.ts +5 -6
  71. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.d.ts.map +1 -1
  72. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.js +13 -11
  73. package/src/engine/graphics/ecs/mesh-v2/shaded_geometry_announce_change.d.ts +14 -0
  74. package/src/engine/graphics/ecs/mesh-v2/shaded_geometry_announce_change.d.ts.map +1 -0
  75. package/src/engine/graphics/ecs/mesh-v2/shaded_geometry_announce_change.js +21 -0
  76. package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts +1 -1
  77. package/src/engine/graphics/ecs/particles/ParticleEffect.js +1 -1
  78. package/src/engine/graphics/sh3/path_tracer/populate_path_traced_scene_from_ecd.d.ts +1 -1
  79. package/src/engine/graphics/sh3/path_tracer/populate_path_traced_scene_from_ecd.js +1 -1
  80. package/src/engine/graphics3/AnimationGraphSystem.js +3 -3
  81. package/src/engine/graphics3/AnimationSystem.js +2 -2
  82. package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
  83. package/src/engine/graphics3/DebugDrawSystem.js +2 -4
  84. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +34 -27
  85. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
  86. package/src/engine/graphics3/GPUParticleEmitterSystem.js +185 -85
  87. package/src/engine/graphics3/HighlightOutlineSystem.d.ts +4 -3
  88. package/src/engine/graphics3/HighlightOutlineSystem.d.ts.map +1 -1
  89. package/src/engine/graphics3/HighlightOutlineSystem.js +7 -9
  90. package/src/engine/graphics3/LightSystem.d.ts +7 -5
  91. package/src/engine/graphics3/LightSystem.d.ts.map +1 -1
  92. package/src/engine/graphics3/LightSystem.js +36 -22
  93. package/src/engine/graphics3/MeshSystem.d.ts +43 -39
  94. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  95. package/src/engine/graphics3/MeshSystem.js +324 -331
  96. package/src/engine/graphics3/PathDisplaySystem.d.ts.map +1 -1
  97. package/src/engine/graphics3/PathDisplaySystem.js +2 -4
  98. package/src/engine/graphics3/PickingQuery.d.ts +15 -21
  99. package/src/engine/graphics3/PickingQuery.d.ts.map +1 -1
  100. package/src/engine/graphics3/PickingQuery.js +21 -25
  101. package/src/engine/graphics3/PickingSystem.d.ts +60 -31
  102. package/src/engine/graphics3/PickingSystem.d.ts.map +1 -1
  103. package/src/engine/graphics3/PickingSystem.js +416 -273
  104. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +22 -12
  105. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  106. package/src/engine/graphics3/ShadedGeometrySystem.js +309 -174
  107. package/src/engine/graphics3/TerrainSystem.d.ts +19 -11
  108. package/src/engine/graphics3/TerrainSystem.d.ts.map +1 -1
  109. package/src/engine/graphics3/TerrainSystem.js +102 -53
  110. package/src/engine/graphics3/TooltipComponentSystem.d.ts.map +1 -1
  111. package/src/engine/graphics3/TooltipComponentSystem.js +2 -14
  112. package/src/engine/graphics3/Trail3DSystem.d.ts.map +1 -1
  113. package/src/engine/graphics3/Trail3DSystem.js +2 -4
  114. package/src/engine/graphics3/animation/ClipListPlayer.d.ts +4 -4
  115. package/src/engine/graphics3/animation/ClipListPlayer.d.ts.map +1 -1
  116. package/src/engine/graphics3/animation/ClipListPlayer.js +2 -2
  117. package/src/engine/graphics3/highlight/pack_highlight_table.d.ts +9 -11
  118. package/src/engine/graphics3/highlight/pack_highlight_table.d.ts.map +1 -1
  119. package/src/engine/graphics3/highlight/pack_highlight_table.js +11 -18
  120. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +4 -3
  121. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  122. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +75 -74
  123. package/src/engine/graphics3/prefab/Prefab.d.ts +130 -0
  124. package/src/engine/graphics3/prefab/Prefab.d.ts.map +1 -0
  125. package/src/engine/graphics3/prefab/Prefab.js +162 -0
  126. package/src/engine/graphics3/prefab/PrefabInstance.d.ts +72 -0
  127. package/src/engine/graphics3/prefab/PrefabInstance.d.ts.map +1 -0
  128. package/src/engine/graphics3/prefab/PrefabInstance.js +80 -0
  129. package/src/engine/graphics3/prefab/prefab_compile.d.ts +23 -0
  130. package/src/engine/graphics3/prefab/prefab_compile.d.ts.map +1 -0
  131. package/src/engine/graphics3/prefab/prefab_compile.js +334 -0
  132. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts +46 -0
  133. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -0
  134. package/src/engine/graphics3/prefab/prefab_instantiate.js +230 -0
  135. package/src/engine/graphics3/prefab/prefab_normalize_skin_frames.d.ts +70 -0
  136. package/src/engine/graphics3/prefab/prefab_normalize_skin_frames.d.ts.map +1 -0
  137. package/src/engine/graphics3/prefab/prefab_normalize_skin_frames.js +210 -0
  138. package/src/engine/graphics3/prefab/prefab_place.d.ts +60 -0
  139. package/src/engine/graphics3/prefab/prefab_place.d.ts.map +1 -0
  140. package/src/engine/graphics3/prefab/prefab_place.js +130 -0
  141. package/src/engine/graphics3/prefab/prefab_skin_clip_scale_conflicts.d.ts +60 -0
  142. package/src/engine/graphics3/prefab/prefab_skin_clip_scale_conflicts.d.ts.map +1 -0
  143. package/src/engine/graphics3/prefab/prefab_skin_clip_scale_conflicts.js +128 -0
  144. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts +40 -0
  145. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -0
  146. package/src/engine/graphics3/prefab/prefab_skin_frame.js +116 -0
  147. package/src/engine/graphics3/preview/make_model_preview_scene.d.ts +16 -14
  148. package/src/engine/graphics3/preview/make_model_preview_scene.d.ts.map +1 -1
  149. package/src/engine/graphics3/preview/make_model_preview_scene.js +126 -154
  150. package/src/engine/graphics3/preview/make_model_thumbnail.js +1 -1
  151. package/src/engine/graphics3/register_instance_animation.d.ts +6 -6
  152. package/src/engine/graphics3/register_instance_animation.d.ts.map +1 -1
  153. package/src/engine/graphics3/register_instance_animation.js +4 -4
  154. package/src/engine/graphics3/shade_bundle_bounds.d.ts +2 -6
  155. package/src/engine/graphics3/shade_bundle_bounds.d.ts.map +1 -1
  156. package/src/engine/graphics3/shade_bundle_bounds.js +47 -55
  157. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts +11 -18
  158. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts.map +1 -1
  159. package/src/engine/graphics3/terrain/pack_terrain_row_table.js +48 -53
  160. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +17 -2
  161. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  162. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +284 -256
  163. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +13 -15
  164. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  165. package/src/engine/physics/cloth/ecs/ClothInstance.js +12 -14
  166. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +7 -8
  167. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -1
  168. package/src/engine/physics/cloth/ecs/ClothRig.js +7 -8
  169. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +5 -4
  170. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  171. package/src/engine/physics/cloth/ecs/ClothSystem.js +11 -12
  172. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -23
  173. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  174. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +201 -199
  175. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  176. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +8 -0
  177. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts +18 -34
  178. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -1
  179. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +58 -115
  180. package/src/engine/physics/cloth/playground/README.md +11 -11
  181. package/src/engine/physics/cloth/playground/garment_build.d.ts +0 -1
  182. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -1
  183. package/src/engine/physics/cloth/playground/garment_build.js +64 -58
  184. package/src/engine/physics/cloth/playground/garment_main.js +59 -33
  185. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  186. package/src/shade/RENDERER_CONTRACT.md +85 -53
  187. package/src/shade/device/ShadeGPUCommandContext.d.ts +23 -0
  188. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  189. package/src/shade/device/ShadeGPUCommandContext.js +36 -0
  190. package/src/shade/playground/add_random_meshes.d.ts +4 -4
  191. package/src/shade/playground/add_random_meshes.d.ts.map +1 -1
  192. package/src/shade/playground/add_random_meshes.js +20 -16
  193. package/src/shade/playground/avboit/main.d.ts +1 -0
  194. package/src/shade/playground/avboit/main.d.ts.map +1 -1
  195. package/src/shade/playground/avboit/main.js +916 -875
  196. package/src/shade/playground/basis_textures/main.d.ts.map +1 -1
  197. package/src/shade/playground/basis_textures/main.js +22 -8
  198. package/src/shade/playground/basis_textures/texture_inventory.d.ts +2 -2
  199. package/src/shade/playground/basis_textures/texture_inventory.d.ts.map +1 -1
  200. package/src/shade/playground/basis_textures/texture_inventory.js +6 -7
  201. package/src/shade/playground/ground_seam/main.d.ts.map +1 -1
  202. package/src/shade/playground/ground_seam/main.js +13 -4
  203. package/src/shade/playground/ground_seam/make_ground.d.ts +13 -4
  204. package/src/shade/playground/ground_seam/make_ground.d.ts.map +1 -1
  205. package/src/shade/playground/ground_seam/make_ground.js +21 -16
  206. package/src/shade/playground/particle_ecs/bonfire_editor.js +3 -3
  207. package/src/shade/playground/particle_system/main.js +11 -10
  208. package/src/shade/playground/particle_system/particle_prototype.d.ts +15 -10
  209. package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
  210. package/src/shade/playground/particle_system/particle_prototype.js +56 -15
  211. package/src/shade/playground/particle_system/particle_scene.d.ts +68 -28
  212. package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -1
  213. package/src/shade/playground/particle_system/particle_scene.js +149 -53
  214. package/src/shade/playground/readback_crossover/index.html +41 -0
  215. package/src/shade/playground/readback_crossover/main.d.ts +2 -0
  216. package/src/shade/playground/readback_crossover/main.d.ts.map +1 -0
  217. package/src/shade/playground/readback_crossover/main.js +372 -0
  218. package/src/shade/playground/skinned_blas_refit/README.md +11 -7
  219. package/src/shade/playground/skinned_blas_refit/add_floor.d.ts +13 -44
  220. package/src/shade/playground/skinned_blas_refit/add_floor.d.ts.map +1 -1
  221. package/src/shade/playground/skinned_blas_refit/add_floor.js +19 -59
  222. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  223. package/src/shade/playground/skinned_blas_refit/main.js +67 -58
  224. package/src/shade/playground/skinned_blas_refit/place_character.d.ts +40 -54
  225. package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -1
  226. package/src/shade/playground/skinned_blas_refit/place_character.js +47 -74
  227. package/src/shade/playground/skinned_blas_refit/sweep_views.d.ts +3 -3
  228. package/src/shade/playground/skinned_blas_refit/sweep_views.d.ts.map +1 -1
  229. package/src/shade/playground/skinned_blas_refit/sweep_views.js +4 -3
  230. package/src/shade/playground/skinned_blas_refit/verify_clone_leaves.d.ts +3 -3
  231. package/src/shade/playground/skinned_blas_refit/verify_clone_leaves.d.ts.map +1 -1
  232. package/src/shade/playground/skinned_blas_refit/verify_clone_leaves.js +11 -4
  233. package/src/shade/playground/skinned_blas_refit/verify_instance_bounds.d.ts.map +1 -1
  234. package/src/shade/playground/skinned_blas_refit/verify_instance_bounds.js +38 -9
  235. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.d.ts +3 -3
  236. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.d.ts.map +1 -1
  237. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.js +9 -6
  238. package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.d.ts +3 -3
  239. package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.d.ts.map +1 -1
  240. package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.js +3 -3
  241. package/src/shade/playground/skinned_mesh_soup/README.md +6 -6
  242. package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
  243. package/src/shade/playground/skinned_mesh_soup/main.js +44 -102
  244. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts +5 -5
  245. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -1
  246. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +42 -33
  247. package/src/shade/playground/sponza_path_trace/main.d.ts +1 -0
  248. package/src/shade/playground/sponza_path_trace/main.d.ts.map +1 -1
  249. package/src/shade/playground/sponza_path_trace/main.js +393 -363
  250. package/src/shade/playground/ssr_reprojection/main.js +11 -9
  251. package/src/shade/playground/ssr_reprojection/scene.d.ts +15 -4
  252. package/src/shade/playground/ssr_reprojection/scene.d.ts.map +1 -1
  253. package/src/shade/playground/ssr_reprojection/scene.js +32 -11
  254. package/src/shade/playground/ssr_variance/main.js +1 -1
  255. package/src/shade/playground/ssr_variance/scene.d.ts +10 -4
  256. package/src/shade/playground/ssr_variance/scene.d.ts.map +1 -1
  257. package/src/shade/playground/ssr_variance/scene.js +39 -15
  258. package/src/shade/playground/vgeo_viewer/main.js +6 -2
  259. package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
  260. package/src/shade/playground/volumetrics_froxel/main.js +936 -922
  261. package/src/shade/renderer/GraphicsContext.d.ts +7 -0
  262. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  263. package/src/shade/renderer/GraphicsContext.js +11 -0
  264. package/src/shade/renderer/Renderer.d.ts +3 -2
  265. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  266. package/src/shade/renderer/Renderer.js +3 -2
  267. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +39 -47
  268. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  269. package/src/shade/renderer/animation/GPUAnimationManager.js +319 -256
  270. package/src/shade/renderer/animation/ShadeAnimationChannel.d.ts +26 -22
  271. package/src/shade/renderer/animation/ShadeAnimationChannel.d.ts.map +1 -1
  272. package/src/shade/renderer/animation/ShadeAnimationChannel.js +28 -23
  273. package/src/shade/renderer/animation/ShadeAnimationClip.d.ts +14 -6
  274. package/src/shade/renderer/animation/ShadeAnimationClip.d.ts.map +1 -1
  275. package/src/shade/renderer/animation/ShadeAnimationClip.js +20 -8
  276. package/src/shade/renderer/animation/Skin.d.ts +19 -19
  277. package/src/shade/renderer/animation/Skin.d.ts.map +1 -1
  278. package/src/shade/renderer/animation/Skin.js +15 -13
  279. package/src/shade/renderer/animation/pose/pose_evaluate_local.d.ts +6 -5
  280. package/src/shade/renderer/animation/pose/pose_evaluate_local.d.ts.map +1 -1
  281. package/src/shade/renderer/animation/pose/pose_evaluate_local.js +9 -9
  282. package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts +5 -59
  283. package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts.map +1 -1
  284. package/src/shade/renderer/animation/skin_clip_scale_conflicts.js +8 -132
  285. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +65 -62
  286. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  287. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +148 -194
  288. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts.map +1 -1
  289. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +4 -7
  290. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts +2 -2
  291. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.js +2 -2
  292. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts +74 -0
  293. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts.map +1 -0
  294. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.js +240 -0
  295. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts +14 -0
  296. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  297. package/src/shade/renderer/buffer/table/GPUDatabase.js +64 -6
  298. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.d.ts +190 -0
  299. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.d.ts.map +1 -0
  300. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.js +1323 -0
  301. package/src/shade/renderer/buffer/table/GPUPageMetadata.d.ts +10 -0
  302. package/src/shade/renderer/buffer/table/GPUPageMetadata.d.ts.map +1 -1
  303. package/src/shade/renderer/buffer/table/GPUPageMetadata.js +12 -0
  304. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts +96 -0
  305. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts.map +1 -0
  306. package/src/shade/renderer/buffer/table/GPUReadbackStatus.d.ts +15 -0
  307. package/src/shade/renderer/buffer/table/GPUReadbackStatus.d.ts.map +1 -0
  308. package/src/shade/renderer/buffer/table/GPUReadbackStatus.js +34 -0
  309. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +75 -7
  310. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  311. package/src/shade/renderer/buffer/table/GPUTypedTable.js +518 -135
  312. package/src/shade/renderer/buffer/table/GPU_TABLE_GATHER_DESCRIPTOR_WORDS.d.ts +19 -0
  313. package/src/shade/renderer/buffer/table/GPU_TABLE_GATHER_DESCRIPTOR_WORDS.d.ts.map +1 -0
  314. package/src/shade/renderer/buffer/table/GPU_TABLE_GATHER_DESCRIPTOR_WORDS.js +18 -0
  315. package/src/shade/renderer/buffer/table/WordViews.d.ts +39 -0
  316. package/src/shade/renderer/buffer/table/WordViews.d.ts.map +1 -0
  317. package/src/shade/renderer/buffer/table/WordViews.js +62 -0
  318. package/src/shade/renderer/buffer/table/gpu_table_gather_shader.d.ts +27 -0
  319. package/src/shade/renderer/buffer/table/gpu_table_gather_shader.d.ts.map +1 -0
  320. package/src/shade/renderer/buffer/table/gpu_table_gather_shader.js +117 -0
  321. package/src/shade/renderer/buffer/table/serde/generate_record_writer.d.ts +121 -0
  322. package/src/shade/renderer/buffer/table/serde/generate_record_writer.d.ts.map +1 -0
  323. package/src/shade/renderer/buffer/table/serde/generate_record_writer.js +395 -0
  324. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  325. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +70 -20
  326. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +1 -1
  327. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  328. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +6 -5
  329. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +3 -3
  330. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  331. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +15 -11
  332. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_bake_for_scene.d.ts +1 -1
  333. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_bake_for_scene.js +4 -4
  334. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_generate_tree_from_scene.d.ts +1 -3
  335. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_generate_tree_from_scene.d.ts.map +1 -1
  336. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_generate_tree_from_scene.js +5 -4
  337. package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.js +1 -1
  338. package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.d.ts.map +1 -1
  339. package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.js +1 -4
  340. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts +8 -3
  341. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts.map +1 -1
  342. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.js +19 -14
  343. package/src/shade/renderer/global_illumination/lpv/placement/graph_generate_probe_locations.d.ts.map +1 -1
  344. package/src/shade/renderer/global_illumination/lpv/placement/graph_generate_probe_locations.js +9 -1
  345. package/src/shade/renderer/global_illumination/lpv/placement/software/lpv_generate_probe_locations2.d.ts +3 -3
  346. package/src/shade/renderer/global_illumination/lpv/placement/software/lpv_generate_probe_locations2.d.ts.map +1 -1
  347. package/src/shade/renderer/global_illumination/lpv/placement/software/lpv_generate_probe_locations2.js +12 -5
  348. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +1 -1
  349. package/src/shade/renderer/light/GPULightCollection.d.ts +29 -0
  350. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  351. package/src/shade/renderer/light/GPULightCollection.js +444 -329
  352. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.d.ts.map +1 -1
  353. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.js +7 -1
  354. package/src/shade/renderer/light/LightCollection.d.ts +29 -1
  355. package/src/shade/renderer/light/LightCollection.d.ts.map +1 -1
  356. package/src/shade/renderer/light/LightCollection.js +50 -1
  357. package/src/shade/renderer/light/make_sunlight.js +2 -2
  358. package/src/shade/renderer/light/model/Light.d.ts +29 -2
  359. package/src/shade/renderer/light/model/Light.d.ts.map +1 -1
  360. package/src/shade/renderer/light/model/Light.js +30 -2
  361. package/src/shade/renderer/light/model/io/light_record_directional.d.ts +3 -1
  362. package/src/shade/renderer/light/model/io/light_record_directional.d.ts.map +1 -1
  363. package/src/shade/renderer/light/model/io/light_record_directional.js +8 -5
  364. package/src/shade/renderer/light/model/io/light_record_point.d.ts +3 -1
  365. package/src/shade/renderer/light/model/io/light_record_point.d.ts.map +1 -1
  366. package/src/shade/renderer/light/model/io/light_record_point.js +5 -2
  367. package/src/shade/renderer/light/model/io/light_record_spot.d.ts +4 -1
  368. package/src/shade/renderer/light/model/io/light_record_spot.d.ts.map +1 -1
  369. package/src/shade/renderer/light/model/io/light_record_spot.js +10 -6
  370. package/src/shade/renderer/light/place_light.d.ts +16 -0
  371. package/src/shade/renderer/light/place_light.d.ts.map +1 -0
  372. package/src/shade/renderer/light/place_light.js +36 -0
  373. package/src/shade/renderer/light/shader_refresh_light_poses.d.ts +44 -0
  374. package/src/shade/renderer/light/shader_refresh_light_poses.d.ts.map +1 -0
  375. package/src/shade/renderer/light/shader_refresh_light_poses.js +154 -0
  376. package/src/shade/renderer/lightmap/GPULightMap.js +1 -1
  377. package/src/shade/renderer/lightmap/bake/raster/graph_draw_lightmap_viz_buffer.d.ts.map +1 -1
  378. package/src/shade/renderer/lightmap/bake/raster/graph_draw_lightmap_viz_buffer.js +12 -14
  379. package/src/shade/renderer/loader/SceneBundle.d.ts +53 -28
  380. package/src/shade/renderer/loader/SceneBundle.d.ts.map +1 -1
  381. package/src/shade/renderer/loader/SceneBundle.js +111 -56
  382. package/src/shade/renderer/loader/SceneNode.d.ts +81 -0
  383. package/src/shade/renderer/loader/SceneNode.d.ts.map +1 -0
  384. package/src/shade/renderer/loader/SceneNode.js +114 -0
  385. package/src/shade/renderer/loader/gltf/load_gltf.d.ts +3 -2
  386. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  387. package/src/shade/renderer/loader/gltf/load_gltf.js +110 -142
  388. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  389. package/src/shade/renderer/loader/usd/UsdExtensionRegistry.d.ts +4 -4
  390. package/src/shade/renderer/loader/usd/UsdExtensionRegistry.d.ts.map +1 -1
  391. package/src/shade/renderer/loader/usd/UsdExtensionRegistry.js +2 -2
  392. package/src/shade/renderer/loader/usd/load_usd.d.ts +3 -2
  393. package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
  394. package/src/shade/renderer/loader/usd/load_usd.js +4 -5
  395. package/src/shade/renderer/loader/usd/usd_build_scene.d.ts +3 -3
  396. package/src/shade/renderer/loader/usd/usd_build_scene.d.ts.map +1 -1
  397. package/src/shade/renderer/loader/usd/usd_build_scene.js +47 -55
  398. package/src/shade/renderer/material/GPUMaterialManager.js +1 -1
  399. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +5 -4
  400. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  401. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +8 -15
  402. package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.d.ts +15 -13
  403. package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.d.ts.map +1 -1
  404. package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.js +40 -21
  405. package/src/shade/renderer/particles/DESIGN.md +53 -50
  406. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +31 -17
  407. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  408. package/src/shade/renderer/particles/GPUParticleSystem.js +54 -91
  409. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +12 -11
  410. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
  411. package/src/shade/renderer/particles/runtime/EmitterRegistry.js +12 -11
  412. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +13 -19
  413. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -1
  414. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +19 -25
  415. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +34 -24
  416. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  417. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +53 -40
  418. package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.js +1 -1
  419. package/src/shade/renderer/path_tracer/graph_path_trace_scene.js +1 -1
  420. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  421. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.d.ts.map +1 -1
  422. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.js +2 -1
  423. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_scene_meshes_cull_and_classify_buckets.d.ts.map +1 -1
  424. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_scene_meshes_cull_and_classify_buckets.js +5 -2
  425. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +1 -1
  426. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
  427. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +1 -1
  428. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +1 -1
  429. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +1 -1
  430. package/src/shade/renderer/scene/DynamicMesh.d.ts +13 -4
  431. package/src/shade/renderer/scene/DynamicMesh.d.ts.map +1 -1
  432. package/src/shade/renderer/scene/DynamicMesh.js +14 -4
  433. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts +38 -18
  434. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts.map +1 -1
  435. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.js +112 -60
  436. package/src/shade/renderer/scene/GPUSceneContext.d.ts +55 -48
  437. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  438. package/src/shade/renderer/scene/GPUSceneContext.js +594 -928
  439. package/src/shade/renderer/scene/NODE3D_STRUCT.d.ts +5 -5
  440. package/src/shade/renderer/scene/NODE3D_STRUCT.js +5 -5
  441. package/src/shade/renderer/scene/Node3D.d.ts +27 -8
  442. package/src/shade/renderer/scene/Node3D.d.ts.map +1 -1
  443. package/src/shade/renderer/scene/Node3DDirtyList.d.ts +59 -0
  444. package/src/shade/renderer/scene/Node3DDirtyList.d.ts.map +1 -0
  445. package/src/shade/renderer/scene/Scene.d.ts +18 -60
  446. package/src/shade/renderer/scene/Scene.d.ts.map +1 -1
  447. package/src/shade/renderer/scene/Scene.js +53 -146
  448. package/src/shade/renderer/scene/SkinnedMesh.d.ts +10 -93
  449. package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +1 -1
  450. package/src/shade/renderer/scene/bvh/StaticSceneBVH.d.ts +24 -3
  451. package/src/shade/renderer/scene/bvh/StaticSceneBVH.d.ts.map +1 -1
  452. package/src/shade/renderer/scene/bvh/StaticSceneBVH.js +53 -13
  453. package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.d.ts +5 -6
  454. package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.d.ts.map +1 -1
  455. package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.js +5 -6
  456. package/src/shade/renderer/scene/optimization/scene_optimize.d.ts +10 -2
  457. package/src/shade/renderer/scene/optimization/scene_optimize.d.ts.map +1 -1
  458. package/src/shade/renderer/scene/optimization/scene_optimize.js +266 -230
  459. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.d.ts +53 -0
  460. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.d.ts.map +1 -0
  461. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.js +144 -0
  462. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts +227 -0
  463. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -0
  464. package/src/shade/renderer/scene/rows/GPUSceneRows.js +1136 -0
  465. package/src/shade/renderer/scene/rows/place_primitive.d.ts +48 -0
  466. package/src/shade/renderer/scene/rows/place_primitive.d.ts.map +1 -0
  467. package/src/shade/renderer/scene/rows/place_primitive.js +98 -0
  468. package/src/shade/renderer/scene/serialization/deserialize_scene.d.ts +10 -8
  469. package/src/shade/renderer/scene/serialization/deserialize_scene.d.ts.map +1 -1
  470. package/src/shade/renderer/scene/serialization/deserialize_scene.js +24 -27
  471. package/src/shade/renderer/scene/serialization/serialize_scene.d.ts +9 -2
  472. package/src/shade/renderer/scene/serialization/serialize_scene.d.ts.map +1 -1
  473. package/src/shade/renderer/scene/serialization/serialize_scene.js +25 -4
  474. package/src/shade/renderer/scene/verify_gpu_tlas_build.js +2 -2
  475. package/src/shade/renderer/shader/chunk/light/DIRECTIONAL_LIGHT_STRUCT.d.ts.map +1 -1
  476. package/src/shade/renderer/shader/chunk/light/DIRECTIONAL_LIGHT_STRUCT.js +5 -0
  477. package/src/shade/renderer/shader/chunk/light/POINT_LIGHT_STRUCT.d.ts.map +1 -1
  478. package/src/shade/renderer/shader/chunk/light/POINT_LIGHT_STRUCT.js +5 -0
  479. package/src/shade/renderer/shader/chunk/light/SPOT_LIGHT_STRUCT.d.ts.map +1 -1
  480. package/src/shade/renderer/shader/chunk/light/SPOT_LIGHT_STRUCT.js +5 -0
  481. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts +39 -0
  482. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
  483. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +112 -64
  484. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +7 -0
  485. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  486. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +1541 -1352
  487. package/src/shade/renderer/shadow/map/PointLightShadowmap.js +1 -1
  488. package/src/shade/renderer/shadow/map/SpotLightShadowmap.js +1 -1
  489. package/src/shade/renderer/shadow/map/TetrahedronPointLightShadowmap.js +1 -1
  490. package/src/shade/renderer/shadow/map/csm/CSM_CASTER_RANGE_STRUCT.d.ts +29 -0
  491. package/src/shade/renderer/shadow/map/csm/CSM_CASTER_RANGE_STRUCT.d.ts.map +1 -0
  492. package/src/shade/renderer/shadow/map/csm/CSM_CASTER_RANGE_STRUCT.js +43 -0
  493. package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_CASTER_RANGE_MARGIN_FRACTION.d.ts +13 -0
  494. package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_CASTER_RANGE_MARGIN_FRACTION.d.ts.map +1 -0
  495. package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_CASTER_RANGE_MARGIN_FRACTION.js +12 -0
  496. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts +49 -0
  497. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts.map +1 -0
  498. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.js +194 -0
  499. package/src/shade/renderer/shadow/map/csm_debug_draw_preview.js +1 -1
  500. package/src/shade/renderer/shadow/map/shadowmap_update_score.js +1 -1
  501. package/src/shade/renderer/shadow/ray/RTXShadows.js +1 -1
  502. package/src/shade/renderer/shadow/ray/staged/trace/graph_trace_rays.js +1 -1
  503. package/src/shade/renderer/shadow/sdf/cascade/CascadedSceneSDF.d.ts.map +1 -1
  504. package/src/shade/renderer/shadow/sdf/cascade/CascadedSceneSDF.js +3 -1
  505. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +8 -8
  506. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  507. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +4 -3
  508. package/src/engine/graphics3/instantiate_scene_bundle.js +0 -164
  509. package/src/engine/graphics3/shade_node_to_entity_composition.js +0 -88
  510. package/src/shade/renderer/animation/compute_skin_world_bounds.js +0 -146
  511. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.js +0 -531
  512. package/src/shade/renderer/animation/pose/pose_evaluate_world.js +0 -76
  513. package/src/shade/renderer/animation/skin_bind_transform.js +0 -33
  514. package/src/shade/renderer/animation/skin_frame_defect.js +0 -132
  515. package/src/shade/renderer/animation/skin_joint_matrix.js +0 -46
  516. package/src/shade/renderer/animation/skin_normalize_mesh_frame.js +0 -216
  517. package/src/shade/renderer/scene/InstanceBatch.js +0 -235
  518. package/src/shade/renderer/scene/Mesh.js +0 -168
  519. package/src/shade/renderer/scene/Node3D.js +0 -263
  520. package/src/shade/renderer/scene/SceneNodeBinding.js +0 -56
  521. package/src/shade/renderer/scene/SkinnedMesh.js +0 -170
  522. package/src/shade/renderer/scene/TransformAuthority.js +0 -33
@@ -3,8 +3,8 @@
3
3
  A specialized, deeply-integrated, GPU-driven particle engine for the v2 renderer.
4
4
  Destiny-style: **one** simulation dispatch runs **all** particles of **all** emitters by
5
5
  interpreting a compact per-emitter bytecode program (a shader VM). Effects are authored as
6
- node graphs and lowered to that bytecode by a testable JS compiler. Emitters are scene nodes, and
7
- the decision to spawn is the GPU's.
6
+ node graphs and lowered to that bytecode by a testable JS compiler. Emitters run at entities'
7
+ rows, and the decision to spawn is the GPU's.
8
8
 
9
9
  ## Goals (from the brief)
10
10
 
@@ -18,8 +18,8 @@ the decision to spawn is the GPU's.
18
18
  - Texture lookup via atlas (region table; mirrors meep `AtlasPatch` uv offset/scale).
19
19
  - Soft-depth fade (flagged).
20
20
  - `GPUDatabase` for CPU-managed, low-churn tables (emitters).
21
- - Scene-node / bone attachment: an emitter **is** a `Node3D`; its world matrix is its row of the
22
- scene's `transforms` table, composed by the GPU hierarchy pass.
21
+ - Scene / bone attachment: an emitter stands at an entity with a row; its world matrix is that row
22
+ of the scene's `transforms` table, composed by the GPU hierarchy pass.
23
23
  - Distinct per-particle lifecycle: **no** built-in age/position — the schema + program define state.
24
24
  - Billboard drawing reuses engine shader chunks incl. lighting (forward-shaded, optional per emitter).
25
25
  - Blend modes (alpha + additive) via a **single** premultiplied blend setup.
@@ -33,7 +33,7 @@ the decision to spawn is the GPU's.
33
33
  authoring: NodeGraph (nodes+ports) ──compile──▶ Program (bytecode: INIT + UPDATE)
34
34
  standard node library │
35
35
  ▼
36
- runtime CPU: ParticleEmitter (a Node3D) ── Scene ──▶ GPUSceneContext (transforms table)
36
+ runtime CPU: ParticleEmitter (at an entity) ── Scene ──▶ GPUSceneContext (transforms table)
37
37
  EmitterRegistry ── GPUDatabase(emitters + emitter_state) ─┤ ProgramHeap ([header][constants][code])
38
38
  GPUParticleSystem (owns every buffer, records the frame)
39
39
  ▼
@@ -222,33 +222,32 @@ disk/cone), authored curves and RGB/RGBA gradients, noise (curl), integrate, gra
222
222
  compare/select, kill-if. Curves and gradients expand into graph nodes that emit ordinary VM
223
223
  arithmetic; no animation-table binding or sampling opcode is needed.
224
224
 
225
- ### Emitters are scene nodes
226
-
227
- `ParticleEmitter extends Node3D`. Add one to a `Scene` — on its own or under a joint — and the
228
- scene context's membership sweep gives it a `transforms` row like any node; the GPU hierarchy pass
229
- composes its `global` from its own transform and its parents' every frame, animation included.
230
- `GPUParticleSystem` sweeps the scene's node list when the scene's membership version moves, gives
231
- each emitter node a row in the emitter table pointed at its `transforms` row, and retires the row
232
- when the node leaves. Attaching an emitter to a bone is `joint.addChild(emitter)`; there is no
233
- per-frame transform copy, and an emitter under a GPU-animated joint follows it — which the old
234
- CPU-side copy of `transform_global` could not do, since the CPU never updates that matrix for a
235
- node the GPU owns.
236
-
237
- **The node knows nothing about the GPU.** A `ParticleEmitter` is a transform, an attribute
238
- `layout`, a compiled `program`, a `texture` URL, and the emission parameters — all of it the
239
- author's, all of it meaning the same thing with no device present, all of it what a saved effect is
240
- made of. Everything the system assigns is a `GPUParticleEmitterContext`, held by the
225
+ ### Emitters run at entities' rows
226
+
227
+ A `ParticleEmitter` is placed by registration: `GPUParticleSystem#add_emitter(emitter,
228
+ transform_row)` gives it a row in the emitter table pointed at a `transforms` row — an entity's,
229
+ one on, held through the scene context's rows by whoever owns the entity — and `remove_emitter`
230
+ retires the row and frees its particles. The GPU hierarchy pass composes that row's `global` from
231
+ its pose and its parents' every frame, animation included, so an emitter registered at a joint's
232
+ row follows the joint with nothing copied through the CPU — which a CPU-side copy of a world
233
+ matrix could not do, since the CPU never sees the matrix of a row the GPU owns. Nothing walks the
234
+ scene: an emitter is where its owner says it is, and per-frame upkeep is proportional to what
235
+ changed rather than to how many emitters there are.
236
+
237
+ **The emitter knows nothing about the GPU, and nothing about where.** A `ParticleEmitter` is an
238
+ attribute `layout`, a compiled `program`, a `texture` URL, and the emission parameters — all of
239
+ it the author's, all of it meaning the same thing with no device present, all of it what a saved
240
+ effect is made of. Everything the system assigns is a `GPUParticleEmitterContext`, held by the
241
241
  `EmitterRegistry` against the emitter and reached through `registry.context(emitter)`: the table
242
- row, the generation, the program placement, the node's `transforms` row, the atlas patch. So an
243
- emitter cannot be saved with a row in it, cannot be given one by hand, and "is this emitter live?"
244
- is asked of the registry rather than read off a `-1` that anything could have written. The record
245
- writer is where the two meet — `write_emitter_record(record, emitter, context)`, next to the struct
246
- it fills.
247
-
248
- Restaging is driven by `Node3D#version`, the node's own change counter, which the renderer already
249
- reads to decide whether a transform needs re-uploading; the context remembers the version its row
250
- was staged from. An author who edits an emitter says so the way they say it for any node —
251
- `needsUpdate = true` — and there is no second flag to forget. A change to the context itself (a
242
+ row, the generation, the program placement, the `transforms` row it is placed at, the atlas patch.
243
+ So an emitter cannot be saved with a row in it, cannot be given one by hand, and "is this emitter
244
+ live?" is asked of the registry rather than read off a `-1` that anything could have written. The
245
+ record writer is where the two meet — `write_emitter_record(record, emitter, context)`, next to
246
+ the struct it fills.
247
+
248
+ Restaging is driven by `ParticleEmitter#version`, the emitter's own change counter; the context
249
+ remembers the version its row was staged from. An author who edits an emitter says so with
250
+ `needsUpdate = true`, and there is no second flag to forget. A change to the context itself (a
252
251
  `transforms` row, a repacked atlas patch) moves no version, so the context marks itself instead.
253
252
 
254
253
  ### Emitter table (`GPUDatabase`)
@@ -450,7 +449,7 @@ An emitter that sets `EMITTER_FLAG.CULL` has the box on its state row tested aga
450
449
  frustum by the tick pass, with the renderer's shared `chunk_aabb3_intersects_frustum`. The tick does
451
450
  not measure it — it reads what the bounds passes published at the end of the previous frame — so all
452
451
  that is in the spawn path is one frustum test. Because the box is where the particles are rather
453
- than where the node is, an effect whose particles have drifted on screen keeps spawning even when
452
+ than where the emitter is, an effect whose particles have drifted on screen keeps spawning even when
454
453
  its emitter has not. Culled emitters spawn nothing and accrue sleep; on wake the tick adds a
455
454
  catch-up of at most `max_catchup_seconds` of rate. Live particles keep simulating while their
456
455
  emitter is culled, so its box keeps moving and keeps being published. HiZ occlusion is not
@@ -595,22 +594,25 @@ compared and hashed in (`ParticleProgram#constant_words`): `-0` and `+0` are the
595
594
  different constants, and whether a NaN's payload survives a round trip through a JS `number` is
596
595
  implementation-defined even though V8 happens to preserve it.
597
596
 
598
- The system builds one `ParticleEmitter` scene node per linked entity and owns it — placed from the
599
- entity's transform on `TRANSFORM64_EVENT_CHANGE`, added to the scene when the component has a
600
- compiled effect, and retired with the entity. `node_of(entity)` hands the node out for the things an
601
- entity reference cannot express (parenting to the emitter, reading the composed world matrix);
602
- `burst(entity, count)` is the entity-addressed one-shot, queued and drained after the frame's
603
- membership sweep so it works before the first frame has run.
597
+ The system builds one `ParticleEmitter` per linked entity and owns it — registered with the
598
+ scene's particle system at the entity's row (`row_of_entity`, held through the scene context's
599
+ rows) when the component has a compiled effect and a context exists, its row marked from the
600
+ entity's transform on `TRANSFORM64_EVENT_CHANGE`, and retired with the entity. Registration runs at
601
+ link, at every `update` and at `FrameStart`, so an entity spawned mid-level stands where it should
602
+ from its first frame and a device restart re-registers every entry with the context that replaced
603
+ the old one. `emitter_of(entity)` hands the emitter out for what an entity reference cannot express
604
+ (asking the particle system about it); `burst(entity, count)` is the entity-addressed one-shot,
605
+ queued and drained inside the frame so it works before the first frame has run.
604
606
 
605
607
  Component changes are found by **comparison** rather than announced: once a frame each entity's
606
- fields are compared against what was last written to its node, and the node is marked dirty only
607
- where they differ, so a component nobody touched costs a run of integer comparisons and no upload.
608
- That is what lets gameplay write `effect.spawn_rate = 0` from code that has never heard of this
609
- system.
608
+ fields are compared against what was last written to its emitter, and the emitter is marked dirty
609
+ only where they differ, so a component nobody touched costs a run of integer comparisons and no
610
+ upload. That is what lets gameplay write `effect.spawn_rate = 0` from code that has never heard of
611
+ this system.
610
612
 
611
- `GPUParticleSystem` itself still finds emitters by sweeping the scene's node list, so a caller with
612
- no ECS — a playground, a tool — can build `ParticleEmitter` nodes and add them to a `Scene` directly.
613
- Such an emitter has nothing in the ECS system's atlas and is given the white texel; see below.
613
+ A caller with no ECS — a playground, a tool — registers a `ParticleEmitter` with the scene's
614
+ `GPUParticleSystem` directly, at a row of an entity it placed itself. Such an emitter has nothing
615
+ in the ECS system's atlas and is given the white texel; see below.
614
616
 
615
617
  `shade/playground/particle_ecs/` is the worked example: a bonfire whose flame, smoke, embers and soot
616
618
  are four entities, alongside `ShadedGeometry` and `Light` entities in the same scene.
@@ -621,10 +623,11 @@ an image, its patch is removed. Loads completing after a URL change, removal or
621
623
  Failed images are reported and remain transparent until the URL changes or the emitter is re-added.
622
624
  Untextured emitters use a white texel; pending images use a transparent texel.
623
625
 
624
- At `FrameStart`, after the scene context has established transform rows, the system calls
625
- `GPUParticleSystem.sync_membership()`, uploads changed atlas pixels, and refreshes the patch region of
626
- every emitter in the scene — the ones it built get their entity's image, and any other gets the white
627
- texel, because the atlas is the scene's and an emitter it did not build has nothing in it.
626
+ At `FrameStart`, after the scene context has established transform rows, the system registers
627
+ any emitter not yet registered with the frame's context, uploads changed atlas pixels, and refreshes
628
+ the patch region of every emitter the particle system holds — the ones it built get their entity's
629
+ image, and any other gets the white texel, because the atlas is the scene's and an emitter it did
630
+ not build has nothing in it.
628
631
  This occurs before particle simulation stages emitter rows. Every repack or resize therefore updates
629
632
  existing emitters too. The extension enables the renderer's GPU particle feature for its scene;
630
633
  rendering uses the existing AVBOIT path. The system owns a `GPUTextureContext` for the atlas, using
@@ -691,7 +694,7 @@ src/shade/renderer/particles/
691
694
  coherence/graph_particle_bucket.js frame-graph wiring, around graph_prefix_scan_csdldf
692
695
  runtime/ProgramHeap.js the one packed [header][constants][code] buffer, allocator-backed
693
696
  runtime/ProgramPlacement.js where one program sits in it — what an emitter record carries
694
- runtime/ParticleEmitter.js one emitter — a Node3D and an effect, with no GPU in it
697
+ runtime/ParticleEmitter.js one emitter — authoring data for an effect, with no GPU in it
695
698
  runtime/GPUParticleEmitterContext.js what a registry assigns one: row, generation, placement, patch
696
699
  runtime/EmitterRegistry.js GPUDatabase(emitters) + the live emitters + their contexts + the program heap
697
700
  runtime/create_particle_effect.js layout + INIT/UPDATE graphs → compiled effect
@@ -53,14 +53,14 @@
53
53
  * effects it holds and this is where that number meets the VM's; nothing about authoring a graph has
54
54
  * a register ceiling.
55
55
  *
56
- * ## Emitters are scene nodes
56
+ * ## Emitters are registered at rows
57
57
  *
58
- * There is no `addEmitter`. A {@link ParticleEmitter} is a {@link Node3D}: put it in the scene —
59
- * on its own or under a joint — and the next {@link execute} finds it in the scene's node list,
60
- * gives it a row in the emitter table pointed at the `transforms` row the scene context gave the
61
- * node, and it starts spawning. Take it out of the scene and its row is retired and its particles
62
- * freed. The sweep runs only when the scene's membership version moves, which is how per-frame
63
- * upkeep stays proportional to what changed rather than to how many emitters there are.
58
+ * {@link add_emitter} gives a {@link ParticleEmitter} a row in the emitter table pointed at a
59
+ * `transforms` row — an entity's, one on, held through the scene context's rows by whoever owns
60
+ * the entity — and it starts spawning on the next {@link execute}; under a joint's row it moves
61
+ * with the joint. {@link remove_emitter} retires the row and frees its particles. Nothing here
62
+ * walks the scene: an emitter is where its owner says it is, and per-frame upkeep is proportional
63
+ * to what changed rather than to how many emitters there are.
64
64
  *
65
65
  * ## Spawning is the GPU's decision
66
66
  *
@@ -108,7 +108,8 @@ export class GPUParticleSystem {
108
108
  */
109
109
  graphics: object;
110
110
  /**
111
- * The scene whose nodes the emitters are, and whose database their world matrices come from.
111
+ * The scene whose rows the emitters are placed at, and whose database their world matrices
112
+ * come from.
112
113
  * @type {import("../scene/GPUSceneContext.js").GPUSceneContext}
113
114
  */
114
115
  scene_context: import("../scene/GPUSceneContext.js").GPUSceneContext;
@@ -202,7 +203,7 @@ export class GPUParticleSystem {
202
203
  * theirs.
203
204
  *
204
205
  * Call after the scene context has built for the frame (`GPUSceneContext#update`), so every
205
- * emitter node has its `transforms` row, and after the hierarchy pass has run, so the rows'
206
+ * emitter's `transforms` row is uploaded, and after the hierarchy pass has run, so the rows'
206
207
  * `global` matrices are this frame's.
207
208
  *
208
209
  * **Once per frame, not once per view.** This advances the simulation by `dt` and hands out
@@ -304,16 +305,29 @@ export class GPUParticleSystem {
304
305
  emission: number;
305
306
  };
306
307
  /**
307
- * Bring the emitter set in line with the scene: emitter nodes that arrived get rows, nodes that
308
- * left give theirs back. Runs only when the scene's membership version has moved.
308
+ * Register an emitter at a `transforms` row, and if it asks, warm it up before its first frame.
309
309
  *
310
- * A node the scene context has not placed yet (no `transforms` row) is left for the next frame,
311
- * and the version is not recorded, so the sweep runs again until every emitter is bound.
312
- * An atlas owner may call this after the scene context builds, before setting row regions.
313
- * execute() calls it as well; unchanged membership costs one version comparison.
314
- * @returns {void}
310
+ * The row is an entity's, one on (`row_of_entity`), and whoever owns the entity holds it through
311
+ * the scene context's rows for as long as the emitter is registered; this only records which
312
+ * row the emitter's particles are born at. Nothing is uploaded until the next {@link execute}.
313
+ *
314
+ * @param {import("./runtime/ParticleEmitter.js").ParticleEmitter} emitter
315
+ * @param {number} transform_row
316
+ */
317
+ add_emitter(emitter: import("./runtime/ParticleEmitter.js").ParticleEmitter, transform_row: number): void;
318
+ /**
319
+ * Retire an emitter's row; its particles go within a frame, carrying the row's generation.
320
+ *
321
+ * @param {import("./runtime/ParticleEmitter.js").ParticleEmitter} emitter
322
+ */
323
+ remove_emitter(emitter: import("./runtime/ParticleEmitter.js").ParticleEmitter): void;
324
+ /**
325
+ * Point a registered emitter at another row.
326
+ *
327
+ * @param {import("./runtime/ParticleEmitter.js").ParticleEmitter} emitter
328
+ * @param {number} transform_row
315
329
  */
316
- sync_membership(): void;
330
+ set_transform_row(emitter: import("./runtime/ParticleEmitter.js").ParticleEmitter, transform_row: number): void;
317
331
  /**
318
332
  * Sizes of the persistent buffers, in bytes, as they stand — one entry per distinct buffer, so
319
333
  * this is the feature's reserved footprint and not a list of the names it binds them under.
@@ -1 +1 @@
1
- {"version":3,"file":"GPUParticleSystem.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/GPUParticleSystem.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GPUParticleSystem.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/GPUParticleSystem.js"],"names":[],"mappings":"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"}
@@ -109,14 +109,14 @@ const DEFAULT_CAPACITY = 524288;
109
109
  * effects it holds and this is where that number meets the VM's; nothing about authoring a graph has
110
110
  * a register ceiling.
111
111
  *
112
- * ## Emitters are scene nodes
112
+ * ## Emitters are registered at rows
113
113
  *
114
- * There is no `addEmitter`. A {@link ParticleEmitter} is a {@link Node3D}: put it in the scene —
115
- * on its own or under a joint — and the next {@link execute} finds it in the scene's node list,
116
- * gives it a row in the emitter table pointed at the `transforms` row the scene context gave the
117
- * node, and it starts spawning. Take it out of the scene and its row is retired and its particles
118
- * freed. The sweep runs only when the scene's membership version moves, which is how per-frame
119
- * upkeep stays proportional to what changed rather than to how many emitters there are.
114
+ * {@link add_emitter} gives a {@link ParticleEmitter} a row in the emitter table pointed at a
115
+ * `transforms` row — an entity's, one on, held through the scene context's rows by whoever owns
116
+ * the entity — and it starts spawning on the next {@link execute}; under a joint's row it moves
117
+ * with the joint. {@link remove_emitter} retires the row and frees its particles. Nothing here
118
+ * walks the scene: an emitter is where its owner says it is, and per-frame upkeep is proportional
119
+ * to what changed rather than to how many emitters there are.
120
120
  *
121
121
  * ## Spawning is the GPU's decision
122
122
  *
@@ -155,7 +155,8 @@ export class GPUParticleSystem {
155
155
  graphics;
156
156
 
157
157
  /**
158
- * The scene whose nodes the emitters are, and whose database their world matrices come from.
158
+ * The scene whose rows the emitters are placed at, and whose database their world matrices
159
+ * come from.
159
160
  * @type {import("../scene/GPUSceneContext.js").GPUSceneContext}
160
161
  */
161
162
  scene_context;
@@ -243,7 +244,7 @@ export class GPUParticleSystem {
243
244
  /**
244
245
  * Emitters registered since the last frame with a pre-warm to run — the input of the warm-up
245
246
  * pipeline (`warmup/`), consumed by the frame that records it. Filled where the emitter is
246
- * registered ({@link sync_membership}), which is the one moment the host knows an emitter is
247
+ * registered ({@link add_emitter}), which is the one moment the host knows an emitter is
247
248
  * new: the GPU decides everything else about spawning, but "this one has just arrived and asks
248
249
  * to arrive warm" is a host-side fact.
249
250
  *
@@ -258,14 +259,6 @@ export class GPUParticleSystem {
258
259
  */
259
260
  #warmup_words = new Uint32Array(0);
260
261
 
261
- /**
262
- * Emitter node -> the sweep that last saw it in the scene.
263
- * @type {Map<import("./runtime/ParticleEmitter.js").ParticleEmitter, number>}
264
- */
265
- #swept = new Map();
266
-
267
- /** @type {number} */
268
- #sweep = 0;
269
262
 
270
263
  /**
271
264
  * The 1x1 white texture {@link atlas} points at until a caller replaces it. Held so
@@ -274,11 +267,6 @@ export class GPUParticleSystem {
274
267
  */
275
268
  #default_atlas = null;
276
269
 
277
- /**
278
- * The scene membership version the emitter set was last reconciled against.
279
- * @type {number}
280
- */
281
- #instances_version = -1;
282
270
 
283
271
  /**
284
272
  * Program assignments used to build the previous frame's coherence list.
@@ -389,7 +377,7 @@ export class GPUParticleSystem {
389
377
 
390
378
  const context = this.registry.context(emitter);
391
379
 
392
- assert.defined(context, "emitter is not in the scene");
380
+ assert.defined(context, "emitter is not registered");
393
381
 
394
382
  const ring = this.#spawn_commands;
395
383
  const base = this.#spawn_command_count * PARTICLE_SPAWN_COMMAND_WORDS;
@@ -418,7 +406,7 @@ export class GPUParticleSystem {
418
406
  * theirs.
419
407
  *
420
408
  * Call after the scene context has built for the frame (`GPUSceneContext#update`), so every
421
- * emitter node has its `transforms` row, and after the hierarchy pass has run, so the rows'
409
+ * emitter's `transforms` row is uploaded, and after the hierarchy pass has run, so the rows'
422
410
  * `global` matrices are this frame's.
423
411
  *
424
412
  * **Once per frame, not once per view.** This advances the simulation by `dt` and hands out
@@ -439,7 +427,6 @@ export class GPUParticleSystem {
439
427
  assert.defined(graph, "graph");
440
428
  assert.isNumber(dt, "dt");
441
429
 
442
- this.sync_membership();
443
430
  this.#upload();
444
431
 
445
432
  const frame = this.#frame;
@@ -601,72 +588,51 @@ export class GPUParticleSystem {
601
588
  }
602
589
 
603
590
  /**
604
- * Bring the emitter set in line with the scene: emitter nodes that arrived get rows, nodes that
605
- * left give theirs back. Runs only when the scene's membership version has moved.
591
+ * Register an emitter at a `transforms` row, and if it asks, warm it up before its first frame.
606
592
  *
607
- * A node the scene context has not placed yet (no `transforms` row) is left for the next frame,
608
- * and the version is not recorded, so the sweep runs again until every emitter is bound.
609
- * An atlas owner may call this after the scene context builds, before setting row regions.
610
- * execute() calls it as well; unchanged membership costs one version comparison.
611
- * @returns {void}
593
+ * The row is an entity's, one on (`row_of_entity`), and whoever owns the entity holds it through
594
+ * the scene context's rows for as long as the emitter is registered; this only records which
595
+ * row the emitter's particles are born at. Nothing is uploaded until the next {@link execute}.
596
+ *
597
+ * @param {import("./runtime/ParticleEmitter.js").ParticleEmitter} emitter
598
+ * @param {number} transform_row
612
599
  */
613
- sync_membership() {
614
- const scene = this.scene_context.scene;
615
- const batch = scene.instances;
616
-
617
- if (batch.version === this.#instances_version) {
618
- return;
600
+ add_emitter(emitter, transform_row) {
601
+ assert.defined(emitter, 'emitter');
602
+ assert.equal(emitter.isParticleEmitter, true, 'emitter.isParticleEmitter !== true');
603
+ assert.isNonNegativeInteger(transform_row, 'transform_row');
604
+
605
+ this.registry.add(emitter, transform_row);
606
+
607
+ // Just arrived, and asked to arrive warm: the warm-up pipeline runs its simulation forward
608
+ // this frame, before it is first drawn. A reused row is a new emitter as far as this is
609
+ // concerned — it is the emitter that asks, not the row.
610
+ if (emitter.prewarm > 0) {
611
+ this.#warmup_queue.push(emitter);
619
612
  }
613
+ }
620
614
 
621
- const sweep = ++this.#sweep;
622
- const nodes = batch.nodes;
623
- const node_count = nodes.length;
624
- const mapping = this.scene_context.id_mapping;
625
- const registry = this.registry;
626
- const swept = this.#swept;
627
-
628
- let complete = true;
629
-
630
- for (let i = 0; i < node_count; i++) {
631
- const node = nodes[i];
632
-
633
- if (node.isParticleEmitter !== true) {
634
- continue;
635
- }
636
-
637
- const transform_row = mapping.get(node.id);
638
-
639
- if (transform_row === undefined) {
640
- complete = false;
641
- continue;
642
- }
643
-
644
- if (registry.context(node) === undefined) {
645
- registry.add(node, transform_row);
646
-
647
- // Just arrived, and asked to arrive warm: the warm-up pipeline runs its simulation
648
- // forward this frame, before it is first drawn. A reused row is a new emitter as far
649
- // as this is concerned — it is the emitter that asks, not the row.
650
- if (node.prewarm > 0) {
651
- this.#warmup_queue.push(node);
652
- }
653
- } else {
654
- registry.set_transform_row(node, transform_row);
655
- }
615
+ /**
616
+ * Retire an emitter's row; its particles go within a frame, carrying the row's generation.
617
+ *
618
+ * @param {import("./runtime/ParticleEmitter.js").ParticleEmitter} emitter
619
+ */
620
+ remove_emitter(emitter) {
621
+ assert.defined(emitter, 'emitter');
656
622
 
657
- swept.set(node, sweep);
658
- }
623
+ this.registry.remove(emitter);
624
+ }
659
625
 
660
- for (const [emitter, seen] of swept) {
661
- if (seen !== sweep) {
662
- registry.remove(emitter);
663
- swept.delete(emitter);
664
- }
665
- }
626
+ /**
627
+ * Point a registered emitter at another row.
628
+ *
629
+ * @param {import("./runtime/ParticleEmitter.js").ParticleEmitter} emitter
630
+ * @param {number} transform_row
631
+ */
632
+ set_transform_row(emitter, transform_row) {
633
+ assert.isNonNegativeInteger(transform_row, 'transform_row');
666
634
 
667
- if (complete) {
668
- this.#instances_version = batch.version;
669
- }
635
+ this.registry.set_transform_row(emitter, transform_row);
670
636
  }
671
637
 
672
638
  /**
@@ -1086,17 +1052,14 @@ export class GPUParticleSystem {
1086
1052
 
1087
1053
  destroy() {
1088
1054
  /*
1089
- The emitters go first, and they matter more than the buffers: they are the scene's nodes,
1090
- they outlive this system, and each is holding a row of the table about to be freed. A node
1091
- left holding one is stranded — the next system's membership sweep reads `row !== -1` as
1092
- "already mine", takes the moved branch rather than the arrived one, and never registers it.
1093
- Retiring them here puts every emitter back where it was before this system saw it.
1055
+ The emitters go first, and they matter more than the buffers: they belong to their owners,
1056
+ they outlive this system, and each is holding a row of the table about to be freed.
1057
+ Retiring them here puts every emitter back where it was before this system saw it, so its
1058
+ owner can register it with the next system.
1094
1059
  */
1095
1060
  for (const emitter of this.registry.emitters.slice()) {
1096
1061
  this.registry.remove(emitter);
1097
1062
  }
1098
- this.#swept.clear();
1099
- this.#instances_version = -1;
1100
1063
 
1101
1064
  for (const buffer of Object.values(this.buffers)) {
1102
1065
  if (Array.isArray(buffer)) {
@@ -12,9 +12,9 @@
12
12
  * particles of a removed emitter — which carry its generation — cannot be mistaken for the new
13
13
  * tenant's. The simulate pass kills them on sight; see {@link ../data/particle_header.js}.
14
14
  *
15
- * **None of that bookkeeping is on the emitter.** An emitter is a scene node and a description of
16
- * an effect, with nothing in it that depends on a device; the row, the generation, the program
17
- * placement, the node's `transforms` row and the atlas patch are a
15
+ * **None of that bookkeeping is on the emitter.** An emitter is a description of an effect, with
16
+ * nothing in it that depends on a device; the row, the generation, the program placement, the
17
+ * `transforms` row it is placed at and the atlas patch are a
18
18
  * {@link ./GPUParticleEmitterContext.js} this registry holds against the emitter and hands out
19
19
  * through {@link EmitterRegistry#context}. Registering an emitter creates one, removing it destroys
20
20
  * one, and an emitter with no context here is an emitter this registry does not have.
@@ -109,7 +109,7 @@ export class EmitterRegistry {
109
109
  get max_register_count(): number;
110
110
  /**
111
111
  * What this registry assigned an emitter: its table row, generation, program placement, the
112
- * `transforms` row of its node and its atlas patch.
112
+ * `transforms` row it is placed at and its atlas patch.
113
113
  *
114
114
  * `undefined` for an emitter this registry does not hold — which is the way to ask whether one
115
115
  * is live, there being no `-1` on the emitter to read instead.
@@ -123,8 +123,9 @@ export class EmitterRegistry {
123
123
  *
124
124
  * @param {ParticleEmitter|object} config a {@link ParticleEmitter}, or a description
125
125
  * {@link ParticleEmitter.from} accepts
126
- * @param {number} [transform_row] the emitter node's row in the scene's `transforms` table, if
127
- * already known; {@link set_transform_row} sets it later otherwise
126
+ * @param {number} [transform_row] the row of the scene's `transforms` table the emitter is
127
+ * placed at — its entity's, one on — if already known; {@link set_transform_row} sets it
128
+ * later otherwise
128
129
  * @returns {ParticleEmitter}
129
130
  */
130
131
  add(config: ParticleEmitter | object, transform_row?: number): ParticleEmitter;
@@ -168,7 +169,7 @@ export class EmitterRegistry {
168
169
  */
169
170
  get(row: number): ParticleEmitter | undefined;
170
171
  /**
171
- * Point an emitter's record at its node's row in the scene's `transforms` table. The row is
172
+ * Point an emitter's record at another row of the scene's `transforms` table. The row is
172
173
  * restaged on the next flush.
173
174
  *
174
175
  * @param {ParticleEmitter} emitter
@@ -189,10 +190,10 @@ export class EmitterRegistry {
189
190
  /**
190
191
  * Restage the table rows of every emitter whose fields have moved since the last flush.
191
192
  *
192
- * "Moved" is the node's own change counter: an emitter is restaged when its
193
- * {@link ../../scene/Node3D.js Node3D#version} is not the one its row was staged from, or when
194
- * something in its context changed. So an author marks an edited emitter the way they mark any
195
- * edited node, with `needsUpdate = true`, and there is no second flag to forget.
193
+ * "Moved" is the emitter's own change counter: an emitter is restaged when its
194
+ * {@link ./ParticleEmitter.js ParticleEmitter#version} is not the one its row was staged from,
195
+ * or when something in its context changed. So an author marks an edited emitter with
196
+ * `needsUpdate = true`, and there is no second flag to forget.
196
197
  *
197
198
  * Cheap to call every frame: an emitter that has not changed costs one integer comparison, and
198
199
  * the table coalesces repeated writes to one row within a frame anyway. Walks the context map
@@ -1 +1 @@
1
- {"version":3,"file":"EmitterRegistry.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/EmitterRegistry.js"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH;IA8EI;;OAEG;IACH,+BASC;IAxFD;;OAEG;IACH,UAFU,WAAW,CAEZ;IAET;;;OAGG;IACH,UAFU,WAAW,CAEQ;IAE7B;;;OAGG;IACH,4BAFU,MAAM,CAEe;IAE/B;;;OAGG;IACH,UAFU,eAAe,EAAE,CAEb;IAEd;;;;;OAKG;IACH,QAFU,eAAe,EAAE,CAEf;IAEZ;;;;;;;;;;OAUG;IACH,8BAEC;IA8CD;;;OAGG;IACH,8EAEC;IAED;;;;OAIG;IACH,oFAEC;IAED;;OAEG;IACH,oBAEC;IAED;;;OAGG;IACH,4BAEC;IAED;;;;;OAKG;IACH,kCAEC;IAED;;;;;;;OAOG;IACH,iCAEC;IAED;;;;;;;;;OASG;IACH,iBAHW,eAAe,GACb,yBAAyB,GAAC,SAAS,CAI/C;IAED;;;;;;;;OAQG;IACH,YANW,eAAe,GAAC,MAAM,kBAEtB,MAAM,GAEJ,eAAe,CA+B3B;IAED;;;;;;;;;;;;;OAaG;IACH,gBAFW,eAAe,QA6BzB;IAED;;;;;;;;;;;;;;;OAeG;IACH,qBAHW,eAAe,WACf,OAAO,2BAA2B,EAAE,eAAe,QA0B7D;IAED;;;;;OAKG;IACH,SAHW,MAAM,GACJ,eAAe,GAAC,SAAS,CAIrC;IAED;;;;;;OAMG;IACH,2BAHW,eAAe,iBACf,MAAM,QAehB;IAED;;;;;;;;;OASG;IACH,0BAHW,eAAe,UACf,UAAU,MAAM,CAAC,QAoB3B;IAED;;;;;;;;;;;;;OAaG;IACH,cA4BC;IAED;;;;;;;;;OASG;IACH,iBAFa,WAAW,CAMvB;;CACJ;;4BA7c2B,mCAAmC;4BAYnC,kBAAkB;gCADd,sBAAsB;0CADZ,gCAAgC"}
1
+ {"version":3,"file":"EmitterRegistry.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/EmitterRegistry.js"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH;IA8EI;;OAEG;IACH,+BASC;IAxFD;;OAEG;IACH,UAFU,WAAW,CAEZ;IAET;;;OAGG;IACH,UAFU,WAAW,CAEQ;IAE7B;;;OAGG;IACH,4BAFU,MAAM,CAEe;IAE/B;;;OAGG;IACH,UAFU,eAAe,EAAE,CAEb;IAEd;;;;;OAKG;IACH,QAFU,eAAe,EAAE,CAEf;IAEZ;;;;;;;;;;OAUG;IACH,8BAEC;IA8CD;;;OAGG;IACH,8EAEC;IAED;;;;OAIG;IACH,oFAEC;IAED;;OAEG;IACH,oBAEC;IAED;;;OAGG;IACH,4BAEC;IAED;;;;;OAKG;IACH,kCAEC;IAED;;;;;;;OAOG;IACH,iCAEC;IAED;;;;;;;;;OASG;IACH,iBAHW,eAAe,GACb,yBAAyB,GAAC,SAAS,CAI/C;IAED;;;;;;;;;OASG;IACH,YAPW,eAAe,GAAC,MAAM,kBAEtB,MAAM,GAGJ,eAAe,CA+B3B;IAED;;;;;;;;;;;;;OAaG;IACH,gBAFW,eAAe,QA6BzB;IAED;;;;;;;;;;;;;;;OAeG;IACH,qBAHW,eAAe,WACf,OAAO,2BAA2B,EAAE,eAAe,QA0B7D;IAED;;;;;OAKG;IACH,SAHW,MAAM,GACJ,eAAe,GAAC,SAAS,CAIrC;IAED;;;;;;OAMG;IACH,2BAHW,eAAe,iBACf,MAAM,QAehB;IAED;;;;;;;;;OASG;IACH,0BAHW,eAAe,UACf,UAAU,MAAM,CAAC,QAoB3B;IAED;;;;;;;;;;;;;OAaG;IACH,cA4BC;IAED;;;;;;;;;OASG;IACH,iBAFa,WAAW,CAMvB;;CACJ;;4BA9c2B,mCAAmC;4BAYnC,kBAAkB;gCADd,sBAAsB;0CADZ,gCAAgC"}
@@ -38,9 +38,9 @@ const RECORD = create_emitter_record();
38
38
  * particles of a removed emitter — which carry its generation — cannot be mistaken for the new
39
39
  * tenant's. The simulate pass kills them on sight; see {@link ../data/particle_header.js}.
40
40
  *
41
- * **None of that bookkeeping is on the emitter.** An emitter is a scene node and a description of
42
- * an effect, with nothing in it that depends on a device; the row, the generation, the program
43
- * placement, the node's `transforms` row and the atlas patch are a
41
+ * **None of that bookkeeping is on the emitter.** An emitter is a description of an effect, with
42
+ * nothing in it that depends on a device; the row, the generation, the program placement, the
43
+ * `transforms` row it is placed at and the atlas patch are a
44
44
  * {@link ./GPUParticleEmitterContext.js} this registry holds against the emitter and hands out
45
45
  * through {@link EmitterRegistry#context}. Registering an emitter creates one, removing it destroys
46
46
  * one, and an emitter with no context here is an emitter this registry does not have.
@@ -202,7 +202,7 @@ export class EmitterRegistry {
202
202
 
203
203
  /**
204
204
  * What this registry assigned an emitter: its table row, generation, program placement, the
205
- * `transforms` row of its node and its atlas patch.
205
+ * `transforms` row it is placed at and its atlas patch.
206
206
  *
207
207
  * `undefined` for an emitter this registry does not hold — which is the way to ask whether one
208
208
  * is live, there being no `-1` on the emitter to read instead.
@@ -219,8 +219,9 @@ export class EmitterRegistry {
219
219
  *
220
220
  * @param {ParticleEmitter|object} config a {@link ParticleEmitter}, or a description
221
221
  * {@link ParticleEmitter.from} accepts
222
- * @param {number} [transform_row] the emitter node's row in the scene's `transforms` table, if
223
- * already known; {@link set_transform_row} sets it later otherwise
222
+ * @param {number} [transform_row] the row of the scene's `transforms` table the emitter is
223
+ * placed at — its entity's, one on — if already known; {@link set_transform_row} sets it
224
+ * later otherwise
224
225
  * @returns {ParticleEmitter}
225
226
  */
226
227
  add(config, transform_row = 0) {
@@ -350,7 +351,7 @@ export class EmitterRegistry {
350
351
  }
351
352
 
352
353
  /**
353
- * Point an emitter's record at its node's row in the scene's `transforms` table. The row is
354
+ * Point an emitter's record at another row of the scene's `transforms` table. The row is
354
355
  * restaged on the next flush.
355
356
  *
356
357
  * @param {ParticleEmitter} emitter
@@ -404,10 +405,10 @@ export class EmitterRegistry {
404
405
  /**
405
406
  * Restage the table rows of every emitter whose fields have moved since the last flush.
406
407
  *
407
- * "Moved" is the node's own change counter: an emitter is restaged when its
408
- * {@link ../../scene/Node3D.js Node3D#version} is not the one its row was staged from, or when
409
- * something in its context changed. So an author marks an edited emitter the way they mark any
410
- * edited node, with `needsUpdate = true`, and there is no second flag to forget.
408
+ * "Moved" is the emitter's own change counter: an emitter is restaged when its
409
+ * {@link ./ParticleEmitter.js ParticleEmitter#version} is not the one its row was staged from,
410
+ * or when something in its context changed. So an author marks an edited emitter with
411
+ * `needsUpdate = true`, and there is no second flag to forget.
411
412
  *
412
413
  * Cheap to call every frame: an emitter that has not changed costs one integer comparison, and
413
414
  * the table coalesces repeated writes to one row within a frame anyway. Walks the context map