diff options
Diffstat (limited to 'src/camera.rs')
-rw-r--r-- | src/camera.rs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/camera.rs b/src/camera.rs new file mode 100644 index 0000000..d2fbd5e --- /dev/null +++ b/src/camera.rs @@ -0,0 +1,93 @@ +use crate::vector::Vector; +use std::{cmp::{max, min}, f32::consts::PI, f64::MAX_EXP, fmt}; + +const WIDTH: i32 = 60; +const HEIGHT: i32 = 30; + +#[derive(Debug)] +pub struct Buffer (pub [[char; 60]; 30]); + +impl fmt::Display for Buffer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for i in 0..30 { + for j in 0..60 { + write!(f, "{}", self.0[i][j])?; + } + writeln!(f)?; + } + write!(f, "") + } +} + +#[derive(Debug)] +pub struct Camera { + pub position: Vector, + pub direction: Vector, + pub angle: f32, + pub distance: f32, + pub brightness: f32, + pub aspect_ratio: f32, + pub buffer: Buffer, +} + +impl Camera { + pub fn sdf(&self, point: Vector) -> f32 { + let center = Vector { x: 3.0, y: 0.0, z: 0.0 }; + let radius = 1.0; + + return (point - center).magnitude() - radius + } + + pub fn screen(&self) -> (f32, f32) { + let width = self.distance * 2.0 * (self.angle / 2.0).tan(); + let height = width * self.aspect_ratio; + // println!("Screen {}x{} units", width, height); + (width, height) + } + pub fn render(& mut self) { + let palette = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "; + let (screen_width, screen_height) = self.screen(); + + let h_step = self.direction.rotate_z(PI / 2.0).normalized() * screen_width / WIDTH as f32; + let v_step = Vector { x: 0.0, y: 0.0, z: -screen_height / HEIGHT as f32 }; + // println!("Steps: h{}, v{}", h_step, v_step); + + // Initialize with a corner + let point = self.position + (self.direction.normalized() * self.distance) - (h_step * (WIDTH / 2) as f32 + v_step * (HEIGHT / 2) as f32); + // println!("Corner: {}", point); + + let mut ray_dir = point - self.position; + + for i in 0..HEIGHT as usize { + ray_dir = ray_dir + v_step; + for j in 0..WIDTH as usize { + ray_dir = ray_dir + h_step; + + + let brightness = self.shoot_ray(ray_dir); + self.buffer.0[i][j] = palette.chars().nth((brightness * palette.len() as f32) as usize - 1).unwrap(); + // println!("[{}, {}]: {}", i, j, ray_dir); + } + ray_dir = ray_dir - h_step * WIDTH as f32; + } + } + + pub fn shoot_ray(&self, direction: Vector) -> f32 { + let threshold = 0.1; + + let ray = direction.normalized(); + let mut point = self.position; + let mut dist = 0.0; + + while dist < self.brightness { + dist = self.sdf(point); + if dist < threshold { + // println!("Dist: {}, point {}", dist, point); + return (point - self.position).magnitude() / self.brightness + } + point = point + ray * dist; + } + + return 1.0 + } +} |