Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions rustrays/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# rustrays

This is a Rust port of [the Go port][1] of [the business card raytracer][2].

## Prerequisites

* rust 0.9

## Usage

$ rustc --opt-level 3 rustrays/rays.rs
$ rustrays/rays
$ open render.ppm


[1]: https://github.com/kidoman/rays/tree/master/gorays
[2]: https://gist.github.com/kid0m4n/6680629
39 changes: 39 additions & 0 deletions rustrays/art.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use vector::Vector;
use std::path::Path;
use std::io::fs::File;
use std::io::buffered::BufferedReader;

pub struct Art(~[~str]);

pub fn readArt(artfile: &str) -> Art {
let mut lines : ~[~str] = ~[];
let mut file = BufferedReader::new(File::open(&Path::new(artfile)));
for line in file.lines() {
lines.push(line.trim_right().to_owned());
}
Art(lines)
}

impl Art {
pub fn objects(&self) -> ~[Vector] {
let lines: &~[~str] = match self {
&Art(ref a) => a
};

let mut objects: ~[Vector] = ~[];
let mut j = 0;
for ref line in lines.iter() {
for (k, ref char) in line.char_indices() {
match *char {
' ' => { },
_ => {
let v = Vector {x: k as f64, y: 6.5, z: -((lines.len()-j) as f64) - 1.0 };
objects.push(v);
}
}
}
j += 1;
}
objects
}
}
21 changes: 21 additions & 0 deletions rustrays/camera.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use vector::Vector;

pub struct Camera {
dir: Vector,
up: Vector,
right: Vector,
eyeOffset: Vector,
ar: f64
}

impl Camera {
pub fn new(dir: Vector, size: int) -> Camera {
let dir = dir.normalize();
let up = Vector { x: 0.0, y: 0.0, z: 1.0 }.crossProduct(dir).normalize().scale(0.002);
let right = dir.crossProduct(up).normalize().scale(0.002);
let eyeOffset = up.add(&right).scale(-256.0).add(&dir);
let ar = 512.0 / (size as f64);

Camera { dir: dir, up: up, right: right, eyeOffset: eyeOffset, ar: ar }
}
}
26 changes: 26 additions & 0 deletions rustrays/image.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use std::vec;
use std::io::fs::File;
use std::path::Path;

pub struct Image {
size: int,
data: ~[u8]
}

impl Image {
pub fn new(size: int) -> Image {
let cap = (3 * size * size) as uint;
let mut vec = vec::with_capacity(cap);
unsafe {
vec.set_len(cap);
}
return Image { size: size, data: vec }
}

pub fn save(&self, outputfile: &str) {
let mut file = File::create(&Path::new(outputfile));
let s = format!("P6 {} {} 255 ", self.size, self.size);
file.write(s.as_bytes());
file.write(self.data);
}
}
19 changes: 19 additions & 0 deletions rustrays/misc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pub unsafe fn rnd(s: *mut u32) -> f64 {
let mut ss : u32 = *s;
ss += ss;
ss ^= 1;

if (ss as i32) < 0 {
ss ^= 0x88888eef;
}
*s = ss;

return ((*s%95) as f64) / 95.0;
}

pub fn clamp(v: f64) -> u8 {
if v > 255.0 {
return 255u8
}
return v as u8;
}
136 changes: 136 additions & 0 deletions rustrays/rays.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#[feature(globs)];
extern mod native;
extern mod extra;

use extra::getopts::*;
use std::os;
use std::path::Path;
use extra::time::precise_time_ns;
use extra::arc::Arc;
use extra::comm::DuplexStream;

use camera::Camera;
use result::Result;
use worker::Worker;
use image::Image;
use vector::Vector;
use art::{Art,readArt};

mod art;
mod image;
mod camera;
mod vector;
mod result;
mod worker;
mod misc;

#[start]
fn start(argc: int, argv: **u8) -> int {
native::start(argc, argv, main)
}

fn main() {
let args = os::args();
let opts = ~[
optflagopt("m"),
optflagopt("t"),
optflagopt("p"),
optflagopt("o"),
optflagopt("r"),
optflagopt("a"),
optflagopt("h")
];

let matches = match getopts(args.tail(), opts) {
Ok(m) => { m }
Err(f) => { fail!(f.to_err_msg()) }
};

let mp = match matches.opt_str("m") {
Some(s) => { std::num::FromStrRadix::from_str_radix(s, 10).unwrap() }
None => { 1f32 }
};

let size = std::f32::sqrt(mp * 1000000f32) as int;

let times = match matches.opt_str("t") {
Some(s) => { std::num::FromStrRadix::from_str_radix(s, 10).unwrap() }
None => { 1 }
};
println(format!("Will render {} time(s)", times));

let procs = match matches.opt_str("p") {
Some(s) => { std::num::FromStrRadix::from_str_radix(s, 10).unwrap() }
None => { std::rt::default_sched_threads() as int }
};
if procs < 1 {
fail!("procs ({}) needs to be >= 1", procs)
}

let outputfile = match matches.opt_str("o") {
Some(s) => { s }
None => { ~"render.ppm" }
};

let resultfile = match matches.opt_str("r") {
Some(s) => { s }
None => { ~"result.json" }
};

let home = match matches.opt_str("h") {
Some(s) => { s }
None => { std::os::getenv("RAYS_HOME").unwrap_or_default() }
};

let mut artfile = match matches.opt_str("a") {
Some(s) => { s }
None => { ~"ART" }
};

if artfile == ~"ART" {
let path = Path::new(home).join(artfile);
artfile = path.as_str().unwrap().into_owned();
}

let ar : Art = readArt(artfile);
let objects_arc = Arc::new(ar.objects());

let mut result = Result { samples: ~[] };
let image : *mut Image = &mut Image::new(size);

for t in range(0, times) {
print(format!("Starting render\\#{0} of size {1} MP ({2}x{3}) with {4} task(s).", t+1, mp, size, size, procs));
std::io::stdio::flush();
let startTime = precise_time_ns();

let cam = Camera::new(Vector { x: -3.1, y: -16.0, z: 1.9 }, size);

let mut chans = ~[];

for i in range(0, procs) {
let (main, worker) = DuplexStream::new();
worker.send(objects_arc.clone());
chans.push(worker);

do spawn {
let local_arc : Arc<~[Vector]> = main.recv();
Worker { id: i, cam: cam, image: image, objects: local_arc.get() }.render(procs as uint);
main.send(());
}
}
chans.iter().advance( |worker| {
worker.recv();
true
});

let duration = (precise_time_ns() - startTime) as f64 / 1e9;
result.samples.push(duration);
println(format!(" Time taken for render {}", duration));
}

println(format!("Average time {}", result.average()));
result.save(resultfile);
unsafe {
(*image).save(outputfile);
}
}
42 changes: 42 additions & 0 deletions rustrays/result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
extern mod extra;

use std::io::fs::File;
use extra::json::PrettyEncoder;
use extra::serialize::Encodable;

pub struct Result {
samples: ~[f64]
}

#[deriving(Encodable)]
struct JsonResult<'a> {
average: f64,
samples: &'a[f64]
}

impl Result {
pub fn sum(&self) -> f64 {
let mut sum = 0.0;
for &s in self.samples.iter() {
sum += s;
}
sum
}

pub fn average(&self) -> f64 {
self.sum() / self.samples.len() as f64
}

pub fn save(&self, resultfile: &str) {
match File::create(&Path::new(resultfile)) {
Some(ref mut file) => {
let mut enc = PrettyEncoder::new(file);
JsonResult { average: self.average(), samples: self.samples }.encode(&mut enc);
file.flush();
}
None => {
println(format!("Opening {} file failed!", resultfile));
}
};
}
}
36 changes: 36 additions & 0 deletions rustrays/vector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::to_str::ToStr;
use std::num::rsqrt;

pub struct Vector {
x: f64,
y: f64,
z: f64
}

impl Vector {
pub fn add(&self, r: &Vector) -> Vector {
Vector { x: r.x + self.x, y: r.y + self.y, z: r.z + self.z }
}

pub fn scale(&self, r: f64) -> Vector {
Vector { x: self.x * r, y: self.y * r, z: self.z * r }
}

pub fn dotProduct(&self, r: &Vector) -> f64 {
return self.x*r.x + self.y*r.y + self.z*r.z
}

pub fn crossProduct(&self, r: Vector) -> Vector {
Vector { x: self.y * r.z - self.z * r.y, y: self.z * r.x - self.x * r.z, z: self.x * r.y - self.y * r.x }
}

pub fn normalize(&self) -> Vector {
self.scale(rsqrt(self.x * self.x + self.y * self.y + self.z * self.z))
}
}

impl ToStr for Vector {
fn to_str(&self) -> ~str {
format!("Vector [x={}, y={}, z={}]", self.x, self.y, self.z)
}
}
Loading