@woosh/meep-engine 3.44.0 → 3.45.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 (233) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/collection/array/array_sort_insertion_ascending.d.ts +19 -0
  4. package/src/core/collection/array/array_sort_insertion_ascending.d.ts.map +1 -0
  5. package/src/core/collection/array/array_sort_insertion_ascending.js +31 -0
  6. package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.d.ts +27 -0
  7. package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.d.ts.map +1 -0
  8. package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.js +39 -0
  9. package/src/core/geom/3d/aabb/aabb3_from_v3_array.d.ts.map +1 -1
  10. package/src/core/geom/3d/aabb/aabb3_from_v3_array.js +4 -1
  11. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts +2 -2
  12. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -1
  13. package/src/core/geom/3d/aabb/aabb3_transform_oriented.js +1 -1
  14. package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.d.ts +21 -0
  15. package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.d.ts.map +1 -0
  16. package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.js +36 -0
  17. package/src/core/geom/3d/pose/pose3_apply_point_array.d.ts +25 -0
  18. package/src/core/geom/3d/pose/pose3_apply_point_array.d.ts.map +1 -0
  19. package/src/core/geom/3d/pose/pose3_apply_point_array.js +40 -0
  20. package/src/core/geom/3d/pose/pose3_compose_array.d.ts +28 -0
  21. package/src/core/geom/3d/pose/pose3_compose_array.d.ts.map +1 -0
  22. package/src/core/geom/3d/pose/pose3_compose_array.js +41 -0
  23. package/src/core/geom/3d/pose/pose3_to_local_array.d.ts +29 -0
  24. package/src/core/geom/3d/pose/pose3_to_local_array.d.ts.map +1 -0
  25. package/src/core/geom/3d/pose/pose3_to_local_array.js +42 -0
  26. package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.d.ts +28 -0
  27. package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.d.ts.map +1 -0
  28. package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.js +66 -0
  29. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.d.ts +22 -0
  30. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.d.ts.map +1 -0
  31. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.js +30 -0
  32. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.d.ts +23 -0
  33. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.d.ts.map +1 -0
  34. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.js +31 -0
  35. package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.d.ts +26 -0
  36. package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.d.ts.map +1 -0
  37. package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.js +46 -0
  38. package/src/core/geom/vec3/v3_distance_array.d.ts +11 -0
  39. package/src/core/geom/vec3/v3_distance_array.d.ts.map +1 -0
  40. package/src/core/geom/vec3/v3_distance_array.js +19 -0
  41. package/src/core/geom/vec3/v3_normalize_array_checked.d.ts +23 -0
  42. package/src/core/geom/vec3/v3_normalize_array_checked.d.ts.map +1 -0
  43. package/src/core/geom/vec3/v3_normalize_array_checked.js +49 -0
  44. package/src/core/geom/vec3/v3_reject_array.d.ts +15 -0
  45. package/src/core/geom/vec3/v3_reject_array.d.ts.map +1 -0
  46. package/src/core/geom/vec3/v3_reject_array.js +32 -0
  47. package/src/core/graph/csr/csr_build_incidence.d.ts +26 -0
  48. package/src/core/graph/csr/csr_build_incidence.d.ts.map +1 -0
  49. package/src/core/graph/csr/csr_build_incidence.js +71 -0
  50. package/src/core/graph/csr/csr_graph_color_greedy.d.ts +25 -0
  51. package/src/core/graph/csr/csr_graph_color_greedy.d.ts.map +1 -0
  52. package/src/core/graph/csr/csr_graph_color_greedy.js +83 -0
  53. package/src/core/graph/csr/csr_graph_validate_coloring.d.ts +15 -0
  54. package/src/core/graph/csr/csr_graph_validate_coloring.d.ts.map +1 -0
  55. package/src/core/graph/csr/csr_graph_validate_coloring.js +33 -0
  56. package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.d.ts +26 -0
  57. package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.d.ts.map +1 -0
  58. package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.js +71 -0
  59. package/src/core/math/max2_exact.d.ts +15 -0
  60. package/src/core/math/max2_exact.d.ts.map +1 -0
  61. package/src/core/math/max2_exact.js +30 -0
  62. package/src/core/math/min2_exact.d.ts +20 -0
  63. package/src/core/math/min2_exact.d.ts.map +1 -0
  64. package/src/core/math/min2_exact.js +35 -0
  65. package/src/engine/ecs/ik/IKGoalSystem.d.ts.map +1 -1
  66. package/src/engine/ecs/ik/IKGoalSystem.js +3 -19
  67. package/src/engine/ecs/parent/parent_entity_model_of.d.ts +17 -0
  68. package/src/engine/ecs/parent/parent_entity_model_of.d.ts.map +1 -0
  69. package/src/engine/ecs/parent/parent_entity_model_of.js +26 -0
  70. package/src/engine/ecs/transform/t64_read_pose_array.d.ts +15 -0
  71. package/src/engine/ecs/transform/t64_read_pose_array.d.ts.map +1 -0
  72. package/src/engine/ecs/transform/t64_read_pose_array.js +24 -0
  73. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts +2 -0
  74. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts.map +1 -1
  75. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.js +10 -21
  76. package/src/engine/graphics3/AnimationGraphSystem.d.ts +5 -0
  77. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  78. package/src/engine/graphics3/AnimationGraphSystem.js +48 -2
  79. package/src/engine/graphics3/AnimationSystem.d.ts +5 -0
  80. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  81. package/src/engine/graphics3/AnimationSystem.js +47 -2
  82. package/src/engine/graphics3/register_clips.d.ts +29 -0
  83. package/src/engine/graphics3/register_clips.d.ts.map +1 -1
  84. package/src/engine/graphics3/register_clips.js +52 -0
  85. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +9 -0
  86. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
  87. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +3 -1
  88. package/src/engine/physics/cloth/PLAN.md +10 -8
  89. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +22 -0
  90. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -1
  91. package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +51 -19
  92. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  93. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +16 -2
  94. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -1
  95. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +19 -24
  96. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +7 -0
  97. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  98. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +85 -67
  99. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +19 -101
  101. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +2 -5
  102. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -1
  103. package/src/engine/physics/cloth/collider/cloth_collider_pack.js +7 -15
  104. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -1
  105. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +16 -61
  106. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +0 -1
  107. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +6 -19
  108. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +1 -2
  109. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
  110. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +3 -12
  111. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  112. package/src/engine/physics/cloth/ecs/ClothWorld.js +40 -130
  113. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  114. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +17 -58
  115. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  116. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +3 -3
  117. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  118. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +44 -104
  119. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -1
  120. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +6 -13
  121. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -1
  122. package/src/engine/physics/cloth/ecs/cloth_holds.js +15 -40
  123. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
  124. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +45 -79
  125. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  126. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +7 -27
  127. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  128. package/src/engine/physics/cloth/ecs/cloth_write_back.js +30 -62
  129. package/src/engine/physics/cloth/playground/cloth_playground_build.d.ts.map +1 -1
  130. package/src/engine/physics/cloth/playground/cloth_playground_build.js +2 -3
  131. package/src/engine/physics/cloth/playground/collide_main.js +2 -28
  132. package/src/engine/physics/cloth/playground/garment_main.js +4 -19
  133. package/src/engine/physics/cloth/playground/main.js +6 -48
  134. package/src/engine/physics/cloth/playground/rig_main.js +947 -955
  135. package/src/engine/physics/cloth/playground/wind_main.js +8 -7
  136. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  137. package/src/engine/physics/cloth/solver/ClothState.js +16 -76
  138. package/src/engine/physics/cloth/solver/cloth_color_particles.d.ts +10 -8
  139. package/src/engine/physics/cloth/solver/cloth_color_particles.d.ts.map +1 -1
  140. package/src/engine/physics/cloth/solver/cloth_color_particles.js +30 -102
  141. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  142. package/src/engine/physics/cloth/solver/cloth_contact_find.js +3 -2
  143. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -1
  144. package/src/engine/physics/cloth/solver/cloth_hold_line.js +2 -14
  145. package/src/engine/physics/cloth/solver/cloth_kinetic_energy.d.ts +21 -0
  146. package/src/engine/physics/cloth/solver/cloth_kinetic_energy.d.ts.map +1 -0
  147. package/src/engine/physics/cloth/solver/cloth_kinetic_energy.js +45 -0
  148. package/src/engine/physics/cloth/solver/cloth_particle_coupling.d.ts +32 -0
  149. package/src/engine/physics/cloth/solver/cloth_particle_coupling.d.ts.map +1 -0
  150. package/src/engine/physics/cloth/solver/cloth_particle_coupling.js +133 -0
  151. package/src/engine/physics/cloth/solver/cloth_particle_of_source.d.ts +16 -0
  152. package/src/engine/physics/cloth/solver/cloth_particle_of_source.d.ts.map +1 -0
  153. package/src/engine/physics/cloth/solver/cloth_particle_of_source.js +19 -0
  154. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
  155. package/src/engine/physics/cloth/solver/cloth_self_find.js +6 -55
  156. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
  157. package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +30 -65
  158. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  159. package/src/engine/physics/cloth/solver/cloth_step.js +6 -28
  160. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
  161. package/src/engine/physics/cloth/solver/cloth_step_instance.js +2 -3
  162. package/src/engine/physics/cloth/solver/cloth_stretch_residual.d.ts +21 -0
  163. package/src/engine/physics/cloth/solver/cloth_stretch_residual.d.ts.map +1 -0
  164. package/src/engine/physics/cloth/solver/cloth_stretch_residual.js +54 -0
  165. package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.d.ts +15 -0
  166. package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.d.ts.map +1 -1
  167. package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.js +28 -0
  168. package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.d.ts +30 -0
  169. package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.d.ts.map +1 -0
  170. package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.js +56 -0
  171. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -1
  172. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +3 -17
  173. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +2 -1
  174. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
  175. package/src/engine/physics/cloth/wind/ClothFluidWind.js +7 -25
  176. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +3 -1
  177. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  178. package/src/engine/physics/cloth/wind/cloth_sample_air.js +40 -62
  179. package/src/engine/physics/ecs/ContactProbeSystem.d.ts.map +1 -1
  180. package/src/engine/physics/ecs/ContactProbeSystem.js +2 -18
  181. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  182. package/src/engine/physics/ecs/PhysicsSystem.js +9 -50
  183. package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.d.ts +24 -0
  184. package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.d.ts.map +1 -0
  185. package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.js +42 -0
  186. package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.d.ts +25 -0
  187. package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.d.ts.map +1 -0
  188. package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.js +40 -0
  189. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.d.ts.map +1 -1
  190. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.js +40 -90
  191. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  192. package/src/engine/physics/narrowphase/capsule_contacts.js +3 -5
  193. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
  194. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +2 -14
  195. package/src/engine/physics/narrowphase/hull_sphere_contact.d.ts.map +1 -1
  196. package/src/engine/physics/narrowphase/hull_sphere_contact.js +2 -5
  197. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  198. package/src/engine/physics/narrowphase/narrowphase_step.js +13 -32
  199. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
  200. package/src/engine/physics/narrowphase/sphere_box_contact.js +2 -5
  201. package/src/format/texture/basis/transcode/etc1s_to_astc.d.ts.map +1 -1
  202. package/src/format/texture/basis/transcode/etc1s_to_astc.js +2 -1
  203. package/src/shade/playground/image_decode_bench/main.js +2 -1
  204. package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.d.ts.map +1 -1
  205. package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.js +2 -1
  206. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -1
  207. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +2 -1
  208. package/src/shade/playground/ssr_variance/statistics.d.ts.map +1 -1
  209. package/src/shade/playground/ssr_variance/statistics.js +2 -1
  210. package/src/shade/playground/texture_encode/main.d.ts.map +1 -1
  211. package/src/shade/playground/texture_encode/main.js +2 -1
  212. package/src/shade/playground/volumetrics_froxel/measure.d.ts.map +1 -1
  213. package/src/shade/playground/volumetrics_froxel/measure.js +2 -1
  214. package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts.map +1 -1
  215. package/src/shade/renderer/buffer/table/gpu_database_check_links.js +2 -1
  216. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -1
  217. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +3 -2
  218. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -1
  219. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +2 -1
  220. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts.map +1 -1
  221. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.js +2 -1
  222. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts.map +1 -1
  223. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.js +2 -1
  224. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts.map +1 -1
  225. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.js +3 -2
  226. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.d.ts.map +1 -1
  227. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.js +2 -1
  228. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts.map +1 -1
  229. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.js +2 -1
  230. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  231. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +3 -2
  232. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -1
  233. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +3 -2
@@ -1,8 +1,15 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
2
  import { BVH, NULL_NODE } from "../../../../core/bvh2/bvh3/BVH.js";
3
+ import { number_compare_ascending } from "../../../../core/primitives/numbers/number_compare_ascending.js";
3
4
  import {
4
5
  bvh_query_user_data_intersects_aabb
5
6
  } from "../../../../core/bvh2/bvh3/query/bvh_query_user_data_intersects_aabb.js";
7
+ import { array_copy } from "../../../../core/collection/array/array_copy.js";
8
+ import { array_range_equal_strict } from "../../../../core/collection/array/array_range_equal_strict.js";
9
+ import { array_remove_first } from "../../../../core/collection/array/array_remove_first.js";
10
+ import { array_sort_insertion_ascending } from "../../../../core/collection/array/array_sort_insertion_ascending.js";
11
+ import { aabb3_array_round_outward_f32 } from "../../../../core/geom/3d/aabb/aabb3_array_round_outward_f32.js";
12
+ import { FAT_LINEAR } from "../../broadphase/compute_fat_world_aabb.js";
6
13
  import {
7
14
  CCR_AABB_MAX_X,
8
15
  CCR_AABB_MAX_Y,
@@ -341,11 +348,9 @@ export class ClothColliderIndex {
341
348
  const node = this.#node[handle];
342
349
 
343
350
  if (node === NULL_NODE) {
344
- const at = this.#planes.indexOf(handle);
351
+ const planes = this.#planes;
345
352
 
346
- if (at >= 0) {
347
- this.#planes.splice(at, 1);
348
- }
353
+ array_remove_first(planes, handle, 0, planes.length);
349
354
  } else {
350
355
  this.#bvh.remove_leaf(node);
351
356
  this.#bvh.release_node(node);
@@ -419,22 +424,11 @@ export class ClothColliderIndex {
419
424
  this.max_inflation = table[r + CCR_INFLATION];
420
425
  }
421
426
 
422
- const moved = table[r + CCR_PREV_TX] !== table[r + CCR_TX]
423
- || table[r + CCR_PREV_TY] !== table[r + CCR_TY]
424
- || table[r + CCR_PREV_TZ] !== table[r + CCR_TZ]
425
- || table[r + CCR_PREV_QX] !== table[r + CCR_QX]
426
- || table[r + CCR_PREV_QY] !== table[r + CCR_QY]
427
- || table[r + CCR_PREV_QZ] !== table[r + CCR_QZ]
428
- || table[r + CCR_PREV_QW] !== table[r + CCR_QW];
429
-
430
- table[r + CCR_PREV_TX] = table[r + CCR_TX];
431
- table[r + CCR_PREV_TY] = table[r + CCR_TY];
432
- table[r + CCR_PREV_TZ] = table[r + CCR_TZ];
427
+ // A pose is seven contiguous slots, translation then rotation, in
428
+ // both the current and the previous half of the record.
429
+ const moved = !array_range_equal_strict(table, r + CCR_PREV_TX, table, r + CCR_TX, POSE_SLOTS);
433
430
 
434
- table[r + CCR_PREV_QX] = table[r + CCR_QX];
435
- table[r + CCR_PREV_QY] = table[r + CCR_QY];
436
- table[r + CCR_PREV_QZ] = table[r + CCR_QZ];
437
- table[r + CCR_PREV_QW] = table[r + CCR_QW];
431
+ array_copy(table, r + CCR_TX, table, r + CCR_PREV_TX, POSE_SLOTS);
438
432
 
439
433
  if (moved) {
440
434
  cloth_collider_refit_bounds(table, handle, CCR_STRIDE);
@@ -451,6 +445,13 @@ export class ClothColliderIndex {
451
445
  * ignores it, so a distance in the shape's local frame is a distance in
452
446
  * world space.
453
447
  *
448
+ * A pose equal to the one the record already holds is not refit: its
449
+ * bounds were fit to exactly this pair of poses when either last changed —
450
+ * here, in {@link placePose}, or in {@link advance} — so the refit would
451
+ * write what is there. That is what a collider that never moves costs, and
452
+ * why nothing has to say it will not: 1.43 µs per collider per step
453
+ * refitting, 0.42 µs skipping, of which {@link advance} is 0.32.
454
+ *
454
455
  * @param {number} handle
455
456
  * @param {number} tx
456
457
  * @param {number} ty
@@ -471,6 +472,35 @@ export class ClothColliderIndex {
471
472
 
472
473
  const r = handle * CCR_STRIDE;
473
474
 
475
+ if (table[r + CCR_TX] === tx && table[r + CCR_TY] === ty && table[r + CCR_TZ] === tz
476
+ && table[r + CCR_QX] === qx && table[r + CCR_QY] === qy
477
+ && table[r + CCR_QZ] === qz && table[r + CCR_QW] === qw
478
+ // no leaf — never posed, or a plane, which is never in the tree — refits regardless
479
+ && this.#node[handle] !== NULL_NODE) {
480
+ return;
481
+ }
482
+
483
+ this.#pose(handle, tx, ty, tz, qx, qy, qz, qw);
484
+ }
485
+
486
+ /**
487
+ * Write the current pose and refit, unconditionally.
488
+ *
489
+ * @param {number} handle
490
+ * @param {number} tx
491
+ * @param {number} ty
492
+ * @param {number} tz
493
+ * @param {number} qx
494
+ * @param {number} qy
495
+ * @param {number} qz
496
+ * @param {number} qw
497
+ * @private
498
+ */
499
+ #pose(handle, tx, ty, tz, qx, qy, qz, qw) {
500
+ const table = this.table;
501
+
502
+ const r = handle * CCR_STRIDE;
503
+
474
504
  if (table[r + CCR_TX] !== tx || table[r + CCR_TY] !== ty || table[r + CCR_TZ] !== tz
475
505
  || table[r + CCR_QX] !== qx || table[r + CCR_QY] !== qy
476
506
  || table[r + CCR_QZ] !== qz || table[r + CCR_QW] !== qw) {
@@ -561,9 +591,15 @@ export class ClothColliderIndex {
561
591
  if (lower < STORED_AABB[axis] || upper > STORED_AABB[axis + 3]) contained = false;
562
592
  // A one-step outlier must not leave a scene-sized leaf behind once
563
593
  // motion stops. Allow ordinary jitter to keep spending the slack.
594
+ // The yardstick is twice what a store would write now: the slack
595
+ // on both sides plus the outward rounding, which grows each side by
596
+ // under one float32 step of its magnitude. Without that term a leaf
597
+ // far enough out that a step outgrows the slack — past about four
598
+ // hundred kilometres — would read as oversized straight after being
599
+ // stored, and be re-homed every step.
564
600
  if (STORED_AABB[axis + 3] - STORED_AABB[axis]
565
- > 2 * (upper - lower + 2 * BVH_LEAF_SLACK
566
- + (Math.abs(lower) + Math.abs(upper)) * FLOAT32_ROUNDING)) oversized = true;
601
+ > 2 * (upper - lower + 2 * FAT_LINEAR
602
+ + (Math.abs(lower) + Math.abs(upper) + 2 * FAT_LINEAR) * FLOAT32_STEP)) oversized = true;
567
603
  }
568
604
 
569
605
  if (contained && !oversized) {
@@ -589,18 +625,18 @@ export class ClothColliderIndex {
589
625
  * Write a record's swept bounds plus its contact reach into {@link FAT_AABB}
590
626
  * with the slack the refit skip spends, and store them on the leaf.
591
627
  *
592
- * The slack is also what makes the tree's `Float32` nodes safe to hold a
593
- * `Float64` world, and it has two terms because one is not enough. The
594
- * constant covers jitter. The relative term covers the rounding
595
- * {@link BVH#node_set_aabb} does on the way in: a bound can move by an ulp,
596
- * and `Float32`'s ulp is a *proportion* of the magnitude — a millimetre at
597
- * ten kilometres out, but **a whole metre at ten thousand**, which is well
598
- * past the constant: measured, a leaf there comes back 45 cm inside its own
599
- * record. A bound that rounds inward past its slack is a leaf
600
- * smaller than the record it stands for, and that is a collider the tree
601
- * stops answering with — silently, and only far from the origin, which is
602
- * the worst shape a bug can have. Two ulps of the magnitude puts it back
603
- * outside at every scale the `Float64` table is kept for.
628
+ * The slack covers jitter; it does not cover the tree's `Float32` nodes
629
+ * holding a `Float64` world. {@link BVH#node_set_aabb} rounds each bound to
630
+ * the nearest `Float32`, and `Float32`'s step is a *proportion* of the
631
+ * magnitude — a millimetre at ten kilometres out, but **a whole metre at
632
+ * ten thousand**, which is well past any constant: measured, a leaf there
633
+ * fattened by 5 cm came back 45 cm inside its own record. A bound that
634
+ * rounds inward past its slack is a leaf smaller than the record it stands
635
+ * for, and that is a collider the tree stops answering with — silently,
636
+ * and only far from the origin, which is the worst shape a bug can have.
637
+ * So the fattened box is rounded outward to `Float32` before it is stored,
638
+ * which makes the store exact at every scale and leaves the constant to do
639
+ * only its own job.
604
640
  *
605
641
  * The exact test in {@link query} reads the `Float64` record, so the tree
606
642
  * only ever has to avoid a false **negative**; being generous here costs a
@@ -618,10 +654,12 @@ export class ClothColliderIndex {
618
654
  const lower = table[r + CCR_AABB_MIN_X + axis] - reach;
619
655
  const upper = table[r + CCR_AABB_MAX_X + axis] + reach;
620
656
 
621
- FAT_AABB[axis] = lower - BVH_LEAF_SLACK - Math.abs(lower) * FLOAT32_ROUNDING;
622
- FAT_AABB[axis + 3] = upper + BVH_LEAF_SLACK + Math.abs(upper) * FLOAT32_ROUNDING;
657
+ FAT_AABB[axis] = lower - FAT_LINEAR;
658
+ FAT_AABB[axis + 3] = upper + FAT_LINEAR;
623
659
  }
624
660
 
661
+ aabb3_array_round_outward_f32(FAT_AABB, 0, FAT_AABB, 0);
662
+
625
663
  this.#bvh.node_set_aabb(node, FAT_AABB);
626
664
  }
627
665
 
@@ -657,7 +695,9 @@ export class ClothColliderIndex {
657
695
  this.table[r + CCR_PREV_QZ] = qz;
658
696
  this.table[r + CCR_PREV_QW] = qw;
659
697
 
660
- this.setPose(handle, tx, ty, tz, qx, qy, qz, qw);
698
+ // Not {@link setPose}: the previous pose has just changed, so the
699
+ // bounds are stale even when the current one has not.
700
+ this.#pose(handle, tx, ty, tz, qx, qy, qz, qw);
661
701
  }
662
702
 
663
703
  /**
@@ -926,21 +966,19 @@ export class ClothColliderIndex {
926
966
  }
927
967
 
928
968
  /**
929
- * How far past a record's swept bounds its leaf is stored, metres. The same
930
- * constant `compute_fat_world_aabb` spends on a rigid body, and for the same
931
- * reason: a collider jittering inside its own slack must not cost a refit.
969
+ * One `Float32` step as a proportion of a value's magnitude, an upper bound
970
+ * for every normal `Float32`: 23 fraction bits, so a step is at most `2^-23`
971
+ * of the magnitude. The most an outward rounding can widen a bound by.
932
972
  * @type {number}
933
973
  */
934
- const BVH_LEAF_SLACK = 0.05;
974
+ const FLOAT32_STEP = 2 ** -23;
935
975
 
936
976
  /**
937
- * Two `Float32` ulps as a proportion of a value's magnitude — what a bound has
938
- * to be widened by to survive being stored in a `Float32` leaf whatever the
939
- * rounding does. `Float32` carries 23 fraction bits, so one ulp is `2^-23` of
940
- * the magnitude and two is the first multiple that is unconditionally outside.
977
+ * Slots in one pose, `[tx, ty, tz, qx, qy, qz, qw]`: {@link CCR_TX} to {@link CCR_QW}, and the same
978
+ * from {@link CCR_PREV_TX}.
941
979
  * @type {number}
942
980
  */
943
- const FLOAT32_ROUNDING = 2 ** -22;
981
+ const POSE_SLOTS = 7;
944
982
 
945
983
  /**
946
984
  * The box being queried, `[min_x, min_y, min_z, max_x, max_y, max_z]`: what the tree is walked with
@@ -972,23 +1010,12 @@ function sort_handles(handles) {
972
1010
  const n = handles.length;
973
1011
 
974
1012
  if (n > INSERTION_SORT_LIMIT) {
975
- handles.sort(ASCENDING);
1013
+ handles.sort(number_compare_ascending);
976
1014
 
977
1015
  return;
978
1016
  }
979
1017
 
980
- for (let i = 1; i < n; i++) {
981
- const handle = handles[i];
982
-
983
- let j = i - 1;
984
-
985
- while (j >= 0 && handles[j] > handle) {
986
- handles[j + 1] = handles[j];
987
- j--;
988
- }
989
-
990
- handles[j + 1] = handle;
991
- }
1018
+ array_sort_insertion_ascending(handles, 0, n);
992
1019
  }
993
1020
 
994
1021
  /**
@@ -1002,12 +1029,3 @@ const FAT_AABB = new Float64Array(6);
1002
1029
  * @type {Float32Array}
1003
1030
  */
1004
1031
  const STORED_AABB = new Float32Array(6);
1005
-
1006
- /**
1007
- * @param {number} a
1008
- * @param {number} b
1009
- * @returns {number}
1010
- */
1011
- function ASCENDING(a, b) {
1012
- return a - b;
1013
- }
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_collider_bounds.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/cloth_collider_bounds.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,oDAJW,MAAM,eACN,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;GAOG;AACH,mDALW,YAAY,GAAC,YAAY,UACzB,MAAM,UACN,MAAM,GACJ,IAAI,CAoBhB"}
1
+ {"version":3,"file":"cloth_collider_bounds.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/cloth_collider_bounds.js"],"names":[],"mappings":"AAkBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,oDAJW,MAAM,eACN,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;GAOG;AACH,mDALW,YAAY,GAAC,YAAY,UACzB,MAAM,UACN,MAAM,GACJ,IAAI,CA2BhB"}
@@ -1,16 +1,13 @@
1
- import { aabb3_matrix4_project } from "../../../../core/geom/3d/aabb/aabb3_matrix4_project.js";
2
- import {
3
- m4_from_rotation_translation_scale_array
4
- } from "../../../../core/geom/3d/mat4/m4_from_rotation_translation_scale_array.js";
1
+ import { aabb3_transform_oriented_array } from "../../../../core/geom/3d/aabb/aabb3_transform_oriented.js";
5
2
  import { v3_quaternion_apply_array } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
3
+ import { max2_exact } from "../../../../core/math/max2_exact.js";
4
+ import { min2_exact } from "../../../../core/math/min2_exact.js";
6
5
  import { ClothColliderKind } from "./ClothColliderKind.js";
7
6
  import {
8
7
  CCR_AABB_MAX_X,
9
8
  CCR_AABB_MIN_X,
10
9
  CCR_KIND,
11
10
  CCR_PARAM_0,
12
- CCR_PARAM_1,
13
- CCR_PARAM_2,
14
11
  CCR_PARAM_3,
15
12
  CCR_PREV_QX,
16
13
  CCR_PREV_TX,
@@ -87,91 +84,25 @@ export function cloth_collider_refit_bounds(table, record, stride) {
87
84
 
88
85
  cloth_collider_local_bounds(LOCAL_BOUNDS, table, record, stride);
89
86
 
90
- project(CURRENT_BOUNDS, table, r + CCR_QX, r + CCR_TX);
91
- project(PREVIOUS_BOUNDS, table, r + CCR_PREV_QX, r + CCR_PREV_TX);
87
+ // Each pose is seven contiguous slots, translation then rotation, which is
88
+ // the layout the transform reads — so it reads them where they sit in the
89
+ // table rather than as numbers handed through a call, each of which would
90
+ // be boxed into a heap object wherever the call is not inlined.
91
+ aabb3_transform_oriented_array(CURRENT_BOUNDS, 0, LOCAL_BOUNDS, 0, table, r + CCR_TX);
92
+ aabb3_transform_oriented_array(PREVIOUS_BOUNDS, 0, LOCAL_BOUNDS, 0, table, r + CCR_PREV_TX);
92
93
 
94
+ // Not `aabb3_array_combine`: its `min2` / `max2` drop a NaN in their first
95
+ // operand, so a NaN pose would leave the other pose's bound depending on
96
+ // which side it was on. The refit keeps `Math.min`'s answer instead.
93
97
  for (let axis = 0; axis < 3; axis++) {
94
- table[r + CCR_AABB_MIN_X + axis] = min_exact(CURRENT_BOUNDS[axis], PREVIOUS_BOUNDS[axis]);
95
- table[r + CCR_AABB_MAX_X + axis] = max_exact(CURRENT_BOUNDS[axis + 3], PREVIOUS_BOUNDS[axis + 3]);
96
- }
97
- }
98
-
99
- /**
100
- * `Math.min(a, b)` without the call: the smaller, NaN if either is, and `-0` below `+0`. The refit
101
- * runs a few times a cloth a step, so V8 is slow to optimise it, and until it does `Math.min` is a
102
- * call into a builtin that hands its answer back boxed into a heap object.
103
- *
104
- * The same as `Math.min` under `Object.is` for every pair of numbers. A NaN answer is the canonical
105
- * NaN; which NaN `Math.min` answers is the platform's (on x64, the one with the sign bit set).
106
- *
107
- * @param {number} a
108
- * @param {number} b
109
- * @returns {number}
110
- * @private
111
- */
112
- function min_exact(a, b) {
113
- if (a < b) {
114
- return a;
115
- }
116
-
117
- if (b < a) {
118
- return b;
98
+ table[r + CCR_AABB_MIN_X + axis] = min2_exact(CURRENT_BOUNDS[axis], PREVIOUS_BOUNDS[axis]);
99
+ table[r + CCR_AABB_MAX_X + axis] = max2_exact(CURRENT_BOUNDS[axis + 3], PREVIOUS_BOUNDS[axis + 3]);
119
100
  }
120
-
121
- if (a === b) {
122
- // equal, and of two zeros the negative one if either is
123
- return a === 0 && 1 / a > 0 ? b : a;
124
- }
125
-
126
- // one of them is NaN
127
- return NaN;
128
101
  }
129
102
 
130
103
  /**
131
- * `Math.max(a, b)` without the call, as {@link min_exact}: the larger, NaN if either is, and `+0`
132
- * above `-0`.
133
- *
134
- * @param {number} a
135
- * @param {number} b
136
- * @returns {number}
137
- * @private
138
- */
139
- function max_exact(a, b) {
140
- if (a > b) {
141
- return a;
142
- }
143
-
144
- if (b > a) {
145
- return b;
146
- }
147
-
148
- if (a === b) {
149
- // equal, and of two zeros the positive one if either is
150
- return a === 0 && 1 / a < 0 ? b : a;
151
- }
152
-
153
- return NaN;
154
- }
155
-
156
- /**
157
- * @param {Float64Array} out
158
- * @param {Float32Array|Float64Array} table
159
- * @param {number} rotation slot of the pose's rotation
160
- * @param {number} translation slot of the pose's translation
161
- * @private
162
- */
163
- function project(out, table, rotation, translation) {
164
- // The pose is read where it sits in the table. Handed to the compose as ten numbers, the seven
165
- // that are not small integers were each boxed into a heap object wherever the call was not
166
- // inlined.
167
- m4_from_rotation_translation_scale_array(POSE, table, rotation, table, translation, UNIT_SCALE, 0);
168
-
169
- aabb3_matrix4_project(out, LOCAL_BOUNDS, POSE);
170
- }
171
-
172
- /**
173
- * A half-space's bounds, which cannot go through {@link aabb3_matrix4_project}
174
- * — an infinite extent multiplied by a zero matrix element is `NaN`. The
104
+ * A half-space's bounds, which cannot go through {@link aabb3_transform_oriented_array}
105
+ * — an infinite extent multiplied by a zero rotation element is `NaN`. The
175
106
  * plane's world normal is its local normal rotated by the pose, and the bound
176
107
  * exists on an axis exactly when that normal is aligned with it.
177
108
  *
@@ -190,7 +121,7 @@ function refit_plane(table, r) {
190
121
  const rotation = r + PLANE_POSES[p];
191
122
  const translation = r + PLANE_POSES[p + 1];
192
123
 
193
- // the local normal and the rotation straight from the table, as in `project`
124
+ // the local normal and the rotation straight from the table, as for the other kinds
194
125
  v3_quaternion_apply_array(PLANE_NORMAL, 0, table, r + CCR_PARAM_0, table, rotation);
195
126
 
196
127
  // The boundary plane passes through `R·(offset·n_local) + t`, so its
@@ -208,9 +139,9 @@ function refit_plane(table, r) {
208
139
  // different ways is not a half-space, so the looser of the two wins
209
140
  // and a rotating plane simply stops bounding anything.
210
141
  if (n > PLANE_AXIS_TOLERANCE) {
211
- table[r + CCR_AABB_MAX_X + axis] = max_exact(table[r + CCR_AABB_MAX_X + axis], offset);
142
+ table[r + CCR_AABB_MAX_X + axis] = max2_exact(table[r + CCR_AABB_MAX_X + axis], offset);
212
143
  } else if (n < -PLANE_AXIS_TOLERANCE) {
213
- table[r + CCR_AABB_MIN_X + axis] = min_exact(table[r + CCR_AABB_MIN_X + axis], -offset);
144
+ table[r + CCR_AABB_MIN_X + axis] = min2_exact(table[r + CCR_AABB_MIN_X + axis], -offset);
214
145
  }
215
146
  }
216
147
  }
@@ -268,16 +199,3 @@ const CURRENT_BOUNDS = new Float64Array(6);
268
199
  * @private
269
200
  */
270
201
  const PREVIOUS_BOUNDS = new Float64Array(6);
271
-
272
- /**
273
- * @type {Float64Array}
274
- * @private
275
- */
276
- const POSE = new Float64Array(16);
277
-
278
- /**
279
- * The scale {@link project} composes with: a collider's pose is rigid.
280
- * @type {Float64Array}
281
- * @private
282
- */
283
- const UNIT_SCALE = new Float64Array([1, 1, 1]);
@@ -5,11 +5,8 @@
5
5
  * It runs when a `ClothCollider` is linked or its shape changes, never per step
6
6
  * and never per particle.
7
7
  *
8
- * `instanceof` rather than the prototype markers the physics narrowphase uses,
9
- * because this needs to distinguish *five* kinds rather than short-circuit one,
10
- * and because a marker per kind would be five new fields on `core` shapes for
11
- * one consumer's benefit. The ordering matters in one place and is commented
12
- * where it does.
8
+ * Each kind is asked by its prototype marker, as the physics narrowphase asks;
9
+ * the five are unrelated classes, so the order of the tests does not matter.
13
10
  *
14
11
  * @author Alex Goldring
15
12
  * @copyright Company Named Limited (c) 2026
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_collider_pack.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/cloth_collider_pack.js"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;;;GASG;AACH,2CAPW,YAAY,GAAC,YAAY,UACzB,MAAM,kCAEN,MAAM,GACJ,OAAO,CAiFnB;AAED;;;;;;;;;;;;;;GAcG;AACH,iDANW,YAAY,GAAC,MAAM,EAAE,SACrB,YAAY,GAAC,YAAY,UACzB,MAAM,UACN,MAAM,GACJ,OAAO,CAqCnB"}
1
+ {"version":3,"file":"cloth_collider_pack.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/cloth_collider_pack.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;GASG;AACH,2CAPW,YAAY,GAAC,YAAY,UACzB,MAAM,kCAEN,MAAM,GACJ,OAAO,CAiFnB;AAED;;;;;;;;;;;;;;GAcG;AACH,iDANW,YAAY,GAAC,MAAM,EAAE,SACrB,YAAY,GAAC,YAAY,UACzB,MAAM,UACN,MAAM,GACJ,OAAO,CAqCnB"}
@@ -1,8 +1,3 @@
1
- import { BoxShape3D } from "../../../../core/geom/3d/shape/BoxShape3D.js";
2
- import { CapsuleShape3D } from "../../../../core/geom/3d/shape/CapsuleShape3D.js";
3
- import { CylinderShape3D } from "../../../../core/geom/3d/shape/CylinderShape3D.js";
4
- import { PlaneShape3D } from "../../../../core/geom/3d/shape/PlaneShape3D.js";
5
- import { SphereShape3D } from "../../../../core/geom/3d/shape/SphereShape3D.js";
6
1
  import { ClothColliderKind } from "./ClothColliderKind.js";
7
2
  import {
8
3
  CCR_FEATURE,
@@ -20,11 +15,8 @@ import {
20
15
  * It runs when a `ClothCollider` is linked or its shape changes, never per step
21
16
  * and never per particle.
22
17
  *
23
- * `instanceof` rather than the prototype markers the physics narrowphase uses,
24
- * because this needs to distinguish *five* kinds rather than short-circuit one,
25
- * and because a marker per kind would be five new fields on `core` shapes for
26
- * one consumer's benefit. The ordering matters in one place and is commented
27
- * where it does.
18
+ * Each kind is asked by its prototype marker, as the physics narrowphase asks;
19
+ * the five are unrelated classes, so the order of the tests does not matter.
28
20
  *
29
21
  * @author Alex Goldring
30
22
  * @copyright Company Named Limited (c) 2026
@@ -43,7 +35,7 @@ import {
43
35
  export function cloth_collider_pack(table, record, shape, stride) {
44
36
  const r = record * stride;
45
37
 
46
- if (shape instanceof SphereShape3D) {
38
+ if (shape.isSphereShape3D === true) {
47
39
  // Covers UnitSphereShape3D, which is a SphereShape3D of radius 1.
48
40
  const radius = shape.radius;
49
41
 
@@ -57,7 +49,7 @@ export function cloth_collider_pack(table, record, shape, stride) {
57
49
  return true;
58
50
  }
59
51
 
60
- if (shape instanceof CapsuleShape3D) {
52
+ if (shape.isCapsuleShape3D === true) {
61
53
  const radius = shape.radius;
62
54
 
63
55
  table[r + CCR_KIND] = ClothColliderKind.Capsule;
@@ -72,7 +64,7 @@ export function cloth_collider_pack(table, record, shape, stride) {
72
64
  return true;
73
65
  }
74
66
 
75
- if (shape instanceof BoxShape3D) {
67
+ if (shape.isBoxShape3D === true) {
76
68
  // Covers UnitCubeShape3D, which is a BoxShape3D pinned to 0.5.
77
69
  const h = shape.half_extents;
78
70
 
@@ -90,7 +82,7 @@ export function cloth_collider_pack(table, record, shape, stride) {
90
82
  return true;
91
83
  }
92
84
 
93
- if (shape instanceof CylinderShape3D) {
85
+ if (shape.isCylinderShape3D === true) {
94
86
  const radius = shape.radius;
95
87
 
96
88
  table[r + CCR_KIND] = ClothColliderKind.Cylinder;
@@ -103,7 +95,7 @@ export function cloth_collider_pack(table, record, shape, stride) {
103
95
  return true;
104
96
  }
105
97
 
106
- if (shape instanceof PlaneShape3D) {
98
+ if (shape.isPlaneShape3D === true) {
107
99
  table[r + CCR_KIND] = ClothColliderKind.Plane;
108
100
  table[r + CCR_PARAM_0] = shape.normal_x;
109
101
  table[r + CCR_PARAM_1] = shape.normal_y;
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_collider_sdf.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/cloth_collider_sdf.js"],"names":[],"mappings":"AAmCA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,8CALW,YAAY,GAAC,YAAY,SACzB,MAAM,KACN,MAAM,GACJ,IAAI,CAiDhB;AAED;;;;;;;;;;;;;;GAcG;AACH,yDATW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,mBAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,GACJ,MAAM,CAclB;AAED;;;;;;;;;;;;;;GAcG;AACH,0DATW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAElC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,SACN,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,gBAClC,MAAM,GACJ,IAAI,CAgChB;AAED;;;;;;;;;;;;;;;GAeG;AACH,+CATW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,GACJ,IAAI,CAQhB;AAED;;;;;;;;;;;GAWG;AACH,qDARW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,SACN,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,gBAClC,MAAM,GACJ,IAAI,CAUhB;AAED;;;;;;;;;;;;;GAaG;AACH,6CATW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,GACJ,IAAI,CAQhB;AAED;;;;;;;;;;;GAWG;AACH,mDARW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,SACN,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,gBAClC,MAAM,GACJ,IAAI,CAUhB"}
1
+ {"version":3,"file":"cloth_collider_sdf.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/cloth_collider_sdf.js"],"names":[],"mappings":"AA4BA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,8CALW,YAAY,GAAC,YAAY,SACzB,MAAM,KACN,MAAM,GACJ,IAAI,CAmBhB;AAED;;;;;;;;;;;;;;GAcG;AACH,yDATW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,mBAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,GACJ,MAAM,CAclB;AAED;;;;;;;;;;;;;;GAcG;AACH,0DATW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAElC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,SACN,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,gBAClC,MAAM,GACJ,IAAI,CAgChB;AAED;;;;;;;;;;;;;;;GAeG;AACH,+CATW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,GACJ,IAAI,CAQhB;AAED;;;;;;;;;;;GAWG;AACH,qDARW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,SACN,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,gBAClC,MAAM,GACJ,IAAI,CAMhB;AAED;;;;;;;;;;;;;GAaG;AACH,6CATW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,GACJ,IAAI,CAQhB;AAED;;;;;;;;;;;GAWG;AACH,mDARW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAClC,MAAM,SACN,YAAY,GAAC,YAAY,UACzB,MAAM,SACN,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,gBAClC,MAAM,GACJ,IAAI,CAMhB"}
@@ -1,31 +1,24 @@
1
+ import { pose3_apply_inverse_point_array } from "../../../../core/geom/3d/pose/pose3_apply_inverse_point_array.js";
2
+ import { pose3_apply_point_array } from "../../../../core/geom/3d/pose/pose3_apply_point_array.js";
3
+ import { quat3_nlerp_array } from "../../../../core/geom/3d/quaternion/quat3_nlerp.js";
1
4
  import { sdf3_box_gradient_array } from "../../../../core/geom/3d/shape/sdf/sdf3_box.js";
2
5
  import { sdf3_capsule_gradient_array } from "../../../../core/geom/3d/shape/sdf/sdf3_capsule.js";
3
6
  import { sdf3_cylinder_gradient_array } from "../../../../core/geom/3d/shape/sdf/sdf3_cylinder.js";
4
7
  import { sdf3_plane_gradient_array } from "../../../../core/geom/3d/shape/sdf/sdf3_plane.js";
5
8
  import { sdf3_sphere_gradient_array } from "../../../../core/geom/3d/shape/sdf/sdf3_sphere.js";
6
9
  import { v3_quaternion_apply_array } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
7
- import { v3_quaternion_apply_inverse_array } from "../../../../core/geom/vec3/v3_quaternion_apply_inverse.js";
8
10
  import {
9
- CCR_INTERP_QW,
10
11
  CCR_INTERP_QX,
11
- CCR_INTERP_QY,
12
- CCR_INTERP_QZ,
13
12
  CCR_INTERP_TX,
14
13
  CCR_INTERP_TY,
15
14
  CCR_INTERP_TZ,
16
15
  CCR_KIND,
17
16
  CCR_PARAM_0,
18
- CCR_PREV_QW,
19
17
  CCR_PREV_QX,
20
- CCR_PREV_QY,
21
- CCR_PREV_QZ,
22
18
  CCR_PREV_TX,
23
19
  CCR_PREV_TY,
24
20
  CCR_PREV_TZ,
25
- CCR_QW,
26
21
  CCR_QX,
27
- CCR_QY,
28
- CCR_QZ,
29
22
  CCR_STRIDE,
30
23
  CCR_TX,
31
24
  CCR_TY,
@@ -89,42 +82,12 @@ export function cloth_collider_pose_at(table, count, t) {
89
82
  table[r + CCR_INTERP_TY] = s * table[r + CCR_PREV_TY] + t * table[r + CCR_TY];
90
83
  table[r + CCR_INTERP_TZ] = s * table[r + CCR_PREV_TZ] + t * table[r + CCR_TZ];
91
84
 
92
- const ax = table[r + CCR_PREV_QX];
93
- const ay = table[r + CCR_PREV_QY];
94
- const az = table[r + CCR_PREV_QZ];
95
- const aw = table[r + CCR_PREV_QW];
96
-
97
- let bx = table[r + CCR_QX];
98
- let by = table[r + CCR_QY];
99
- let bz = table[r + CCR_QZ];
100
- let bw = table[r + CCR_QW];
101
-
102
- // `q` and `−q` are one rotation, so the pair has to be brought onto the
103
- // same hemisphere or the interpolation takes the long way round — which
104
- // for a collider is a bone that spins through the character.
105
- if (ax * bx + ay * by + az * bz + aw * bw < 0) {
106
- bx = -bx;
107
- by = -by;
108
- bz = -bz;
109
- bw = -bw;
110
- }
111
-
112
- const qx = s * ax + t * bx;
113
- const qy = s * ay + t * by;
114
- const qz = s * az + t * bz;
115
- const qw = s * aw + t * bw;
116
-
117
- const length = Math.sqrt(qx * qx + qy * qy + qz * qz + qw * qw);
118
-
119
- // Two opposed quaternions cancel exactly, which the hemisphere fix
120
- // above makes impossible; the guard is for a record whose poses were
121
- // never written rather than for a rotation.
122
- const inverse = length > 0 ? 1 / length : 0;
123
-
124
- table[r + CCR_INTERP_QX] = qx * inverse;
125
- table[r + CCR_INTERP_QY] = qy * inverse;
126
- table[r + CCR_INTERP_QZ] = qz * inverse;
127
- table[r + CCR_INTERP_QW] = length > 0 ? qw * inverse : 1;
85
+ // Both poses' quaternions are contiguous `[x, y, z, w]` slots, so the
86
+ // blend reads them in place. `q` and `−q` are one rotation; the
87
+ // hemisphere flip inside the nlerp is what keeps the pair from
88
+ // interpolating the long way round — which for a collider is a bone
89
+ // that spins through the character.
90
+ quat3_nlerp_array(table, r + CCR_INTERP_QX, table, r + CCR_PREV_QX, table, r + CCR_QX, t);
128
91
  }
129
92
  }
130
93
 
@@ -175,11 +138,11 @@ export function cloth_collider_signed_distance(gradient, gradient_offset, table,
175
138
  export function cloth_collider_signed_distance_array(out, out_offset, table, record, point, point_offset) {
176
139
  const r = record * CCR_STRIDE;
177
140
 
178
- LOCAL_POINT[0] = point[point_offset] - table[r + CCR_INTERP_TX];
179
- LOCAL_POINT[1] = point[point_offset + 1] - table[r + CCR_INTERP_TY];
180
- LOCAL_POINT[2] = point[point_offset + 2] - table[r + CCR_INTERP_TZ];
181
-
182
- v3_quaternion_apply_inverse_array(LOCAL_POINT, 0, LOCAL_POINT, 0, table, r + CCR_INTERP_QX);
141
+ pose3_apply_inverse_point_array(
142
+ LOCAL_POINT, 0,
143
+ table, r + CCR_INTERP_TX, table, r + CCR_INTERP_QX,
144
+ point, point_offset
145
+ );
183
146
 
184
147
  const kind = table[r + CCR_KIND];
185
148
 
@@ -243,11 +206,7 @@ export function cloth_collider_from_local(out, out_offset, table, record, x, y,
243
206
  export function cloth_collider_from_local_array(out, out_offset, table, record, point, point_offset) {
244
207
  const r = record * CCR_STRIDE;
245
208
 
246
- v3_quaternion_apply_array(out, out_offset, point, point_offset, table, r + CCR_INTERP_QX);
247
-
248
- out[out_offset] += table[r + CCR_INTERP_TX];
249
- out[out_offset + 1] += table[r + CCR_INTERP_TY];
250
- out[out_offset + 2] += table[r + CCR_INTERP_TZ];
209
+ pose3_apply_point_array(out, out_offset, table, r + CCR_INTERP_TX, table, r + CCR_INTERP_QX, point, point_offset);
251
210
  }
252
211
 
253
212
  /**
@@ -287,11 +246,7 @@ export function cloth_collider_to_local(out, out_offset, table, record, x, y, z)
287
246
  export function cloth_collider_to_local_array(out, out_offset, table, record, point, point_offset) {
288
247
  const r = record * CCR_STRIDE;
289
248
 
290
- LOCAL_POINT[0] = point[point_offset] - table[r + CCR_INTERP_TX];
291
- LOCAL_POINT[1] = point[point_offset + 1] - table[r + CCR_INTERP_TY];
292
- LOCAL_POINT[2] = point[point_offset + 2] - table[r + CCR_INTERP_TZ];
293
-
294
- v3_quaternion_apply_inverse_array(out, out_offset, LOCAL_POINT, 0, table, r + CCR_INTERP_QX);
249
+ pose3_apply_inverse_point_array(out, out_offset, table, r + CCR_INTERP_TX, table, r + CCR_INTERP_QX, point, point_offset);
295
250
  }
296
251
 
297
252
  /**
@@ -4,6 +4,5 @@
4
4
  export type ClothColliderFlags = number;
5
5
  export namespace ClothColliderFlags {
6
6
  let None: number;
7
- let Static: number;
8
7
  }
9
8
  //# sourceMappingURL=ClothColliderFlags.d.ts.map