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

nordisk/facett

facett-graphview/examples/world_mega_still.rs

//! **world_mega_still** — ONE gigantic composite still of the whole code-universe graph:
//! a dense high-res RASTER of the node/edge cloud (tiled on the GPU past the 2048² cap and
//! stitched) with a crisp vector TEXT/label layer (repo labels at cluster centroids, a
//! title, a colour↔repo legend, node/edge counts, a timestamp) burned OVER it into ONE
//! image. Reuses the shared instanced GPU cloud + the world galaxy layout + categorical
//! colour; the text is rasterised + composited by pure-Rust resvg/usvg/tiny_skia.
//!
//! Outputs `<base>.png` (the huge composite) + `<base>.svg` (the scalable text layer).
//!
//! FORMAT: PNG, not JPEG2000 — there is NO pure-Rust JPEG2000 encoder on crates.io (every
//! JP2 crate binds C OpenJPEG, forbidden here). PNG is the lossless pure-Rust raster; the
//! text also stays crisp/scalable in the separate `.svg`. No C imaging tool is shelled out.
//!
//! ```bash
//! cargo run -p facett-graphview --features gpu --example world_mega_still --release -- \
//!     100000 8960 ~/git/workspace_nordisk/scratch/world-mega-still
//! ```

use std::time::Instant;

use facett_graphview::world::{layout_world, LayoutBudget, Lod, WorldGraph};
use facett_graphview::world_still::{
    burn_svg_over_rgba, render_world_still_mega, world_text_svg, MegaLabels,
};

fn main() {
    let args: Vec<String> = std::env::args().skip(1).collect();
    let target: usize = args.first().and_then(|s| s.parse().ok()).unwrap_or(100_000);
    // Mega edge in px. Rounded down to a multiple of the tile so tiling is clean.
    let mega_req: u32 = args.get(1).and_then(|s| s.parse().ok()).unwrap_or(8960);
    let base = args
        .get(2)
        .cloned()
        .unwrap_or_else(|| format!("{}/git/workspace_nordisk/scratch/world-mega-still", std::env::var("HOME").unwrap_or_default()));
    let dark = !args.iter().any(|a| a == "light");

    // Tiling: interior 1792 + 128 halo per side = 2048 (the downlevel max texture). The
    // halo keeps bloom seamless across tile seams.
    let tile: u32 = 1792;
    let halo: u32 = 128;
    let tiles_side = (mega_req.max(tile) as f32 / tile as f32).round().max(1.0) as u32;
    let mega = tile * tiles_side; // clean multiple of the tile
    let edge_cap = 400_000usize;

    let t0 = Instant::now();
    let w = WorldGraph::synthetic(target, Lod::Functions, true);
    let build_ms = t0.elapsed().as_secs_f64() * 1e3;

    let t1 = Instant::now();
    let (pos, lane) = layout_world(&w, &LayoutBudget::default());
    let layout_ms = t1.elapsed().as_secs_f64() * 1e3;

    // 1) Dense RASTER (tiled GPU cloud, stitched).
    let t2 = Instant::now();
    let Some(mut raster) = render_world_still_mega(&w, &pos, mega, mega, dark, edge_cap, tile, halo)
    else {
        eprintln!("world_mega_still: NO usable GPU adapter — the mega/still path builds but needs a device here");
        std::process::exit(2);
    };
    let render_ms = t2.elapsed().as_secs_f64() * 1e3;

    // 2) Crisp vector TEXT layer (SVG), kept as a scalable sidecar too.
    let opts = MegaLabels {
        title: "facett — the code-universe graph".into(),
        dark,
        node_count: w.n,
        edge_count: w.edges.len(),
        synthetic: w.synthetic_flag(),
        timestamp: format!("rendered {} · lane={}", today(), lane.key()),
        max_repo_labels: 120,
    };
    let svg = world_text_svg(&w, &pos, raster.width, raster.height, &opts);
    let svg_path = format!("{base}.svg");
    std::fs::write(&svg_path, &svg).expect("write SVG text layer");

    // 3) BURN IN — composite the crisp text OVER the raster, flatten to ONE image.
    let t3 = Instant::now();
    let burned = burn_svg_over_rgba(&mut raster.rgba, raster.width, raster.height, &svg);
    let burn_ms = t3.elapsed().as_secs_f64() * 1e3;

    // 4) Save the composite. PNG — the honest pure-Rust high-quality raster (no JP2 in Rust).
    let png_path = format!("{base}.png");
    image::save_buffer(
        &png_path,
        &raster.rgba,
        raster.width,
        raster.height,
        image::ColorType::Rgba8,
    )
    .expect("write composite PNG");
    let png_bytes = std::fs::metadata(&png_path).map(|m| m.len()).unwrap_or(0);

    println!(
        "world_mega_still: target={target} nodes={} edges={} lane={} synthetic={}\n  \
         build={build_ms:.1}ms layout={layout_ms:.1}ms render={render_ms:.1}ms burn={burn_ms:.1}ms\n  \
         raster {}x{} in {} tiles ({}px interior + {}px halo) · scene {} nodes + {} edges\n  \
         text burned in: {} · format: PNG (pure Rust — NO pure-Rust JPEG2000 encoder exists)\n  \
         composite → {png_path} ({:.1} MB)\n  text layer → {svg_path}",
        w.n, w.edges.len(), lane.key(), w.synthetic_flag(),
        raster.width, raster.height, raster.tiles, tile, halo,
        raster.nodes, raster.edges, burned,
        png_bytes as f64 / 1e6,
    );
}

/// A tiny date stamp (UTC yyyy-mm-dd) with no chrono dep — from the system clock.
fn today() -> String {
    let secs = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_secs())
        .unwrap_or(0);
    let days = secs / 86_400;
    // Civil-from-days (Howard Hinnant's algorithm).
    let z = days as i64 + 719_468;
    let era = z.div_euclid(146_097);
    let doe = z - era * 146_097;
    let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146_096) / 365;
    let y = yoe + era * 400;
    let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
    let mp = (5 * doy + 2) / 153;
    let d = doy - (153 * mp + 2) / 5 + 1;
    let m = if mp < 10 { mp + 3 } else { mp - 9 };
    let y = if m <= 2 { y + 1 } else { y };
    format!("{y:04}-{m:02}-{d:02}")
}