Skip to main content

roxlap_core/
lib.rs

1//! roxlap engine core.
2//!
3//! A pure-Rust port of Ken Silverman's Voxlap voxel engine. See
4//! `PORTING-RUST.md` at the workspace root for the substage roadmap.
5//!
6//! Stage R3 lands the public [`Engine`] / [`Camera`] surface with a
7//! sky-fill stub renderer. R4 replaces the stub with the full
8//! opticast + grouscan algorithm.
9//!
10//! # World handedness and the horizontal mirror
11//!
12//! roxlap's world is **z-down**: `x` = east, `y` = north, `z` points
13//! *down* into the map. Physically the triple (east, north, up) is
14//! left-handed, so a faithfully-projected view is **horizontally
15//! mirrored** relative to a real camera at the same heading — the
16//! viewer's geometric *right* lands on screen-*left*. This is Voxlap's
17//! native convention; it is baked into the projection, the frustum
18//! cull, the scan loops, and every bit-exact oracle golden, and is
19//! reproduced deliberately. It is **not** a bug.
20//!
21//! The camera basis the engine actually renders with is
22//! right-handed in the `(right, down, forward)` sense
23//! (`right × down = +forward`). Build it with
24//! [`Camera::from_yaw_pitch`], [`Camera::orbit`], or
25//! [`Camera::look_at`] — never by rotating [`Camera::default`], whose
26//! placeholder basis is left-handed and will make the sprite cull
27//! reject every sprite.
28//!
29//! ## I want an un-mirrored world
30//!
31//! Do **not** "fix" the mirror by negating `right` in the basis. That
32//! flips the chirality to `right × down = -forward`; the world still
33//! renders, but the sprite frustum cull then rejects every sprite
34//! (and you diverge from the oracle goldens). The mirror is in the
35//! projection, not the basis.
36//!
37//! Handle it on the **consumer side** instead — pick one and stay
38//! consistent:
39//!
40//! - mirror a single world axis in your scene → world mapping (e.g.
41//!   negate world-x when you place content), or
42//! - negate your yaw input so headings sweep the opposite way.
43//!
44//! Either re-establishes the chirality your project expects without
45//! touching the engine. (A true engine-side de-mirror would mean
46//! negating screen-x in *both* the grid raycaster and the sprite
47//! rasteriser while preserving the cull's normal winding — a large,
48//! golden-breaking change that diverges from Voxlap, and is out of
49//! scope here.)
50
51mod camera;
52pub mod camera_math;
53pub(crate) mod column_walk;
54pub mod drawtile;
55mod engine;
56// `equivec` (voxlap's normal table) moved to roxlap-formats so kv6
57// model builders can fill per-voxel `dir` without a circular dep;
58// re-exported here so in-crate `crate::equivec::…` paths (the sprite
59// `kv6colmul` build) keep resolving.
60pub(crate) use roxlap_formats::equivec;
61pub(crate) mod fixed;
62pub mod gline;
63pub mod grid_view;
64pub(crate) mod grouscan;
65pub mod kfa_draw;
66pub mod meltsphere;
67pub mod opticast;
68pub mod opticast_prelude;
69pub(crate) mod projection;
70pub(crate) mod ptfaces16;
71pub mod rasterizer;
72pub mod ray_aabb;
73pub(crate) mod ray_step;
74pub mod scalar_rasterizer;
75pub(crate) mod scan_loops;
76pub mod sky;
77pub mod sprite;
78pub mod world_lighting;
79pub mod world_query;
80
81pub use camera::Camera;
82pub use engine::{Engine, LightSrc, DEFAULT_KV6COL};
83pub use grid_view::{ChunkGrid, GridView};
84pub use opticast::{opticast, OpticastOutcome, OpticastSettings};
85pub use world_lighting::{
86    apply_lighting_with_cache, update_lighting, update_lighting_chunk, EstNormCache,
87};