@woosh/meep-engine 3.29.0 → 3.30.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 (226) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/bundle-worker-terrain.js +1 -1
  3. package/package.json +1 -1
  4. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  5. package/src/core/binary/BinaryBuffer.js +14 -2
  6. package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
  7. package/src/core/bvh2/bvh3/BVH.js +14 -1
  8. package/src/core/cache/FrequencySketch.d.ts +3 -1
  9. package/src/core/cache/FrequencySketch.d.ts.map +1 -1
  10. package/src/core/cache/FrequencySketch.js +10 -4
  11. package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -1
  12. package/src/core/cache/wtinylfu/CacheWTinylfu.js +24 -2
  13. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts +20 -0
  14. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  15. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +69 -4
  16. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +48 -18
  17. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  18. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +262 -70
  19. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts +25 -0
  20. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts.map +1 -0
  21. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +228 -0
  22. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts +13 -0
  23. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts.map +1 -1
  24. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js +10 -128
  25. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
  26. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +11 -1
  27. package/src/core/graph/mn_graph_collapse_weighted_edge.js +6 -6
  28. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
  29. package/src/core/math/lookup/ParameterLookupTable.js +10 -5
  30. package/src/core/math/noise/sdnoise.d.ts.map +1 -1
  31. package/src/core/math/noise/sdnoise.js +16 -10
  32. package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
  33. package/src/core/model/object/ImmutableObjectPool.js +17 -7
  34. package/src/core/process/executor/ConcurrentExecutor.d.ts +1 -5
  35. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  36. package/src/core/process/executor/ConcurrentExecutor.js +95 -1
  37. package/src/core/process/task/task_find_dependency_cycle.d.ts +17 -0
  38. package/src/core/process/task/task_find_dependency_cycle.d.ts.map +1 -0
  39. package/src/core/process/task/task_find_dependency_cycle.js +81 -0
  40. package/src/core/wfc/WFCCellChoice.d.ts +17 -0
  41. package/src/core/wfc/WFCCellChoice.d.ts.map +1 -0
  42. package/src/core/wfc/WFCCellChoice.js +36 -0
  43. package/src/core/wfc/WFCLattice.d.ts +105 -0
  44. package/src/core/wfc/WFCLattice.d.ts.map +1 -0
  45. package/src/core/wfc/WFCLattice.js +235 -0
  46. package/src/core/wfc/WFCRuleTable.d.ts +172 -0
  47. package/src/core/wfc/WFCRuleTable.d.ts.map +1 -0
  48. package/src/core/wfc/WFCRuleTable.js +334 -0
  49. package/src/core/wfc/WFCState.d.ts +273 -0
  50. package/src/core/wfc/WFCState.d.ts.map +1 -0
  51. package/src/core/wfc/WFCState.js +552 -0
  52. package/src/core/wfc/WFCStatus.d.ts +11 -0
  53. package/src/core/wfc/WFCStatus.d.ts.map +1 -0
  54. package/src/core/wfc/WFCStatus.js +28 -0
  55. package/src/core/wfc/WFCTileWeights.d.ts +48 -0
  56. package/src/core/wfc/WFCTileWeights.d.ts.map +1 -0
  57. package/src/core/wfc/WFCTileWeights.js +86 -0
  58. package/src/core/wfc/WFC_UNRESOLVED.d.ts +12 -0
  59. package/src/core/wfc/WFC_UNRESOLVED.d.ts.map +1 -0
  60. package/src/core/wfc/WFC_UNRESOLVED.js +11 -0
  61. package/src/core/wfc/wfc_estimate_bytes.d.ts +24 -0
  62. package/src/core/wfc/wfc_estimate_bytes.d.ts.map +1 -0
  63. package/src/core/wfc/wfc_estimate_bytes.js +47 -0
  64. package/src/core/wfc/wfc_rule_table_tile_components.d.ts +27 -0
  65. package/src/core/wfc/wfc_rule_table_tile_components.d.ts.map +1 -0
  66. package/src/core/wfc/wfc_rule_table_tile_components.js +80 -0
  67. package/src/core/wfc/wfc_solve.d.ts +21 -0
  68. package/src/core/wfc/wfc_solve.d.ts.map +1 -0
  69. package/src/core/wfc/wfc_solve.js +154 -0
  70. package/src/core/wfc/wfc_state_apply_boundary.d.ts +18 -0
  71. package/src/core/wfc/wfc_state_apply_boundary.d.ts.map +1 -0
  72. package/src/core/wfc/wfc_state_apply_boundary.js +61 -0
  73. package/src/core/wfc/wfc_state_assign.d.ts +11 -0
  74. package/src/core/wfc/wfc_state_assign.d.ts.map +1 -0
  75. package/src/core/wfc/wfc_state_assign.js +36 -0
  76. package/src/core/wfc/wfc_state_ban_bits.d.ts +17 -0
  77. package/src/core/wfc/wfc_state_ban_bits.d.ts.map +1 -0
  78. package/src/core/wfc/wfc_state_ban_bits.js +81 -0
  79. package/src/core/wfc/wfc_state_collapse.d.ts +12 -0
  80. package/src/core/wfc/wfc_state_collapse.d.ts.map +1 -0
  81. package/src/core/wfc/wfc_state_collapse.js +73 -0
  82. package/src/core/wfc/wfc_state_flush_dirty.d.ts +12 -0
  83. package/src/core/wfc/wfc_state_flush_dirty.d.ts.map +1 -0
  84. package/src/core/wfc/wfc_state_flush_dirty.js +39 -0
  85. package/src/core/wfc/wfc_state_propagate.d.ts +14 -0
  86. package/src/core/wfc/wfc_state_propagate.d.ts.map +1 -0
  87. package/src/core/wfc/wfc_state_propagate.js +155 -0
  88. package/src/core/wfc/wfc_state_read.d.ts +11 -0
  89. package/src/core/wfc/wfc_state_read.d.ts.map +1 -0
  90. package/src/core/wfc/wfc_state_read.js +38 -0
  91. package/src/core/wfc/wfc_state_restrict.d.ts +18 -0
  92. package/src/core/wfc/wfc_state_restrict.d.ts.map +1 -0
  93. package/src/core/wfc/wfc_state_restrict.js +39 -0
  94. package/src/core/wfc/wfc_state_set_eligible.d.ts +24 -0
  95. package/src/core/wfc/wfc_state_set_eligible.d.ts.map +1 -0
  96. package/src/core/wfc/wfc_state_set_eligible.js +49 -0
  97. package/src/core/wfc/wfc_state_undo_to.d.ts +13 -0
  98. package/src/core/wfc/wfc_state_undo_to.d.ts.map +1 -0
  99. package/src/core/wfc/wfc_state_undo_to.js +84 -0
  100. package/src/core/wfc/wfc_words_per_cell.d.ts +11 -0
  101. package/src/core/wfc/wfc_words_per_cell.d.ts.map +1 -0
  102. package/src/core/wfc/wfc_words_per_cell.js +16 -0
  103. package/src/engine/ecs/EntityComponentDataset.d.ts +8 -0
  104. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  105. package/src/engine/ecs/EntityComponentDataset.js +37 -14
  106. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +8 -1
  107. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
  108. package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +37 -2
  109. package/src/engine/ecs/guid/UUID.d.ts.map +1 -1
  110. package/src/engine/ecs/guid/UUID.js +45 -17
  111. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +1 -1
  112. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +3 -1
  113. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
  114. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +366 -360
  115. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.d.ts.map +1 -1
  116. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +24 -10
  117. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  118. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +24 -5
  119. package/src/engine/interpolation/Interpoland.d.ts +7 -1
  120. package/src/engine/interpolation/Interpoland.d.ts.map +1 -1
  121. package/src/engine/interpolation/Interpoland.js +8 -1
  122. package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
  123. package/src/engine/interpolation/InterpolationSystem.js +3 -0
  124. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +5 -3
  125. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
  126. package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -3
  127. package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -1
  128. package/src/engine/interpolation/pose_interpoland.js +2 -0
  129. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  130. package/src/engine/network/orchestrator/NetworkPeer.js +15 -10
  131. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  132. package/src/engine/physics/cloth/ecs/ClothWorld.js +17 -0
  133. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  134. package/src/engine/physics/mls-mpm/MLS_MPM.js +14 -0
  135. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +2 -1
  136. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -1
  137. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +1 -1
  138. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +1 -0
  139. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
  140. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +1 -0
  141. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
  142. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +2 -1
  143. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
  144. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +12 -3
  145. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +1 -0
  146. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -1
  147. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -0
  148. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
  149. package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
  150. package/src/engine/sound/sopra/runtime/EventInstance.js +4 -1
  151. package/src/format/image/avif/av1/decode/decode_coefficients.d.ts.map +1 -1
  152. package/src/format/image/avif/av1/decode/decode_coefficients.js +248 -259
  153. package/src/format/image/avif/av1/decode/read_golomb.d.ts +21 -0
  154. package/src/format/image/avif/av1/decode/read_golomb.d.ts.map +1 -0
  155. package/src/format/image/avif/av1/decode/read_golomb.js +49 -0
  156. package/src/format/image/avif/av1/filter/loop_restoration.js +461 -451
  157. package/src/format/image/avif/av1/util/round2.d.ts +19 -2
  158. package/src/format/image/avif/av1/util/round2.d.ts.map +1 -1
  159. package/src/format/image/avif/av1/util/round2.js +51 -27
  160. package/src/format/image/avif/heif/parse_avif_file.js +24 -0
  161. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  162. package/src/shade/renderer/buffer/table/GPUTypedTable.js +14 -0
  163. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +46 -3
  164. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +91 -1
  165. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +0 -13
  166. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  167. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +0 -15
  168. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +5 -5
  169. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +11 -1
  170. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -1
  171. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +11 -1
  172. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +18 -9
  173. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
  174. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +20 -26
  175. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +1 -3
  176. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
  177. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +2 -5
  178. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -1
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +14 -1
  181. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
  182. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +12 -3
  183. package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.d.ts.map +1 -1
  184. package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.js +7 -1
  185. package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
  186. package/src/shade/renderer/lightmap/GPULightMap.js +349 -336
  187. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  188. package/src/shade/renderer/loader/gltf/load_gltf.js +1137 -1128
  189. package/src/shade/renderer/particles/DESIGN.md +14 -5
  190. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +25 -10
  191. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  192. package/src/shade/renderer/particles/GPUParticleSystem.js +182 -38
  193. package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
  194. package/src/shade/renderer/particles/graph/groups/simplex_reference.js +16 -10
  195. package/src/shade/renderer/particles/graph_particles.d.ts +4 -2
  196. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  197. package/src/shade/renderer/particles/graph_particles.js +8 -2
  198. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
  199. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +8 -2
  200. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
  201. package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -4
  202. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +31 -0
  203. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +1 -0
  204. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +62 -0
  205. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +13 -0
  206. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  207. package/src/shade/renderer/particles/vm/ParticleVMReference.js +95 -17
  208. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +21 -0
  209. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -0
  210. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +28 -0
  211. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  212. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +19 -2
  213. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  214. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +19 -2
  215. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  216. package/src/shade/renderer/shader/type/WebGPUStruct.js +12 -0
  217. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts +8 -2
  218. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
  219. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +41 -6
  220. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2383 -2356
  221. package/src/view/tooltip/DomTooltipManager.d.ts +7 -0
  222. package/src/view/tooltip/DomTooltipManager.d.ts.map +1 -1
  223. package/src/view/tooltip/DomTooltipManager.js +22 -0
  224. package/src/view/tooltip/DomTooltipObserver.d.ts.map +1 -1
  225. package/src/view/tooltip/DomTooltipObserver.js +13 -3
  226. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +0 -45
@@ -0,0 +1,228 @@
1
+ import { NULL_POINTER } from "../BinaryTopology.js";
2
+
3
+ /**
4
+ * How far along a segment an edge collapse may place its surviving vertex before one of the
5
+ * triangles it keeps turns over.
6
+ *
7
+ * **It is one walk and not a search, because the fold test is linear in the placement.** A surviving
8
+ * triangle keeps two of its corners, `b` and `c`, exactly where they were, so with the third at `p`
9
+ * its area vector is
10
+ *
11
+ * N(p) = (b - p) x (c - p) = b x c + p x (b - c)
12
+ *
13
+ * which is affine in `p`. "Still facing the way it did", `N(before) . N(p) > 0`, is therefore a
14
+ * linear inequality; the placements that fold nothing are an intersection of open half-spaces, which
15
+ * is convex; and along a segment `p(t) = from + t (to - from)` the test collapses to an affine
16
+ * function of the single parameter `t`. Two evaluations give the exact crossing rather than
17
+ * approaching it -- with `d0` at `from` and `d1` at `to`, the triangle reaches zero area at
18
+ * `t = d0 / (d0 - d1)` -- and the smallest crossing over both fans is the answer.
19
+ *
20
+ * The walk is {@link bt_edge_collapse_would_fold}'s, which is the same question asked at one point
21
+ * instead of two, and that function is now this one.
22
+ *
23
+ * **What it is for.** A quadric names the placement that best fits the surface and cannot see a fold
24
+ * at all: on a flat region every placement in the plane scores zero, so nothing in the price stops a
25
+ * one-ring that is not star-shaped about the target from turning inside out. A caller that tests its
26
+ * preferred placement and abandons the collapse when it folds has treated a bad *placement* as an
27
+ * impossible *operation*, and those are different things -- measured over one Zorah primitive, 15%
28
+ * of all candidate collapses were discarded that way, and the simplifier then reported itself
29
+ * finished with a mesh it could still have halved. Sliding back toward a placement the surface
30
+ * already passes through is what turns that refusal into an answer, and this is what says how far
31
+ * back to slide.
32
+ *
33
+ * @author Alex Goldring
34
+ * @copyright Company Named Limited (c) 2026
35
+ */
36
+
37
+ const scratch_moved = new Float32Array(3);
38
+ const scratch_b = new Float32Array(3);
39
+ const scratch_c = new Float32Array(3);
40
+ const scratch_before = new Float32Array(3);
41
+ const scratch_at_from = new Float32Array(3);
42
+ const scratch_at_to = new Float32Array(3);
43
+
44
+ /**
45
+ * Unnormalised triangle normal `(b - a) x (c - a)`, written into `out`.
46
+ *
47
+ * Deliberately not `v3_compute_triangle_normal`: this needs the raw cross product, because a
48
+ * vanishing magnitude is what says the result is a zero-area sliver and the `dot <= 0` test below is
49
+ * what rejects it. Normalising discards that magnitude, and that function answers `(0, 1, 0)` for a
50
+ * degenerate triangle -- which would let a collapse-to-sliver walk straight past the guard.
51
+ *
52
+ * @param {Float32Array} out
53
+ * @param {number} ax
54
+ * @param {number} ay
55
+ * @param {number} az
56
+ * @param {number} bx
57
+ * @param {number} by
58
+ * @param {number} bz
59
+ * @param {number} cx
60
+ * @param {number} cy
61
+ * @param {number} cz
62
+ */
63
+ function triangle_cross(out, ax, ay, az, bx, by, bz, cx, cy, cz) {
64
+ const ux = bx - ax;
65
+ const uy = by - ay;
66
+ const uz = bz - az;
67
+
68
+ const vx = cx - ax;
69
+ const vy = cy - ay;
70
+ const vz = cz - az;
71
+
72
+ out[0] = uy * vz - uz * vy;
73
+ out[1] = uz * vx - ux * vz;
74
+ out[2] = ux * vy - uy * vx;
75
+ }
76
+
77
+ /**
78
+ * The limit over one endpoint's fan.
79
+ *
80
+ * Faces that also hold `other` are skipped: those are the collapse's own faces and they die with it.
81
+ *
82
+ * @param {BinaryTopology} mesh
83
+ * @param {number} moved the vertex whose position changes
84
+ * @param {number} other the collapse's other endpoint
85
+ * @param {Float32Array|number[]} from
86
+ * @param {number} from_offset
87
+ * @param {Float32Array|number[]} to
88
+ * @param {number} to_offset
89
+ * @returns {number} as {@link bt_edge_collapse_fold_limit}, over this fan alone
90
+ */
91
+ function fan_fold_limit(mesh, moved, other, from, from_offset, to, to_offset) {
92
+ mesh.vertex_read_coordinate(scratch_moved, 0, moved);
93
+
94
+ const face_pool = mesh.faces;
95
+
96
+ let edge = mesh.vertex_read_edge(moved);
97
+
98
+ if (edge === NULL_POINTER) {
99
+ return 1;
100
+ }
101
+
102
+ const start_edge = edge;
103
+
104
+ let limit = 1;
105
+
106
+ do {
107
+ const first_loop = mesh.edge_read_loop(edge);
108
+
109
+ if (first_loop !== NULL_POINTER) {
110
+ let loop = first_loop;
111
+
112
+ do {
113
+ // each face of the fan is reached exactly once, via the loop anchored at `moved`
114
+ if (mesh.loop_read_vertex(loop) === moved) {
115
+ const face = mesh.loop_read_face(loop);
116
+
117
+ if (face !== NULL_POINTER && face_pool.is_allocated(face)) {
118
+ const loop_b = mesh.loop_read_next(loop);
119
+ const loop_c = mesh.loop_read_next(loop_b);
120
+
121
+ // triangles only; a larger polygon has no single normal to compare
122
+ if (mesh.loop_read_next(loop_c) === loop) {
123
+ const b = mesh.loop_read_vertex(loop_b);
124
+ const c = mesh.loop_read_vertex(loop_c);
125
+
126
+ if (b !== other && c !== other) {
127
+ mesh.vertex_read_coordinate(scratch_b, 0, b);
128
+ mesh.vertex_read_coordinate(scratch_c, 0, c);
129
+
130
+ triangle_cross(
131
+ scratch_before,
132
+ scratch_moved[0], scratch_moved[1], scratch_moved[2],
133
+ scratch_b[0], scratch_b[1], scratch_b[2],
134
+ scratch_c[0], scratch_c[1], scratch_c[2]
135
+ );
136
+ triangle_cross(
137
+ scratch_at_from,
138
+ from[from_offset], from[from_offset + 1], from[from_offset + 2],
139
+ scratch_b[0], scratch_b[1], scratch_b[2],
140
+ scratch_c[0], scratch_c[1], scratch_c[2]
141
+ );
142
+ triangle_cross(
143
+ scratch_at_to,
144
+ to[to_offset], to[to_offset + 1], to[to_offset + 2],
145
+ scratch_b[0], scratch_b[1], scratch_b[2],
146
+ scratch_c[0], scratch_c[1], scratch_c[2]
147
+ );
148
+
149
+ const d0 = scratch_before[0] * scratch_at_from[0]
150
+ + scratch_before[1] * scratch_at_from[1]
151
+ + scratch_before[2] * scratch_at_from[2];
152
+
153
+ if (d0 <= 0) {
154
+ // `from` is not a placement at all, so there is no segment left
155
+ // to measure and nothing further to learn from this fan.
156
+ return -1;
157
+ }
158
+
159
+ const d1 = scratch_before[0] * scratch_at_to[0]
160
+ + scratch_before[1] * scratch_at_to[1]
161
+ + scratch_before[2] * scratch_at_to[2];
162
+
163
+ if (d1 <= 0) {
164
+ // Affine in `t` and positive at `0`, so it has exactly one root
165
+ // on the segment and `d0 - d1` cannot vanish.
166
+ const crossing = d0 / (d0 - d1);
167
+
168
+ if (crossing < limit) {
169
+ limit = crossing;
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
176
+
177
+ loop = mesh.loop_read_radial_next(loop);
178
+ } while (loop !== first_loop && loop !== NULL_POINTER);
179
+ }
180
+
181
+ edge = (mesh.edge_read_vertex1(edge) === moved)
182
+ ? mesh.edge_read_v1_disk_next(edge)
183
+ : mesh.edge_read_v2_disk_next(edge);
184
+ } while (edge !== start_edge && edge !== NULL_POINTER);
185
+
186
+ return limit;
187
+ }
188
+
189
+ /**
190
+ * How far from `from` toward `to` may a collapse of `survivor`-`victim` place the surviving vertex
191
+ * and still turn no surviving triangle over?
192
+ *
193
+ * Both fans are walked, because both endpoints move: the victim onto the placement by definition,
194
+ * and the survivor too wherever the caller puts it somewhere other than where it already sits. The
195
+ * union of the two is the set of faces the collapse reshapes, which is what makes the answer
196
+ * symmetric in the two endpoints -- a caller that has not yet settled which of them survives can
197
+ * rely on that.
198
+ *
199
+ * @param {BinaryTopology} mesh
200
+ * @param {number} survivor the endpoint that stays allocated
201
+ * @param {number} victim the endpoint that is removed
202
+ * @param {Float32Array|number[]} from the placement to measure from, at `t = 0`
203
+ * @param {Float32Array|number[]} to the placement wanted, at `t = 1`
204
+ * @param {number} [from_offset]
205
+ * @param {number} [to_offset]
206
+ * @returns {number} where the first surviving triangle reaches **zero** area, so the placements that
207
+ * fold nothing are `t` in `[0, limit)` -- open at the top, since zero area is refused along with
208
+ * a flip, and a caller therefore takes a fraction of this rather than this. `1` when nothing on
209
+ * the segment folds, and `-1` when `from` itself does, which is the one answer no amount of
210
+ * sliding recovers from.
211
+ */
212
+ export function bt_edge_collapse_fold_limit(
213
+ mesh, survivor, victim, from, to, from_offset = 0, to_offset = 0
214
+ ) {
215
+ const on_victim = fan_fold_limit(mesh, victim, survivor, from, from_offset, to, to_offset);
216
+
217
+ if (on_victim < 0) {
218
+ return -1;
219
+ }
220
+
221
+ const on_survivor = fan_fold_limit(mesh, survivor, victim, from, from_offset, to, to_offset);
222
+
223
+ if (on_survivor < 0) {
224
+ return -1;
225
+ }
226
+
227
+ return Math.min(on_victim, on_survivor);
228
+ }
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Triangle-inversion rejection for an edge collapse: would any triangle that survives it come out
3
+ * facing the other way?
4
+ *
5
+ * @author Alex Goldring
6
+ * @copyright Company Named Limited (c) 2026
7
+ */
1
8
  /**
2
9
  * Would collapsing `survivor`-`victim` onto `target` turn any surviving triangle inside out?
3
10
  *
@@ -17,6 +24,12 @@
17
24
  * worse rather than better — a pinned endpoint takes the placement with it, and the surviving
18
25
  * vertex lands on the pin rather than anywhere the geometry chose.
19
26
  *
27
+ * **A `true` here is not a reason to abandon the collapse**, and a caller free to choose the
28
+ * placement should not treat it as one. The set of placements that fold nothing is convex, so a
29
+ * caller holding one placement it likes and one that works can slide between them and find the
30
+ * best point that does — {@link bt_edge_collapse_fold_limit} is that question, this is the same
31
+ * walk asking it at a single point, and this function is a call to that one.
32
+ *
20
33
  * @param {BinaryTopology} mesh
21
34
  * @param {number} survivor the endpoint that stays allocated
22
35
  * @param {number} victim the endpoint that is removed
@@ -1 +1 @@
1
- {"version":3,"file":"bt_edge_collapse_would_fold.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js"],"names":[],"mappings":"AAuIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,4EANW,MAAM,UACN,MAAM,UACN,YAAY,GAAC,MAAM,EAAE,kBACrB,MAAM,GACJ,OAAO,CAKnB"}
1
+ {"version":3,"file":"bt_edge_collapse_would_fold.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,4EANW,MAAM,UACN,MAAM,UACN,YAAY,GAAC,MAAM,EAAE,kBACrB,MAAM,GACJ,OAAO,CAMnB"}
@@ -1,4 +1,4 @@
1
- import { NULL_POINTER } from "../BinaryTopology.js";
1
+ import { bt_edge_collapse_fold_limit } from "./bt_edge_collapse_fold_limit.js";
2
2
 
3
3
  /**
4
4
  * Triangle-inversion rejection for an edge collapse: would any triangle that survives it come out
@@ -8,131 +8,6 @@ import { NULL_POINTER } from "../BinaryTopology.js";
8
8
  * @copyright Company Named Limited (c) 2026
9
9
  */
10
10
 
11
- const scratch_moved = new Float32Array(3);
12
- const scratch_b = new Float32Array(3);
13
- const scratch_c = new Float32Array(3);
14
- const scratch_before = new Float32Array(3);
15
- const scratch_after = new Float32Array(3);
16
-
17
- /**
18
- * Unnormalised triangle normal `(b - a) x (c - a)`, written into `out`.
19
- *
20
- * Deliberately not `v3_compute_triangle_normal`: this needs the raw cross product, because a
21
- * vanishing magnitude is what says the result is a zero-area sliver and the `dot <= 0` test below is
22
- * what rejects it. Normalising discards that magnitude, and that function answers `(0, 1, 0)` for a
23
- * degenerate triangle — which would let a collapse-to-sliver walk straight past the guard.
24
- *
25
- * @param {Float32Array} out
26
- * @param {number} ax
27
- * @param {number} ay
28
- * @param {number} az
29
- * @param {number} bx
30
- * @param {number} by
31
- * @param {number} bz
32
- * @param {number} cx
33
- * @param {number} cy
34
- * @param {number} cz
35
- */
36
- function triangle_cross(out, ax, ay, az, bx, by, bz, cx, cy, cz) {
37
- const ux = bx - ax;
38
- const uy = by - ay;
39
- const uz = bz - az;
40
-
41
- const vx = cx - ax;
42
- const vy = cy - ay;
43
- const vz = cz - az;
44
-
45
- out[0] = uy * vz - uz * vy;
46
- out[1] = uz * vx - ux * vz;
47
- out[2] = ux * vy - uy * vx;
48
- }
49
-
50
- /**
51
- * Does moving `moved` to `target` reverse any triangle in its fan?
52
- *
53
- * Faces that also hold `other` are skipped: those are the collapse's own faces and they die with it.
54
- *
55
- * @param {BinaryTopology} mesh
56
- * @param {number} moved the vertex whose position changes
57
- * @param {number} other the collapse's other endpoint
58
- * @param {Float32Array|number[]} target
59
- * @param {number} target_offset
60
- * @returns {boolean}
61
- */
62
- function fan_would_fold(mesh, moved, other, target, target_offset) {
63
- mesh.vertex_read_coordinate(scratch_moved, 0, moved);
64
-
65
- const face_pool = mesh.faces;
66
-
67
- let edge = mesh.vertex_read_edge(moved);
68
-
69
- if (edge === NULL_POINTER) {
70
- return false;
71
- }
72
-
73
- const start_edge = edge;
74
-
75
- do {
76
- const first_loop = mesh.edge_read_loop(edge);
77
-
78
- if (first_loop !== NULL_POINTER) {
79
- let loop = first_loop;
80
-
81
- do {
82
- // each face of the fan is reached exactly once, via the loop anchored at `moved`
83
- if (mesh.loop_read_vertex(loop) === moved) {
84
- const face = mesh.loop_read_face(loop);
85
-
86
- if (face !== NULL_POINTER && face_pool.is_allocated(face)) {
87
- const loop_b = mesh.loop_read_next(loop);
88
- const loop_c = mesh.loop_read_next(loop_b);
89
-
90
- // triangles only; a larger polygon has no single normal to compare
91
- if (mesh.loop_read_next(loop_c) === loop) {
92
- const b = mesh.loop_read_vertex(loop_b);
93
- const c = mesh.loop_read_vertex(loop_c);
94
-
95
- if (b !== other && c !== other) {
96
- mesh.vertex_read_coordinate(scratch_b, 0, b);
97
- mesh.vertex_read_coordinate(scratch_c, 0, c);
98
-
99
- triangle_cross(
100
- scratch_before,
101
- scratch_moved[0], scratch_moved[1], scratch_moved[2],
102
- scratch_b[0], scratch_b[1], scratch_b[2],
103
- scratch_c[0], scratch_c[1], scratch_c[2]
104
- );
105
- triangle_cross(
106
- scratch_after,
107
- target[target_offset], target[target_offset + 1], target[target_offset + 2],
108
- scratch_b[0], scratch_b[1], scratch_b[2],
109
- scratch_c[0], scratch_c[1], scratch_c[2]
110
- );
111
-
112
- const dot = scratch_before[0] * scratch_after[0]
113
- + scratch_before[1] * scratch_after[1]
114
- + scratch_before[2] * scratch_after[2];
115
-
116
- if (dot <= 0) {
117
- return true;
118
- }
119
- }
120
- }
121
- }
122
- }
123
-
124
- loop = mesh.loop_read_radial_next(loop);
125
- } while (loop !== first_loop && loop !== NULL_POINTER);
126
- }
127
-
128
- edge = (mesh.edge_read_vertex1(edge) === moved)
129
- ? mesh.edge_read_v1_disk_next(edge)
130
- : mesh.edge_read_v2_disk_next(edge);
131
- } while (edge !== start_edge && edge !== NULL_POINTER);
132
-
133
- return false;
134
- }
135
-
136
11
  /**
137
12
  * Would collapsing `survivor`-`victim` onto `target` turn any surviving triangle inside out?
138
13
  *
@@ -152,6 +27,12 @@ function fan_would_fold(mesh, moved, other, target, target_offset) {
152
27
  * worse rather than better — a pinned endpoint takes the placement with it, and the surviving
153
28
  * vertex lands on the pin rather than anywhere the geometry chose.
154
29
  *
30
+ * **A `true` here is not a reason to abandon the collapse**, and a caller free to choose the
31
+ * placement should not treat it as one. The set of placements that fold nothing is convex, so a
32
+ * caller holding one placement it likes and one that works can slide between them and find the
33
+ * best point that does — {@link bt_edge_collapse_fold_limit} is that question, this is the same
34
+ * walk asking it at a single point, and this function is a call to that one.
35
+ *
155
36
  * @param {BinaryTopology} mesh
156
37
  * @param {number} survivor the endpoint that stays allocated
157
38
  * @param {number} victim the endpoint that is removed
@@ -160,6 +41,7 @@ function fan_would_fold(mesh, moved, other, target, target_offset) {
160
41
  * @returns {boolean}
161
42
  */
162
43
  export function bt_edge_collapse_would_fold(mesh, survivor, victim, target, target_offset = 0) {
163
- return fan_would_fold(mesh, victim, survivor, target, target_offset)
164
- || fan_would_fold(mesh, survivor, victim, target, target_offset);
44
+ return bt_edge_collapse_fold_limit(
45
+ mesh, survivor, victim, target, target, target_offset, target_offset
46
+ ) < 0;
165
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bt_mesh_build_face_bvh.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,6EAwDC"}
1
+ {"version":3,"file":"bt_mesh_build_face_bvh.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,6EAkEC"}
@@ -15,12 +15,22 @@ export function bt_mesh_build_face_bvh(bvh, mesh) {
15
15
  // clear out the BVH
16
16
  bvh.release_all();
17
17
 
18
- // NOTE: we assume there are no holes in the allocation, data must be packed
19
18
  const face_count = mesh.faces.size;
20
19
 
21
20
  const vertex_position = new Float32Array(3);
22
21
 
23
22
  for (let face_id = 0; face_id < face_count; face_id++) {
23
+ /**
24
+ * The face pool can have holes: `bt_face_kill` leaves the slot unallocated with its loop
25
+ * pointer at NULL_POINTER, and reading a loop at that address is off the end of the
26
+ * DataView. The navmesh pipeline compacts only inside three conditional branches, so "the
27
+ * caller hands us a packed mesh" was a precondition no caller could honour. The sibling
28
+ * builder, `bt_mesh_build_surface_triangle_bvh`, skips them the same way.
29
+ */
30
+ if (!mesh.faces.is_allocated(face_id)) {
31
+ continue;
32
+ }
33
+
24
34
  let bounds_x0 = Infinity;
25
35
  let bounds_y0 = Infinity;
26
36
  let bounds_z0 = Infinity;
@@ -62,12 +62,12 @@ export function mn_graph_collapse_weighted_edge(
62
62
  heap.delete(b_edge);
63
63
  }
64
64
 
65
- const heap_index = heap.data.indexOf(target_edge);
66
-
67
- if (heap_index !== -1) {
68
- // updated edge is in the heap, re-score
69
- heap.bubbleDown(heap_index);
70
- }
65
+ // The merge above raises the survivor's weight, and the heap is keyed on `-weight`, so the
66
+ // survivor's score *falls* and it has to move up. `bubbleDown` alone, which is what this
67
+ // used to do, is a no-op for an element that has sunk below its parent — the heaviest edge
68
+ // then sits stranded under a lighter one and the coarsener stops collapsing in weight
69
+ // order. `updateElementScore` goes both ways, and does not need the heap's private `data`.
70
+ heap.updateElementScore(target_edge);
71
71
 
72
72
  }
73
73
 
@@ -1 +1 @@
1
- {"version":3,"file":"ParameterLookupTable.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/lookup/ParameterLookupTable.js"],"names":[],"mappings":"AAWA;IAibI;;;;;OAKG;IACH,sBAJW,MAAM,UACN,MAAM,EAAE,cACR,MAAM,EAAE,wBAQlB;IAED;;;;OAIG;IACH,8CAFa,oBAAoB,CA0BhC;IA5bD;;;;OAIG;IACH,uBAHW,MAAM,EAYhB;IA5CD;;;OAGG;IACH,MAFU,MAAM,EAAE,GAAC,YAAY,CAErB;IAEV;;;OAGG;IACH,WAFU,MAAM,EAAE,GAAC,YAAY,CAEhB;IAEf;;;OAGG;IACH,UAFU,MAAM,CAEH;IAEb;;;OAGG;IACH,UAFU,MAAM,CAEH;IAEb;;;OAGG;IACH,cAA4C;IAUxC;;;OAGG;IACH,UAFU,MAAM,CAEQ;IAI5B;;;OAGG;IACH,WAFW,yBAAyB,QAInC;IAED;;;OAGG;IACH,aAFW,yBAAyB,GAAC,MAAM,QAI1C;IAED;;;;OAIG;IACH,WAHW,yBAAyB,GACvB,OAAO,CAInB;IAED,yBAEC;IAED,0BAGC;IAED;;;;MAMC;IAED;;;;OAIG;IACH,2CA2CC;IAED;;;OAGG;IACH,6CAkCC;IAED;;;;OAIG;IACH,iBAHW,MAAM,UACN,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,QA0D5C;IAED,gCAUC;IAED;;;;OAIG;IACH,cAHW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,GAAC,UAAU,cAC7C,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,QA4B5C;IAED;;;;OAIG;IACH,mBAHW,MAAM,SACN,MAAM,EAAE,QAqClB;IAED;;OAEG;IACH,0BAkBC;IAED,eAgBC;IAED;;;;OAIG;IACH,cAHW,oBAAoB,GAClB,OAAO,CAenB;IAED,oBAwCC;IAgDL;;;OAGG;IACH,iCAFU,OAAO,CAEoC;CANpD;0CAheyC,gCAAgC"}
1
+ {"version":3,"file":"ParameterLookupTable.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/lookup/ParameterLookupTable.js"],"names":[],"mappings":"AAWA;IAsbI;;;;;OAKG;IACH,sBAJW,MAAM,UACN,MAAM,EAAE,cACR,MAAM,EAAE,wBAQlB;IAED;;;;OAIG;IACH,8CAFa,oBAAoB,CA0BhC;IAjcD;;;;OAIG;IACH,uBAHW,MAAM,EAYhB;IA5CD;;;OAGG;IACH,MAFU,MAAM,EAAE,GAAC,YAAY,CAErB;IAEV;;;OAGG;IACH,WAFU,MAAM,EAAE,GAAC,YAAY,CAEhB;IAEf;;;OAGG;IACH,UAFU,MAAM,CAEH;IAEb;;;OAGG;IACH,UAFU,MAAM,CAEH;IAEb;;;OAGG;IACH,cAA4C;IAUxC;;;OAGG;IACH,UAFU,MAAM,CAEQ;IAI5B;;;OAGG;IACH,WAFW,yBAAyB,QAInC;IAED;;;OAGG;IACH,aAFW,yBAAyB,GAAC,MAAM,QAI1C;IAED;;;;OAIG;IACH,WAHW,yBAAyB,GACvB,OAAO,CAInB;IAED,yBAEC;IAED,0BAGC;IAED;;;;MAMC;IAED;;;;OAIG;IACH,2CAgDC;IAED;;;OAGG;IACH,6CAkCC;IAED;;;;OAIG;IACH,iBAHW,MAAM,UACN,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,QA0D5C;IAED,gCAUC;IAED;;;;OAIG;IACH,cAHW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,GAAC,UAAU,cAC7C,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,QA4B5C;IAED;;;;OAIG;IACH,mBAHW,MAAM,SACN,MAAM,EAAE,QAqClB;IAED;;OAEG;IACH,0BAkBC;IAED,eAgBC;IAED;;;;OAIG;IACH,cAHW,oBAAoB,GAClB,OAAO,CAenB;IAED,oBAwCC;IAgDL;;;OAGG;IACH,iCAFU,OAAO,CAEoC;CANpD;0CAreyC,gCAAgC"}
@@ -107,15 +107,20 @@ export class ParameterLookupTable {
107
107
  toBinaryBuffer(buffer) {
108
108
  const itemCount = this.positions.length;
109
109
 
110
- const itemCountBitSize = Math.log2(itemCount);
111
-
112
110
  let itemCountByteSize;
113
111
 
114
- if (itemCountBitSize <= 8) {
112
+ /**
113
+ * Sized from the value and not from `Math.log2(itemCount)`: the bits needed to hold `n` are
114
+ * `ceil(log2(n + 1))`, so a log2 test is off by exactly one representable value at each
115
+ * boundary. 256 read as "8 bits, fits a byte" and `setUint8` then wrote `256 % 256 === 0`,
116
+ * which left the reader allocating nothing and stopping the cursor an entire payload short
117
+ * of where the writer left it.
118
+ */
119
+ if (itemCount < 256) {
115
120
  itemCountByteSize = 1;
116
- } else if (itemCountBitSize <= 16) {
121
+ } else if (itemCount < 65536) {
117
122
  itemCountByteSize = 2;
118
- } else if (itemCountBitSize <= 32) {
123
+ } else if (itemCount < 4294967296) {
119
124
  itemCountByteSize = 4;
120
125
  } else {
121
126
  throw new Error(`Item count is too high`);
@@ -1 +1 @@
1
- {"version":3,"file":"sdnoise.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/noise/sdnoise.js"],"names":[],"mappings":"AA6LA;;;;;;;GAOG;AACH,sCAHW,MAAM,EAAE,KADR,MAAM,GAEJ,MAAM,CAmDlB;AAUD;;;;;;;;GAQG;AACH,sCAHW,MAAM,EAAE,KAFR,MAAM,KACN,MAAM,GAEJ,MAAM,CAkIlB;AAUD;;;;;;;;;GASG;AACH,sCAHW,MAAM,EAAE,KAHR,MAAM,KACN,MAAM,KACN,MAAM,GAEJ,MAAM,CA+OlB;AAMD;;;;;;;;;;GAUG;AACH,sCAPW,MAAM,EAAE,KACR,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,GACJ,MAAM,CA+RlB"}
1
+ {"version":3,"file":"sdnoise.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/noise/sdnoise.js"],"names":[],"mappings":"AA6LA;;;;;;;GAOG;AACH,sCAHW,MAAM,EAAE,KADR,MAAM,GAEJ,MAAM,CAsDlB;AAUD;;;;;;;;GAQG;AACH,sCAHW,MAAM,EAAE,KAFR,MAAM,KACN,MAAM,GAEJ,MAAM,CAmIlB;AAUD;;;;;;;;;GASG;AACH,sCAHW,MAAM,EAAE,KAHR,MAAM,KACN,MAAM,KACN,MAAM,GAEJ,MAAM,CAgPlB;AAMD;;;;;;;;;;GAUG;AACH,sCAPW,MAAM,EAAE,KACR,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,GACJ,MAAM,CAgSlB"}
@@ -196,7 +196,10 @@ function grad4(result, hash) {
196
196
  * @returns {number}
197
197
  */
198
198
  export function sdnoise1(derivatives, x) {
199
- const i0 = x | 0;
199
+ //Math.floor, not `| 0`: `| 0` truncates toward zero, which names the cell above a negative
200
+ //point rather than the one containing it, and tears the field along every negative cell boundary.
201
+ //Gustavson's reference uses FASTFLOOR here for exactly this reason.
202
+ const i0 = Math.floor(x);
200
203
  const i1 = i0 + 1;
201
204
 
202
205
  const x0 = x - i0;
@@ -275,8 +278,9 @@ export function sdnoise2(derivatives, x, y) {
275
278
  const xs = x + s;
276
279
  const ys = y + s;
277
280
 
278
- let ii, i = xs | 0;
279
- let jj, j = ys | 0;
281
+ //see sdnoise1 on why this is Math.floor and not `| 0`
282
+ let ii, i = Math.floor(xs);
283
+ let jj, j = Math.floor(ys);
280
284
 
281
285
  const t = (i + j) * G2;
282
286
  const X0 = i - t; /* Unskew the cell origin back to (x,y) space */
@@ -426,9 +430,10 @@ export function sdnoise3(derivatives, x, y, z) {
426
430
  const ys = y + s;
427
431
  const zs = z + s;
428
432
 
429
- const i = xs | 0;
430
- const j = ys | 0;
431
- const k = zs | 0;
433
+ //see sdnoise1 on why this is Math.floor and not `| 0`
434
+ const i = Math.floor(xs);
435
+ const j = Math.floor(ys);
436
+ const k = Math.floor(zs);
432
437
 
433
438
  const t = (i + j + k) * G3;
434
439
 
@@ -683,10 +688,11 @@ export function sdnoise4(derivatives, x, y, z, w) {
683
688
  const zs = z + s;
684
689
  const ws = w + s;
685
690
 
686
- let ii, i = xs | 0;
687
- let jj, j = ys | 0;
688
- let kk, k = zs | 0;
689
- let ll, l = ws | 0;
691
+ //see sdnoise1 on why this is Math.floor and not `| 0`
692
+ let ii, i = Math.floor(xs);
693
+ let jj, j = Math.floor(ys);
694
+ let kk, k = Math.floor(zs);
695
+ let ll, l = Math.floor(ws);
690
696
 
691
697
  const t = (i + j + k + l) * G4; // Factor for 4D unskewing
692
698
  const X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
@@ -1 +1 @@
1
- {"version":3,"file":"ImmutableObjectPool.d.ts","sourceRoot":"","sources":["../../../../../src/core/model/object/ImmutableObjectPool.js"],"names":[],"mappings":"AAIA;;GAEG;AACH;IA+BI;;;OAaC;IA3CD;;;OAGG;IACH,wBAAwB;IACxB;;;OAGG;IACH,MAFU,QAAQ,GAAG,EAAE,aAAa,GAAG,EAAC,KAAK,CAAC,EAAE,CAAC,CAE5B;IAErB;;;;OAIG;IACH,gBAAe;IACf;;;;OAIG;IACH,eAAc;IAEd;;;OAGG;IACH,MAFU,MAAM,CAEP;IAIL;;;OAGG;IACH,UAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,gBAFU,MAAM,CAEoB;IAGxC,qBAuBC;IAED;;;;;OAKG;IACH,yBAUC;IAED;;;OAGG;IACH,cAIC;IAED;;;;OAIG;IACH,wBAkBC;IAED,mCA2CC;CACJ;wBA9KuB,iCAAiC;6BAD5B,6BAA6B"}
1
+ {"version":3,"file":"ImmutableObjectPool.d.ts","sourceRoot":"","sources":["../../../../../src/core/model/object/ImmutableObjectPool.js"],"names":[],"mappings":"AAIA;;GAEG;AACH;IA+BI;;;OAaC;IA3CD;;;OAGG;IACH,wBAAwB;IACxB;;;OAGG;IACH,MAFU,QAAQ,GAAG,EAAE,aAAa,GAAG,EAAC,KAAK,CAAC,EAAE,CAAC,CAE5B;IAErB;;;;OAIG;IACH,gBAAe;IACf;;;;OAIG;IACH,eAAc;IAEd;;;OAGG;IACH,MAFU,MAAM,CAEP;IAIL;;;OAGG;IACH,UAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,gBAFU,MAAM,CAEoB;IAGxC,qBAuBC;IAED;;;;;OAKG;IACH,yBAUC;IAED;;;OAGG;IACH,cAIC;IAED;;;;OAIG;IACH,wBAkBC;IAED,mCAqDC;CACJ;wBAxLuB,iCAAiC;6BAD5B,6BAA6B"}
@@ -131,14 +131,9 @@ export class ImmutableObjectPool {
131
131
 
132
132
  add(key, value) {
133
133
 
134
- let elements = this.data.get(key);
135
-
136
- if (elements === undefined) {
137
- // no elements for this key, create container
138
- elements = [];
139
- this.data.set(key, elements);
134
+ const existing_elements = this.data.get(key);
140
135
 
141
- } else if (elements.length >= this.perKeyCapacity) {
136
+ if (existing_elements !== undefined && existing_elements.length >= this.perKeyCapacity) {
142
137
  // reached capacity for this key, discard element
143
138
  return false;
144
139
  }
@@ -149,6 +144,21 @@ export class ImmutableObjectPool {
149
144
  this.__removeElement(this.__first);
150
145
  }
151
146
 
147
+ /**
148
+ * Resolved after the eviction, never before. When the victim is the last element under this
149
+ * same key, `__removeElement` deletes the bucket out of the map — a reference taken before
150
+ * that points at an array nothing can reach any more, and the element pushed into it is
151
+ * counted in `size` and linked into the eviction list but invisible to `get`, which then
152
+ * makes `clear` throw when it walks the list onto it.
153
+ */
154
+ let elements = this.data.get(key);
155
+
156
+ if (elements === undefined) {
157
+ // no elements for this key, create container
158
+ elements = [];
159
+ this.data.set(key, elements);
160
+ }
161
+
152
162
  const cache_element = new CacheElement();
153
163
 
154
164
  cache_element.value = value;
@@ -85,11 +85,7 @@ declare class ConcurrentExecutor {
85
85
  * @returns {boolean}
86
86
  */
87
87
  contains(task: Task): boolean;
88
- /**
89
- * kicks the scheduler into action, this is an internal method and should not be called from outside
90
- * @private
91
- */
92
- private prod;
88
+ prod(): void;
93
89
  join(callback: any): void;
94
90
  #private;
95
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ConcurrentExecutor.d.ts","sourceRoot":"","sources":["../../../../../src/core/process/executor/ConcurrentExecutor.js"],"names":[],"mappings":";mBAQa,OAAO,iBAAiB,EAAE,IAAI;wBAC9B,OAAO,sBAAsB,EAAE,OAAO;AAYnD;;GAEG;AACH;IAaI;;;;;OAKG;IACH,wBAJW,MAAM,aACN,MAAM,EAwChB;IApCG;;;OAGG;IACH,WAFU,MAAM,CAEU;IAC1B;;;OAGG;IACH,UAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,iBAFU,IAAI,EAAE,CAES;IAEzB;;;OAGG;IACH,YAFU,IAAI,EAAE,CAEI;IAEpB;;;;MAIC;IAED,cAAiB;IAEjB;;;OAGG;IACH,QAFU,MAAM,GAAC,gBAAgB,CAES;IAG9C;;;OAGG;IACH,oBAFW,SAAS,QAqEnB;IAED;;;OAGG;IACH,mBAFW,SAAS,QAenB;IAED;;;;OAIG;IACH,iBAHW,IAAI,GACH,OAAO,CAwBlB;IAED;;;OAGG;IACH,UAFW,IAAI,QAKd;IAED;;;OAGG;IACH,eAFW,IAAI,EAAE,QAMhB;IAED;;;;OAIG;IACH,kBAkCC;IAED;;OAEG;IACH,qBAyCC;IAED;;;;OAIG;IACH,eAHW,IAAI,GACF,OAAO,CAYnB;IAwLD;;;OAGG;IACH,aAQC;IAED,0BAMC;;CACJ;;;;mBAhhBkB,+BAA+B;wBAohBxC,MAAM"}
1
+ {"version":3,"file":"ConcurrentExecutor.d.ts","sourceRoot":"","sources":["../../../../../src/core/process/executor/ConcurrentExecutor.js"],"names":[],"mappings":";mBASa,OAAO,iBAAiB,EAAE,IAAI;wBAC9B,OAAO,sBAAsB,EAAE,OAAO;AAYnD;;GAEG;AACH;IAaI;;;;;OAKG;IACH,wBAJW,MAAM,aACN,MAAM,EAwChB;IApCG;;;OAGG;IACH,WAFU,MAAM,CAEU;IAC1B;;;OAGG;IACH,UAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,iBAFU,IAAI,EAAE,CAES;IAEzB;;;OAGG;IACH,YAFU,IAAI,EAAE,CAEI;IAEpB;;;;MAIC;IAED,cAAiB;IAEjB;;;OAGG;IACH,QAFU,MAAM,GAAC,gBAAgB,CAES;IAG9C;;;OAGG;IACH,oBAFW,SAAS,QAqEnB;IAED;;;OAGG;IACH,mBAFW,SAAS,QAenB;IAED;;;;OAIG;IACH,iBAHW,IAAI,GACH,OAAO,CAwBlB;IAED;;;OAGG;IACH,UAFW,IAAI,QAKd;IAED;;;OAGG;IACH,eAFW,IAAI,EAAE,QAMhB;IAED;;;;OAIG;IACH,kBAkCC;IAED;;OAEG;IACH,qBAgDC;IAED;;;;OAIG;IACH,eAHW,IAAI,GACF,OAAO,CAYnB;IA8QD,aAYC;IAED,0BAMC;;CACJ;;;;mBA9mBkB,+BAA+B;wBAknBxC,MAAM"}