latkit 0.2.1

Columnar data drawn as vertices, edges, lines, and areas on the GPU.
Documentation
// From positions to the screen. Positions are (high, low) pairs: their difference from the camera's
// center is taken in parts, so f64 data keeps its precision at any zoom. Every pass projects through
// its eye: the view, the light that casts shadows, or an exported image.

import package::lib::types::{SPACE_EARTH};
import package::lib::bind::{frame, eye};

const PI: f32 = 3.14159265;
const TAU: f32 = 6.28318531;
const MAX_LATITUDE: f32 = 85.05113;
// Depth is reversed: the near plane is at 1 and the far plane at 0, which keeps precision far away.
const NEAR_Z: f32 = 1.0;
const FAR_Z: f32 = 0.0;

// The offset of `p` from the camera's center, in position units.
fn relative(hi: vec2f, lo: vec2f) -> vec2f {
    return (hi - frame.center_hi) + (lo - frame.center_lo);
}

fn mercator_y(latitude: f32) -> f32 {
    let lat = radians(clamp(latitude, -MAX_LATITUDE, MAX_LATITUDE));
    return log(tan(PI / 4.0 + lat / 2.0));
}

// Web mercator radians from the center; near the center, a local expansion keeps precision.
fn mercator(hi: vec2f, lo: vec2f) -> vec2f {
    let d = relative(hi, lo);
    let lat = clamp(hi.y + lo.y, -MAX_LATITUDE, MAX_LATITUDE);
    let near = radians(d.y) / cos(radians(lat - 0.5 * d.y));
    let far = mercator_y(lat) - frame.mercator_y;
    return vec2f(radians(d.x), select(far, near, abs(d.y) < 0.25));
}

// `p` on the unit sphere, turned so the camera's center faces +z.
fn on_sphere(hi: vec2f, lo: vec2f) -> vec3f {
    let lon = radians(relative(hi, lo).x);
    let lat = radians(clamp(hi.y + lo.y, -90.0, 90.0));
    let lat0 = radians(frame.center_hi.y + frame.center_lo.y);
    let v = vec3f(cos(lat) * sin(lon), sin(lat), cos(lat) * cos(lon));
    return vec3f(v.x, v.y * cos(lat0) - v.z * sin(lat0), v.y * sin(lat0) + v.z * cos(lat0));
}

// World coordinates: plane or plot units, or mercator radians morphing onto the globe. Only the
// morph works out both.
fn world(hi: vec2f, lo: vec2f, z: f32) -> vec3f {
    if frame.space != SPACE_EARTH {
        return vec3f(relative(hi, lo), z);
    }
    if frame.globe <= 0.0 {
        return vec3f(mercator(hi, lo), z);
    }
    let lat0 = radians(frame.center_hi.y + frame.center_lo.y);
    let s = on_sphere(hi, lo) * (1.0 + z);
    let round = vec3f(s.xy, s.z - 1.0) / cos(lat0);
    if frame.globe >= 1.0 {
        return round;
    }
    return mix(vec3f(mercator(hi, lo), z), round, frame.globe);
}

fn clip_of(w: vec3f) -> vec4f {
    return eye.clip_from_world * vec4f(w, 1.0);
}

fn project(hi: vec2f, lo: vec2f, z: f32) -> vec4f {
    return clip_of(world(hi, lo, z));
}

// The globe's center in world units: a sphere of radius `-center.z` whose top touches the ground at
// the camera's center.
fn globe_center() -> vec3f {
    return vec3f(0.0, 0.0, -1.0 / cos(radians(frame.center_hi.y + frame.center_lo.y)));
}

// Whether world point `w` shows past the globe: on the round globe, whether it lies in front of the
// plane the eye sees the globe's edge on, exactly, at any pitch. On the map, or while the globe
// morphs, everything shows, and what the ground hides is left to its depth.
fn shows(w: vec3f) -> bool {
    if frame.space != SPACE_EARTH || frame.globe < 1.0 {
        return true;
    }
    let c = globe_center();
    return dot(w - c, eye.position.xyz - w) > 0.0;
}

// CSS pixels from the top left.
fn to_screen(clip: vec4f) -> vec2f {
    let ndc = clip.xy / clip.w;
    return (vec2f(ndc.x, -ndc.y) * 0.5 + 0.5) * eye.size;
}

// Clip coordinates for a screen point at the depth of `at`.
fn to_clip(screen: vec2f, at: vec4f) -> vec4f {
    let ndc = screen / eye.size * 2.0 - 1.0;
    return vec4f(vec2f(ndc.x, -ndc.y) * at.w, at.z, at.w);
}

// `clip` a little toward the camera, so a mark lying on a face draws over it.
fn nearer(clip: vec4f) -> vec4f {
    return vec4f(clip.xy, min(clip.z * 1.003, clip.w), clip.w);
}

// A position outside the clip volume: the primitive is dropped.
fn culled() -> vec4f {
    return vec4f(2.0, 2.0, 2.0, 1.0);
}