@woosh/meep-engine 3.22.0 → 3.23.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 (267) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +118 -0
  3. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -0
  4. package/src/core/geom/3d/hash-grid/PointHashGrid3.js +283 -0
  5. package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -1
  6. package/src/core/geom/3d/shape/BoxShape3D.js +6 -17
  7. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
  8. package/src/core/geom/3d/shape/CapsuleShape3D.js +3 -14
  9. package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
  10. package/src/core/geom/3d/shape/CylinderShape3D.js +3 -21
  11. package/src/core/geom/3d/shape/PlaneShape3D.d.ts +105 -0
  12. package/src/core/geom/3d/shape/PlaneShape3D.d.ts.map +1 -0
  13. package/src/core/geom/3d/shape/PlaneShape3D.js +251 -0
  14. package/src/core/geom/3d/shape/SphereShape3D.js +3 -3
  15. package/src/core/geom/3d/shape/json/shape_to_type.d.ts.map +1 -1
  16. package/src/core/geom/3d/shape/json/shape_to_type.js +3 -0
  17. package/src/core/geom/3d/shape/json/type_adapters.d.ts +14 -0
  18. package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
  19. package/src/core/geom/3d/shape/json/type_adapters.js +15 -0
  20. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts +51 -0
  21. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts.map +1 -0
  22. package/src/core/geom/3d/shape/sdf/sdf3_box.js +113 -0
  23. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts +46 -0
  24. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts.map +1 -0
  25. package/src/core/geom/3d/shape/sdf/sdf3_capsule.js +82 -0
  26. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts +60 -0
  27. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts.map +1 -0
  28. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.js +126 -0
  29. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts +50 -0
  30. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts.map +1 -0
  31. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.js +53 -0
  32. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts +52 -0
  33. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts.map +1 -0
  34. package/src/core/geom/3d/shape/sdf/sdf3_plane.js +61 -0
  35. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts +41 -0
  36. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts.map +1 -0
  37. package/src/core/geom/3d/shape/sdf/sdf3_sphere.js +71 -0
  38. package/src/core/process/ConcurrencyGate.d.ts +103 -0
  39. package/src/core/process/ConcurrencyGate.d.ts.map +1 -0
  40. package/src/core/process/ConcurrencyGate.js +207 -0
  41. package/src/engine/asset/AssetManager.d.ts +10 -0
  42. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  43. package/src/engine/asset/AssetManager.js +10 -0
  44. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +30 -13
  45. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts +26 -0
  46. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts.map +1 -0
  47. package/src/engine/graphics3/pose/collect_entity_playbacks.js +40 -0
  48. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  49. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +74 -101
  50. package/src/engine/physics/cloth/MEASUREMENTS.md +1287 -4
  51. package/src/engine/physics/cloth/PLAN.md +1967 -1581
  52. package/src/engine/physics/cloth/build/ClothProxy.d.ts +147 -0
  53. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -0
  54. package/src/engine/physics/cloth/build/ClothProxy.js +207 -0
  55. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +70 -0
  56. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -0
  57. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +256 -0
  58. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +176 -0
  59. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +435 -0
  61. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts +12 -0
  62. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts.map +1 -0
  63. package/src/engine/physics/cloth/collider/ClothColliderKind.js +38 -0
  64. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts +120 -0
  65. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/collider/ClothColliderRecord.js +137 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +25 -0
  68. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -0
  69. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +190 -0
  70. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +44 -0
  71. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -0
  72. package/src/engine/physics/cloth/collider/cloth_collider_pack.js +173 -0
  73. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +94 -0
  74. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +275 -0
  76. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts +126 -0
  77. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -0
  78. package/src/engine/physics/cloth/ecs/ClothCollider.js +199 -0
  79. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +9 -0
  80. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +32 -0
  82. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +114 -0
  83. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +243 -0
  85. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +66 -57
  86. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +109 -1
  87. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  88. package/src/engine/physics/cloth/ecs/ClothInstance.js +479 -363
  89. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +95 -0
  90. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -0
  91. package/src/engine/physics/cloth/ecs/ClothRig.js +140 -0
  92. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +30 -1
  93. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  94. package/src/engine/physics/cloth/ecs/ClothSystem.js +1021 -773
  95. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +90 -0
  96. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -0
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +374 -0
  98. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts +32 -3
  99. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.js +283 -254
  101. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +59 -0
  102. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -0
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +328 -0
  104. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +13 -0
  105. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -0
  106. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +288 -0
  107. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +58 -0
  108. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -0
  109. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +199 -0
  110. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +8 -63
  111. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  112. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +317 -645
  113. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +61 -0
  114. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  115. package/src/engine/physics/cloth/ecs/cloth_write_back.js +212 -449
  116. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts +49 -0
  117. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -0
  118. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +115 -0
  119. package/src/engine/physics/cloth/playground/README.md +155 -1
  120. package/src/engine/physics/cloth/playground/collide.html +178 -0
  121. package/src/engine/physics/cloth/playground/collide_build.d.ts +95 -0
  122. package/src/engine/physics/cloth/playground/collide_build.d.ts.map +1 -0
  123. package/src/engine/physics/cloth/playground/collide_build.js +315 -0
  124. package/src/engine/physics/cloth/playground/collide_main.d.ts +2 -0
  125. package/src/engine/physics/cloth/playground/collide_main.d.ts.map +1 -0
  126. package/src/engine/physics/cloth/playground/collide_main.js +720 -0
  127. package/src/engine/physics/cloth/playground/garment.html +182 -0
  128. package/src/engine/physics/cloth/playground/garment_build.d.ts +78 -0
  129. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -0
  130. package/src/engine/physics/cloth/playground/garment_build.js +359 -0
  131. package/src/engine/physics/cloth/playground/garment_main.d.ts +2 -0
  132. package/src/engine/physics/cloth/playground/garment_main.d.ts.map +1 -0
  133. package/src/engine/physics/cloth/playground/garment_main.js +633 -0
  134. package/src/engine/physics/cloth/solver/ClothState.d.ts +208 -5
  135. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/ClothState.js +302 -8
  137. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +87 -0
  138. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_contact_find.js +343 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +112 -0
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -0
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +448 -0
  143. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts +4 -1
  144. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +16 -1
  146. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +112 -5
  147. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +117 -6
  149. package/src/engine/physics/cloth/solver/cloth_step.d.ts +40 -9
  150. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step.js +122 -10
  152. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +95 -0
  153. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -0
  154. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +285 -0
  155. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts +129 -0
  156. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -0
  157. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +501 -0
  158. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +75 -0
  159. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -0
  160. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +202 -0
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/shade/playground/vgeo_viewer/README.md +18 -0
  163. package/src/shade/playground/vgeo_viewer/main.js +87 -50
  164. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  165. package/src/shade/renderer/buffer/table/GPUDatabase.js +191 -62
  166. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +94 -2
  167. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  168. package/src/shade/renderer/buffer/table/GPUTypedTable.js +414 -2
  169. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts +14 -0
  170. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts.map +1 -0
  171. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.js +13 -0
  172. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts +17 -0
  173. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts.map +1 -0
  174. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.js +116 -0
  175. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +9 -4
  176. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  177. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +843 -734
  178. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts +12 -0
  179. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts.map +1 -1
  180. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js +13 -0
  181. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +17 -0
  182. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  183. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +185 -30
  184. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +17 -0
  185. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +141 -24
  186. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +204 -64
  187. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +110 -10
  188. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +19 -0
  189. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +19 -6
  190. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  191. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +26 -7
  192. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +173 -14
  193. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  194. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +458 -51
  195. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +49 -13
  196. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  197. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +52 -14
  198. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts +20 -0
  199. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts.map +1 -0
  200. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.js +19 -0
  201. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts +27 -0
  202. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts.map +1 -0
  203. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.js +48 -0
  204. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts +29 -0
  205. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts.map +1 -0
  206. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.js +60 -0
  207. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +8 -1
  208. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  209. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +32 -2
  210. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +258 -0
  211. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +1 -0
  212. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +723 -0
  213. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +49 -0
  214. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +1 -0
  215. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +50 -0
  216. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  217. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  218. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts +3 -0
  219. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
  220. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +121 -21
  221. package/src/shade/renderer/texture/virtual/README.md +6 -4
  222. package/src/shade/renderer/texture/virtual/VirtualTextureManager.d.ts.map +1 -1
  223. package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +7 -0
  224. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.d.ts +3 -3
  225. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +3 -3
  226. package/src/engine/ecs/system/SystemExecutionPhase.d.ts +0 -9
  227. package/src/engine/ecs/system/SystemExecutionPhase.d.ts.map +0 -1
  228. package/src/engine/graphics/texture/virtual/NOTES.md +0 -128
  229. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts +0 -6
  230. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts.map +0 -1
  231. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.js +0 -5
  232. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts +0 -49
  233. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts.map +0 -1
  234. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.js +0 -264
  235. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts +0 -44
  236. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts.map +0 -1
  237. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.js +0 -228
  238. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts +0 -3
  239. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts.map +0 -1
  240. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.js +0 -73
  241. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts +0 -14
  242. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts.map +0 -1
  243. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.js +0 -85
  244. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts +0 -12
  245. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts.map +0 -1
  246. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.js +0 -63
  247. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts +0 -12
  248. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts.map +0 -1
  249. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.js +0 -243
  250. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts +0 -30
  251. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts.map +0 -1
  252. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.js +0 -39
  253. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts +0 -9
  254. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts.map +0 -1
  255. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.js +0 -24
  256. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts +0 -9
  257. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts.map +0 -1
  258. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.js +0 -26
  259. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts +0 -11
  260. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts.map +0 -1
  261. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.js +0 -12
  262. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts +0 -7
  263. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts.map +0 -1
  264. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.js +0 -16
  265. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts +0 -7
  266. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts.map +0 -1
  267. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.js +0 -35
@@ -1,449 +1,212 @@
1
- import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
2
- import { quat3_nlerp } from "../../../../core/geom/3d/quaternion/quat3_nlerp.js";
3
- import { quat3_shortest_arc } from "../../../../core/geom/3d/quaternion/quat3_shortest_arc.js";
4
- import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
5
- import {
6
- v3_quaternion_apply_inverse
7
- } from "../../../../core/geom/vec3/v3_quaternion_apply_inverse.js";
8
- import { t64_announce_change } from "../../../ecs/transform/t64_announce_change.js";
9
- import {
10
- TRANSFORM64_ROTATION_OFFSET,
11
- TRANSFORM64_TRANSLATION_OFFSET
12
- } from "../../../ecs/transform/Transform64.js";
13
-
14
- /**
15
- * # Putting the answer back — §11.1
16
- *
17
- * Position directly, rotation derived from the direction to the child,
18
- * interpolated between the parent-driven and the child-driven orientation —
19
- * which is what keeps a two-link chain from looking hinged.
20
- *
21
- * ## Rotation is a swing on top of the animated orientation
22
- *
23
- * A particle has a position and no orientation, so an entity's rotation has to
24
- * be reconstructed. The reconstruction here is the minimal rotation carrying
25
- * the link's **animated** direction onto its **simulated** one, composed onto
26
- * the animated orientation:
27
- *
28
- * q_node = swing(d_animated → d_simulated) ⊗ q_animated
29
- *
30
- * Twist about the link is therefore inherited from the animation rather than
31
- * invented, which is right: a chain of particles carries no twist degree of
32
- * freedom and any twist this code produced would be a fabrication. And the
33
- * whole thing degenerates correctly — at `blend = 0` the simulated direction
34
- * *is* the animated one, the swing is the identity, and the write-back
35
- * reproduces the authored pose exactly.
36
- *
37
- * A node with a parent and children has two links and two swings, and takes the
38
- * half-way rotation between them. A leaf has only its parent's. That is
39
- * §11.1's "interpolated between parent-driven and child-driven orientation",
40
- * and without it every link points at its child and a two-link chain reads as a
41
- * hinge with a corner in it.
42
- *
43
- * ## Both transforms are written, and that is what makes ordering harmless
44
- *
45
- * Each simulated node gets its **world** `Transform64` and its **local**
46
- * `TransformAttachment#transform`, and the two agree. Writing only the world
47
- * one is cheaper and is a trap: the attachment system recomposes a child from
48
- * its local whenever the parent announces, so any announcement arriving after
49
- * cloth had written would replace the simulated pose with the authored one for
50
- * the rest of the frame — and where in the fixed step cloth ran would be a
51
- * correctness question. With the local written too, **a recomposition
52
- * reproduces exactly what cloth just wrote**, and cloth's placement costs at
53
- * worst a shape one fixed step stale.
54
- *
55
- * That is also the shape of the engine's own precedent:
56
- * `InverseKinematicsSystem` reads world transforms the hierarchy has composed
57
- * and writes local ones back, and §11.2's rig path writes
58
- * `Node3D.transform_local` for the same reason — a local transform is what a
59
- * joint angle *is*.
60
- *
61
- * A node's local transform is its pose relative to its **parent's**, so this
62
- * needs the parent's reconstructed rotation as well as its position — which is
63
- * what {@link ClothInstance#blended_rotation} is for, and why the pass runs in
64
- * the walk's breadth-first order.
65
- *
66
- * The authored pose is not lost by being overwritten: it was captured at seed
67
- * and lives in the cloth (`cloth_seed_subtree.js`), which is what `blend = 0`
68
- * returns to and what the leash centres are measured from.
69
- *
70
- * ## What is announced
71
- *
72
- * Nothing on a simulated node: every one of its simulated children has already
73
- * been written by this same pass, so the cascade would recompute a pose that is
74
- * already correct, once per level, quadratically for a chain. What *is*
75
- * announced is each pruned boundary — the root of a `ClothExclude` subtree, or
76
- * a nested `Cloth`'s anchor — which this pass poses by hand against the link it
77
- * hangs from, so everything below the cut follows the simulation through the
78
- * ordinary attachment cascade and nothing above it is disturbed.
79
- *
80
- * @author Alex Goldring
81
- * @copyright Company Named Limited (c) 2026
82
- */
83
-
84
- /**
85
- * Scratch for one node's swing quaternions. Module-level: the write-back
86
- * allocates nothing.
87
- * @type {Float64Array}
88
- * @private
89
- */
90
- const SWING = new Float64Array(12);
91
-
92
- /** Where the parent-driven swing sits in {@link SWING}. @private */
93
- const SWING_PARENT = 0;
94
- /** Where the child-driven swing sits in {@link SWING}. @private */
95
- const SWING_CHILD = 4;
96
- /** Where the blended swing, and then the local rotation, sit. @private */
97
- const SWING_OUT = 8;
98
-
99
- /**
100
- * @type {Float64Array}
101
- * @private
102
- */
103
- const DIRECTION = new Float64Array(12);
104
-
105
- /**
106
- * Write one cloth's solved pose onto its subtree.
107
- *
108
- * @param {ClothInstance} instance
109
- * @param {EntityComponentDataset} ecd
110
- * @returns {void}
111
- */
112
- export function cloth_write_back(instance, ecd) {
113
- const node_count = instance.node_count;
114
-
115
- const state = instance.state;
116
- const particle_of_node = instance.particle_of_node;
117
-
118
- const blended = instance.blended_position;
119
- const animated = instance.animated_position;
120
-
121
- let blend = instance.cloth.blend;
122
-
123
- if (blend < 0) {
124
- blend = 0;
125
- } else if (blend > 1) {
126
- blend = 1;
127
- }
128
-
129
- const position = state.position;
130
-
131
- for (let node = 0; node < node_count; node++) {
132
- const p = particle_of_node[node] * 3;
133
- const n = node * 3;
134
-
135
- blended[n] = animated[n] + blend * (position[p] - animated[n]);
136
- blended[n + 1] = animated[n + 1] + blend * (position[p + 1] - animated[n + 1]);
137
- blended[n + 2] = animated[n + 2] + blend * (position[p + 2] - animated[n + 2]);
138
- }
139
-
140
- const anchor = instance.node_transform[0];
141
-
142
- const ax = anchor[TRANSFORM64_TRANSLATION_OFFSET];
143
- const ay = anchor[TRANSFORM64_TRANSLATION_OFFSET + 1];
144
- const az = anchor[TRANSFORM64_TRANSLATION_OFFSET + 2];
145
-
146
- const aqx = anchor[TRANSFORM64_ROTATION_OFFSET];
147
- const aqy = anchor[TRANSFORM64_ROTATION_OFFSET + 1];
148
- const aqz = anchor[TRANSFORM64_ROTATION_OFFSET + 2];
149
- const aqw = anchor[TRANSFORM64_ROTATION_OFFSET + 3];
150
-
151
- const parent = instance.node_parent;
152
- const rotation = instance.animated_rotation;
153
-
154
- const local_rotation = instance.blended_rotation;
155
-
156
- // The anchor is the origin of the frame it anchors, so its reconstructed
157
- // rotation — which its children's local transforms are relative to — is the
158
- // identity rather than anything read back off it.
159
- local_rotation[0] = 0;
160
- local_rotation[1] = 0;
161
- local_rotation[2] = 0;
162
- local_rotation[3] = 1;
163
-
164
- for (let node = 1; node < node_count; node++) {
165
- const transform = instance.node_transform[node];
166
-
167
- const n = node * 3;
168
-
169
- v3_quaternion_apply(
170
- transform, TRANSFORM64_TRANSLATION_OFFSET,
171
- blended[n], blended[n + 1], blended[n + 2],
172
- aqx, aqy, aqz, aqw
173
- );
174
-
175
- transform[TRANSFORM64_TRANSLATION_OFFSET] += ax;
176
- transform[TRANSFORM64_TRANSLATION_OFFSET + 1] += ay;
177
- transform[TRANSFORM64_TRANSLATION_OFFSET + 2] += az;
178
-
179
- const has_parent_swing = link_swing(instance, parent[node], node, SWING_PARENT);
180
- const has_child_swing = children_swing(instance, node, SWING_CHILD);
181
-
182
- let swing = SWING_OUT;
183
-
184
- if (has_parent_swing && has_child_swing) {
185
- quat3_nlerp(
186
- SWING, SWING_OUT,
187
- SWING[SWING_PARENT], SWING[SWING_PARENT + 1], SWING[SWING_PARENT + 2], SWING[SWING_PARENT + 3],
188
- SWING[SWING_CHILD], SWING[SWING_CHILD + 1], SWING[SWING_CHILD + 2], SWING[SWING_CHILD + 3],
189
- 0.5
190
- );
191
- } else if (has_child_swing) {
192
- swing = SWING_CHILD;
193
- } else {
194
- // A leaf, or a link so short its direction is meaningless — in
195
- // which case `link_swing` left the identity there.
196
- swing = SWING_PARENT;
197
- }
198
-
199
- // Animated orientation first, then the swing: the swing is expressed in
200
- // the cloth's local frame, and the anchor's rotation carries the pair
201
- // out to world.
202
- quat3_multiply(
203
- local_rotation, node * 4,
204
- SWING[swing], SWING[swing + 1], SWING[swing + 2], SWING[swing + 3],
205
- rotation[node * 4], rotation[node * 4 + 1], rotation[node * 4 + 2], rotation[node * 4 + 3]
206
- );
207
-
208
- quat3_multiply(
209
- transform, TRANSFORM64_ROTATION_OFFSET,
210
- aqx, aqy, aqz, aqw,
211
- local_rotation[node * 4], local_rotation[node * 4 + 1],
212
- local_rotation[node * 4 + 2], local_rotation[node * 4 + 3]
213
- );
214
-
215
- transform.updateMatrix();
216
-
217
- write_local(instance, node, parent[node]);
218
- }
219
-
220
- pose_pruned(instance, ecd);
221
- }
222
-
223
- /**
224
- * Express one node's solved pose relative to its parent's, and write it into
225
- * the entity's `TransformAttachment`.
226
- *
227
- * Both poses are already in the cloth's own frame, so the parent's inverse is
228
- * its reconstructed rotation conjugated — there is no matrix inverse here and
229
- * no scale, which is the same rigid-pose convention the colliders use.
230
- *
231
- * @param {ClothInstance} instance
232
- * @param {number} node
233
- * @param {number} parent
234
- * @private
235
- */
236
- function write_local(instance, node, parent) {
237
- const attachment = instance.node_attachment[node];
238
-
239
- if (attachment === undefined || attachment === null) {
240
- return;
241
- }
242
-
243
- const blended = instance.blended_position;
244
- const rotation = instance.blended_rotation;
245
-
246
- const local = attachment.transform;
247
-
248
- const pqx = rotation[parent * 4];
249
- const pqy = rotation[parent * 4 + 1];
250
- const pqz = rotation[parent * 4 + 2];
251
- const pqw = rotation[parent * 4 + 3];
252
-
253
- v3_quaternion_apply_inverse(
254
- local, TRANSFORM64_TRANSLATION_OFFSET,
255
- blended[node * 3] - blended[parent * 3],
256
- blended[node * 3 + 1] - blended[parent * 3 + 1],
257
- blended[node * 3 + 2] - blended[parent * 3 + 2],
258
- pqx, pqy, pqz, pqw
259
- );
260
-
261
- quat3_multiply(
262
- local, TRANSFORM64_ROTATION_OFFSET,
263
- -pqx, -pqy, -pqz, pqw,
264
- rotation[node * 4], rotation[node * 4 + 1], rotation[node * 4 + 2], rotation[node * 4 + 3]
265
- );
266
-
267
- // `multiplyTransforms` reads the matrix, not the components, so a local
268
- // transform that is not refreshed here composes the pose it had last time.
269
- local.updateMatrix();
270
- }
271
-
272
- /**
273
- * Swing of the link from `from` to `to`, into `SWING` at `out`.
274
- *
275
- * @param {ClothInstance} instance
276
- * @param {number} from node
277
- * @param {number} to node
278
- * @param {number} out
279
- * @returns {boolean} false when the link is too short to carry a direction, in
280
- * which case the identity was written
281
- * @private
282
- */
283
- function link_swing(instance, from, to, out) {
284
- const animated = instance.animated_position;
285
- const blended = instance.blended_position;
286
-
287
- const a = from * 3;
288
- const b = to * 3;
289
-
290
- const has_animated = unit(DIRECTION, 0,
291
- animated[b] - animated[a], animated[b + 1] - animated[a + 1], animated[b + 2] - animated[a + 2]);
292
-
293
- const has_blended = unit(DIRECTION, 3,
294
- blended[b] - blended[a], blended[b + 1] - blended[a + 1], blended[b + 2] - blended[a + 2]);
295
-
296
- if (!has_animated || !has_blended) {
297
- identity(out);
298
-
299
- return false;
300
- }
301
-
302
- quat3_shortest_arc(
303
- SWING, out,
304
- DIRECTION[0], DIRECTION[1], DIRECTION[2],
305
- DIRECTION[3], DIRECTION[4], DIRECTION[5]
306
- );
307
-
308
- return true;
309
- }
310
-
311
- /**
312
- * Swing of a node's outgoing links, averaged over its simulated children.
313
- *
314
- * The average is over **unit** directions rather than over child positions, so
315
- * a fork whose two branches are of different lengths is not dominated by the
316
- * longer one.
317
- *
318
- * @param {ClothInstance} instance
319
- * @param {number} node
320
- * @param {number} out
321
- * @returns {boolean}
322
- * @private
323
- */
324
- function children_swing(instance, node, out) {
325
- const start = instance.node_child_offset[node];
326
- const end = instance.node_child_offset[node + 1];
327
-
328
- if (start === end) {
329
- identity(out);
330
-
331
- return false;
332
- }
333
-
334
- const animated = instance.animated_position;
335
- const blended = instance.blended_position;
336
- const child = instance.node_child;
337
-
338
- const a = node * 3;
339
-
340
- let anim_x = 0, anim_y = 0, anim_z = 0;
341
- let sim_x = 0, sim_y = 0, sim_z = 0;
342
-
343
- for (let i = start; i < end; i++) {
344
- const b = child[i] * 3;
345
-
346
- if (unit(DIRECTION, 6,
347
- animated[b] - animated[a], animated[b + 1] - animated[a + 1], animated[b + 2] - animated[a + 2])) {
348
- anim_x += DIRECTION[6];
349
- anim_y += DIRECTION[7];
350
- anim_z += DIRECTION[8];
351
- }
352
-
353
- if (unit(DIRECTION, 9,
354
- blended[b] - blended[a], blended[b + 1] - blended[a + 1], blended[b + 2] - blended[a + 2])) {
355
- sim_x += DIRECTION[9];
356
- sim_y += DIRECTION[10];
357
- sim_z += DIRECTION[11];
358
- }
359
- }
360
-
361
- const has_animated = unit(DIRECTION, 0, anim_x, anim_y, anim_z);
362
- const has_blended = unit(DIRECTION, 3, sim_x, sim_y, sim_z);
363
-
364
- if (!has_animated || !has_blended) {
365
- // Branches that cancel — a node with two children pointing opposite
366
- // ways has no outgoing direction to speak of, and the parent link is a
367
- // better answer than an arbitrary one.
368
- identity(out);
369
-
370
- return false;
371
- }
372
-
373
- quat3_shortest_arc(
374
- SWING, out,
375
- DIRECTION[0], DIRECTION[1], DIRECTION[2],
376
- DIRECTION[3], DIRECTION[4], DIRECTION[5]
377
- );
378
-
379
- return true;
380
- }
381
-
382
- /**
383
- * Pose the entities the walk pruned, and announce there.
384
- *
385
- * @param {ClothInstance} instance
386
- * @param {EntityComponentDataset} ecd
387
- * @private
388
- */
389
- function pose_pruned(instance, ecd) {
390
- const count = instance.pruned_count;
391
-
392
- for (let i = 0; i < count; i++) {
393
- const transform = instance.pruned_transform[i];
394
- const attachment = instance.pruned_attachment[i];
395
-
396
- if (transform === undefined || attachment === undefined) {
397
- continue;
398
- }
399
-
400
- transform.multiplyTransforms(
401
- instance.node_transform[instance.pruned_parent[i]],
402
- attachment.transform
403
- );
404
-
405
- // The one announcement this pass makes. Everything below a pruned
406
- // boundary is outside the cloth and reaches its new pose through the
407
- // ordinary attachment cascade; everything above it has already been
408
- // written by hand.
409
- t64_announce_change(ecd, instance.pruned_entity[i]);
410
- }
411
- }
412
-
413
- /**
414
- * Normalise into `DIRECTION`, reporting whether there was a direction to find.
415
- *
416
- * @param {Float64Array} out
417
- * @param {number} offset
418
- * @param {number} x
419
- * @param {number} y
420
- * @param {number} z
421
- * @returns {boolean}
422
- * @private
423
- */
424
- function unit(out, offset, x, y, z) {
425
- const length_squared = x * x + y * y + z * z;
426
-
427
- if (length_squared < 1e-24) {
428
- return false;
429
- }
430
-
431
- const inverse = 1 / Math.sqrt(length_squared);
432
-
433
- out[offset] = x * inverse;
434
- out[offset + 1] = y * inverse;
435
- out[offset + 2] = z * inverse;
436
-
437
- return true;
438
- }
439
-
440
- /**
441
- * @param {number} offset
442
- * @private
443
- */
444
- function identity(offset) {
445
- SWING[offset] = 0;
446
- SWING[offset + 1] = 0;
447
- SWING[offset + 2] = 0;
448
- SWING[offset + 3] = 1;
449
- }
1
+ import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
2
+ import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
3
+ import {
4
+ v3_quaternion_apply_inverse
5
+ } from "../../../../core/geom/vec3/v3_quaternion_apply_inverse.js";
6
+ import { t64_announce_change } from "../../../ecs/transform/t64_announce_change.js";
7
+ import {
8
+ TRANSFORM64_ROTATION_OFFSET,
9
+ TRANSFORM64_TRANSLATION_OFFSET
10
+ } from "../../../ecs/transform/Transform64.js";
11
+ import { cloth_reconstruct_pose } from "./cloth_reconstruct_pose.js";
12
+
13
+ /**
14
+ * # Putting the answer back onto entities — §11.1
15
+ *
16
+ * `cloth_reconstruct_pose.js` turns particles into a pose in the cloth's own
17
+ * frame — positions blended towards the animated ones, orientations
18
+ * reconstructed as a swing on the animated orientation. This file is what puts
19
+ * that pose onto **entities**; `cloth_write_back_rig.js` is what puts the same
20
+ * pose onto a skinned model's joints, and the split is M3's, made when the
21
+ * second writer arrived rather than by anticipating it.
22
+ *
23
+ * ## Both transforms are written, and that is what makes ordering harmless
24
+ *
25
+ * Each simulated node gets its **world** `Transform64` and its **local**
26
+ * `TransformAttachment#transform`, and the two agree. Writing only the world
27
+ * one is cheaper and is a trap: the attachment system recomposes a child from
28
+ * its local whenever the parent announces, so any announcement arriving after
29
+ * cloth had written would replace the simulated pose with the authored one for
30
+ * the rest of the frame — and where in the fixed step cloth ran would be a
31
+ * correctness question. With the local written too, **a recomposition
32
+ * reproduces exactly what cloth just wrote**, and cloth's placement costs at
33
+ * worst a shape one fixed step stale.
34
+ *
35
+ * That is also the shape of the engine's own precedent:
36
+ * `InverseKinematicsSystem` reads world transforms the hierarchy has composed
37
+ * and writes local ones back, and §11.2's rig path writes
38
+ * `Node3D.transform_local` for the same reason — a local transform is what a
39
+ * joint angle *is*.
40
+ *
41
+ * A node's local transform is its pose relative to its **parent's**, so this
42
+ * needs the parent's reconstructed rotation as well as its position — which is
43
+ * what {@link ClothInstance#blended_rotation} is for, and why the pass runs in
44
+ * the walk's breadth-first order.
45
+ *
46
+ * The authored pose is not lost by being overwritten: it was captured at seed
47
+ * and lives in the cloth (`cloth_seed_subtree.js`), which is what `blend = 0`
48
+ * returns to and what the leash centres are measured from.
49
+ *
50
+ * ## What is announced
51
+ *
52
+ * Nothing on a simulated node: every one of its simulated children has already
53
+ * been written by this same pass, so the cascade would recompute a pose that is
54
+ * already correct, once per level, quadratically for a chain. What *is*
55
+ * announced is each pruned boundary — the root of a `ClothExclude` subtree, or
56
+ * a nested `Cloth`'s anchor — which this pass poses by hand against the link it
57
+ * hangs from, so everything below the cut follows the simulation through the
58
+ * ordinary attachment cascade and nothing above it is disturbed.
59
+ *
60
+ * @author Alex Goldring
61
+ * @copyright Company Named Limited (c) 2026
62
+ */
63
+
64
+ /**
65
+ * Write one cloth's solved pose onto its subtree.
66
+ *
67
+ * @param {ClothInstance} instance
68
+ * @param {EntityComponentDataset} ecd
69
+ * @returns {void}
70
+ */
71
+ export function cloth_write_back(instance, ecd) {
72
+ cloth_reconstruct_pose(instance);
73
+
74
+ const node_count = instance.node_count;
75
+
76
+ const blended = instance.blended_position;
77
+ const reconstructed = instance.blended_rotation;
78
+
79
+ const anchor = instance.node_transform[0];
80
+
81
+ const ax = anchor[TRANSFORM64_TRANSLATION_OFFSET];
82
+ const ay = anchor[TRANSFORM64_TRANSLATION_OFFSET + 1];
83
+ const az = anchor[TRANSFORM64_TRANSLATION_OFFSET + 2];
84
+
85
+ const aqx = anchor[TRANSFORM64_ROTATION_OFFSET];
86
+ const aqy = anchor[TRANSFORM64_ROTATION_OFFSET + 1];
87
+ const aqz = anchor[TRANSFORM64_ROTATION_OFFSET + 2];
88
+ const aqw = anchor[TRANSFORM64_ROTATION_OFFSET + 3];
89
+
90
+ const parent = instance.node_parent;
91
+
92
+ for (let node = 1; node < node_count; node++) {
93
+ const transform = instance.node_transform[node];
94
+
95
+ const n = node * 3;
96
+
97
+ v3_quaternion_apply(
98
+ transform, TRANSFORM64_TRANSLATION_OFFSET,
99
+ blended[n], blended[n + 1], blended[n + 2],
100
+ aqx, aqy, aqz, aqw
101
+ );
102
+
103
+ transform[TRANSFORM64_TRANSLATION_OFFSET] += ax;
104
+ transform[TRANSFORM64_TRANSLATION_OFFSET + 1] += ay;
105
+ transform[TRANSFORM64_TRANSLATION_OFFSET + 2] += az;
106
+
107
+ quat3_multiply(
108
+ transform, TRANSFORM64_ROTATION_OFFSET,
109
+ aqx, aqy, aqz, aqw,
110
+ reconstructed[node * 4], reconstructed[node * 4 + 1],
111
+ reconstructed[node * 4 + 2], reconstructed[node * 4 + 3]
112
+ );
113
+
114
+ transform.updateMatrix();
115
+
116
+ write_local(instance, node, parent[node]);
117
+ }
118
+
119
+ pose_pruned(instance, ecd);
120
+ }
121
+
122
+ /**
123
+ * Express one node's solved pose relative to its parent's, and write it into
124
+ * the entity's `TransformAttachment`.
125
+ *
126
+ * Both poses are already in the cloth's own frame, so the parent's inverse is
127
+ * its reconstructed rotation conjugated — there is no matrix inverse here and
128
+ * no scale, which is the same rigid-pose convention the colliders use.
129
+ *
130
+ * @param {ClothInstance} instance
131
+ * @param {number} node
132
+ * @param {number} parent
133
+ * @private
134
+ */
135
+ function write_local(instance, node, parent) {
136
+ const attachment = instance.node_attachment[node];
137
+
138
+ if (attachment === undefined || attachment === null) {
139
+ return;
140
+ }
141
+
142
+ cloth_write_local_pose(attachment.transform, instance, node, parent);
143
+ }
144
+
145
+ /**
146
+ * One node's pose relative to its parent's, in whatever `Transform64` the
147
+ * caller holds. Both writers need it and neither owns it.
148
+ *
149
+ * @param {Transform64} local written in place, matrix included
150
+ * @param {ClothInstance} instance
151
+ * @param {number} node
152
+ * @param {number} parent
153
+ * @returns {void}
154
+ */
155
+ export function cloth_write_local_pose(local, instance, node, parent) {
156
+ const blended = instance.blended_position;
157
+ const rotation = instance.blended_rotation;
158
+
159
+ const pqx = rotation[parent * 4];
160
+ const pqy = rotation[parent * 4 + 1];
161
+ const pqz = rotation[parent * 4 + 2];
162
+ const pqw = rotation[parent * 4 + 3];
163
+
164
+ v3_quaternion_apply_inverse(
165
+ local, TRANSFORM64_TRANSLATION_OFFSET,
166
+ blended[node * 3] - blended[parent * 3],
167
+ blended[node * 3 + 1] - blended[parent * 3 + 1],
168
+ blended[node * 3 + 2] - blended[parent * 3 + 2],
169
+ pqx, pqy, pqz, pqw
170
+ );
171
+
172
+ quat3_multiply(
173
+ local, TRANSFORM64_ROTATION_OFFSET,
174
+ -pqx, -pqy, -pqz, pqw,
175
+ rotation[node * 4], rotation[node * 4 + 1], rotation[node * 4 + 2], rotation[node * 4 + 3]
176
+ );
177
+
178
+ // `multiplyTransforms` reads the matrix, not the components, so a local
179
+ // transform that is not refreshed here composes the pose it had last time.
180
+ local.updateMatrix();
181
+ }
182
+
183
+ /**
184
+ * Pose the entities the walk pruned, and announce there.
185
+ *
186
+ * @param {ClothInstance} instance
187
+ * @param {EntityComponentDataset} ecd
188
+ * @private
189
+ */
190
+ function pose_pruned(instance, ecd) {
191
+ const count = instance.pruned_count;
192
+
193
+ for (let i = 0; i < count; i++) {
194
+ const transform = instance.pruned_transform[i];
195
+ const attachment = instance.pruned_attachment[i];
196
+
197
+ if (transform === undefined || attachment === undefined) {
198
+ continue;
199
+ }
200
+
201
+ transform.multiplyTransforms(
202
+ instance.node_transform[instance.pruned_parent[i]],
203
+ attachment.transform
204
+ );
205
+
206
+ // The one announcement this pass makes. Everything below a pruned
207
+ // boundary is outside the cloth and reaches its new pose through the
208
+ // ordinary attachment cascade; everything above it has already been
209
+ // written by hand.
210
+ t64_announce_change(ecd, instance.pruned_entity[i]);
211
+ }
212
+ }