Skip to main content

roxlap_core/
opticast.rs

1//! Per-frame render settings shared by the CPU renderer.
2//!
3//! Historically this module also held voxlap's `opticast` orchestrator
4//! (the four-quadrant 2.5D scan loops). That renderer was replaced by
5//! the per-pixel 3D-DDA renderer in [`crate::dda`] and removed; what
6//! remains is [`OpticastSettings`], the framebuffer + projection +
7//! scan-distance bundle both the DDA renderer and the sprite raycaster
8//! still consume. (The name is kept for API stability; "opticast"
9//! survives only as a label for the settings struct.)
10
11/// Per-frame settings the renderer forwards through its passes. Most
12/// fields map onto a classic raycaster control: `(hx, hy, hz)` are the
13/// pinhole projection centre + focal length (the voxlap `setcamera`
14/// `dahx`/`dahy`/`dahz`), `mip_*` drive the distance-mip ladder, and
15/// `max_scan_dist` bounds the ray.
16///
17/// `y_start..y_end` is the strip-render iteration bound. Default is the
18/// full framebuffer (`0..yres`). Tile / strip callers set a sub-range
19/// to render only that horizontal strip; the projection centre stays in
20/// absolute screen coords, only the viewport edges shrink.
21#[derive(Debug, Clone, Copy)]
22pub struct OpticastSettings {
23    pub xres: u32,
24    pub yres: u32,
25    /// First y-row this render call covers (inclusive). `0` for
26    /// full-frame.
27    pub y_start: u32,
28    /// One past the last y-row (exclusive). `yres` for full-frame.
29    pub y_end: u32,
30    pub hx: f32,
31    pub hy: f32,
32    pub hz: f32,
33    pub anginc: f32,
34    pub mip_levels: u32,
35    pub mip_scan_dist: i32,
36    pub max_scan_dist: i32,
37}
38
39impl OpticastSettings {
40    /// Default settings for a `width × height` framebuffer with the
41    /// convention `(hx, hy, hz) = (w/2, h/2, w/2)` and `anginc = 1`.
42    /// Renders the full frame (`y_start = 0, y_end = height`).
43    //
44    // `width` / `height` cast to f32 is bounded by realistic screen
45    // sizes (≤ 16M, well within f32's 24-bit mantissa).
46    #[allow(clippy::cast_precision_loss)]
47    #[must_use]
48    pub fn for_oracle_framebuffer(width: u32, height: u32) -> Self {
49        let half_w = (width as f32) * 0.5;
50        let half_h = (height as f32) * 0.5;
51        Self {
52            xres: width,
53            yres: height,
54            y_start: 0,
55            y_end: height,
56            hx: half_w,
57            hy: half_h,
58            hz: half_w,
59            anginc: 1.0,
60            mip_levels: 1,
61            mip_scan_dist: 4,
62            max_scan_dist: 1024,
63        }
64    }
65
66    /// Restrict this settings struct to the `[y_start, y_end)`
67    /// horizontal strip. Used by the per-strip parallel dispatch — each
68    /// strip clones the base settings and clamps the y-range. Caller is
69    /// responsible for ensuring `y_start < y_end <= yres`.
70    #[must_use]
71    pub fn with_y_range(mut self, y_start: u32, y_end: u32) -> Self {
72        self.y_start = y_start;
73        self.y_end = y_end;
74        self
75    }
76}