@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.
- package/package.json +1 -1
- package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +118 -0
- package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -0
- package/src/core/geom/3d/hash-grid/PointHashGrid3.js +283 -0
- package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/BoxShape3D.js +6 -17
- package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/CapsuleShape3D.js +3 -14
- package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/CylinderShape3D.js +3 -21
- package/src/core/geom/3d/shape/PlaneShape3D.d.ts +105 -0
- package/src/core/geom/3d/shape/PlaneShape3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/PlaneShape3D.js +251 -0
- package/src/core/geom/3d/shape/SphereShape3D.js +3 -3
- package/src/core/geom/3d/shape/json/shape_to_type.d.ts.map +1 -1
- package/src/core/geom/3d/shape/json/shape_to_type.js +3 -0
- package/src/core/geom/3d/shape/json/type_adapters.d.ts +14 -0
- package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
- package/src/core/geom/3d/shape/json/type_adapters.js +15 -0
- package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts +51 -0
- package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_box.js +113 -0
- package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts +46 -0
- package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_capsule.js +82 -0
- package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts +60 -0
- package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_cylinder.js +126 -0
- package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts +50 -0
- package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.js +53 -0
- package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts +52 -0
- package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_plane.js +61 -0
- package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts +41 -0
- package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts.map +1 -0
- package/src/core/geom/3d/shape/sdf/sdf3_sphere.js +71 -0
- package/src/core/process/ConcurrencyGate.d.ts +103 -0
- package/src/core/process/ConcurrencyGate.d.ts.map +1 -0
- package/src/core/process/ConcurrencyGate.js +207 -0
- package/src/engine/asset/AssetManager.d.ts +10 -0
- package/src/engine/asset/AssetManager.d.ts.map +1 -1
- package/src/engine/asset/AssetManager.js +10 -0
- package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +30 -13
- package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts +26 -0
- package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts.map +1 -0
- package/src/engine/graphics3/pose/collect_entity_playbacks.js +40 -0
- package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
- package/src/engine/graphics3/pose/query_entity_node_world_pose.js +74 -101
- package/src/engine/physics/cloth/MEASUREMENTS.md +1287 -4
- package/src/engine/physics/cloth/PLAN.md +1967 -1581
- package/src/engine/physics/cloth/build/ClothProxy.d.ts +147 -0
- package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -0
- package/src/engine/physics/cloth/build/ClothProxy.js +207 -0
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +70 -0
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -0
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +256 -0
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +176 -0
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/ClothColliderIndex.js +435 -0
- package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts +12 -0
- package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/ClothColliderKind.js +38 -0
- package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts +120 -0
- package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/ClothColliderRecord.js +137 -0
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +25 -0
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +190 -0
- package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +44 -0
- package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/cloth_collider_pack.js +173 -0
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +94 -0
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -0
- package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +275 -0
- package/src/engine/physics/cloth/ecs/ClothCollider.d.ts +126 -0
- package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothCollider.js +199 -0
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +9 -0
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +32 -0
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +114 -0
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +243 -0
- package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +66 -57
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +109 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +479 -363
- package/src/engine/physics/cloth/ecs/ClothRig.d.ts +95 -0
- package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/ClothRig.js +140 -0
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +30 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.js +1021 -773
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +90 -0
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_build_rows.js +374 -0
- package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts +32 -3
- package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_library.js +283 -254
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +59 -0
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +328 -0
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +13 -0
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +288 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +58 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +199 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +8 -63
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +317 -645
- package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +61 -0
- package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_write_back.js +212 -449
- package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts +49 -0
- package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -0
- package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +115 -0
- package/src/engine/physics/cloth/playground/README.md +155 -1
- package/src/engine/physics/cloth/playground/collide.html +178 -0
- package/src/engine/physics/cloth/playground/collide_build.d.ts +95 -0
- package/src/engine/physics/cloth/playground/collide_build.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/collide_build.js +315 -0
- package/src/engine/physics/cloth/playground/collide_main.d.ts +2 -0
- package/src/engine/physics/cloth/playground/collide_main.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/collide_main.js +720 -0
- package/src/engine/physics/cloth/playground/garment.html +182 -0
- package/src/engine/physics/cloth/playground/garment_build.d.ts +78 -0
- package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/garment_build.js +359 -0
- package/src/engine/physics/cloth/playground/garment_main.d.ts +2 -0
- package/src/engine/physics/cloth/playground/garment_main.d.ts.map +1 -0
- package/src/engine/physics/cloth/playground/garment_main.js +633 -0
- package/src/engine/physics/cloth/solver/ClothState.d.ts +208 -5
- package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/ClothState.js +302 -8
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +87 -0
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_contact_find.js +343 -0
- package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +112 -0
- package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_self_find.js +448 -0
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts +4 -1
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +16 -1
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +112 -5
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solver_constants.js +117 -6
- package/src/engine/physics/cloth/solver/cloth_step.d.ts +40 -9
- package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_step.js +122 -10
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +95 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +285 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts +129 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +501 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +75 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +202 -0
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/playground/vgeo_viewer/README.md +18 -0
- package/src/shade/playground/vgeo_viewer/main.js +87 -50
- package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabase.js +191 -62
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +94 -2
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +414 -2
- package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts +14 -0
- package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.js +13 -0
- package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts +17 -0
- package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.js +116 -0
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +9 -4
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +843 -734
- package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts +12 -0
- package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js +13 -0
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +17 -0
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +185 -30
- package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +17 -0
- package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +141 -24
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +204 -64
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +110 -10
- package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +19 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +19 -6
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +26 -7
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +173 -14
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +458 -51
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +49 -13
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +52 -14
- package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.js +19 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts +27 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.js +48 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts +29 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.js +60 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +8 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +32 -2
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +258 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +723 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +49 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +50 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts +3 -0
- package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
- package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +121 -21
- package/src/shade/renderer/texture/virtual/README.md +6 -4
- package/src/shade/renderer/texture/virtual/VirtualTextureManager.d.ts.map +1 -1
- package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +7 -0
- package/src/shade/renderer/texture/virtual/source/VTSourceTiled.d.ts +3 -3
- package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +3 -3
- package/src/engine/ecs/system/SystemExecutionPhase.d.ts +0 -9
- package/src/engine/ecs/system/SystemExecutionPhase.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/NOTES.md +0 -128
- package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts +0 -6
- package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.js +0 -5
- package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts +0 -49
- package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.js +0 -264
- package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts +0 -44
- package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/VirtualTextureUsage.js +0 -228
- package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts +0 -3
- package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.js +0 -73
- package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts +0 -14
- package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.js +0 -85
- package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts +0 -12
- package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/debug/UsageDebugView.js +0 -63
- package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts +0 -12
- package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.js +0 -243
- package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts +0 -30
- package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.js +0 -39
- package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts +0 -9
- package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/compose_finger_print.js +0 -24
- package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts +0 -9
- package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/compose_tile_address.js +0 -26
- package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts +0 -11
- package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.js +0 -12
- package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts +0 -7
- package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.js +0 -16
- package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts +0 -7
- package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts.map +0 -1
- package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.js +0 -35
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { combine_hash } from "../../../../core/collection/array/combine_hash.js";
|
|
3
|
+
import { computeHashFloat } from "../../../../core/primitives/numbers/computeHashFloat.js";
|
|
4
|
+
import { ClothColliderFlags } from "./ClothColliderFlags.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* # The marker that opts a collider into cloth
|
|
8
|
+
*
|
|
9
|
+
* Put this beside an existing `(Collider, Transform64)` and cloth collides
|
|
10
|
+
* against it. That is the whole of the component's job, and it is the third
|
|
11
|
+
* instance of a pattern the engine already has twice: `AcousticBody` opts a
|
|
12
|
+
* collider into the acoustic simulation and carries an `AcousticMaterial`,
|
|
13
|
+
* `FluidObstacle` opts a collider into the fluid simulation and carries an
|
|
14
|
+
* inflation radius. This should read as a sibling of those two rather than as a
|
|
15
|
+
* new invention.
|
|
16
|
+
*
|
|
17
|
+
* Everything not here is read from components the entity already has: geometry
|
|
18
|
+
* and friction from `Collider`, pose from `Transform64`.
|
|
19
|
+
*
|
|
20
|
+
* ## No `RigidBody` required
|
|
21
|
+
*
|
|
22
|
+
* A deliberate divergence from `FluidObstacle`, which requires one because it
|
|
23
|
+
* needs a wall velocity. Cloth's colliders are overwhelmingly character bones —
|
|
24
|
+
* ordinary entities in a `TransformAttachment` hierarchy — and making each of
|
|
25
|
+
* them a physics body to be seen by cloth would tax the common case. Collider
|
|
26
|
+
* velocity is derived from the pose delta between fixed steps, which the index
|
|
27
|
+
* caches anyway for swept collision (§8.2). A world prop that *does* carry a
|
|
28
|
+
* `RigidBody` adds a `ClothCollider` the same way and lands in the same index;
|
|
29
|
+
* the two cases are not distinguished.
|
|
30
|
+
*
|
|
31
|
+
* ## Layer and mask, which §3.5 did not have
|
|
32
|
+
*
|
|
33
|
+
* §3.5 gives this component three fields and says layer filtering comes "from
|
|
34
|
+
* the `Cloth` side". It cannot: `Cloth#mask` is a mask *of collider layers*,
|
|
35
|
+
* and with no `RigidBody` required there is nowhere else for a collider's layer
|
|
36
|
+
* to live. So the pair is here, with `RigidBody`'s own semantics — a cloth and
|
|
37
|
+
* a collider interact when each is in the other's mask — which is what
|
|
38
|
+
* `Cloth.js` already says it means by "`RigidBody` semantics".
|
|
39
|
+
*
|
|
40
|
+
* @author Alex Goldring
|
|
41
|
+
* @copyright Company Named Limited (c) 2026
|
|
42
|
+
*/
|
|
43
|
+
export class ClothCollider {
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Extra thickness in metres, on top of `ClothDynamics#thickness`.
|
|
47
|
+
*
|
|
48
|
+
* The contact row holds cloth at `thickness + inflation` from the surface,
|
|
49
|
+
* so this is how a garment is kept off a body it would otherwise graze —
|
|
50
|
+
* the same idea as `FluidObstacle#inflation`, and useful for the same
|
|
51
|
+
* reason: a collider that approximates a limb loosely wants the cloth held
|
|
52
|
+
* a little further out than the approximation.
|
|
53
|
+
* @type {number}
|
|
54
|
+
*/
|
|
55
|
+
inflation = 0;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Multiplies the entity's `Collider#friction` before it is combined with
|
|
59
|
+
* the cloth's own. `0` makes the surface frictionless to cloth without
|
|
60
|
+
* making it frictionless to rigid bodies, which is the case this exists
|
|
61
|
+
* for: a character's collision capsules are tuned for footing, and a cape
|
|
62
|
+
* that grips them the same way reads as glued.
|
|
63
|
+
* @type {number}
|
|
64
|
+
*/
|
|
65
|
+
friction_scale = 1;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Collision layer this collider belongs to, `RigidBody` semantics.
|
|
69
|
+
* @type {number}
|
|
70
|
+
*/
|
|
71
|
+
layer = 1;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Which `Cloth` layers this collider acts on.
|
|
75
|
+
* @type {number}
|
|
76
|
+
*/
|
|
77
|
+
mask = 0xFFFFFFFF;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @see ClothColliderFlags
|
|
81
|
+
* @type {number}
|
|
82
|
+
*/
|
|
83
|
+
flags = ClothColliderFlags.None;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {object} [spec]
|
|
87
|
+
* @param {number} [spec.inflation]
|
|
88
|
+
* @param {number} [spec.friction_scale]
|
|
89
|
+
* @param {number} [spec.layer]
|
|
90
|
+
* @param {number} [spec.mask]
|
|
91
|
+
* @param {number} [spec.flags]
|
|
92
|
+
* @returns {ClothCollider}
|
|
93
|
+
*/
|
|
94
|
+
static from(spec = {}) {
|
|
95
|
+
const r = new ClothCollider();
|
|
96
|
+
|
|
97
|
+
const {
|
|
98
|
+
inflation = r.inflation,
|
|
99
|
+
friction_scale = r.friction_scale,
|
|
100
|
+
layer = r.layer,
|
|
101
|
+
mask = r.mask,
|
|
102
|
+
flags = r.flags
|
|
103
|
+
} = spec;
|
|
104
|
+
|
|
105
|
+
assert.isNumber(inflation, 'inflation');
|
|
106
|
+
assert.isNumber(friction_scale, 'friction_scale');
|
|
107
|
+
assert.isNonNegativeInteger(layer, 'layer');
|
|
108
|
+
assert.isNonNegativeInteger(mask, 'mask');
|
|
109
|
+
assert.isNonNegativeInteger(flags, 'flags');
|
|
110
|
+
|
|
111
|
+
r.inflation = inflation;
|
|
112
|
+
r.friction_scale = friction_scale;
|
|
113
|
+
r.layer = layer;
|
|
114
|
+
r.mask = mask;
|
|
115
|
+
r.flags = flags;
|
|
116
|
+
|
|
117
|
+
return r;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @param {number|ClothColliderFlags} flag
|
|
122
|
+
* @returns {boolean}
|
|
123
|
+
*/
|
|
124
|
+
getFlag(flag) {
|
|
125
|
+
return (this.flags & flag) === flag;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @param {ClothCollider} other
|
|
130
|
+
* @returns {boolean}
|
|
131
|
+
*/
|
|
132
|
+
equals(other) {
|
|
133
|
+
if (other === this) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (other === null || other === undefined || other.isClothCollider !== true) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return this.inflation === other.inflation
|
|
142
|
+
&& this.friction_scale === other.friction_scale
|
|
143
|
+
&& this.layer === other.layer
|
|
144
|
+
&& this.mask === other.mask
|
|
145
|
+
&& this.flags === other.flags;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @returns {number}
|
|
150
|
+
*/
|
|
151
|
+
hash() {
|
|
152
|
+
return combine_hash(
|
|
153
|
+
computeHashFloat(this.inflation),
|
|
154
|
+
computeHashFloat(this.friction_scale),
|
|
155
|
+
this.layer,
|
|
156
|
+
this.mask,
|
|
157
|
+
this.flags
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
toJSON() {
|
|
162
|
+
return {
|
|
163
|
+
inflation: this.inflation,
|
|
164
|
+
friction_scale: this.friction_scale,
|
|
165
|
+
layer: this.layer,
|
|
166
|
+
mask: this.mask,
|
|
167
|
+
flags: this.flags
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @param {object} json
|
|
173
|
+
*/
|
|
174
|
+
fromJSON({
|
|
175
|
+
inflation = 0,
|
|
176
|
+
friction_scale = 1,
|
|
177
|
+
layer = 1,
|
|
178
|
+
mask = 0xFFFFFFFF,
|
|
179
|
+
flags = ClothColliderFlags.None
|
|
180
|
+
}) {
|
|
181
|
+
this.inflation = inflation;
|
|
182
|
+
this.friction_scale = friction_scale;
|
|
183
|
+
this.layer = layer;
|
|
184
|
+
this.mask = mask;
|
|
185
|
+
this.flags = flags;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
toString() {
|
|
189
|
+
return `ClothCollider${JSON.stringify(this.toJSON())}`;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @readonly
|
|
195
|
+
* @type {boolean}
|
|
196
|
+
*/
|
|
197
|
+
ClothCollider.prototype.isClothCollider = true;
|
|
198
|
+
|
|
199
|
+
ClothCollider.typeName = "ClothCollider";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClothColliderFlags.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/ClothColliderFlags.js"],"names":[],"mappings":";;;iCAIU,MAAM"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Switches on {@link ClothCollider}.
|
|
3
|
+
*
|
|
4
|
+
* @readonly
|
|
5
|
+
* @enum {number}
|
|
6
|
+
*
|
|
7
|
+
* @author Alex Goldring
|
|
8
|
+
* @copyright Company Named Limited (c) 2026
|
|
9
|
+
*/
|
|
10
|
+
export const ClothColliderFlags = {
|
|
11
|
+
None: 0,
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The collider never moves, so it is placed once and never swept.
|
|
15
|
+
*
|
|
16
|
+
* §8.2's swept collision interpolates each collider's pose between the
|
|
17
|
+
* previous step's and this one's, and rolling one pose into the other and
|
|
18
|
+
* refitting the swept bounds is the per-collider, per-step cost of that. A
|
|
19
|
+
* ground plane, a wall, a rock pays it for nothing, and a large static
|
|
20
|
+
* collider pays the most because its bounds are the biggest thing the
|
|
21
|
+
* broadphase tests against.
|
|
22
|
+
*
|
|
23
|
+
* Set this and the pose is written once, at link, into **both** slots, so
|
|
24
|
+
* the sweep degenerates to the pose it already had. Move the entity anyway
|
|
25
|
+
* and the cloth will not notice: that is the trade, and it is why this is
|
|
26
|
+
* an author's assertion rather than something derived from a pose that
|
|
27
|
+
* happens not to have changed yet.
|
|
28
|
+
*/
|
|
29
|
+
Static: 1
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
Object.freeze(ClothColliderFlags);
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # The index's owner
|
|
3
|
+
*
|
|
4
|
+
* Observes `(ClothCollider, Collider, Transform64)` and maintains a
|
|
5
|
+
* {@link ClothColliderIndex}. The same shape as
|
|
6
|
+
* `AcousticOccluderIndex`/`OccluderBody` in the sound simulation, and for the
|
|
7
|
+
* same reason: the consumer needs a compact, pose-cached, broadphase-able view
|
|
8
|
+
* of a set of colliders that is deliberately not the physics BVH, because
|
|
9
|
+
* `ColliderObserverSystem` skips colliders with no owning body and a
|
|
10
|
+
* character's bone colliders have none.
|
|
11
|
+
*
|
|
12
|
+
* ## It has no `fixedUpdate`, and that is §4.1 applied a second time
|
|
13
|
+
*
|
|
14
|
+
* The index has to be refreshed from the world's transforms **before** any
|
|
15
|
+
* cloth reads it, and the engine's two ordering mechanisms cannot express that:
|
|
16
|
+
* `updateExecutionOrder` scores a system as a sum over the components it
|
|
17
|
+
* references and sorts descending, so a system can only be moved *earlier* by
|
|
18
|
+
* touching more, and `ClothSystem` — which reads and writes `Transform64` and
|
|
19
|
+
* `TransformAttachment` — outscores a system that only reads. Registration
|
|
20
|
+
* order does not break a non-tie.
|
|
21
|
+
*
|
|
22
|
+
* §4.1's conclusion applies unchanged: the answer is not a third mechanism, it
|
|
23
|
+
* is not needing one. So this system does not step at all. {@link refresh} is
|
|
24
|
+
* called once, at the top of `ClothSystem#fixedUpdate`, before any cloth is
|
|
25
|
+
* advanced — one call site, no flag to keep true, and the collider poses are
|
|
26
|
+
* read at exactly the moment the anchor poses are, which is what makes a
|
|
27
|
+
* contact consistent rather than merely fresh.
|
|
28
|
+
*
|
|
29
|
+
* The consequence, stated: with no `ClothSystem` in the manager the index is
|
|
30
|
+
* never refreshed. Nothing reads it either, so the cost of that is zero and the
|
|
31
|
+
* alternative — refreshing on a schedule nobody consumes — is worse.
|
|
32
|
+
*
|
|
33
|
+
* ## A mesh collider is skipped, once, loudly
|
|
34
|
+
*
|
|
35
|
+
* §8.2 restricts cloth to analytic primitives, which is universal in shipping
|
|
36
|
+
* cloth systems and is what makes the inner loop arithmetic rather than a BVH
|
|
37
|
+
* descent. A `Collider` carrying a mesh or a heightmap is skipped with one
|
|
38
|
+
* warning naming the entity, and the documented answer is to add primitive
|
|
39
|
+
* `ClothCollider` children — which is what an author would do for a character
|
|
40
|
+
* anyway.
|
|
41
|
+
*
|
|
42
|
+
* @author Alex Goldring
|
|
43
|
+
* @copyright Company Named Limited (c) 2026
|
|
44
|
+
*/
|
|
45
|
+
export class ClothColliderSystem extends System<any> {
|
|
46
|
+
constructor();
|
|
47
|
+
dependencies: (typeof Transform64 | typeof Collider | typeof ClothCollider)[];
|
|
48
|
+
components_used: (ResourceAccessSpecification<typeof Transform64> | ResourceAccessSpecification<typeof Collider> | ResourceAccessSpecification<typeof ClothCollider>)[];
|
|
49
|
+
/**
|
|
50
|
+
* @type {ClothColliderIndex}
|
|
51
|
+
*/
|
|
52
|
+
index: ClothColliderIndex;
|
|
53
|
+
/**
|
|
54
|
+
* Handle in {@link index} per linked entity. An entity whose shape cloth
|
|
55
|
+
* cannot collide against is absent rather than present with `-1`, so the
|
|
56
|
+
* refresh loop iterates only over colliders that exist.
|
|
57
|
+
* @type {Map<number, number>}
|
|
58
|
+
* @private
|
|
59
|
+
*/
|
|
60
|
+
private __handles;
|
|
61
|
+
/**
|
|
62
|
+
* Live `(ClothCollider, Collider, Transform64)` per handle, in the order
|
|
63
|
+
* they were linked. Held rather than looked up per step for the same reason
|
|
64
|
+
* `ClothInstance` holds its transforms: a refresh is a loop over live
|
|
65
|
+
* colliders, not a query.
|
|
66
|
+
* @type {{collider: ClothCollider, transform: Transform64, entity: number, handle: number}[]}
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
private __linked;
|
|
70
|
+
/**
|
|
71
|
+
* @param {ClothCollider} cloth_collider
|
|
72
|
+
* @param {Collider} collider
|
|
73
|
+
* @param {Transform64} transform
|
|
74
|
+
* @param {number} entity
|
|
75
|
+
*/
|
|
76
|
+
link(cloth_collider: ClothCollider, collider: Collider, transform: Transform64, entity: number): void;
|
|
77
|
+
/**
|
|
78
|
+
* @param {ClothCollider} cloth_collider
|
|
79
|
+
* @param {Collider} collider
|
|
80
|
+
* @param {Transform64} transform
|
|
81
|
+
* @param {number} entity
|
|
82
|
+
*/
|
|
83
|
+
unlink(cloth_collider: ClothCollider, collider: Collider, transform: Transform64, entity: number): void;
|
|
84
|
+
/**
|
|
85
|
+
* Roll every collider's pose forward one fixed step and re-read it from the
|
|
86
|
+
* world. Called by `ClothSystem` at the top of its own fixed update; see the
|
|
87
|
+
* class docblock for why it is a call rather than an ordering.
|
|
88
|
+
*
|
|
89
|
+
* @returns {void}
|
|
90
|
+
*/
|
|
91
|
+
refresh(): void;
|
|
92
|
+
/**
|
|
93
|
+
* Re-read a collider's surface and filter from its components. An author
|
|
94
|
+
* changing `inflation` or a layer at runtime says so here; nothing polls
|
|
95
|
+
* for it, which is the same contract `ClothSystem#reseed` carries for a
|
|
96
|
+
* structural change.
|
|
97
|
+
*
|
|
98
|
+
* @param {number} entity
|
|
99
|
+
* @returns {void}
|
|
100
|
+
*/
|
|
101
|
+
refreshSurface(entity: number): void;
|
|
102
|
+
/**
|
|
103
|
+
* @param {number} entity
|
|
104
|
+
* @returns {number} the index handle, or `undefined` if the entity is not indexed
|
|
105
|
+
*/
|
|
106
|
+
handleOf(entity: number): number;
|
|
107
|
+
}
|
|
108
|
+
import { System } from "../../../ecs/System.js";
|
|
109
|
+
import { Transform64 } from "../../../ecs/transform/Transform64.js";
|
|
110
|
+
import { Collider } from "../../ecs/Collider.js";
|
|
111
|
+
import { ClothCollider } from "./ClothCollider.js";
|
|
112
|
+
import { ResourceAccessSpecification } from "../../../../core/model/ResourceAccessSpecification.js";
|
|
113
|
+
import { ClothColliderIndex } from "../collider/ClothColliderIndex.js";
|
|
114
|
+
//# sourceMappingURL=ClothColliderSystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClothColliderSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/ClothColliderSystem.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH;;IAEI,8EAAsD;IAEtD,wKAIE;IAEF;;OAEG;IACH,OAFU,kBAAkB,CAEK;IAEjC;;;;;;OAMG;IACH,kBAAsB;IAEtB;;;;;;;OAOG;IACH,iBAAc;IAEd;;;;;OAKG;IACH,qBALW,aAAa,YACb,QAAQ,aACR,WAAW,UACX,MAAM,QAsChB;IAED;;;;;OAKG;IACH,uBALW,aAAa,YACb,QAAQ,aACR,WAAW,UACX,MAAM,QAmBhB;IAED;;;;;;OAMG;IACH,WAFa,IAAI,CAkChB;IAED;;;;;;;;OAQG;IACH,uBAHW,MAAM,GACJ,IAAI,CAyBhB;IAED;;;OAGG;IACH,iBAHW,MAAM,GACJ,MAAM,CAIlB;CACJ;uBAhPsB,wBAAwB;4BAKxC,uCAAuC;yBACrB,uBAAuB;8BAElB,oBAAoB;4CATN,uDAAuD;mCAQhE,mCAAmC"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { ResourceAccessKind } from "../../../../core/model/ResourceAccessKind.js";
|
|
2
|
+
import { ResourceAccessSpecification } from "../../../../core/model/ResourceAccessSpecification.js";
|
|
3
|
+
import { System } from "../../../ecs/System.js";
|
|
4
|
+
import {
|
|
5
|
+
TRANSFORM64_ROTATION_OFFSET,
|
|
6
|
+
TRANSFORM64_TRANSLATION_OFFSET,
|
|
7
|
+
Transform64
|
|
8
|
+
} from "../../../ecs/transform/Transform64.js";
|
|
9
|
+
import { Collider } from "../../ecs/Collider.js";
|
|
10
|
+
import { ClothColliderIndex } from "../collider/ClothColliderIndex.js";
|
|
11
|
+
import { ClothCollider } from "./ClothCollider.js";
|
|
12
|
+
import { ClothColliderFlags } from "./ClothColliderFlags.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* # The index's owner
|
|
16
|
+
*
|
|
17
|
+
* Observes `(ClothCollider, Collider, Transform64)` and maintains a
|
|
18
|
+
* {@link ClothColliderIndex}. The same shape as
|
|
19
|
+
* `AcousticOccluderIndex`/`OccluderBody` in the sound simulation, and for the
|
|
20
|
+
* same reason: the consumer needs a compact, pose-cached, broadphase-able view
|
|
21
|
+
* of a set of colliders that is deliberately not the physics BVH, because
|
|
22
|
+
* `ColliderObserverSystem` skips colliders with no owning body and a
|
|
23
|
+
* character's bone colliders have none.
|
|
24
|
+
*
|
|
25
|
+
* ## It has no `fixedUpdate`, and that is §4.1 applied a second time
|
|
26
|
+
*
|
|
27
|
+
* The index has to be refreshed from the world's transforms **before** any
|
|
28
|
+
* cloth reads it, and the engine's two ordering mechanisms cannot express that:
|
|
29
|
+
* `updateExecutionOrder` scores a system as a sum over the components it
|
|
30
|
+
* references and sorts descending, so a system can only be moved *earlier* by
|
|
31
|
+
* touching more, and `ClothSystem` — which reads and writes `Transform64` and
|
|
32
|
+
* `TransformAttachment` — outscores a system that only reads. Registration
|
|
33
|
+
* order does not break a non-tie.
|
|
34
|
+
*
|
|
35
|
+
* §4.1's conclusion applies unchanged: the answer is not a third mechanism, it
|
|
36
|
+
* is not needing one. So this system does not step at all. {@link refresh} is
|
|
37
|
+
* called once, at the top of `ClothSystem#fixedUpdate`, before any cloth is
|
|
38
|
+
* advanced — one call site, no flag to keep true, and the collider poses are
|
|
39
|
+
* read at exactly the moment the anchor poses are, which is what makes a
|
|
40
|
+
* contact consistent rather than merely fresh.
|
|
41
|
+
*
|
|
42
|
+
* The consequence, stated: with no `ClothSystem` in the manager the index is
|
|
43
|
+
* never refreshed. Nothing reads it either, so the cost of that is zero and the
|
|
44
|
+
* alternative — refreshing on a schedule nobody consumes — is worse.
|
|
45
|
+
*
|
|
46
|
+
* ## A mesh collider is skipped, once, loudly
|
|
47
|
+
*
|
|
48
|
+
* §8.2 restricts cloth to analytic primitives, which is universal in shipping
|
|
49
|
+
* cloth systems and is what makes the inner loop arithmetic rather than a BVH
|
|
50
|
+
* descent. A `Collider` carrying a mesh or a heightmap is skipped with one
|
|
51
|
+
* warning naming the entity, and the documented answer is to add primitive
|
|
52
|
+
* `ClothCollider` children — which is what an author would do for a character
|
|
53
|
+
* anyway.
|
|
54
|
+
*
|
|
55
|
+
* @author Alex Goldring
|
|
56
|
+
* @copyright Company Named Limited (c) 2026
|
|
57
|
+
*/
|
|
58
|
+
export class ClothColliderSystem extends System {
|
|
59
|
+
|
|
60
|
+
dependencies = [ClothCollider, Collider, Transform64];
|
|
61
|
+
|
|
62
|
+
components_used = [
|
|
63
|
+
ResourceAccessSpecification.from(ClothCollider, ResourceAccessKind.Read),
|
|
64
|
+
ResourceAccessSpecification.from(Collider, ResourceAccessKind.Read),
|
|
65
|
+
ResourceAccessSpecification.from(Transform64, ResourceAccessKind.Read)
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @type {ClothColliderIndex}
|
|
70
|
+
*/
|
|
71
|
+
index = new ClothColliderIndex();
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Handle in {@link index} per linked entity. An entity whose shape cloth
|
|
75
|
+
* cannot collide against is absent rather than present with `-1`, so the
|
|
76
|
+
* refresh loop iterates only over colliders that exist.
|
|
77
|
+
* @type {Map<number, number>}
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
__handles = new Map();
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Live `(ClothCollider, Collider, Transform64)` per handle, in the order
|
|
84
|
+
* they were linked. Held rather than looked up per step for the same reason
|
|
85
|
+
* `ClothInstance` holds its transforms: a refresh is a loop over live
|
|
86
|
+
* colliders, not a query.
|
|
87
|
+
* @type {{collider: ClothCollider, transform: Transform64, entity: number, handle: number}[]}
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
__linked = [];
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {ClothCollider} cloth_collider
|
|
94
|
+
* @param {Collider} collider
|
|
95
|
+
* @param {Transform64} transform
|
|
96
|
+
* @param {number} entity
|
|
97
|
+
*/
|
|
98
|
+
link(cloth_collider, collider, transform, entity) {
|
|
99
|
+
const handle = this.index.add(
|
|
100
|
+
collider.shape,
|
|
101
|
+
collider.friction * cloth_collider.friction_scale,
|
|
102
|
+
cloth_collider.inflation,
|
|
103
|
+
cloth_collider.layer,
|
|
104
|
+
cloth_collider.mask,
|
|
105
|
+
entity
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (handle < 0) {
|
|
109
|
+
console.warn(
|
|
110
|
+
`ClothColliderSystem: entity ${entity} carries a ${collider.shape.constructor.name}, `
|
|
111
|
+
+ `which cloth does not collide against (§8.2 — analytic primitives only). `
|
|
112
|
+
+ `Add primitive ClothCollider children instead.`
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this.__handles.set(entity, handle);
|
|
119
|
+
|
|
120
|
+
this.__linked.push({ collider: cloth_collider, transform, entity, handle });
|
|
121
|
+
|
|
122
|
+
// Placed rather than posed, so its first step sweeps nothing. A
|
|
123
|
+
// collider that has just appeared did not move.
|
|
124
|
+
this.index.placePose(
|
|
125
|
+
handle,
|
|
126
|
+
transform[TRANSFORM64_TRANSLATION_OFFSET],
|
|
127
|
+
transform[TRANSFORM64_TRANSLATION_OFFSET + 1],
|
|
128
|
+
transform[TRANSFORM64_TRANSLATION_OFFSET + 2],
|
|
129
|
+
transform[TRANSFORM64_ROTATION_OFFSET],
|
|
130
|
+
transform[TRANSFORM64_ROTATION_OFFSET + 1],
|
|
131
|
+
transform[TRANSFORM64_ROTATION_OFFSET + 2],
|
|
132
|
+
transform[TRANSFORM64_ROTATION_OFFSET + 3]
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @param {ClothCollider} cloth_collider
|
|
138
|
+
* @param {Collider} collider
|
|
139
|
+
* @param {Transform64} transform
|
|
140
|
+
* @param {number} entity
|
|
141
|
+
*/
|
|
142
|
+
unlink(cloth_collider, collider, transform, entity) {
|
|
143
|
+
const handle = this.__handles.get(entity);
|
|
144
|
+
|
|
145
|
+
if (handle === undefined) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this.__handles.delete(entity);
|
|
150
|
+
this.index.remove(handle);
|
|
151
|
+
|
|
152
|
+
for (let i = 0; i < this.__linked.length; i++) {
|
|
153
|
+
if (this.__linked[i].entity === entity) {
|
|
154
|
+
this.__linked.splice(i, 1);
|
|
155
|
+
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Roll every collider's pose forward one fixed step and re-read it from the
|
|
163
|
+
* world. Called by `ClothSystem` at the top of its own fixed update; see the
|
|
164
|
+
* class docblock for why it is a call rather than an ordering.
|
|
165
|
+
*
|
|
166
|
+
* @returns {void}
|
|
167
|
+
*/
|
|
168
|
+
refresh() {
|
|
169
|
+
const index = this.index;
|
|
170
|
+
|
|
171
|
+
index.advance();
|
|
172
|
+
|
|
173
|
+
const linked = this.__linked;
|
|
174
|
+
|
|
175
|
+
for (let i = 0; i < linked.length; i++) {
|
|
176
|
+
const entry = linked[i];
|
|
177
|
+
|
|
178
|
+
const cloth_collider = entry.collider;
|
|
179
|
+
|
|
180
|
+
if ((cloth_collider.flags & ClothColliderFlags.Static) !== 0) {
|
|
181
|
+
// Placed once at link and never swept. `advance` has just made
|
|
182
|
+
// its previous pose equal to its current one, which is exactly
|
|
183
|
+
// the state a static collider wants and costs nothing to leave.
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const transform = entry.transform;
|
|
188
|
+
|
|
189
|
+
index.setPose(
|
|
190
|
+
entry.handle,
|
|
191
|
+
transform[TRANSFORM64_TRANSLATION_OFFSET],
|
|
192
|
+
transform[TRANSFORM64_TRANSLATION_OFFSET + 1],
|
|
193
|
+
transform[TRANSFORM64_TRANSLATION_OFFSET + 2],
|
|
194
|
+
transform[TRANSFORM64_ROTATION_OFFSET],
|
|
195
|
+
transform[TRANSFORM64_ROTATION_OFFSET + 1],
|
|
196
|
+
transform[TRANSFORM64_ROTATION_OFFSET + 2],
|
|
197
|
+
transform[TRANSFORM64_ROTATION_OFFSET + 3]
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Re-read a collider's surface and filter from its components. An author
|
|
204
|
+
* changing `inflation` or a layer at runtime says so here; nothing polls
|
|
205
|
+
* for it, which is the same contract `ClothSystem#reseed` carries for a
|
|
206
|
+
* structural change.
|
|
207
|
+
*
|
|
208
|
+
* @param {number} entity
|
|
209
|
+
* @returns {void}
|
|
210
|
+
*/
|
|
211
|
+
refreshSurface(entity) {
|
|
212
|
+
const handle = this.__handles.get(entity);
|
|
213
|
+
|
|
214
|
+
if (handle === undefined) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const ecd = this.entityManager.dataset;
|
|
219
|
+
|
|
220
|
+
const cloth_collider = ecd.getComponent(entity, ClothCollider);
|
|
221
|
+
const collider = ecd.getComponent(entity, Collider);
|
|
222
|
+
|
|
223
|
+
if (cloth_collider === undefined || collider === undefined) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
this.index.setSurface(
|
|
228
|
+
handle,
|
|
229
|
+
collider.friction * cloth_collider.friction_scale,
|
|
230
|
+
cloth_collider.inflation
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
this.index.setFilter(handle, cloth_collider.layer, cloth_collider.mask);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @param {number} entity
|
|
238
|
+
* @returns {number} the index handle, or `undefined` if the entity is not indexed
|
|
239
|
+
*/
|
|
240
|
+
handleOf(entity) {
|
|
241
|
+
return this.__handles.get(entity);
|
|
242
|
+
}
|
|
243
|
+
}
|