use crate::camera_math::CameraState;
use crate::fixed::ftol;
use crate::opticast_prelude::PREC;
#[derive(Debug, Clone, Copy)]
pub struct RayStep {
pub strx: f32,
pub stry: f32,
pub heix: f32,
pub heiy: f32,
pub addx: f32,
pub addy: f32,
pub cx16: i32,
pub cy16: i32,
}
#[allow(
clippy::cast_precision_loss,
clippy::cast_possible_truncation,
// strx/stry, heix/heiy, addx/addy, cx16/cy16 are voxlap names.
clippy::similar_names
)]
#[must_use]
pub fn derive_ray_step(camera_state: &CameraState, cx: f32, cy: f32, hz: f32) -> RayStep {
let f = (PREC as f32) / hz;
let strx = camera_state.right[0] * f;
let stry = camera_state.right[1] * f;
let heix = camera_state.down[0] * f;
let heiy = camera_state.down[1] * f;
let addx = camera_state.corn[0][0] * f;
let addy = camera_state.corn[0][1] * f;
let cx16 = ftol(cx * 65536.0);
let cy16 = ftol(cy * 65536.0);
RayStep {
strx,
stry,
heix,
heiy,
addx,
addy,
cx16,
cy16,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::camera_math;
use crate::Camera;
fn bit(v: f32) -> u32 {
v.to_bits()
}
fn looking_down_state() -> CameraState {
let cam = Camera {
pos: [0.0, 0.0, 0.0],
right: [1.0, 0.0, 0.0],
down: [0.0, 1.0, 0.0],
forward: [0.0, 0.0, 1.0],
};
camera_math::derive(&cam, 640, 480, 320.0, 240.0, 320.0)
}
#[test]
#[allow(clippy::cast_precision_loss)]
fn ray_step_for_looking_down_camera() {
let s = looking_down_state();
let r = derive_ray_step(&s, 320.0, 240.0, 320.0);
let f = (PREC as f32) / 320.0;
assert_eq!(bit(r.strx), bit(f));
assert_eq!(bit(r.stry), bit(0.0));
assert_eq!(bit(r.heix), bit(0.0));
assert_eq!(bit(r.heiy), bit(f));
assert_eq!(bit(r.addx), bit(-320.0 * f));
assert_eq!(bit(r.addy), bit(-240.0 * f));
}
#[test]
fn fixed_point_centre_for_integer_inputs() {
let s = looking_down_state();
let r = derive_ray_step(&s, 320.0, 240.0, 320.0);
assert_eq!(r.cx16, 20_971_520);
assert_eq!(r.cy16, 15_728_640);
}
#[test]
fn fixed_point_centre_round_ties_to_even_at_half() {
let s = looking_down_state();
let r = derive_ray_step(&s, 0.5_f32 / 65536.0_f32, 1.5_f32 / 65536.0_f32, 320.0);
assert_eq!(r.cx16, 0);
assert_eq!(r.cy16, 2);
}
#[test]
fn fixed_point_centre_for_negative_half() {
let s = looking_down_state();
let r = derive_ray_step(&s, -0.5_f32 / 65536.0_f32, -1.5_f32 / 65536.0_f32, 320.0);
assert_eq!(r.cx16, 0);
assert_eq!(r.cy16, -2);
}
#[test]
fn z_components_not_present_in_ray_step() {
let s = looking_down_state();
let r = derive_ray_step(&s, 320.0, 240.0, 320.0);
let _ = (r.strx, r.stry, r.heix, r.heiy, r.addx, r.addy);
}
}