use crate::Camera;
#[derive(Debug, Clone, Copy)]
pub struct CameraState {
pub pos: [f32; 3],
pub right: [f32; 3],
pub down: [f32; 3],
pub forward: [f32; 3],
pub corn: [[f32; 3]; 4],
}
#[allow(
clippy::cast_possible_truncation,
clippy::cast_precision_loss,
clippy::cast_lossless
)]
#[must_use]
pub fn derive(camera: &Camera, xres: u32, yres: u32, hx: f32, hy: f32, hz: f32) -> CameraState {
let pos = camera.pos.map(|v| v as f32);
let right = camera.right.map(|v| v as f32);
let down = camera.down.map(|v| v as f32);
let forward = camera.forward.map(|v| v as f32);
let ray = |sx: f32, sy: f32| {
[
sx * right[0] + sy * down[0] + hz * forward[0],
sx * right[1] + sy * down[1] + hz * forward[1],
sx * right[2] + sy * down[2] + hz * forward[2],
]
};
let (w, h) = (xres as f32, yres as f32);
let corn = [
ray(-hx, -hy),
ray(w - hx, -hy),
ray(w - hx, h - hy),
ray(-hx, h - hy),
];
CameraState {
pos,
right,
down,
forward,
corn,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn bits3(a: [f32; 3]) -> [u32; 3] {
a.map(f32::to_bits)
}
fn identity_cam() -> Camera {
Camera {
pos: [0.0, 0.0, 0.0],
right: [1.0, 0.0, 0.0],
down: [0.0, 0.0, 1.0],
forward: [0.0, 1.0, 0.0],
}
}
#[test]
fn identity_camera_basis_and_corners() {
let s = derive(&identity_cam(), 640, 480, 320.0, 240.0, 320.0);
assert_eq!(bits3(s.right), bits3([1.0, 0.0, 0.0]));
assert_eq!(bits3(s.down), bits3([0.0, 0.0, 1.0]));
assert_eq!(bits3(s.forward), bits3([0.0, 1.0, 0.0]));
assert_eq!(bits3(s.corn[0]), bits3([-320.0, 320.0, -240.0]));
assert_eq!(bits3(s.corn[1]), bits3([320.0, 320.0, -240.0]));
assert_eq!(bits3(s.corn[2]), bits3([320.0, 320.0, 240.0]));
assert_eq!(bits3(s.corn[3]), bits3([-320.0, 320.0, 240.0]));
}
#[test]
fn yawed_camera_corner_propagates() {
let cam = Camera {
pos: [0.0, 0.0, 0.0],
right: [0.0, 1.0, 0.0],
down: [0.0, 0.0, 1.0],
forward: [-1.0, 0.0, 0.0],
};
let s = derive(&cam, 640, 480, 320.0, 240.0, 320.0);
assert_eq!(bits3(s.corn[0]), bits3([-320.0, -320.0, -240.0]));
}
#[test]
fn position_is_narrowed_through() {
let cam = Camera {
pos: [10.5, 20.25, 30.0],
..identity_cam()
};
let s = derive(&cam, 64, 64, 32.0, 32.0, 32.0);
assert_eq!(bits3(s.pos), bits3([10.5, 20.25, 30.0]));
}
}