diff --git a/src/assembly.rs b/src/assembly.rs index 60b4b94..1a449ef 100644 --- a/src/assembly.rs +++ b/src/assembly.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use math::Matrix4x4; use bvh::BVH; -use surface::Surface; +use surface::{Surface, SurfaceIntersection}; +use ray::Ray; #[derive(Debug)] @@ -23,6 +24,38 @@ pub struct Assembly { object_accel: BVH, } +impl Assembly { + pub fn new() -> Assembly { + Assembly { + instances: Vec::new(), + xforms: Vec::new(), + objects: Vec::new(), + object_map: HashMap::new(), + assemblies: Vec::new(), + assembly_map: HashMap::new(), + object_accel: BVH::new_empty(), + } + } + + // TODO: this is just temporary. Remove this and move tracing functionality + // into the tracer. + pub fn intersect_rays(&self, rays: &mut [Ray], isects: &mut [SurfaceIntersection]) { + for obj in self.objects.iter() { + match obj { + &Object::Surface(ref surface) => { + surface.intersect_rays(rays, isects); + } + } + } + } + + + pub fn add_object(&mut self, name: &str, obj: Object) { + self.object_map.insert(name.to_string(), self.objects.len()); + self.objects.push(obj); + } +} + #[derive(Debug)] pub enum Object { diff --git a/src/bvh.rs b/src/bvh.rs index 202bf9c..18e4668 100644 --- a/src/bvh.rs +++ b/src/bvh.rs @@ -28,15 +28,19 @@ enum BVHNode { } impl BVH { - pub fn from_objects<'a, T, F>(objects: &mut [T], objects_per_leaf: usize, bounder: F) -> BVH - where F: 'a + Fn(&T) -> &'a [BBox] - { - let mut bvh = BVH { + pub fn new_empty() -> BVH { + BVH { nodes: Vec::new(), bounds: Vec::new(), depth: 0, bounds_cache: Vec::new(), - }; + } + } + + pub fn from_objects<'a, T, F>(objects: &mut [T], objects_per_leaf: usize, bounder: F) -> BVH + where F: 'a + Fn(&T) -> &'a [BBox] + { + let mut bvh = BVH::new_empty(); bvh.recursive_build(0, 0, objects_per_leaf, objects, &bounder); bvh.bounds_cache.clear(); diff --git a/src/main.rs b/src/main.rs index abf7cbd..8911086 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ mod bbox; mod camera; mod parse; mod renderer; +mod tracer; mod image; mod triangle; mod surface; @@ -30,6 +31,8 @@ use docopt::Docopt; use math::{Point, Matrix4x4}; use ray::Ray; use camera::Camera; +use scene::Scene; +use assembly::{Assembly, Object}; use renderer::Renderer; use surface::triangle_mesh::TriangleMesh; use parse::DataTree; @@ -128,12 +131,21 @@ fn main() { vec![20.0], vec![1026.0]); + let mut assembly = Assembly::new(); + assembly.add_object("yar", Object::Surface(Box::new(mesh))); + + let scene = Scene { + name: None, + background_color: (0.0, 0.0, 0.0), + camera: cam, + root: assembly, + }; + let r = Renderer { output_file: args.arg_imgpath.clone(), resolution: (512, 512), spp: samples_per_pixel as usize, - camera: cam, - scene: mesh, + scene: scene, }; r.render(); diff --git a/src/parse/data_tree.rs b/src/parse/data_tree.rs index ac50c18..e7e2131 100644 --- a/src/parse/data_tree.rs +++ b/src/parse/data_tree.rs @@ -42,6 +42,34 @@ impl<'a> DataTree<'a> { } } + pub fn type_name(&'a self) -> &'a str { + match self { + &DataTree::Internal{type_name, ..} => type_name, + &DataTree::Leaf{type_name, ..} => type_name, + } + } + + pub fn is_internal(&self) -> bool { + match self { + &DataTree::Internal{..} => true, + &DataTree::Leaf{..} => false, + } + } + + pub fn is_leaf(&self) -> bool { + match self { + &DataTree::Internal{..} => false, + &DataTree::Leaf{..} => true, + } + } + + pub fn leaf_contents(&'a self) -> Option<&'a str> { + match self { + &DataTree::Internal{..} => None, + &DataTree::Leaf{contents, ..} => Some(contents), + } + } + pub fn get_first_child_with_type_name(&'a self, type_name: &str) -> Option<&'a DataTree> { if let &DataTree::Internal { ref children, .. } = self { for child in children.iter() { diff --git a/src/parse/mod.rs b/src/parse/mod.rs index b4eae1d..1725dda 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -1,5 +1,6 @@ mod data_tree; mod psy; +mod psy_assembly; pub mod basics; pub use self::data_tree::DataTree; diff --git a/src/parse/psy.rs b/src/parse/psy.rs index 90b71ab..94be11d 100644 --- a/src/parse/psy.rs +++ b/src/parse/psy.rs @@ -5,9 +5,16 @@ use std::result::Result; use nom; use nom::IResult; -use renderer::Renderer; use super::DataTree; -use super::basics::ws_u32; +use super::basics::{ws_u32, ws_f32}; +use super::psy_assembly::parse_assembly; + +use math::Matrix4x4; +use camera::Camera; +use renderer::Renderer; +use scene::Scene; + + /// Takes in a DataTree representing a Scene node and returns @@ -31,8 +38,59 @@ pub fn parse_frame(tree: &DataTree) -> Result { } // Parse output info - let output_info = if let &DataTree::Internal{ref children, ..} = - tree.get_first_child_with_type_name("Output").unwrap() { + let output_info = try!(parse_output_info(tree.get_first_child_with_type_name("Output") + .unwrap())); + + // Parse render settings + let render_settings = try!(parse_render_settings(tree.get_first_child_with_type_name("Rende\ + rSett\ + ings") + .unwrap())); + + // Parse camera + let camera = try!(parse_camera(tree.get_first_child_with_type_name("Camera").unwrap())); + + // Parse world + let world = try!(parse_world(tree.get_first_child_with_type_name("World").unwrap())); + + // Parse root scene assembly + let assembly = try!(parse_assembly(tree.get_first_child_with_type_name("Assembly").unwrap())); + + // Put scene together + let scene_name = if let &DataTree::Internal{ident, ..} = tree { + if let Some(name) = ident { + Some(name.to_string()) + } else { + None + } + } else { + None + }; + let scene = Scene { + name: scene_name, + background_color: world, + camera: camera, + root: assembly, + }; + + // // Put renderer together + // let renderer = Renderer { + // output_file: output_info.0.clone(), + // resolution: (render_settings.0.0 as usize, render_settings.0.1 as usize), + // spp: render_settings.1, + // scene: scene, + // } + // + // return Ok(renderer); + + return Err(()); +} + + + + +fn parse_output_info(tree: &DataTree) -> Result<(String), ()> { + if let &DataTree::Internal{ref children, ..} = tree { let mut found_path = false; let mut path = String::new(); @@ -44,37 +102,25 @@ pub fn parse_frame(tree: &DataTree) -> Result { path = contents.to_string(); } - &DataTree::Leaf { type_name, contents } if type_name == "FileFormat" => { - // TODO - unimplemented!() - } - - &DataTree::Leaf { type_name, contents } if type_name == "ColorSpace" => { - // TODO - unimplemented!() - } - - &DataTree::Leaf { type_name, contents } if type_name == "Dither" => { - // TODO - unimplemented!() - } - _ => {} } } if found_path { - (path) + return Ok((path)); } else { return Err(()); } } else { return Err(()); }; +} - // Parse render settings - let render_settings = if let &DataTree::Internal{ref children, ..} = - tree.get_first_child_with_type_name("RenderSettings").unwrap() { + + + +fn parse_render_settings(tree: &DataTree) -> Result<((u32, u32), u32, u32), ()> { + if let &DataTree::Internal{ref children, ..} = tree { let mut found_res = false; let mut found_spp = false; let mut res = (0, 0); @@ -95,6 +141,7 @@ pub fn parse_frame(tree: &DataTree) -> Result { } } + // SamplesPerPixel &DataTree::Leaf { type_name, contents } if type_name == "SamplesPerPixel" => { if let IResult::Done(_, n) = ws_u32(contents.as_bytes()) { found_spp = true; @@ -105,6 +152,7 @@ pub fn parse_frame(tree: &DataTree) -> Result { } } + // Seed &DataTree::Leaf { type_name, contents } if type_name == "Seed" => { if let IResult::Done(_, n) = ws_u32(contents.as_bytes()) { seed = n; @@ -119,19 +167,169 @@ pub fn parse_frame(tree: &DataTree) -> Result { } if found_res && found_spp { - (res, spp) + return Ok((res, spp, seed)); } else { return Err(()); } } else { return Err(()); }; - - // Parse camera - - // Parse world - - // Parse root scene assembly - - return Err(()); +} + + + + +fn parse_camera(tree: &DataTree) -> Result { + if let &DataTree::Internal{ref children, ..} = tree { + let mut mats = Vec::new(); + let mut fovs = Vec::new(); + let mut focus_distances = Vec::new(); + let mut aperture_radii = Vec::new(); + + // Parse + for child in children.iter() { + match child { + // Fov + &DataTree::Leaf { type_name, contents } if type_name == "Fov" => { + if let IResult::Done(_, fov) = ws_f32(contents.as_bytes()) { + fovs.push(fov * (3.1415926536 / 180.0)); + } else { + // Found Fov, but its contents is not in the right format + return Err(()); + } + } + + // FocalDistance + &DataTree::Leaf { type_name, contents } if type_name == "FocalDistance" => { + if let IResult::Done(_, fd) = ws_f32(contents.as_bytes()) { + focus_distances.push(fd); + } else { + // Found FocalDistance, but its contents is not in the right format + return Err(()); + } + } + + // ApertureRadius + &DataTree::Leaf { type_name, contents } if type_name == "ApertureRadius" => { + if let IResult::Done(_, ar) = ws_f32(contents.as_bytes()) { + aperture_radii.push(ar); + } else { + // Found ApertureRadius, but its contents is not in the right format + return Err(()); + } + } + + // Transform + &DataTree::Leaf { type_name, contents } if type_name == "Transform" => { + if let Ok(mat) = parse_matrix(contents) { + mats.push(mat); + } else { + // Found Transform, but its contents is not in the right format + return Err(()); + } + } + + _ => {} + } + } + + return Ok(Camera::new(mats, fovs, aperture_radii, focus_distances)); + } else { + return Err(()); + } +} + + + + +fn parse_world(tree: &DataTree) -> Result<(f32, f32, f32), ()> { + if tree.is_internal() { + let mut found_background_color = false; + let mut background_color = (0.0, 0.0, 0.0); + + // Parse background shader + let bgs = { + if tree.count_children_with_type_name("BackgroundShader") != 1 { + return Err(()); + } + tree.get_first_child_with_type_name("BackgroundShader").unwrap() + }; + let bgs_type = { + if bgs.count_children_with_type_name("Type") != 1 { + return Err(()); + } + if let &DataTree::Leaf{contents, ..} = tree.get_first_child_with_type_name("Type") + .unwrap() { + contents.trim() + } else { + return Err(()); + } + }; + match bgs_type { + "Color" => { + if let Some(&DataTree::Leaf{contents, ..}) = + bgs.get_first_child_with_type_name("Color") { + if let IResult::Done(_, color) = closure!(tuple!(ws_f32, + ws_f32, + ws_f32))(contents.trim() + .as_bytes()) { + found_background_color = true; + background_color = color; + } else { + return Err(()); + } + } else { + return Err(()); + } + } + + _ => return Err(()), + } + + return Ok(background_color); + } else { + return Err(()); + } +} + + + + +fn parse_matrix(contents: &str) -> Result { + if let IResult::Done(_, ns) = closure!(terminated!(tuple!(ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32, + ws_f32), + nom::eof))(contents.as_bytes()) { + return Ok(Matrix4x4::new_from_values(ns.0, + ns.1, + ns.2, + ns.3, + ns.4, + ns.5, + ns.6, + ns.7, + ns.8, + ns.9, + ns.10, + ns.11, + ns.12, + ns.13, + ns.14, + ns.15)); + } else { + return Err(()); + } } diff --git a/src/parse/psy_assembly.rs b/src/parse/psy_assembly.rs new file mode 100644 index 0000000..0ad21ba --- /dev/null +++ b/src/parse/psy_assembly.rs @@ -0,0 +1,18 @@ +#![allow(dead_code)] + +use std::result::Result; + +use nom; +use nom::IResult; + +use super::DataTree; +use super::basics::{ws_u32, ws_f32}; + +use math::Matrix4x4; +use camera::Camera; +use renderer::Renderer; +use assembly::Assembly; + +pub fn parse_assembly(tree: &DataTree) -> Result { + unimplemented!() +} diff --git a/src/renderer.rs b/src/renderer.rs index 4e78cc5..27435d0 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -10,12 +10,12 @@ use surface; use surface::Surface; use scene::Scene; +#[derive(Debug)] pub struct Renderer { pub output_file: String, pub resolution: (usize, usize), pub spp: usize, - pub camera: Camera, - pub scene: surface::triangle_mesh::TriangleMesh, + pub scene: Scene, } impl Renderer { @@ -39,11 +39,11 @@ impl Renderer { let mut ray = { let filter_x = fast_logit(halton::sample(3, offset + si as u32), 1.5); let filter_y = fast_logit(halton::sample(4, offset + si as u32), 1.5); - self.camera.generate_ray((x as f32 + filter_x) * cmpx - 0.5, - (y as f32 + filter_y) * cmpy - 0.5, - halton::sample(0, offset + si as u32), - halton::sample(1, offset + si as u32), - halton::sample(2, offset + si as u32)) + self.scene.camera.generate_ray((x as f32 + filter_x) * cmpx - 0.5, + (y as f32 + filter_y) * cmpy - 0.5, + halton::sample(0, offset + si as u32), + halton::sample(1, offset + si as u32), + halton::sample(2, offset + si as u32)) }; ray.id = si as u32; rays.push(ray); @@ -51,7 +51,7 @@ impl Renderer { } // Test rays against scene - self.scene.intersect_rays(&mut rays, &mut isects); + self.scene.root.intersect_rays(&mut rays, &mut isects); // Calculate color based on ray hits let mut r = 0.0; diff --git a/src/scene.rs b/src/scene.rs index 1e748f7..ba43ef1 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -4,8 +4,8 @@ use assembly::Assembly; #[derive(Debug)] pub struct Scene { - name: String, - background_color: (f32, f32, f32), - camera: Camera, - root: Assembly, + pub name: Option, + pub background_color: (f32, f32, f32), + pub camera: Camera, + pub root: Assembly, } diff --git a/src/tracer.rs b/src/tracer.rs new file mode 100644 index 0000000..7c5252b --- /dev/null +++ b/src/tracer.rs @@ -0,0 +1,10 @@ +use math::Matrix4x4; +use ray::Ray; +use surface::SurfaceIntersection; + +pub struct Tracer<'a> { + xform_stack: Vec, + world_rays: &'a [Ray], + intersections: &'a mut [SurfaceIntersection], + rays: Vec, +}