aboutsummaryrefslogtreecommitdiff
path: root/src/renderer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/renderer.rs')
-rw-r--r--src/renderer.rs92
1 files changed, 51 insertions, 41 deletions
diff --git a/src/renderer.rs b/src/renderer.rs
index 0c6c8d2..6db67e2 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -1,7 +1,9 @@
-use cgmath::Vector3;
use cgmath::prelude::*;
+use cgmath::Vector3;
use ncurses::addstr;
+use rayon::prelude::*;
use std::f32;
+use std::sync::Arc;
use crate::Buffer;
use crate::Camera;
@@ -9,17 +11,16 @@ use crate::Object;
type Vector = Vector3<f32>;
-pub struct Renderer<'a> {
- pub camera: Box<Camera>,
- pub buffer: Box<Buffer>,
- pub sdf: Box<dyn Fn(Vector, f32) -> f32 + 'a>,
+pub struct Renderer {
+ pub camera: Camera,
+ pub buffer: Buffer,
+ pub sdf: Arc<dyn Fn(Vector3<f32>, f32) -> f32 + Send + Sync>,
}
-impl Renderer<'_> {
- // TODO: figure out how the fuck it actually works
- pub fn new(buffer: Box<Buffer>, camera: Box<Camera>, objects: Vec<Box<dyn Object>>) -> Self {
+impl Renderer {
+ pub fn new(buffer: Buffer, camera: Camera, objects: Vec<Box<dyn Object>>) -> Self {
let sdf = move |point: Vector3<f32>, time: f32| -> f32 {
- let mut dist: f32 = 100000.0;
+ let mut dist = f32::MAX;
for object in objects.iter() {
dist = dist.min(object.sdf(point, time));
}
@@ -29,41 +30,49 @@ impl Renderer<'_> {
Self {
buffer,
camera,
- sdf: Box::new(sdf)
+ sdf: Arc::new(sdf),
}
}
pub fn render(&self, time: f32) {
- let (mut ray_dir, mut step_h, mut step_v) = self.camera.get_screen_iterator();
+ let mut iterator = self.camera.get_screen_iterator();
+ iterator.set_buffer_size(&self.buffer);
- let sdf = |point: Vector3<f32>| -> f32 {
- (self.sdf)(point, time)
- };
+ let sdf = |point: Vector3<f32>| -> f32 { (self.sdf)(point, time) };
- step_v /= self.buffer.height;
- step_h /= self.buffer.width;
+ let ray_dirs: Vec<Vector3<f32>> = iterator.collect();
+
+ // Ray march in parallel
+ let chars: Vec<char> = ray_dirs
+ .par_iter()
+ .map(|ray_dir| {
+ let collision = Self::ray_march(self.camera.position, *ray_dir, &sdf);
+ match collision {
+ Some(point) => Self::light_point(point, &sdf),
+ None => 0.0,
+ }
+ })
+ .map(|brightness| {
+ self.buffer.palette
+ [((1.0 - brightness) * (self.buffer.palette.len() - 1) as f32) as usize]
+ })
+ .collect();
for _i in 0..self.buffer.height as usize {
- ray_dir += step_v;
let mut row = "\n".to_string();
for _j in 0..self.buffer.width as usize {
- ray_dir += step_h;
-
- let collision = Self::ray_march(self.camera.position, ray_dir, &sdf);
-
- let brightness = match collision {
- Some(point) => Self::light_point(point, &sdf),
- None => 0.0
- };
-
- row.push(self.buffer.palette[((1.0 - brightness) * (self.buffer.palette.len() - 1) as f32) as usize]);
+ let character = chars[_i * self.buffer.width as usize + _j];
+ row.push(character);
}
- ray_dir -= step_h * self.buffer.width;
addstr(&row);
}
}
- pub fn ray_march(origin: Vector, direction: Vector, sdf: &dyn Fn(Vector) -> f32) -> Option<Vector> {
+ pub fn ray_march(
+ origin: Vector,
+ direction: Vector,
+ sdf: &dyn Fn(Vector) -> f32,
+ ) -> Option<Vector> {
let threshold = 0.1;
let ray = direction.normalize();
@@ -80,16 +89,16 @@ impl Renderer<'_> {
point += ray * dist;
}
- return None
+ None
}
pub fn light_point(point: Vector, sdf: &dyn Fn(Vector) -> f32) -> f32 {
let light = Vector::new(1.0, 1.0, -1.0);
let ambient = 0.1;
- return ambient + (1.0 - ambient) * (
- Self::diffuse_lighting(point, light, sdf) * 0.7 +
- Self::specular_lighting(point, light, sdf) * 0.3
- )
+ ambient
+ + (1.0 - ambient)
+ * (Self::diffuse_lighting(point, light, sdf) * 0.7
+ + Self::specular_lighting(point, light, sdf) * 0.3)
}
pub fn diffuse_lighting(point: Vector, light: Vector, sdf: &dyn Fn(Vector) -> f32) -> f32 {
@@ -100,22 +109,22 @@ impl Renderer<'_> {
while t < 1.0 {
let h = sdf(point - light * t);
if h < 0.001 {
- return 0.00
+ return 0.00;
}
res = res.min(k * h / t);
t += h;
}
- return res
+ res
}
pub fn specular_lighting(point: Vector, light: Vector, sdf: &dyn Fn(Vector) -> f32) -> f32 {
let normal = Self::normal(point, sdf);
let dot = -(normal.dot(light));
- return dot.min(1.0).max(0.0)
- }
+ dot.min(1.0).max(0.0)
+ }
- pub fn normal(point: Vector, sdf: &dyn Fn(Vector) -> f32) -> Vector {
+ pub fn normal(point: Vector, sdf: &dyn Fn(Vector) -> f32) -> Vector {
let d = 0.001;
let dx = Vector::unit_x() * d;
@@ -124,10 +133,11 @@ impl Renderer<'_> {
let dist = sdf(point);
- return (Vector {
+ (Vector {
x: (sdf(point + dx) - dist),
y: (sdf(point + dy) - dist),
z: (sdf(point + dz) - dist),
- } / d).normalize()
+ } / d)
+ .normalize()
}
}