@woosh/meep-engine 3.64.0 → 3.65.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 (370) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/build/bundle-worker-image-decoder.js +1 -1
  3. package/build/bundle-worker-terrain.js +1 -1
  4. package/package.json +1 -1
  5. package/src/core/binary/BinaryBuffer.d.ts +5 -0
  6. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  7. package/src/core/binary/BinaryBuffer.js +39 -5
  8. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts +65 -6
  9. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts.map +1 -1
  10. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.js +451 -101
  11. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +4 -2
  12. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -1
  13. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +4 -2
  14. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts +8 -1
  15. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts.map +1 -1
  16. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +45 -10
  17. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
  18. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +237 -119
  19. package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts +143 -0
  20. package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts.map +1 -0
  21. package/src/engine/graphics/ecs/grass/GrassSpecies.js +189 -0
  22. package/src/engine/graphics/ecs/grass/GrassSurface.d.ts +25 -0
  23. package/src/engine/graphics/ecs/grass/GrassSurface.d.ts.map +1 -0
  24. package/src/engine/graphics/ecs/grass/GrassSurface.js +32 -0
  25. package/src/engine/graphics/ecs/grass/GroundCover.d.ts +68 -0
  26. package/src/engine/graphics/ecs/grass/GroundCover.d.ts.map +1 -0
  27. package/src/engine/graphics/ecs/grass/GroundCover.js +85 -0
  28. package/src/engine/graphics/texture/sampler/exr_to_sampler2d.d.ts +27 -0
  29. package/src/engine/graphics/texture/sampler/exr_to_sampler2d.d.ts.map +1 -0
  30. package/src/engine/graphics/texture/sampler/exr_to_sampler2d.js +91 -0
  31. package/src/engine/graphics/texture/sampler/sampler2d_to_exr.d.ts +23 -0
  32. package/src/engine/graphics/texture/sampler/sampler2d_to_exr.d.ts.map +1 -0
  33. package/src/engine/graphics/texture/sampler/sampler2d_to_exr.js +64 -0
  34. package/src/engine/graphics3/GrassSurfaceSystem.d.ts +153 -0
  35. package/src/engine/graphics3/GrassSurfaceSystem.d.ts.map +1 -0
  36. package/src/engine/graphics3/GrassSurfaceSystem.js +1076 -0
  37. package/src/engine/graphics3/GroundCoverSystem.d.ts +33 -0
  38. package/src/engine/graphics3/GroundCoverSystem.d.ts.map +1 -0
  39. package/src/engine/graphics3/GroundCoverSystem.js +58 -0
  40. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  41. package/src/engine/network/NetworkSession.js +372 -110
  42. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  43. package/src/engine/network/orchestrator/NetworkPeer.js +6 -1
  44. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  45. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +9 -2
  46. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  47. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +325 -140
  48. package/src/engine/network/sim/SimActionExecutor.d.ts +4 -1
  49. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  50. package/src/engine/network/sim/SimActionExecutor.js +65 -9
  51. package/src/engine/network/state/PredictionHistory.d.ts.map +1 -1
  52. package/src/engine/network/state/PredictionHistory.js +6 -1
  53. package/src/engine/network/time/AdaptiveRenderDelay.d.ts +25 -14
  54. package/src/engine/network/time/AdaptiveRenderDelay.d.ts.map +1 -1
  55. package/src/engine/network/time/AdaptiveRenderDelay.js +38 -20
  56. package/src/engine/network/time/RenderPlayout.d.ts +23 -3
  57. package/src/engine/network/time/RenderPlayout.d.ts.map +1 -1
  58. package/src/engine/network/time/RenderPlayout.js +40 -4
  59. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  60. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts +5 -1
  61. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts.map +1 -1
  62. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.js +27 -1
  63. package/src/format/image/exr/ExrCompression.d.ts +22 -0
  64. package/src/format/image/exr/ExrCompression.d.ts.map +1 -0
  65. package/src/format/image/exr/ExrCompression.js +27 -0
  66. package/src/format/image/exr/ExrImage.d.ts +32 -0
  67. package/src/format/image/exr/ExrImage.d.ts.map +1 -0
  68. package/src/format/image/exr/ExrImage.js +32 -0
  69. package/src/format/image/exr/ExrPixelType.d.ts +13 -0
  70. package/src/format/image/exr/ExrPixelType.d.ts.map +1 -0
  71. package/src/format/image/exr/ExrPixelType.js +18 -0
  72. package/src/format/image/exr/exr_compare_names.d.ts +16 -0
  73. package/src/format/image/exr/exr_compare_names.d.ts.map +1 -0
  74. package/src/format/image/exr/exr_compare_names.js +25 -0
  75. package/src/format/image/exr/exr_constants.d.ts +49 -0
  76. package/src/format/image/exr/exr_constants.d.ts.map +1 -0
  77. package/src/format/image/exr/exr_constants.js +56 -0
  78. package/src/format/image/exr/exr_read.d.ts +32 -0
  79. package/src/format/image/exr/exr_read.d.ts.map +1 -0
  80. package/src/format/image/exr/exr_read.js +531 -0
  81. package/src/format/image/exr/exr_sample_bits.d.ts +16 -0
  82. package/src/format/image/exr/exr_sample_bits.d.ts.map +1 -0
  83. package/src/format/image/exr/exr_sample_bits.js +21 -0
  84. package/src/format/image/exr/exr_scanlines_per_chunk.d.ts +17 -0
  85. package/src/format/image/exr/exr_scanlines_per_chunk.d.ts.map +1 -0
  86. package/src/format/image/exr/exr_scanlines_per_chunk.js +31 -0
  87. package/src/format/image/exr/exr_write.d.ts +27 -0
  88. package/src/format/image/exr/exr_write.d.ts.map +1 -0
  89. package/src/format/image/exr/exr_write.js +378 -0
  90. package/src/shade/device/shader/ShaderModuleCompiler.d.ts +2 -0
  91. package/src/shade/device/shader/ShaderModuleCompiler.d.ts.map +1 -1
  92. package/src/shade/device/shader/ShaderModuleCompiler.js +25 -2
  93. package/src/shade/playground/grass_surfaces/index.html +75 -0
  94. package/src/shade/playground/grass_surfaces/main.d.ts +2 -0
  95. package/src/shade/playground/grass_surfaces/main.d.ts.map +1 -0
  96. package/src/shade/playground/grass_surfaces/main.js +593 -0
  97. package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts +62 -0
  98. package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts.map +1 -0
  99. package/src/shade/playground/grass_surfaces/read_grass_surfaces.js +188 -0
  100. package/src/shade/playground/probe_clipmap/index.html +5 -0
  101. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  102. package/src/shade/playground/probe_clipmap/main.js +34 -1
  103. package/src/shade/playground/probe_clipmap_box/README.md +5 -1
  104. package/src/shade/playground/probe_clipmap_box/index.html +12 -0
  105. package/src/shade/playground/probe_clipmap_box/main.d.ts.map +1 -1
  106. package/src/shade/playground/probe_clipmap_box/main.js +15 -0
  107. package/src/shade/playground/probe_clipmap_box/scene.d.ts +8 -1
  108. package/src/shade/playground/probe_clipmap_box/scene.d.ts.map +1 -1
  109. package/src/shade/playground/probe_clipmap_box/scene.js +74 -6
  110. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  111. package/src/shade/renderer/Renderer.js +47 -43
  112. package/src/shade/renderer/extension/ViewTextures.d.ts +12 -5
  113. package/src/shade/renderer/extension/ViewTextures.d.ts.map +1 -1
  114. package/src/shade/renderer/extension/ViewTextures.js +19 -5
  115. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +3 -1
  116. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts.map +1 -1
  117. package/src/shade/renderer/fluid/GPUFluidCascadeStack.js +6 -1
  118. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +7 -0
  119. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts.map +1 -1
  120. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.js +10 -0
  121. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +7 -1
  122. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  123. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +46 -15
  124. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts +3 -2
  125. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.js +3 -2
  127. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts +22 -0
  128. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts.map +1 -0
  129. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.js +247 -0
  130. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +50 -0
  131. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  132. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +101 -0
  133. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +2 -1
  134. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
  135. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +2 -1
  136. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +8 -0
  137. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
  138. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +12 -0
  139. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +12 -6
  140. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -1
  141. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +35 -29
  142. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.d.ts.map +1 -1
  143. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.js +4 -2
  144. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts.map +1 -1
  145. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.js +6 -4
  146. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts.map +1 -1
  147. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.js +2 -1
  148. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts +6 -5
  149. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts.map +1 -1
  150. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.js +15 -14
  151. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts.map +1 -1
  152. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.js +4 -2
  153. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +19 -2
  154. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  155. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +128 -10
  156. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +19 -13
  157. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  158. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +27 -15
  159. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts +19 -11
  160. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts.map +1 -1
  161. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.js +35 -11
  162. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +3 -3
  163. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  164. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +18 -14
  165. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts +40 -0
  166. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts.map +1 -0
  167. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.js +174 -0
  168. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts +4 -4
  169. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.js +10 -10
  170. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts +31 -0
  171. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts.map +1 -0
  172. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.js +54 -0
  173. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +8 -4
  174. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
  175. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +10 -21
  176. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +7 -2
  177. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -1
  178. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +33 -29
  179. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts +28 -0
  180. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts.map +1 -0
  181. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.js +138 -0
  182. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +7 -3
  183. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
  184. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +28 -17
  185. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +13 -9
  186. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts.map +1 -1
  187. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +18 -11
  188. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +1 -1
  189. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts +18 -18
  190. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts.map +1 -1
  191. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.js +44 -48
  192. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.d.ts.map +1 -1
  193. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.js +4 -2
  194. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts.map +1 -1
  195. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +2 -3
  196. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts +5 -3
  197. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts.map +1 -1
  198. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.js +15 -30
  199. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -1
  200. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  201. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +4 -2
  202. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts +11 -0
  203. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
  204. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +29 -2
  205. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts +40 -0
  206. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts.map +1 -0
  207. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.js +126 -0
  208. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts +36 -0
  209. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts.map +1 -0
  210. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.js +221 -0
  211. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts +40 -0
  212. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts.map +1 -0
  213. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.js +86 -0
  214. package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts +135 -0
  215. package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts.map +1 -0
  216. package/src/shade/renderer/grass/blade/GPUGrassBlades.js +676 -0
  217. package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts +145 -0
  218. package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts.map +1 -0
  219. package/src/shade/renderer/grass/blade/GRASS_BLADE.js +179 -0
  220. package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts +63 -0
  221. package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts.map +1 -0
  222. package/src/shade/renderer/grass/blade/chunk_grass_blade.js +244 -0
  223. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts +58 -0
  224. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts.map +1 -0
  225. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.js +174 -0
  226. package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts +25 -0
  227. package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts.map +1 -0
  228. package/src/shade/renderer/grass/blade/grass_blade_id_draw.js +133 -0
  229. package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts +80 -0
  230. package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts.map +1 -0
  231. package/src/shade/renderer/grass/blade/grass_blade_mechanics.js +92 -0
  232. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts +29 -0
  233. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts.map +1 -0
  234. package/src/shade/renderer/grass/blade/grass_blade_resolve.js +175 -0
  235. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts +14 -0
  236. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts.map +1 -0
  237. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.js +45 -0
  238. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts +61 -0
  239. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts.map +1 -0
  240. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.js +340 -0
  241. package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts +46 -0
  242. package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts.map +1 -0
  243. package/src/shade/renderer/grass/blade/shader_grass_cell_count.js +280 -0
  244. package/src/shade/renderer/grass/population/chunk_grass_population.d.ts +60 -0
  245. package/src/shade/renderer/grass/population/chunk_grass_population.d.ts.map +1 -0
  246. package/src/shade/renderer/grass/population/chunk_grass_population.js +171 -0
  247. package/src/shade/renderer/grass/press/GPUGrassPress.d.ts +99 -0
  248. package/src/shade/renderer/grass/press/GPUGrassPress.d.ts.map +1 -0
  249. package/src/shade/renderer/grass/press/GPUGrassPress.js +436 -0
  250. package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts +179 -0
  251. package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts.map +1 -0
  252. package/src/shade/renderer/grass/press/GRASS_PRESS.js +217 -0
  253. package/src/shade/renderer/grass/press/chunk_grass_press.d.ts +65 -0
  254. package/src/shade/renderer/grass/press/chunk_grass_press.d.ts.map +1 -0
  255. package/src/shade/renderer/grass/press/chunk_grass_press.js +296 -0
  256. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts +31 -0
  257. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts.map +1 -0
  258. package/src/shade/renderer/grass/press/shader_grass_press_mark.js +169 -0
  259. package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts +27 -0
  260. package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts.map +1 -0
  261. package/src/shade/renderer/grass/press/shader_grass_press_stamp.js +183 -0
  262. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts +193 -0
  263. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts.map +1 -0
  264. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.js +1253 -0
  265. package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts +211 -0
  266. package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts.map +1 -0
  267. package/src/shade/renderer/grass/surface/GRASS_SURFACE.js +241 -0
  268. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts +82 -0
  269. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts.map +1 -0
  270. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.js +111 -0
  271. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts +39 -0
  272. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts.map +1 -0
  273. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.js +85 -0
  274. package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts +29 -0
  275. package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts.map +1 -0
  276. package/src/shade/renderer/grass/surface/chunk_grass_directory.js +112 -0
  277. package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts +27 -0
  278. package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts.map +1 -0
  279. package/src/shade/renderer/grass/surface/chunk_grass_slot.js +50 -0
  280. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts +21 -0
  281. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts.map +1 -0
  282. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.js +41 -0
  283. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts +32 -0
  284. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts.map +1 -0
  285. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.js +136 -0
  286. package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts +37 -0
  287. package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts.map +1 -0
  288. package/src/shade/renderer/grass/surface/chunk_grass_surfel.js +85 -0
  289. package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts +25 -0
  290. package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts.map +1 -0
  291. package/src/shade/renderer/grass/surface/chunk_grass_tile.js +52 -0
  292. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts +23 -0
  293. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts.map +1 -0
  294. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.js +87 -0
  295. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts +43 -0
  296. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts.map +1 -0
  297. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.js +265 -0
  298. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts +13 -0
  299. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts.map +1 -0
  300. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.js +49 -0
  301. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts +62 -0
  302. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts.map +1 -0
  303. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.js +162 -0
  304. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts +40 -0
  305. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts.map +1 -0
  306. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.js +155 -0
  307. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts +19 -0
  308. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts.map +1 -0
  309. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.js +58 -0
  310. package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts +30 -0
  311. package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts.map +1 -0
  312. package/src/shade/renderer/grass/surface/shader_grass_surface_want.js +251 -0
  313. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts +21 -0
  314. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts.map +1 -0
  315. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.js +75 -0
  316. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
  317. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +4 -23
  318. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts +12 -0
  319. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts.map +1 -0
  320. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.js +29 -0
  321. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  322. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +22 -0
  323. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  324. package/src/shade/renderer/scene/GPUSceneContext.js +3 -0
  325. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts +27 -0
  326. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts.map +1 -0
  327. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.js +38 -0
  328. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts +28 -0
  329. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts.map +1 -0
  330. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.js +58 -0
  331. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
  332. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +8 -0
  333. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts +8 -0
  334. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts.map +1 -1
  335. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.js +21 -3
  336. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts +37 -0
  337. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts.map +1 -0
  338. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.js +148 -0
  339. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts +20 -0
  340. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts.map +1 -0
  341. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.js +169 -0
  342. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts +18 -0
  343. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts.map +1 -1
  344. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.js +28 -0
  345. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts +13 -0
  346. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts.map +1 -0
  347. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.js +22 -0
  348. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  349. package/src/shade/renderer/water/GPUWaterRenderer.js +4 -0
  350. package/src/shade/renderer/wind/GPUSceneWind.d.ts +52 -5
  351. package/src/shade/renderer/wind/GPUSceneWind.d.ts.map +1 -1
  352. package/src/shade/renderer/wind/GPUSceneWind.js +164 -8
  353. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts +3 -1
  354. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts.map +1 -1
  355. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.js +3 -1
  356. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts +2 -1
  357. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts.map +1 -1
  358. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.js +18 -13
  359. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts +13 -0
  360. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts.map +1 -0
  361. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.js +23 -0
  362. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts +1 -0
  363. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts.map +1 -1
  364. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.js +6 -1
  365. package/src/shade/renderer/wind/wind_field_add_resources.d.ts +11 -0
  366. package/src/shade/renderer/wind/wind_field_add_resources.d.ts.map +1 -1
  367. package/src/shade/renderer/wind/wind_field_add_resources.js +15 -0
  368. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +1 -1
  369. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  370. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +2 -0
@@ -1,3 +1,6 @@
1
+ import { NULL_POINTER } from "../BinaryTopology.js";
2
+ import { bt_edge_get } from "../query/bt_edge_get.js";
3
+ import { bt_edge_create } from "./edge/bt_edge_create.js";
1
4
  import { bt_face_poke } from "./face/bt_face_poke.js";
2
5
  import { bt_radial_loop_add } from "./bt_radial_loop_add.js";
3
6
 
@@ -11,9 +14,6 @@ import { bt_radial_loop_add } from "./bt_radial_loop_add.js";
11
14
  * PRECONDITION: `cycle` is a single closed loop in which every vertex has exactly two incident edges. That
12
15
  * is what the boundary-extraction pass produces; a figure-of-eight or an open chain would walk off.
13
16
  *
14
- * Shared by {@link bt_mesh_close_boundary_holes} and {@link bt_mesh_fill_small_holes}, which each carried
15
- * a byte-identical copy.
16
- *
17
17
  * @param {BinaryTopology} mesh
18
18
  * @param {number[]|Uint32Array} cycle unordered boundary edge ids
19
19
  * @param {number} start_vertex vertex to begin the walk at; must be an endpoint of some edge in `cycle`
@@ -74,101 +74,451 @@ export function bt_boundary_loop_order_from(mesh, cycle, start_vertex, out_verti
74
74
  e_prev = e_next;
75
75
  }
76
76
  }
77
-
78
- /**
79
- * Scratch for {@link bt_boundary_loop_fan_fill}. Module-static because the fill is called once per hole
80
- * and nothing it calls re-enters it.
81
- * @type {number[]}
82
- */
83
- const scratch_coord = [0, 0, 0];
84
-
85
- /** @type {number[]} */
86
- const scratch_ordered_vertices = [];
87
-
88
- /** @type {number[]} */
89
- const scratch_ordered_edges = [];
90
-
91
- /**
92
- * Close one boundary hole: order its cycle, allocate an n-gon face over it, and fan that face from the
93
- * hole's centroid, which adds a Steiner vertex and replaces the n-gon with n triangles.
94
- *
95
- * ## The winding, and what it depends on
96
- *
97
- * Each new loop on a boundary edge must wind **opposite** the existing loop, so the shared edge ends up
98
- * with consistent radial orientation. That is what the start-vertex choice below buys: the seed edge's
99
- * existing loop names one of its two endpoints, and the fill starts at the *other* one.
100
- *
101
- * It works because {@link bt_boundary_loop_order_from} takes `start_vertex`'s first incident edge out of
102
- * its bucket and walks from there, so the order it produces leaves `start_vertex` along an edge, in the
103
- * direction opposite to the existing loop's traversal of the seed edge. Change how that walk picks its
104
- * first edge and the fill face winds the wrong way — which is why the two live in one file.
105
- *
106
- * The face normal stays zero; downstream tetrahedralization is position-only.
107
- *
108
- * `bt_mesh_close_boundary_holes` and `bt_mesh_fill_small_holes` each carried a copy of this — forty
109
- * lines, identical in every step — and only the ordering walk above had been lifted out of them.
110
- *
111
- * @param {BinaryTopology} mesh
112
- * @param {number[]|Uint32Array} cycle unordered boundary edge ids forming one closed loop
113
- *
114
- * @author Alex Goldring
115
- * @copyright Company Named Limited (c) 2026
116
- */
117
- export function bt_boundary_loop_fan_fill(mesh, cycle) {
118
- const n = cycle.length;
119
-
120
- const seed_edge = cycle[0];
121
- const seed_loop = mesh.edge_read_loop(seed_edge);
122
- const existing_loop_vertex = mesh.loop_read_vertex(seed_loop);
123
- const seed_v1 = mesh.edge_read_vertex1(seed_edge);
124
- const seed_v2 = mesh.edge_read_vertex2(seed_edge);
125
- const start_vertex = (existing_loop_vertex === seed_v1) ? seed_v2 : seed_v1;
126
-
127
- const ordered_vertices = scratch_ordered_vertices;
128
- const ordered_edges = scratch_ordered_edges;
129
-
130
- ordered_vertices.length = n;
131
- ordered_edges.length = n;
132
-
133
- bt_boundary_loop_order_from(mesh, cycle, start_vertex, ordered_vertices, ordered_edges);
134
-
135
- // Compute centroid of the hole's vertices.
136
- let cx = 0, cy = 0, cz = 0;
137
-
138
- for (let i = 0; i < n; i++) {
139
- mesh.vertex_read_coordinate(scratch_coord, 0, ordered_vertices[i]);
140
-
141
- cx += scratch_coord[0];
142
- cy += scratch_coord[1];
143
- cz += scratch_coord[2];
144
- }
145
-
146
- cx /= n;
147
- cy /= n;
148
- cz /= n;
149
-
150
- // Allocate a new face plus n loops, wire them into the face cycle and each boundary edge's radial
151
- // cycle.
152
- const new_face = mesh.face_create();
153
-
154
- const loops = new Array(n);
155
-
156
- for (let i = 0; i < n; i++) {
157
- loops[i] = mesh.loop_create();
158
-
159
- mesh.loop_write_vertex(loops[i], ordered_vertices[i]);
160
- mesh.loop_write_face(loops[i], new_face);
161
-
162
- bt_radial_loop_add(mesh, loops[i], ordered_edges[i]);
163
- }
164
-
165
- for (let i = 0; i < n; i++) {
166
- mesh.loop_write_next(loops[i], loops[(i + 1) % n]);
167
- mesh.loop_write_prev(loops[i], loops[(i - 1 + n) % n]);
168
- }
169
-
170
- mesh.face_write_loop(new_face, loops[0]);
171
-
172
- // Fan from centroid — adds the Steiner vertex and replaces the n-gon face with n triangles.
173
- bt_face_poke(mesh, new_face, cx, cy, cz);
174
- }
77
+
78
+ /**
79
+ * Scratch for {@link bt_boundary_loop_fan_fill}. Module-static because the fill is called once per hole
80
+ * and nothing it calls re-enters it.
81
+ * @type {number[]}
82
+ */
83
+ const scratch_coord = [0, 0, 0];
84
+
85
+ /** @type {number[]} */
86
+ const scratch_ordered_vertices = [];
87
+
88
+ /** @type {number[]} */
89
+ const scratch_ordered_edges = [];
90
+
91
+ /**
92
+ * Close one boundary hole: order its cycle, allocate an n-gon face over it, and fan that face from the
93
+ * hole's centroid, which adds a Steiner vertex and replaces the n-gon with n triangles.
94
+ *
95
+ * ## The winding, and what it depends on
96
+ *
97
+ * Each new loop on a boundary edge must wind **opposite** the existing loop, so the shared edge ends up
98
+ * with consistent radial orientation. That is what the start-vertex choice below buys: the seed edge's
99
+ * existing loop names one of its two endpoints, and the fill starts at the *other* one.
100
+ *
101
+ * It works because {@link bt_boundary_loop_order_from} takes `start_vertex`'s first incident edge out of
102
+ * its bucket and walks from there, so the order it produces leaves `start_vertex` along an edge, in the
103
+ * direction opposite to the existing loop's traversal of the seed edge. Change how that walk picks its
104
+ * first edge and the fill face winds the wrong way — which is why the two live in one file.
105
+ *
106
+ * No face normal is computed; downstream tetrahedralization is position-only.
107
+ *
108
+ * The fan covers the hole, and only the hole, when every edge of the loop is visible from the centroid
109
+ * of its vertices. For any other loop use {@link bt_boundary_loop_min_area_fill}.
110
+ *
111
+ * @param {BinaryTopology} mesh
112
+ * @param {number[]|Uint32Array} cycle unordered boundary edge ids forming one closed loop
113
+ *
114
+ * @author Alex Goldring
115
+ * @copyright Company Named Limited (c) 2026
116
+ */
117
+ export function bt_boundary_loop_fan_fill(mesh, cycle) {
118
+ const n = cycle.length;
119
+
120
+ const seed_edge = cycle[0];
121
+ const seed_loop = mesh.edge_read_loop(seed_edge);
122
+ const existing_loop_vertex = mesh.loop_read_vertex(seed_loop);
123
+ const seed_v1 = mesh.edge_read_vertex1(seed_edge);
124
+ const seed_v2 = mesh.edge_read_vertex2(seed_edge);
125
+ const start_vertex = (existing_loop_vertex === seed_v1) ? seed_v2 : seed_v1;
126
+
127
+ const ordered_vertices = scratch_ordered_vertices;
128
+ const ordered_edges = scratch_ordered_edges;
129
+
130
+ ordered_vertices.length = n;
131
+ ordered_edges.length = n;
132
+
133
+ bt_boundary_loop_order_from(mesh, cycle, start_vertex, ordered_vertices, ordered_edges);
134
+
135
+ // Compute centroid of the hole's vertices.
136
+ let cx = 0, cy = 0, cz = 0;
137
+
138
+ for (let i = 0; i < n; i++) {
139
+ mesh.vertex_read_coordinate(scratch_coord, 0, ordered_vertices[i]);
140
+
141
+ cx += scratch_coord[0];
142
+ cy += scratch_coord[1];
143
+ cz += scratch_coord[2];
144
+ }
145
+
146
+ cx /= n;
147
+ cy /= n;
148
+ cz /= n;
149
+
150
+ // Allocate a new face plus n loops, wire them into the face cycle and each boundary edge's radial
151
+ // cycle.
152
+ const new_face = mesh.face_create();
153
+
154
+ const loops = new Array(n);
155
+
156
+ for (let i = 0; i < n; i++) {
157
+ loops[i] = mesh.loop_create();
158
+
159
+ mesh.loop_write_vertex(loops[i], ordered_vertices[i]);
160
+ mesh.loop_write_face(loops[i], new_face);
161
+
162
+ bt_radial_loop_add(mesh, loops[i], ordered_edges[i]);
163
+ }
164
+
165
+ for (let i = 0; i < n; i++) {
166
+ mesh.loop_write_next(loops[i], loops[(i + 1) % n]);
167
+ mesh.loop_write_prev(loops[i], loops[(i - 1 + n) % n]);
168
+ }
169
+
170
+ mesh.face_write_loop(new_face, loops[0]);
171
+
172
+ // Fan from centroid — adds the Steiner vertex and replaces the n-gon face with n triangles.
173
+ bt_face_poke(mesh, new_face, cx, cy, cz);
174
+ }
175
+
176
+ // Scratch for bt_boundary_loop_min_area_fill, grown on demand and never shrunk. Module-static for the
177
+ // same reason as the fan fill's: one call per hole, and nothing it calls re-enters it.
178
+
179
+ /** (x, y, z) per loop vertex, in loop order. */
180
+ let scratch_positions = new Float64Array(0);
181
+
182
+ /** `n * n`: total area of the triangulation chosen for the chain `i .. j`, at `i * n + j`. */
183
+ let scratch_cost = new Float64Array(0);
184
+
185
+ /** `n * n`: summed {@link loop_triangle_shape} of the triangulation chosen for the chain `i .. j`. */
186
+ let scratch_shape = new Float64Array(0);
187
+
188
+ /** `n * n`: the apex `k` of the triangulation chosen for the chain `i .. j`. */
189
+ let scratch_apex = new Uint32Array(0);
190
+
191
+ /** `n * 3`: pending chains while the chosen triangulation is written out, as (i, j, edge joining them). */
192
+ let scratch_stack = new Uint32Array(0);
193
+
194
+ const ZERO_NORMAL = [0, 0, 0];
195
+
196
+ /**
197
+ * How far from equilateral the triangle last given to {@link loop_triangle_area} is: the sum of its
198
+ * squared edge lengths over its area. Least for an equilateral triangle, and infinite for one with no
199
+ * area.
200
+ */
201
+ let loop_triangle_shape = 0;
202
+
203
+ /**
204
+ * Also leaves the triangle's shape in {@link loop_triangle_shape}.
205
+ *
206
+ * @param {number} i
207
+ * @param {number} k
208
+ * @param {number} j loop vertex indices into {@link scratch_positions}
209
+ * @returns {number} area of the triangle they span
210
+ */
211
+ function loop_triangle_area(i, k, j) {
212
+ const p = scratch_positions;
213
+
214
+ const i3 = i * 3;
215
+ const k3 = k * 3;
216
+ const j3 = j * 3;
217
+
218
+ const ux = p[k3] - p[i3];
219
+ const uy = p[k3 + 1] - p[i3 + 1];
220
+ const uz = p[k3 + 2] - p[i3 + 2];
221
+
222
+ const vx = p[j3] - p[i3];
223
+ const vy = p[j3 + 1] - p[i3 + 1];
224
+ const vz = p[j3 + 2] - p[i3 + 2];
225
+
226
+ const wx = vx - ux;
227
+ const wy = vy - uy;
228
+ const wz = vz - uz;
229
+
230
+ const cx = uy * vz - uz * vy;
231
+ const cy = uz * vx - ux * vz;
232
+ const cz = ux * vy - uy * vx;
233
+
234
+ const area = 0.5 * Math.sqrt(cx * cx + cy * cy + cz * cz);
235
+
236
+ const squared_edges = ux * ux + uy * uy + uz * uz
237
+ + vx * vx + vy * vy + vz * vz
238
+ + wx * wx + wy * wy + wz * wz;
239
+
240
+ loop_triangle_shape = area > 0 ? squared_edges / area : Number.POSITIVE_INFINITY;
241
+
242
+ return area;
243
+ }
244
+
245
+ /**
246
+ * Add the triangle `a -> b -> c` on three edges that already exist.
247
+ *
248
+ * @param {BinaryTopology} mesh
249
+ * @param {number} a
250
+ * @param {number} e_ab
251
+ * @param {number} b
252
+ * @param {number} e_bc
253
+ * @param {number} c
254
+ * @param {number} e_ca
255
+ */
256
+ function add_triangle_on_edges(mesh, a, e_ab, b, e_bc, c, e_ca) {
257
+ const face = mesh.face_create();
258
+
259
+ const l_a = mesh.loop_create();
260
+ const l_b = mesh.loop_create();
261
+ const l_c = mesh.loop_create();
262
+
263
+ mesh.loop_write_vertex(l_a, a);
264
+ mesh.loop_write_vertex(l_b, b);
265
+ mesh.loop_write_vertex(l_c, c);
266
+
267
+ mesh.loop_write_face(l_a, face);
268
+ mesh.loop_write_face(l_b, face);
269
+ mesh.loop_write_face(l_c, face);
270
+
271
+ bt_radial_loop_add(mesh, l_a, e_ab);
272
+ bt_radial_loop_add(mesh, l_b, e_bc);
273
+ bt_radial_loop_add(mesh, l_c, e_ca);
274
+
275
+ mesh.loop_write_next(l_a, l_b);
276
+ mesh.loop_write_next(l_b, l_c);
277
+ mesh.loop_write_next(l_c, l_a);
278
+
279
+ mesh.loop_write_prev(l_a, l_c);
280
+ mesh.loop_write_prev(l_b, l_a);
281
+ mesh.loop_write_prev(l_c, l_b);
282
+
283
+ mesh.face_write_loop(face, l_a);
284
+
285
+ // the pool hands back whatever the slot last held; deriving the normal is the caller's business
286
+ mesh.face_write_normal(face, ZERO_NORMAL, 0);
287
+ }
288
+
289
+ /**
290
+ * Close one boundary hole with triangles over the hole's own vertices, choosing the triangulation of
291
+ * least total area. No vertex is added.
292
+ *
293
+ * ## Why least area
294
+ *
295
+ * A fill should cover what the loop encloses and nothing else. For a loop that is a simple polygon in a
296
+ * plane, every triangulation that stays inside it has the same total area — the polygon's — and any that
297
+ * puts a triangle outside has more, because that triangle then has to be paid back by another lying
298
+ * over the surface around the hole, wound the other way. So the least-area triangulation of such a loop
299
+ * IS a triangulation of the hole, whatever its shape, with no test for convexity or containment that
300
+ * could be got wrong. For a loop that is not flat it is the classic choice of closing surface, and no
301
+ * more than that.
302
+ *
303
+ * The fan in {@link bt_boundary_loop_fan_fill} does not have that property: it is a triangulation of the
304
+ * hole only when the whole loop is visible from the centroid of its vertices. For a crescent, an L, or
305
+ * a crack with more than one arm the centroid lies outside the hole, and the fan covers the surface
306
+ * between the two with triangles facing both ways.
307
+ *
308
+ * A loop need not be a simple polygon at all — a hairline crack encloses nothing, and two sheets that
309
+ * overlap by a sliver bound a loop that crosses itself. Least area is still the right answer there: it
310
+ * is the closure that adds as little surface as that loop permits, so the faces of a hole with no width
311
+ * have no area. Where the sheets overlap, some of those faces are wound against the surface: the loop
312
+ * itself is, and no closure made of faces alone can be otherwise.
313
+ *
314
+ * The search is the dynamic programme of Barequet and Sharir, "Filling gaps in the boundary of a
315
+ * polyhedron" (1995): the best triangulation of the chain `i .. j` is the best apex `k` between them
316
+ * plus the best of the two chains either side of it. It measures area in 3D, so the loop needs no plane
317
+ * to be projected onto. Time is cubic in the loop's edge count and memory quadratic.
318
+ *
319
+ * ## Equal areas
320
+ *
321
+ * Every triangulation of a flat hole has the same area, so area alone does not say which to take, and
322
+ * left to rounding the choice falls on triangles across three vertices of one straight side as readily
323
+ * as on any other — faces of no area, where faces with area would do. Among triangulations whose areas
324
+ * are equal to within what rounding can make of them, the one taken is the one whose triangles are
325
+ * nearest equilateral: least in the sum, over its triangles, of squared edge length over area. That is
326
+ * the measure a Delaunay triangulation minimises, and a triangle with no area makes it infinite.
327
+ *
328
+ * ## Edges
329
+ *
330
+ * A diagonal between two loop vertices that the mesh already joins by an edge is never used: the fill
331
+ * would put two more faces on a pair of vertices that already has its own, which is a non-manifold edge
332
+ * as soon as anything fuses the duplicates. When that rules out every triangulation the hole is left
333
+ * open and `false` is returned.
334
+ *
335
+ * ## Winding
336
+ *
337
+ * As in {@link bt_boundary_loop_fan_fill}, and for the reason given there: the loop is ordered from the
338
+ * seed edge's far endpoint, so every new face crosses each boundary edge against the face already on
339
+ * it.
340
+ *
341
+ * Face normals are written as zero.
342
+ *
343
+ * @param {BinaryTopology} mesh
344
+ * @param {number[]|Uint32Array} cycle unordered boundary edge ids forming one closed loop of at least 3 edges
345
+ * @returns {boolean} whether the hole was closed
346
+ *
347
+ * @author Alex Goldring
348
+ * @copyright Company Named Limited (c) 2026
349
+ */
350
+ export function bt_boundary_loop_min_area_fill(mesh, cycle) {
351
+ const n = cycle.length;
352
+
353
+ if (n < 3) {
354
+ return false;
355
+ }
356
+
357
+ const seed_edge = cycle[0];
358
+ const seed_loop = mesh.edge_read_loop(seed_edge);
359
+ const existing_loop_vertex = mesh.loop_read_vertex(seed_loop);
360
+ const seed_v1 = mesh.edge_read_vertex1(seed_edge);
361
+ const seed_v2 = mesh.edge_read_vertex2(seed_edge);
362
+ const start_vertex = (existing_loop_vertex === seed_v1) ? seed_v2 : seed_v1;
363
+
364
+ const vertices = scratch_ordered_vertices;
365
+ const edges = scratch_ordered_edges;
366
+
367
+ vertices.length = n;
368
+ edges.length = n;
369
+
370
+ bt_boundary_loop_order_from(mesh, cycle, start_vertex, vertices, edges);
371
+
372
+ if (n === 3) {
373
+ add_triangle_on_edges(mesh, vertices[0], edges[0], vertices[1], edges[1], vertices[2], edges[2]);
374
+
375
+ return true;
376
+ }
377
+
378
+ if (scratch_positions.length < n * 3) {
379
+ scratch_positions = new Float64Array(n * 3);
380
+ scratch_stack = new Uint32Array(n * 3);
381
+ }
382
+
383
+ if (scratch_cost.length < n * n) {
384
+ scratch_cost = new Float64Array(n * n);
385
+ scratch_shape = new Float64Array(n * n);
386
+ scratch_apex = new Uint32Array(n * n);
387
+ }
388
+
389
+ const positions = scratch_positions;
390
+ const cost = scratch_cost;
391
+ const shape = scratch_shape;
392
+ const apex = scratch_apex;
393
+
394
+ let min_x = Infinity, min_y = Infinity, min_z = Infinity;
395
+ let max_x = -Infinity, max_y = -Infinity, max_z = -Infinity;
396
+
397
+ for (let i = 0; i < n; i++) {
398
+ mesh.vertex_read_coordinate(positions, i * 3, vertices[i]);
399
+
400
+ const x = positions[i * 3];
401
+ const y = positions[i * 3 + 1];
402
+ const z = positions[i * 3 + 2];
403
+
404
+ if (x < min_x) min_x = x;
405
+ if (y < min_y) min_y = y;
406
+ if (z < min_z) min_z = z;
407
+ if (x > max_x) max_x = x;
408
+ if (y > max_y) max_y = y;
409
+ if (z > max_z) max_z = z;
410
+ }
411
+
412
+ // How far apart two sums of triangle areas can be and still be the same area. A triangle's area comes
413
+ // from products of coordinate differences no longer than the loop is across, each rounded to one part
414
+ // in 2^53 of a square that size, and a triangulation adds fewer than n of them.
415
+ const extent_x = max_x - min_x;
416
+ const extent_y = max_y - min_y;
417
+ const extent_z = max_z - min_z;
418
+
419
+ const same_area = 8 * n * Number.EPSILON * (extent_x * extent_x + extent_y * extent_y + extent_z * extent_z);
420
+
421
+ for (let i = 0; i + 1 < n; i++) {
422
+ // a chain of one edge has nothing to triangulate
423
+ cost[i * n + i + 1] = 0;
424
+ shape[i * n + i + 1] = 0;
425
+ }
426
+
427
+ for (let span = 2; span < n; span++) {
428
+ for (let i = 0; i + span < n; i++) {
429
+ const j = i + span;
430
+
431
+ // `least` is the smallest area any apex has offered; `best` and `best_shape` belong to the
432
+ // apex chosen, whose area is within `same_area` of it.
433
+ let least = Number.POSITIVE_INFINITY;
434
+ let best = Number.POSITIVE_INFINITY;
435
+ let best_shape = Number.POSITIVE_INFINITY;
436
+ let best_apex = i + 1;
437
+
438
+ // The chain 0 .. n-1 is closed by the loop's own last edge. Every other chain is closed by
439
+ // a diagonal, which has to be one the mesh does not already have.
440
+ const is_closed_by_loop = span === n - 1;
441
+
442
+ if (is_closed_by_loop || bt_edge_get(mesh, vertices[i], vertices[j]) === NULL_POINTER) {
443
+
444
+ for (let k = i + 1; k < j; k++) {
445
+ const candidate = cost[i * n + k] + cost[k * n + j] + loop_triangle_area(i, k, j);
446
+
447
+ if (!(candidate < Number.POSITIVE_INFINITY)) {
448
+ // one side of this apex cannot be triangulated
449
+ continue;
450
+ }
451
+
452
+ const candidate_shape = shape[i * n + k] + shape[k * n + j] + loop_triangle_shape;
453
+
454
+ if (
455
+ candidate < least - same_area
456
+ || (candidate <= least + same_area && candidate_shape < best_shape)
457
+ ) {
458
+ best = candidate;
459
+ best_shape = candidate_shape;
460
+ best_apex = k;
461
+ }
462
+
463
+ if (candidate < least) {
464
+ least = candidate;
465
+ }
466
+ }
467
+
468
+ }
469
+
470
+ cost[i * n + j] = best;
471
+ shape[i * n + j] = best_shape;
472
+ apex[i * n + j] = best_apex;
473
+ }
474
+ }
475
+
476
+ if (cost[n - 1] === Number.POSITIVE_INFINITY) {
477
+ // every triangulation needs a diagonal the mesh already has
478
+ return false;
479
+ }
480
+
481
+ // Write the chosen triangulation out, chain by chain. Each entry is a chain and the edge that
482
+ // closes it, which exists by the time the entry is read: the loop's own for the first, and a
483
+ // diagonal made by the parent triangle for the rest.
484
+ const stack = scratch_stack;
485
+
486
+ stack[0] = 0;
487
+ stack[1] = n - 1;
488
+ stack[2] = edges[n - 1];
489
+
490
+ let stack_size = 1;
491
+
492
+ while (stack_size > 0) {
493
+ stack_size--;
494
+
495
+ const i = stack[stack_size * 3];
496
+ const j = stack[stack_size * 3 + 1];
497
+ const e_ji = stack[stack_size * 3 + 2];
498
+
499
+ const k = apex[i * n + j];
500
+
501
+ const e_ik = (k === i + 1) ? edges[i] : bt_edge_create(mesh, vertices[i], vertices[k]);
502
+ const e_kj = (j === k + 1) ? edges[k] : bt_edge_create(mesh, vertices[k], vertices[j]);
503
+
504
+ add_triangle_on_edges(mesh, vertices[i], e_ik, vertices[k], e_kj, vertices[j], e_ji);
505
+
506
+ if (k > i + 1) {
507
+ stack[stack_size * 3] = i;
508
+ stack[stack_size * 3 + 1] = k;
509
+ stack[stack_size * 3 + 2] = e_ik;
510
+
511
+ stack_size++;
512
+ }
513
+
514
+ if (j > k + 1) {
515
+ stack[stack_size * 3] = k;
516
+ stack[stack_size * 3 + 1] = j;
517
+ stack[stack_size * 3 + 2] = e_kj;
518
+
519
+ stack_size++;
520
+ }
521
+ }
522
+
523
+ return true;
524
+ }
@@ -10,8 +10,10 @@
10
10
  * Throws if any boundary vertex has more than two boundary edges (figure-8 /
11
11
  * pinched boundaries). Mutates the mesh in place.
12
12
  *
13
- * The per-hole fill is {@link bt_boundary_loop_fan_fill}, which {@link bt_mesh_fill_small_holes} also
14
- * runs — the two used to carry a copy of it each, and the winding argument with it.
13
+ * The per-hole fill is {@link bt_boundary_loop_fan_fill}. A fan covers a hole exactly only when the
14
+ * whole loop is visible from the centroid of its vertices; around any other hole some of its triangles
15
+ * lie over the surface beside the hole, and {@link bt_boundary_loop_min_area_fill} is the fill to use
16
+ * where that matters.
15
17
  *
16
18
  * @param {BinaryTopology} mesh
17
19
  * @returns {number} number of boundary holes that were closed
@@ -1 +1 @@
1
- {"version":3,"file":"bt_mesh_close_boundary_holes.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AACH,oEAFa,MAAM,CAWlB"}
1
+ {"version":3,"file":"bt_mesh_close_boundary_holes.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,oEAFa,MAAM,CAWlB"}
@@ -14,8 +14,10 @@ import { bt_mesh_walk_boundary_loops } from "../query/bt_mesh_walk_boundary_loop
14
14
  * Throws if any boundary vertex has more than two boundary edges (figure-8 /
15
15
  * pinched boundaries). Mutates the mesh in place.
16
16
  *
17
- * The per-hole fill is {@link bt_boundary_loop_fan_fill}, which {@link bt_mesh_fill_small_holes} also
18
- * runs — the two used to carry a copy of it each, and the winding argument with it.
17
+ * The per-hole fill is {@link bt_boundary_loop_fan_fill}. A fan covers a hole exactly only when the
18
+ * whole loop is visible from the centroid of its vertices; around any other hole some of its triangles
19
+ * lie over the surface beside the hole, and {@link bt_boundary_loop_min_area_fill} is the fill to use
20
+ * where that matters.
19
21
  *
20
22
  * @param {BinaryTopology} mesh
21
23
  * @returns {number} number of boundary holes that were closed
@@ -5,7 +5,14 @@
5
5
  * tiny boundary loop - that are numerical noise rather than meaningful openings. Such slivers inflate
6
6
  * the boundary length, the face count, and the loop count. This measures every boundary loop's mean
7
7
  * width (2*area/perimeter, the inradius of the area-equivalent disc) and fills each inner loop narrower
8
- * than `min_width`. The single largest-area loop is treated as the outer boundary and is never filled.
8
+ * than `min_width`.
9
+ *
10
+ * The largest-area loop of each island - each group of faces connected through shared edges - is that
11
+ * island's outline rather than a hole in it, and is never filled, however narrow the island is.
12
+ *
13
+ * Each hole is closed by {@link bt_boundary_loop_min_area_fill}: the triangles of least total area over
14
+ * the hole's own vertices. No vertex is added. A hole that cannot be closed without doubling an edge
15
+ * the mesh already has is left open and not counted.
9
16
  *
10
17
  * @param {BinaryTopology} mesh mesh whose boundary loops are inspected and (where too thin) filled in place
11
18
  * @param {number} min_width minimum mean width an inner loop must have to be kept; thinner loops are filled
@@ -1 +1 @@
1
- {"version":3,"file":"bt_mesh_fill_small_holes.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js"],"names":[],"mappings":"AAwBA;;;;;;;;;;;;GAYG;AACH,0EAHW,MAAM,GACJ,MAAM,CA2ClB"}
1
+ {"version":3,"file":"bt_mesh_fill_small_holes.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js"],"names":[],"mappings":"AAyBA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,0EAHW,MAAM,GACJ,MAAM,CAsElB"}