Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-map/tests/side_carries_depth.rs

//! **Depth rides in `LineVertex::side`, keeping the vertex at 48 B** — lane MP-a.
//!
//! # Why per-DRAW depth is not enough
//!
//! The tile lane's draw is **already band-major** (`gpu/mod.rs`: *"One run per declared
//! draw band"*, groups single-band by construction, sorted on `(draw_band, tile_key)`).
//! So bands already order correctly across tiles — and the two-tile oracle still fails,
//! because `way_draw_band` **deliberately drops the tier**: motorway and residential are
//! both `LINE_BAND + 200`, one band. Inside a band the draw walks TILES, and the
//! casing/fill two-pass runs per draw, so a later tile's casing lands on an earlier
//! tile's fill.
//!
//! Depth therefore has to be **per way**, not per draw. And it cannot be a new vertex
//! field: `LineVertex` is exactly 48 B, asserted at compile time, and that size is
//! load-bearing — the vertex layout, the chunk partition and the bake format all rest
//! on it.
//!
//! # The spare bit
//!
//! `side` is `+1.0` or `-1.0`: one bit of information in a whole `f32`. Packing the
//! depth into its magnitude — `sign(side) * (1.0 + depth)` — keeps the vertex at 48 B and
//! costs one `abs`/`sign` pair in the shader.
//!
//! Precision is the thing to check rather than assume: in `[1, 2)` an `f32` step is
//! `2^-23 ≈ 1.19e-7`, so a depth is representable to about that, and
//! [`CASING_DEPTH_BIAS`] (`1e-6`) is comfortably above it — a casing and its fill stay
//! distinguishable after the round trip. That is asserted here, not argued.
//!
//! | gate | red arm |
//! |---|---|
//! | side survives the round trip, both signs | drop the sign |
//! | depth survives to better than the casing bias | pack into 8 bits |
//! | the packed value never lands on 0, where `sign` is ambiguous | allow depth −1 |
//!
//! ```bash
//! cargo test -p facett-map --test side_carries_depth
//! ```

use facett_map::paint_order::{pack_side_depth, unpack_depth, unpack_side, CASING_DEPTH_BIAS};

/// **Both halves come back.**
#[test]
fn the_side_and_the_depth_both_survive() {
    for side in [1.0f32, -1.0] {
        for depth in [0.0f32, 0.25, 0.5, 0.75, 1.0] {
            let p = pack_side_depth(side, depth);
            assert_eq!(unpack_side(p), side, "side lost for depth {depth}");
            assert!(
                (unpack_depth(p) - depth).abs() < CASING_DEPTH_BIAS / 4.0,
                "depth {depth} came back {} — the error must stay well under the casing \
                 bias {CASING_DEPTH_BIAS}, or a casing and its own fill collapse",
                unpack_depth(p)
            );
        }
    }
}

/// **A casing and its fill stay apart after the round trip.** This is the whole reason
/// the precision matters: if the packing cannot resolve `CASING_DEPTH_BIAS`, the dark
/// outline lands exactly on the bright line it outlines and the z-fight is worse than
/// the bug being fixed.
#[test]
fn a_casing_and_its_fill_stay_distinguishable() {
    let d = facett_map::paint_order::depth_of(1240, false);
    let c = facett_map::paint_order::depth_of(1240, true);
    let (pd, pc) = (pack_side_depth(1.0, d), pack_side_depth(1.0, c));
    assert!(
        unpack_depth(pc) > unpack_depth(pd),
        "after packing, the casing must still be BEHIND its fill: {} vs {}",
        unpack_depth(pc),
        unpack_depth(pd)
    );
    assert_ne!(pd, pc, "the two must not pack to the same bits");
}

/// **The packed value is never zero**, where `sign` cannot tell `+` from `−`. The
/// magnitude starts at `1.0`, so this holds by construction — asserted because the
/// construction is the guarantee.
#[test]
fn the_packed_value_never_reaches_the_ambiguous_zero() {
    for side in [1.0f32, -1.0] {
        for depth in [0.0f32, 1.0] {
            let p = pack_side_depth(side, depth);
            assert!(p.abs() >= 1.0, "packed {p} for side {side}, depth {depth}");
        }
    }
}