Skip to content

Instantly share code, notes, and snippets.

@jamwt
Created October 19, 2016 00:10
Show Gist options
  • Save jamwt/e446e220d2cd87c9dffbe939a0f59705 to your computer and use it in GitHub Desktop.
Save jamwt/e446e220d2cd87c9dffbe939a0f59705 to your computer and use it in GitHub Desktop.
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index b24d5cf..c715446 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -6,4 +6,6 @@ authors = [ "David Shoemaker <[email protected]>" ]
[dependencies]
image = "*"
+itertools = "*"
+rayon = "*"
regex = "*"
diff --git a/rust/src/buffer.rs b/rust/src/buffer.rs
new file mode 100644
index 0000000..3bf0c78
--- /dev/null
+++ b/rust/src/buffer.rs
@@ -0,0 +1,33 @@
+use std::cell::UnsafeCell;
+
+pub struct ParallelPixelBuffer {
+ width: u32,
+ contents: UnsafeCell<Vec<u8>>,
+}
+
+unsafe impl Sync for ParallelPixelBuffer {}
+
+impl ParallelPixelBuffer {
+ pub fn new(width: u32, height: u32) -> ParallelPixelBuffer {
+ ParallelPixelBuffer {
+ width: width,
+ contents: UnsafeCell::new(vec![0u8; (width * height * 3) as usize]),
+ }
+ }
+
+ pub fn put_pixel(&self, l: u32, t: u32, x: u8, y: u8, z: u8) {
+ unsafe {
+ let contents = &mut *self.contents.get();
+ let base = (((t * self.width) + l) * 3) as usize;
+ *contents.get_unchecked_mut(base) = x;
+ *contents.get_unchecked_mut(base + 1) = y;
+ *contents.get_unchecked_mut(base + 2) = z;
+ }
+ }
+
+ pub fn into_inner(self) -> Vec<u8> {
+ unsafe {
+ self.contents.into_inner()
+ }
+ }
+}
diff --git a/rust/src/main.rs b/rust/src/main.rs
index 7c60dfc..0f32c14 100644
--- a/rust/src/main.rs
+++ b/rust/src/main.rs
@@ -1,4 +1,6 @@
extern crate image;
+#[macro_use] extern crate itertools;
+extern crate rayon;
extern crate regex;
use std::fs::File;
@@ -7,6 +9,7 @@ use std::io::Read;
use std::path::Path;
use std::env;
+mod buffer;
mod vector;
mod ray;
mod camera;
diff --git a/rust/src/scene.rs b/rust/src/scene.rs
index 3d21d15..30d89d9 100644
--- a/rust/src/scene.rs
+++ b/rust/src/scene.rs
@@ -1,3 +1,4 @@
+use buffer::ParallelPixelBuffer;
use camera::Camera;
use vector::Vector3;
use ray::{ Ray, HitInfo };
@@ -6,6 +7,7 @@ use image::{ ImageBuffer, Rgb };
use sceneobject::SceneObject;
use light::Light;
use material::Material;
+use rayon::prelude::*;
#[derive(Debug)]
pub struct Scene {
@@ -41,7 +43,13 @@ impl Scene {
}
pub fn raytrace(&self) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
- ImageBuffer::from_fn(self.width, self.height, |x, y| {
+ // TODO(jamwt) -- we don't have to actually collect this
+ // if we implement IntoParallelIterator on our pixel buffer.
+ let coords: Vec<_> = iproduct!(0..self.width, 0..self.height).collect();
+
+ // Now let's do the pixels in parallel.
+ let pixels = ParallelPixelBuffer::new(self.width, self.height);
+ coords.par_iter().for_each(|&(x, y)| {
let eye_ray = self.camera.eye_ray(x, y);
let color = if let Some(hit) = self.trace(&eye_ray, 0.001, f64::MAX) {
self.shade(&hit, &eye_ray, 0) * 255.0
@@ -49,8 +57,10 @@ impl Scene {
else {
self.bgcolor * 255.0
};
- Rgb([color.x as u8, color.y as u8, color.z as u8])
- })
+ pixels.put_pixel(x, y, color.x as u8, color.y as u8, color.z as u8);
+ });
+ ImageBuffer::from_raw(self.width, self.height, pixels.into_inner())
+ .expect("Buffer not big enough??")
}
fn trace(&self, ray: &Ray, min: f64, max: f64) -> Option<HitInfo> {
diff --git a/rust/src/sceneobject.rs b/rust/src/sceneobject.rs
index e6bd88d..432e1c5 100644
--- a/rust/src/sceneobject.rs
+++ b/rust/src/sceneobject.rs
@@ -1,6 +1,6 @@
use ray::{ Ray, HitInfo };
use std::fmt::Debug;
-pub trait SceneObject: Debug {
+pub trait SceneObject: Debug + Sync {
fn intersect(&self, ray: &Ray, min: f64, max: f64) -> Option<HitInfo>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment