@woosh/meep-engine 2.164.0 → 2.165.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BitImage2.d.ts +91 -0
- package/src/core/binary/BitImage2.d.ts.map +1 -0
- package/src/core/binary/BitImage2.js +242 -0
- package/src/core/geom/2d/oriented-box/min_area_rect_2d.d.ts +22 -0
- package/src/core/geom/2d/oriented-box/min_area_rect_2d.d.ts.map +1 -0
- package/src/core/geom/2d/oriented-box/min_area_rect_2d.js +69 -0
- package/src/core/geom/2d/packing/skyline.d.ts +116 -0
- package/src/core/geom/2d/packing/skyline.d.ts.map +1 -0
- package/src/core/geom/2d/packing/skyline.js +258 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_conservative.d.ts +18 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_conservative.d.ts.map +1 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_conservative.js +86 -0
- package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +486 -0
- package/src/core/geom/3d/atlas/BFF_PLAN.md +174 -0
- package/src/core/geom/3d/atlas/Chart.d.ts +58 -0
- package/src/core/geom/3d/atlas/Chart.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/Chart.js +77 -0
- package/src/core/geom/3d/atlas/REVIEW_02.md +392 -0
- package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts +73 -0
- package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_bench_lib.js +315 -0
- package/src/core/geom/3d/atlas/atlas_chart_type.d.ts +17 -0
- package/src/core/geom/3d/atlas/atlas_chart_type.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_chart_type.js +16 -0
- package/src/core/geom/3d/atlas/atlas_compute_charts.d.ts +25 -0
- package/src/core/geom/3d/atlas/atlas_compute_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_compute_charts.js +188 -0
- package/src/core/geom/3d/atlas/atlas_extract_chart.d.ts +17 -0
- package/src/core/geom/3d/atlas/atlas_extract_chart.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_extract_chart.js +107 -0
- package/src/core/geom/3d/atlas/atlas_generate.d.ts +39 -0
- package/src/core/geom/3d/atlas/atlas_generate.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_generate.js +43 -0
- package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts +84 -0
- package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_test_fixtures.js +266 -0
- package/src/core/geom/3d/atlas/atlas_write_chart_uvs.d.ts +25 -0
- package/src/core/geom/3d/atlas/atlas_write_chart_uvs.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_write_chart_uvs.js +36 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.d.ts +22 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.js +62 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.d.ts +9 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.js +33 -0
- package/src/core/geom/3d/atlas/data/atlas_build_face_areas.d.ts +9 -0
- package/src/core/geom/3d/atlas/data/atlas_build_face_areas.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/data/atlas_build_face_areas.js +50 -0
- package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.d.ts +27 -0
- package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.js +39 -0
- package/src/core/geom/3d/atlas/io/bt_loop_uv.d.ts +22 -0
- package/src/core/geom/3d/atlas/io/bt_loop_uv.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/io/bt_loop_uv.js +57 -0
- package/src/core/geom/3d/atlas/pack/ChartPlacement.d.ts +36 -0
- package/src/core/geom/3d/atlas/pack/ChartPlacement.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/pack/ChartPlacement.js +46 -0
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts +62 -0
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +551 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_param_validity.d.ts +22 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_param_validity.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_param_validity.js +73 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts +37 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +270 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts +23 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +224 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.d.ts +14 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.js +38 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.d.ts +22 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.js +86 -0
- package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.d.ts +20 -0
- package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.js +183 -0
- package/src/core/geom/3d/atlas/param/fit_plane_basis.d.ts +27 -0
- package/src/core/geom/3d/atlas/param/fit_plane_basis.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/fit_plane_basis.js +66 -0
- package/src/core/geom/3d/atlas/segment/RegionGraph.d.ts +31 -0
- package/src/core/geom/3d/atlas/segment/RegionGraph.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/RegionGraph.js +40 -0
- package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.d.ts +23 -0
- package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.js +136 -0
- package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.d.ts +24 -0
- package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.js +77 -0
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts +27 -0
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +113 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts +44 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.js +275 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts +22 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.js +199 -0
- package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.d.ts +32 -0
- package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.d.ts.map +1 -0
- package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.js +64 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.d.ts +20 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.js +66 -0
- package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.d.ts.map +1 -1
- package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +13 -11
- package/src/core/geom/3d/sphere/sphere_compute_bounding_of_2_spheres.d.ts.map +1 -1
- package/src/core/geom/3d/sphere/sphere_compute_bounding_of_2_spheres.js +4 -3
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.js +4 -3
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.js +4 -3
- package/src/core/geom/3d/topology/simplify/quadratic/apply_border_penalty_to_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/apply_border_penalty_to_vertex_quadrics.js +10 -6
- package/src/core/geom/3d/topology/struct/TopoMesh.js +2 -2
- package/src/core/geom/3d/topology/struct/TopoTriangle.d.ts +0 -2
- package/src/core/geom/3d/topology/struct/TopoTriangle.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/TopoTriangle.js +2 -2
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +8 -27
- package/src/core/geom/vec3/v3_cotangent.d.ts +20 -0
- package/src/core/geom/vec3/v3_cotangent.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_cotangent.js +29 -0
- package/src/core/geom/vec3/v3_matrix3_multiply.d.ts +19 -0
- package/src/core/geom/vec3/v3_matrix3_multiply.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_matrix3_multiply.js +30 -0
- package/src/core/geom/vec3/v3_multiply.d.ts +16 -0
- package/src/core/geom/vec3/v3_multiply.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_multiply.js +19 -0
- package/src/core/math/linalg/cg/cg_solve.d.ts +24 -0
- package/src/core/math/linalg/cg/cg_solve.d.ts.map +1 -0
- package/src/core/math/linalg/cg/cg_solve.js +106 -0
- package/src/core/math/linalg/cg/cg_solve_normal_equations.d.ts +21 -0
- package/src/core/math/linalg/cg/cg_solve_normal_equations.d.ts.map +1 -0
- package/src/core/math/linalg/cg/cg_solve_normal_equations.js +59 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts +19 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts.map +1 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.js +117 -0
- package/src/core/math/linalg/sparse/SparseMatrixCSR.d.ts +50 -0
- package/src/core/math/linalg/sparse/SparseMatrixCSR.d.ts.map +1 -0
- package/src/core/math/linalg/sparse/SparseMatrixCSR.js +88 -0
- package/src/core/math/linalg/sparse/spm_matvec.d.ts +9 -0
- package/src/core/math/linalg/sparse/spm_matvec.d.ts.map +1 -0
- package/src/core/math/linalg/sparse/spm_matvec.js +22 -0
- package/src/core/math/linalg/sparse/spm_matvec_transpose.d.ts +12 -0
- package/src/core/math/linalg/sparse/spm_matvec_transpose.d.ts.map +1 -0
- package/src/core/math/linalg/sparse/spm_matvec_transpose.js +29 -0
- package/src/core/math/physics/mie/MIE_PARTICLES_STANDARD_PRECOMPUTED.d.ts +39 -0
- package/src/core/math/physics/mie/MIE_PARTICLES_STANDARD_PRECOMPUTED.js +22 -1
- package/src/core/math/physics/mie/compute_mie_particle_properties_rgb.d.ts.map +1 -1
- package/src/core/math/physics/mie/compute_mie_particle_properties_rgb.js +32 -9
- package/src/core/math/physics/mie/compute_mie_phase.d.ts +2 -3
- package/src/core/math/physics/mie/compute_mie_phase.d.ts.map +1 -1
- package/src/core/math/physics/mie/compute_mie_phase.js +1 -3
- package/src/core/math/physics/mie/lorenz_mie_coefs.d.ts +0 -1
- package/src/core/math/physics/mie/lorenz_mie_coefs.d.ts.map +1 -1
- package/src/core/math/physics/mie/lorenz_mie_coefs.js +0 -7
- package/src/engine/ecs/attachment/TransformAttachmentBinding.js +3 -3
- package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +2 -2
- package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/Terrain.js +4 -3
- package/src/engine/ecs/terrain/tiles/TerrainTile.js +2 -2
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +9 -8
- package/src/engine/graphics/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics/GraphicsEngine.js +2 -1
- package/src/engine/graphics/ecs/decal/v2/FPDecalSystem.js +2 -2
- package/src/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +2 -2
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +2 -2
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +0 -1
- package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.d.ts.map +1 -1
- package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +8 -7
- package/src/engine/graphics/geometry/MikkT/AvgTSpace.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/AvgTSpace.js +11 -6
- package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.js +2 -3
- package/src/engine/graphics/geometry/MikkT/CalcTexArea.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/CalcTexArea.js +3 -4
- package/src/engine/graphics/geometry/MikkT/DegenEpilogue.js +4 -4
- package/src/engine/graphics/geometry/MikkT/EvalTspace.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/EvalTspace.js +11 -8
- package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.js +7 -8
- package/src/engine/graphics/geometry/MikkT/GenerateTSpaces.js +8 -8
- package/src/engine/graphics/geometry/MikkT/InitTriInfo.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/InitTriInfo.js +30 -25
- package/src/engine/graphics/geometry/MikkT/MikkTSpace.js +7 -7
- package/src/engine/graphics/geometry/MikkT/NormalizeSafe.d.ts +0 -1
- package/src/engine/graphics/geometry/MikkT/NormalizeSafe.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/NormalizeSafe.js +6 -4
- package/src/engine/graphics/geometry/MikkT/STSpace.d.ts +0 -2
- package/src/engine/graphics/geometry/MikkT/STSpace.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/STSpace.js +3 -3
- package/src/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.d.ts +0 -2
- package/src/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.js +0 -1
- package/src/engine/graphics/impostors/octahedral/ImpostorBaker.d.ts +0 -2
- package/src/engine/graphics/impostors/octahedral/ImpostorBaker.d.ts.map +1 -1
- package/src/engine/graphics/impostors/octahedral/ImpostorBaker.js +4 -3
- package/src/engine/graphics/impostors/octahedral/grid/HemiOctahedralUvEncoder.js +2 -2
- package/src/engine/graphics/impostors/octahedral/grid/UvEncoder.d.ts +17 -7
- package/src/engine/graphics/impostors/voxel/VoxelImpostorBaker.js +2 -2
- package/src/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.js +3 -3
- package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +4 -3
- package/src/engine/graphics/render/forward_plus/LightManager.js +2 -2
- package/src/engine/graphics/render/forward_plus/model/Decal.d.ts +0 -2
- package/src/engine/graphics/render/forward_plus/model/Decal.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/model/Decal.js +3 -3
- package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +4 -3
- package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +6 -4
- package/src/engine/graphics/sh3/lightmap/ARTIFACTS_PLAN.md +146 -0
- package/src/engine/graphics/sh3/lightmap/CODE_REVIEW.md +121 -0
- package/src/engine/graphics/sh3/lightmap/LIGHTMAPPER_REVIEW.md +183 -0
- package/src/engine/graphics/sh3/lightmap/bake_lightmap_for_scene.d.ts +90 -0
- package/src/engine/graphics/sh3/lightmap/bake_lightmap_for_scene.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/bake_lightmap_for_scene.js +678 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_build_geometry.d.ts +32 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_build_geometry.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_build_geometry.js +155 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_denoise.d.ts +49 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_denoise.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_denoise.js +136 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_dilate.d.ts +19 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_dilate.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_dilate.js +89 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_gather.d.ts +54 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_gather.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_gather.js +168 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.d.ts +30 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.js +145 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_seam_fix.d.ts +38 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_seam_fix.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_seam_fix.js +152 -0
- package/src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.d.ts +2 -0
- package/src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.js +186 -0
- package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.js +2 -2
- package/src/engine/graphics/sh3/path_tracer/PathTracer.js +2 -2
- package/src/engine/graphics/sh3/path_tracer/prepare_scene_gltf.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/prepare_scene_gltf.js +6 -4
- package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +3 -3
- package/src/engine/graphics/sh3/path_tracer/texture/sample_material.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/texture/sample_material.js +5 -4
- package/src/engine/graphics/sh3/sky/hosek/prototype_hosek.js +2 -2
- package/src/engine/input/devices/KeyboardDevice.d.ts +61 -14
- package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
- package/src/engine/input/devices/KeyboardDevice.js +41 -15
- package/src/engine/input/devices/isHTMLElementFocusable.d.ts.map +1 -1
- package/src/engine/input/devices/isHTMLElementFocusable.js +2 -9
- package/src/engine/sound/simulation/prototypeAcousticSolver.js +261 -143
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bottom-left skyline rectangle packer (Jylänki's skyline-BL). The skyline is a
|
|
3
|
+
* left-to-right sequence of horizontal segments giving the free height at each
|
|
4
|
+
* column; a rectangle is placed at the lowest-then-leftmost position whose span
|
|
5
|
+
* fits, raising the skyline over its footprint. O(segments) per placement — the
|
|
6
|
+
* scalable packer for large atlases where the exact bitmap canBlit scan is too
|
|
7
|
+
* slow.
|
|
8
|
+
*
|
|
9
|
+
* Segments are packed as `(x, y, width)` uint32 triplets in a single typed
|
|
10
|
+
* array (not an array of objects) for cache locality and zero per-placement
|
|
11
|
+
* allocation: {@link place} rebuilds into a reused scratch buffer and swaps.
|
|
12
|
+
* Rectangles never overlap; simple skyline (no waste-map), so a little space is
|
|
13
|
+
* left under overhangs — fine for texture atlases.
|
|
14
|
+
*
|
|
15
|
+
* @author Alex Goldring
|
|
16
|
+
* @copyright Company Named Limited (c) 2026
|
|
17
|
+
*/
|
|
18
|
+
export class Skyline {
|
|
19
|
+
/**
|
|
20
|
+
* @param {number} width
|
|
21
|
+
* @param {number} height
|
|
22
|
+
*/
|
|
23
|
+
constructor(width: number, height: number);
|
|
24
|
+
/** Current bounds width. @type {number} */
|
|
25
|
+
width: number;
|
|
26
|
+
/** Current bounds height. @type {number} */
|
|
27
|
+
height: number;
|
|
28
|
+
/**
|
|
29
|
+
* x of the most recent successful {@link find} (valid only when `find`
|
|
30
|
+
* returned true).
|
|
31
|
+
* @type {number}
|
|
32
|
+
*/
|
|
33
|
+
found_x: number;
|
|
34
|
+
/** y of the most recent successful {@link find}. @type {number} */
|
|
35
|
+
found_y: number;
|
|
36
|
+
/**
|
|
37
|
+
* Live segment count.
|
|
38
|
+
* @type {number}
|
|
39
|
+
* @private
|
|
40
|
+
*/
|
|
41
|
+
private __count;
|
|
42
|
+
/**
|
|
43
|
+
* Capacity in triplets of {@link __segments} and {@link __scratch}.
|
|
44
|
+
* @type {number}
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
private __capacity;
|
|
48
|
+
/**
|
|
49
|
+
* Packed `(x, y, width)` triplets, x-ascending. Segment k spans columns
|
|
50
|
+
* `[x_k, x_k + width_k)` at free height `y_k`.
|
|
51
|
+
* @type {Uint32Array}
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
private __segments;
|
|
55
|
+
/**
|
|
56
|
+
* Scratch buffer reused by {@link place} to rebuild the segment list, then
|
|
57
|
+
* swapped with {@link __segments}.
|
|
58
|
+
* @type {Uint32Array}
|
|
59
|
+
* @private
|
|
60
|
+
*/
|
|
61
|
+
private __scratch;
|
|
62
|
+
/**
|
|
63
|
+
* Grow the segment and scratch buffers to hold at least `triplets`
|
|
64
|
+
* segments, preserving the live segments.
|
|
65
|
+
* @param {number} triplets
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
68
|
+
private __ensure_capacity;
|
|
69
|
+
/**
|
|
70
|
+
* Highest segment `y` across the columns `[segments[i].x, x_right)` — the
|
|
71
|
+
* floor a rectangle would rest on if its left edge started at segment `i`.
|
|
72
|
+
* @param {number} i start segment index
|
|
73
|
+
* @param {number} x_right exclusive right edge of the span
|
|
74
|
+
* @returns {number}
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
private __level;
|
|
78
|
+
/**
|
|
79
|
+
* Find the lowest-then-leftmost position for a `w x h` rectangle. On success
|
|
80
|
+
* stores it in {@link found_x}/{@link found_y}. Does not mutate the skyline.
|
|
81
|
+
* @param {number} w rectangle width
|
|
82
|
+
* @param {number} h rectangle height
|
|
83
|
+
* @returns {boolean} true if it fits within the current bounds
|
|
84
|
+
*/
|
|
85
|
+
find(w: number, h: number): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Append segment `(x, y, width)` to `scratch[n]`, merging into the previous
|
|
88
|
+
* scratch segment when they are adjacent at the same height.
|
|
89
|
+
* @param {Uint32Array} scratch
|
|
90
|
+
* @param {number} n current scratch segment count
|
|
91
|
+
* @param {number} x
|
|
92
|
+
* @param {number} y
|
|
93
|
+
* @param {number} width
|
|
94
|
+
* @returns {number} the new scratch segment count
|
|
95
|
+
* @private
|
|
96
|
+
*/
|
|
97
|
+
private __emit;
|
|
98
|
+
/**
|
|
99
|
+
* Raise the skyline to account for a `w x h` rectangle placed at (x, y).
|
|
100
|
+
* Rebuilds the (still x-sorted) segment list into the scratch buffer — the
|
|
101
|
+
* portions of old segments left of x and right of x+w, with the new top
|
|
102
|
+
* segment between them — then swaps it in. No per-segment allocation.
|
|
103
|
+
* @param {number} x placement left edge
|
|
104
|
+
* @param {number} y placement bottom edge
|
|
105
|
+
* @param {number} w rectangle width
|
|
106
|
+
* @param {number} h rectangle height
|
|
107
|
+
*/
|
|
108
|
+
place(x: number, y: number, w: number, h: number): void;
|
|
109
|
+
/**
|
|
110
|
+
* Enlarge the bounds, preserving placements. The new width starts at y=0.
|
|
111
|
+
* @param {number} width new width (>= current)
|
|
112
|
+
* @param {number} height new height (>= current)
|
|
113
|
+
*/
|
|
114
|
+
grow(width: number, height: number): void;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=skyline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skyline.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/2d/packing/skyline.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH;IA6CI;;;OAGG;IACH,mBAHW,MAAM,UACN,MAAM,EAYhB;IA1DD,2CAA2C;IAC3C,OADiC,MAAM,CAC7B;IACV,4CAA4C;IAC5C,QADkC,MAAM,CAC7B;IAEX;;;;OAIG;IACH,SAFU,MAAM,CAEJ;IACZ,mEAAmE;IACnE,SADyD,MAAM,CACnD;IAEZ;;;;OAIG;IACH,gBAAY;IAEZ;;;;OAIG;IACH,mBAAgB;IAEhB;;;;;OAKG;IACH,mBAAkD;IAElD;;;;;OAKG;IACH,kBAAiD;IAkBjD;;;;;OAKG;IACH,0BAaC;IAED;;;;;;;OAOG;IACH,gBAWC;IAED;;;;;;OAMG;IACH,QAJW,MAAM,KACN,MAAM,GACJ,OAAO,CA0BnB;IAED;;;;;;;;;;OAUG;IACH,eAeC;IAED;;;;;;;;;OASG;IACH,SALW,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,QAsChB;IAED;;;;OAIG;IACH,YAHW,MAAM,UACN,MAAM,QAsBhB;CACJ"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { assert } from "../../../assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bottom-left skyline rectangle packer (Jylänki's skyline-BL). The skyline is a
|
|
5
|
+
* left-to-right sequence of horizontal segments giving the free height at each
|
|
6
|
+
* column; a rectangle is placed at the lowest-then-leftmost position whose span
|
|
7
|
+
* fits, raising the skyline over its footprint. O(segments) per placement — the
|
|
8
|
+
* scalable packer for large atlases where the exact bitmap canBlit scan is too
|
|
9
|
+
* slow.
|
|
10
|
+
*
|
|
11
|
+
* Segments are packed as `(x, y, width)` uint32 triplets in a single typed
|
|
12
|
+
* array (not an array of objects) for cache locality and zero per-placement
|
|
13
|
+
* allocation: {@link place} rebuilds into a reused scratch buffer and swaps.
|
|
14
|
+
* Rectangles never overlap; simple skyline (no waste-map), so a little space is
|
|
15
|
+
* left under overhangs — fine for texture atlases.
|
|
16
|
+
*
|
|
17
|
+
* @author Alex Goldring
|
|
18
|
+
* @copyright Company Named Limited (c) 2026
|
|
19
|
+
*/
|
|
20
|
+
export class Skyline {
|
|
21
|
+
/** Current bounds width. @type {number} */
|
|
22
|
+
width = 0;
|
|
23
|
+
/** Current bounds height. @type {number} */
|
|
24
|
+
height = 0;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* x of the most recent successful {@link find} (valid only when `find`
|
|
28
|
+
* returned true).
|
|
29
|
+
* @type {number}
|
|
30
|
+
*/
|
|
31
|
+
found_x = 0;
|
|
32
|
+
/** y of the most recent successful {@link find}. @type {number} */
|
|
33
|
+
found_y = 0;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Live segment count.
|
|
37
|
+
* @type {number}
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
__count = 1;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Capacity in triplets of {@link __segments} and {@link __scratch}.
|
|
44
|
+
* @type {number}
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
__capacity = 16;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Packed `(x, y, width)` triplets, x-ascending. Segment k spans columns
|
|
51
|
+
* `[x_k, x_k + width_k)` at free height `y_k`.
|
|
52
|
+
* @type {Uint32Array}
|
|
53
|
+
* @private
|
|
54
|
+
*/
|
|
55
|
+
__segments = new Uint32Array(this.__capacity * 3);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Scratch buffer reused by {@link place} to rebuild the segment list, then
|
|
59
|
+
* swapped with {@link __segments}.
|
|
60
|
+
* @type {Uint32Array}
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
__scratch = new Uint32Array(this.__capacity * 3);
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {number} width
|
|
67
|
+
* @param {number} height
|
|
68
|
+
*/
|
|
69
|
+
constructor(width, height) {
|
|
70
|
+
assert.isNonNegativeInteger(width, "width");
|
|
71
|
+
assert.isNonNegativeInteger(height, "height");
|
|
72
|
+
|
|
73
|
+
this.width = width;
|
|
74
|
+
this.height = height;
|
|
75
|
+
this.__count = 1;
|
|
76
|
+
this.__segments[0] = 0;
|
|
77
|
+
this.__segments[1] = 0;
|
|
78
|
+
this.__segments[2] = width;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Grow the segment and scratch buffers to hold at least `triplets`
|
|
83
|
+
* segments, preserving the live segments.
|
|
84
|
+
* @param {number} triplets
|
|
85
|
+
* @private
|
|
86
|
+
*/
|
|
87
|
+
__ensure_capacity(triplets) {
|
|
88
|
+
if (this.__capacity >= triplets) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
let cap = this.__capacity;
|
|
92
|
+
while (cap < triplets) {
|
|
93
|
+
cap *= 2;
|
|
94
|
+
}
|
|
95
|
+
const grown = new Uint32Array(cap * 3);
|
|
96
|
+
grown.set(this.__segments.subarray(0, this.__count * 3));
|
|
97
|
+
this.__segments = grown;
|
|
98
|
+
this.__scratch = new Uint32Array(cap * 3);
|
|
99
|
+
this.__capacity = cap;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Highest segment `y` across the columns `[segments[i].x, x_right)` — the
|
|
104
|
+
* floor a rectangle would rest on if its left edge started at segment `i`.
|
|
105
|
+
* @param {number} i start segment index
|
|
106
|
+
* @param {number} x_right exclusive right edge of the span
|
|
107
|
+
* @returns {number}
|
|
108
|
+
* @private
|
|
109
|
+
*/
|
|
110
|
+
__level(i, x_right) {
|
|
111
|
+
const seg = this.__segments;
|
|
112
|
+
const count = this.__count;
|
|
113
|
+
let max_y = 0;
|
|
114
|
+
for (let j = i; j < count && seg[j * 3] < x_right; j++) {
|
|
115
|
+
const y = seg[j * 3 + 1];
|
|
116
|
+
if (y > max_y) {
|
|
117
|
+
max_y = y;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return max_y;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Find the lowest-then-leftmost position for a `w x h` rectangle. On success
|
|
125
|
+
* stores it in {@link found_x}/{@link found_y}. Does not mutate the skyline.
|
|
126
|
+
* @param {number} w rectangle width
|
|
127
|
+
* @param {number} h rectangle height
|
|
128
|
+
* @returns {boolean} true if it fits within the current bounds
|
|
129
|
+
*/
|
|
130
|
+
find(w, h) {
|
|
131
|
+
const seg = this.__segments;
|
|
132
|
+
const count = this.__count;
|
|
133
|
+
let best_y = Infinity;
|
|
134
|
+
let best_x = -1;
|
|
135
|
+
|
|
136
|
+
for (let i = 0; i < count; i++) {
|
|
137
|
+
const x = seg[i * 3];
|
|
138
|
+
if (x + w > this.width) {
|
|
139
|
+
break; // segments are x-ascending: nothing further right fits
|
|
140
|
+
}
|
|
141
|
+
const y = this.__level(i, x + w);
|
|
142
|
+
if (y + h <= this.height && (y < best_y || (y === best_y && x < best_x))) {
|
|
143
|
+
best_y = y;
|
|
144
|
+
best_x = x;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (best_x === -1) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
this.found_x = best_x;
|
|
152
|
+
this.found_y = best_y;
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Append segment `(x, y, width)` to `scratch[n]`, merging into the previous
|
|
158
|
+
* scratch segment when they are adjacent at the same height.
|
|
159
|
+
* @param {Uint32Array} scratch
|
|
160
|
+
* @param {number} n current scratch segment count
|
|
161
|
+
* @param {number} x
|
|
162
|
+
* @param {number} y
|
|
163
|
+
* @param {number} width
|
|
164
|
+
* @returns {number} the new scratch segment count
|
|
165
|
+
* @private
|
|
166
|
+
*/
|
|
167
|
+
__emit(scratch, n, x, y, width) {
|
|
168
|
+
if (width <= 0) {
|
|
169
|
+
return n;
|
|
170
|
+
}
|
|
171
|
+
if (n > 0) {
|
|
172
|
+
const last = (n - 1) * 3;
|
|
173
|
+
if (scratch[last + 1] === y && scratch[last] + scratch[last + 2] === x) {
|
|
174
|
+
scratch[last + 2] += width;
|
|
175
|
+
return n;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
scratch[n * 3] = x;
|
|
179
|
+
scratch[n * 3 + 1] = y;
|
|
180
|
+
scratch[n * 3 + 2] = width;
|
|
181
|
+
return n + 1;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Raise the skyline to account for a `w x h` rectangle placed at (x, y).
|
|
186
|
+
* Rebuilds the (still x-sorted) segment list into the scratch buffer — the
|
|
187
|
+
* portions of old segments left of x and right of x+w, with the new top
|
|
188
|
+
* segment between them — then swaps it in. No per-segment allocation.
|
|
189
|
+
* @param {number} x placement left edge
|
|
190
|
+
* @param {number} y placement bottom edge
|
|
191
|
+
* @param {number} w rectangle width
|
|
192
|
+
* @param {number} h rectangle height
|
|
193
|
+
*/
|
|
194
|
+
place(x, y, w, h) {
|
|
195
|
+
// worst case: one segment straddling both edges -> 2 clips + the new top
|
|
196
|
+
this.__ensure_capacity(this.__count + 2);
|
|
197
|
+
|
|
198
|
+
const seg = this.__segments;
|
|
199
|
+
const scratch = this.__scratch;
|
|
200
|
+
const count = this.__count;
|
|
201
|
+
const top = y + h;
|
|
202
|
+
const xr = x + w;
|
|
203
|
+
let n = 0;
|
|
204
|
+
|
|
205
|
+
// portions of segments left of x (x-ascending -> emitted in order)
|
|
206
|
+
for (let i = 0; i < count; i++) {
|
|
207
|
+
const sx = seg[i * 3];
|
|
208
|
+
if (sx < x) {
|
|
209
|
+
const right = Math.min(sx + seg[i * 3 + 2], x);
|
|
210
|
+
n = this.__emit(scratch, n, sx, seg[i * 3 + 1], right - sx);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// the new top segment, in x-order between the left and right portions
|
|
215
|
+
n = this.__emit(scratch, n, x, top, w);
|
|
216
|
+
|
|
217
|
+
// portions of segments right of x+w
|
|
218
|
+
for (let i = 0; i < count; i++) {
|
|
219
|
+
const sx = seg[i * 3];
|
|
220
|
+
const send = sx + seg[i * 3 + 2];
|
|
221
|
+
if (send > xr) {
|
|
222
|
+
const left = Math.max(sx, xr);
|
|
223
|
+
n = this.__emit(scratch, n, left, seg[i * 3 + 1], send - left);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
this.__segments = scratch;
|
|
228
|
+
this.__scratch = seg;
|
|
229
|
+
this.__count = n;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Enlarge the bounds, preserving placements. The new width starts at y=0.
|
|
234
|
+
* @param {number} width new width (>= current)
|
|
235
|
+
* @param {number} height new height (>= current)
|
|
236
|
+
*/
|
|
237
|
+
grow(width, height) {
|
|
238
|
+
if (width > this.width) {
|
|
239
|
+
const last = (this.__count - 1) * 3;
|
|
240
|
+
const seg = this.__segments;
|
|
241
|
+
if (seg[last + 1] === 0 && seg[last] + seg[last + 2] === this.width) {
|
|
242
|
+
// extend the trailing floor segment in place
|
|
243
|
+
seg[last + 2] += width - this.width;
|
|
244
|
+
} else {
|
|
245
|
+
this.__ensure_capacity(this.__count + 1);
|
|
246
|
+
const k = this.__count * 3;
|
|
247
|
+
this.__segments[k] = this.width;
|
|
248
|
+
this.__segments[k + 1] = 0;
|
|
249
|
+
this.__segments[k + 2] = width - this.width;
|
|
250
|
+
this.__count++;
|
|
251
|
+
}
|
|
252
|
+
this.width = width;
|
|
253
|
+
}
|
|
254
|
+
if (height > this.height) {
|
|
255
|
+
this.height = height;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conservative rasterization of a 2D triangle into a bit image: every cell
|
|
3
|
+
* whose unit square overlaps the triangle is set (a superset of exact coverage),
|
|
4
|
+
* so the resulting mask never under-covers — required for packing gutters.
|
|
5
|
+
* Overlap is decided by the separating-axis test between the triangle and each
|
|
6
|
+
* candidate cell square.
|
|
7
|
+
*
|
|
8
|
+
* @param {{width:number, height:number, set:(x:number,y:number)=>void}} image
|
|
9
|
+
* @param {number} x0 @param {number} y0
|
|
10
|
+
* @param {number} x1 @param {number} y1
|
|
11
|
+
* @param {number} x2 @param {number} y2
|
|
12
|
+
*/
|
|
13
|
+
export function tri2_rasterize_conservative(image: {
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
set: (x: number, y: number) => void;
|
|
17
|
+
}, x0: number, y0: number, x1: number, y1: number, x2: number, y2: number): void;
|
|
18
|
+
//# sourceMappingURL=tri2_rasterize_conservative.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tri2_rasterize_conservative.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/2d/triangle/tri2_rasterize_conservative.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH;WALkB,MAAM;YAAS,MAAM;aAAS,MAAM,KAAG,MAAM,KAAG,IAAI;OAC3D,MAAM,MAAa,MAAM,MACzB,MAAM,MAAa,MAAM,MACzB,MAAM,MAAa,MAAM,QAoBnC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conservative rasterization of a 2D triangle into a bit image: every cell
|
|
3
|
+
* whose unit square overlaps the triangle is set (a superset of exact coverage),
|
|
4
|
+
* so the resulting mask never under-covers — required for packing gutters.
|
|
5
|
+
* Overlap is decided by the separating-axis test between the triangle and each
|
|
6
|
+
* candidate cell square.
|
|
7
|
+
*
|
|
8
|
+
* @param {{width:number, height:number, set:(x:number,y:number)=>void}} image
|
|
9
|
+
* @param {number} x0 @param {number} y0
|
|
10
|
+
* @param {number} x1 @param {number} y1
|
|
11
|
+
* @param {number} x2 @param {number} y2
|
|
12
|
+
*/
|
|
13
|
+
export function tri2_rasterize_conservative(image, x0, y0, x1, y1, x2, y2) {
|
|
14
|
+
let min_x = Math.floor(Math.min(x0, x1, x2));
|
|
15
|
+
let min_y = Math.floor(Math.min(y0, y1, y2));
|
|
16
|
+
let max_x = Math.ceil(Math.max(x0, x1, x2));
|
|
17
|
+
let max_y = Math.ceil(Math.max(y0, y1, y2));
|
|
18
|
+
|
|
19
|
+
if (min_x < 0) min_x = 0;
|
|
20
|
+
if (min_y < 0) min_y = 0;
|
|
21
|
+
if (max_x > image.width) max_x = image.width;
|
|
22
|
+
if (max_y > image.height) max_y = image.height;
|
|
23
|
+
|
|
24
|
+
for (let py = min_y; py < max_y; py++) {
|
|
25
|
+
for (let px = min_x; px < max_x; px++) {
|
|
26
|
+
if (tri_box_overlap(x0, y0, x1, y1, x2, y2, px, py, px + 1, py + 1)) {
|
|
27
|
+
image.set(px, py);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Separating-axis overlap test between a triangle and an axis-aligned box.
|
|
35
|
+
*
|
|
36
|
+
* @param {number} ax @param {number} ay first triangle vertex
|
|
37
|
+
* @param {number} bx @param {number} by second triangle vertex
|
|
38
|
+
* @param {number} cx @param {number} cy third triangle vertex
|
|
39
|
+
* @param {number} bminx @param {number} bminy box minimum corner
|
|
40
|
+
* @param {number} bmaxx @param {number} bmaxy box maximum corner
|
|
41
|
+
* @returns {boolean} true if the triangle and box overlap
|
|
42
|
+
*/
|
|
43
|
+
function tri_box_overlap(ax, ay, bx, by, cx, cy, bminx, bminy, bmaxx, bmaxy) {
|
|
44
|
+
// Box axes (x then y).
|
|
45
|
+
if (Math.max(ax, bx, cx) < bminx || Math.min(ax, bx, cx) > bmaxx) return false;
|
|
46
|
+
if (Math.max(ay, by, cy) < bminy || Math.min(ay, by, cy) > bmaxy) return false;
|
|
47
|
+
|
|
48
|
+
// Triangle edge normals.
|
|
49
|
+
if (edge_separates(ax, ay, bx, by, cx, cy, bminx, bminy, bmaxx, bmaxy)) return false;
|
|
50
|
+
if (edge_separates(bx, by, cx, cy, ax, ay, bminx, bminy, bmaxx, bmaxy)) return false;
|
|
51
|
+
if (edge_separates(cx, cy, ax, ay, bx, by, bminx, bminy, bmaxx, bmaxy)) return false;
|
|
52
|
+
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Does the outward normal of edge (p->q) separate the box from the triangle?
|
|
58
|
+
* `r` is the triangle's third vertex (to orient the normal inward).
|
|
59
|
+
*
|
|
60
|
+
* @param {number} px @param {number} py edge start vertex
|
|
61
|
+
* @param {number} qx @param {number} qy edge end vertex
|
|
62
|
+
* @param {number} rx @param {number} ry triangle's third vertex
|
|
63
|
+
* @param {number} bminx @param {number} bminy box minimum corner
|
|
64
|
+
* @param {number} bmaxx @param {number} bmaxy box maximum corner
|
|
65
|
+
* @returns {boolean} true if this edge's axis separates the box from the triangle
|
|
66
|
+
*/
|
|
67
|
+
function edge_separates(px, py, qx, qy, rx, ry, bminx, bminy, bmaxx, bmaxy) {
|
|
68
|
+
const nx = -(qy - py);
|
|
69
|
+
const ny = qx - px;
|
|
70
|
+
|
|
71
|
+
// triangle interval along n
|
|
72
|
+
const dp = nx * px + ny * py;
|
|
73
|
+
const dr = nx * rx + ny * ry;
|
|
74
|
+
let tri_min, tri_max;
|
|
75
|
+
if (dp < dr) { tri_min = dp; tri_max = dr; } else { tri_min = dr; tri_max = dp; }
|
|
76
|
+
|
|
77
|
+
// box interval along n (4 corners)
|
|
78
|
+
const c0 = nx * bminx + ny * bminy;
|
|
79
|
+
const c1 = nx * bmaxx + ny * bminy;
|
|
80
|
+
const c2 = nx * bminx + ny * bmaxy;
|
|
81
|
+
const c3 = nx * bmaxx + ny * bmaxy;
|
|
82
|
+
const box_min = Math.min(c0, c1, c2, c3);
|
|
83
|
+
const box_max = Math.max(c0, c1, c2, c3);
|
|
84
|
+
|
|
85
|
+
return box_max < tri_min || box_min > tri_max;
|
|
86
|
+
}
|