diff --git a/src/assembly.rs b/src/assembly.rs index fa56f81..a1556b9 100644 --- a/src/assembly.rs +++ b/src/assembly.rs @@ -60,43 +60,65 @@ impl AssemblyBuilder { } pub fn add_object(&mut self, name: &str, obj: Object) { + // Make sure the name hasn't already been used. + if self.name_exists(name) { + panic!("Attempted to add object to assembly with a name that already exists."); + } + + // Add object self.object_map.insert(name.to_string(), self.objects.len()); self.objects.push(obj); } pub fn add_assembly(&mut self, name: &str, asmb: Assembly) { + // Make sure the name hasn't already been used. + if self.name_exists(name) { + panic!("Attempted to add assembly to another assembly with a name that already \ + exists."); + } + + // Add assembly self.assembly_map.insert(name.to_string(), self.assemblies.len()); self.assemblies.push(asmb); } - pub fn add_object_instance(&mut self, name: &str, xforms: Option<&[Matrix4x4]>) { - let instance = Instance { - instance_type: InstanceType::Object, - data_index: self.object_map[name], - id: self.instances.len(), - transform_indices: xforms.map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())), + pub fn add_instance(&mut self, name: &str, xforms: Option<&[Matrix4x4]>) { + // Make sure name exists + if !self.name_exists(name) { + panic!("Attempted to add instance with a name that doesn't exist."); + } + + // Create instance + let instance = if self.object_map.contains_key(name) { + Instance { + instance_type: InstanceType::Object, + data_index: self.object_map[name], + id: self.instances.len(), + transform_indices: xforms.map(|xf| { + (self.xforms.len(), self.xforms.len() + xf.len()) + }), + } + } else { + Instance { + instance_type: InstanceType::Assembly, + data_index: self.assembly_map[name], + id: self.instances.len(), + transform_indices: xforms.map(|xf| { + (self.xforms.len(), self.xforms.len() + xf.len()) + }), + } }; self.instances.push(instance); + // Store transforms if let Some(xf) = xforms { self.xforms.extend(xf); } } - pub fn add_assembly_instance(&mut self, name: &str, xforms: Option<&[Matrix4x4]>) { - let instance = Instance { - instance_type: InstanceType::Assembly, - data_index: self.object_map[name], - id: self.instances.len(), - transform_indices: xforms.map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())), - }; - - self.instances.push(instance); - - if let Some(xf) = xforms { - self.xforms.extend(xf); - } + pub fn name_exists(&self, name: &str) -> bool { + self.object_map.contains_key(name) || self.assembly_map.contains_key(name) } pub fn build(mut self) -> Assembly { diff --git a/src/parse/data_tree.rs b/src/parse/data_tree.rs index e7e2131..4ce7d79 100644 --- a/src/parse/data_tree.rs +++ b/src/parse/data_tree.rs @@ -2,6 +2,8 @@ use std::result::Result; use std::cmp::Eq; +use std::iter::{Iterator, Filter}; +use std::slice; #[derive(Debug, Eq, PartialEq)] pub enum DataTree<'a> { @@ -70,50 +72,57 @@ impl<'a> DataTree<'a> { } } - 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() { - match child { - &DataTree::Internal { type_name: tn, .. } => { - if tn == type_name { - return Some(child); - } - } - - &DataTree::Leaf { type_name: tn, .. } => { - if tn == type_name { - return Some(child); - } - } - } - } - return None; + pub fn iter_children(&'a self) -> slice::Iter<'a, DataTree<'a>> { + if let &DataTree::Internal{ref children, ..} = self { + children.iter() } else { - return None; + [].iter() } } - pub fn count_children_with_type_name(&self, type_name: &str) -> usize { - if let &DataTree::Internal { ref children, .. } = self { - let mut count = 0; - for child in children.iter() { - match child { - &DataTree::Internal { type_name: tn, .. } => { - if tn == type_name { - count += 1; - } - } - - &DataTree::Leaf { type_name: tn, .. } => { - if tn == type_name { - count += 1; - } - } - } + pub fn iter_children_with_type(&'a self, type_name: &'static str) -> DataTreeFilterIter<'a> { + if let &DataTree::Internal{ref children, ..} = self { + DataTreeFilterIter { + type_name: type_name, + iter: children.iter(), } - return count; } else { - return 0; + DataTreeFilterIter { + type_name: type_name, + iter: [].iter(), + } + } + } + + pub fn iter_internal_children_with_type(&'a self, + type_name: &'static str) + -> DataTreeFilterInternalIter<'a> { + if let &DataTree::Internal{ref children, ..} = self { + DataTreeFilterInternalIter { + type_name: type_name, + iter: children.iter(), + } + } else { + DataTreeFilterInternalIter { + type_name: type_name, + iter: [].iter(), + } + } + } + + pub fn iter_leaf_children_with_type(&'a self, + type_name: &'static str) + -> DataTreeFilterLeafIter<'a> { + if let &DataTree::Internal{ref children, ..} = self { + DataTreeFilterLeafIter { + type_name: type_name, + iter: children.iter(), + } + } else { + DataTreeFilterLeafIter { + type_name: type_name, + iter: [].iter(), + } } } @@ -134,6 +143,103 @@ impl<'a> DataTree<'a> { } } + +/// An iterator over the children of a DataTree node that filters out the +/// children not matching a specified type name. +pub struct DataTreeFilterIter<'a> { + type_name: &'a str, + iter: slice::Iter<'a, DataTree<'a>>, +} + +impl<'a> Iterator for DataTreeFilterIter<'a> { + type Item = &'a DataTree<'a>; + + fn next(&mut self) -> Option<&'a DataTree<'a>> { + loop { + if let Some(dt) = self.iter.next() { + if dt.type_name() == self.type_name { + return Some(dt); + } else { + continue; + } + } else { + return None; + } + } + } +} + + +/// An iterator over the children of a DataTree node that filters out the +/// children that aren't internal nodes and that don't match a specified +/// type name. +pub struct DataTreeFilterInternalIter<'a> { + type_name: &'a str, + iter: slice::Iter<'a, DataTree<'a>>, +} + +impl<'a> Iterator for DataTreeFilterInternalIter<'a> { + type Item = (&'a str, Option<&'a str>, &'a Vec>); + + fn next(&mut self) -> Option<(&'a str, Option<&'a str>, &'a Vec>)> { + loop { + match self.iter.next() { + Some(&DataTree::Internal{type_name: type_name, ident: ident, children: ref children}) => { + if type_name == self.type_name { + return Some((type_name, ident, children)); + } else { + continue; + } + } + + Some(&DataTree::Leaf{..}) => { + continue; + } + + None => { + return None; + } + } + } + } +} + + +/// An iterator over the children of a DataTree node that filters out the +/// children that aren't internal nodes and that don't match a specified +/// type name. +pub struct DataTreeFilterLeafIter<'a> { + type_name: &'a str, + iter: slice::Iter<'a, DataTree<'a>>, +} + +impl<'a> Iterator for DataTreeFilterLeafIter<'a> { + type Item = (&'a str, &'a str); + + fn next(&mut self) -> Option<(&'a str, &'a str)> { + loop { + match self.iter.next() { + Some(&DataTree::Internal{..}) => { + continue; + } + + Some(&DataTree::Leaf{type_name: type_name, contents: contents}) => { + if type_name == self.type_name { + return Some((type_name, contents)); + } else { + continue; + } + } + + None => { + return None; + } + } + } + } +} + + #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum ParseError { MissingOpener(usize), @@ -537,4 +643,49 @@ mod tests { assert_eq!(i, None); assert_eq!(c.len(), 0); } + + #[test] + fn iter_1() { + let dt = DataTree::from_str(r#" + A {} + B {} + A [] + A {} + B {} + "#) + .unwrap(); + + let mut i = dt.iter_children_with_type("A"); + assert_eq!(i.count(), 3); + } + + #[test] + fn iter_2() { + let dt = DataTree::from_str(r#" + A {} + B {} + A [] + A {} + B {} + "#) + .unwrap(); + + let mut i = dt.iter_internal_children_with_type("A"); + assert_eq!(i.count(), 2); + } + + #[test] + fn iter_3() { + let dt = DataTree::from_str(r#" + A [] + B {} + A {} + A [] + B {} + "#) + .unwrap(); + + let mut i = dt.iter_leaf_children_with_type("A"); + assert_eq!(i.count(), 2); + } } diff --git a/src/parse/psy.rs b/src/parse/psy.rs index c75c395..cf0890e 100644 --- a/src/parse/psy.rs +++ b/src/parse/psy.rs @@ -25,45 +25,47 @@ pub enum PsyParseError { /// a renderer. pub fn parse_scene(tree: &DataTree) -> Result { // Verify we have the right number of each section - if tree.count_children_with_type_name("Output") != 1 { - let count = tree.count_children_with_type_name("Output"); + if tree.iter_children_with_type("Output").count() != 1 { + let count = tree.iter_children_with_type("Output").count(); return Err(PsyParseError::SectionWrongCount("Output", count)); } - if tree.count_children_with_type_name("RenderSettings") != 1 { - let count = tree.count_children_with_type_name("RenderSettings"); + if tree.iter_children_with_type("RenderSettings").count() != 1 { + let count = tree.iter_children_with_type("RenderSettings").count(); return Err(PsyParseError::SectionWrongCount("RenderSettings", count)); } - if tree.count_children_with_type_name("Camera") != 1 { - let count = tree.count_children_with_type_name("Camera"); + if tree.iter_children_with_type("Camera").count() != 1 { + let count = tree.iter_children_with_type("Camera").count(); return Err(PsyParseError::SectionWrongCount("Camera", count)); } - if tree.count_children_with_type_name("World") != 1 { - let count = tree.count_children_with_type_name("World"); + if tree.iter_children_with_type("World").count() != 1 { + let count = tree.iter_children_with_type("World").count(); return Err(PsyParseError::SectionWrongCount("World", count)); } - if tree.count_children_with_type_name("Assembly") != 1 { - let count = tree.count_children_with_type_name("Assembly"); + if tree.iter_children_with_type("Assembly").count() != 1 { + let count = tree.iter_children_with_type("Assembly").count(); return Err(PsyParseError::SectionWrongCount("Root Assembly", count)); } // Parse output info - let output_info = try!(parse_output_info(tree.get_first_child_with_type_name("Output") + let output_info = try!(parse_output_info(tree.iter_children_with_type("Output") + .nth(0) .unwrap())); // Parse render settings - let render_settings = try!(parse_render_settings(tree.get_first_child_with_type_name("Rende\ + let render_settings = try!(parse_render_settings(tree.iter_children_with_type("Rende\ rSett\ ings") + .nth(0) .unwrap())); // Parse camera - let camera = try!(parse_camera(tree.get_first_child_with_type_name("Camera").unwrap())); + let camera = try!(parse_camera(tree.iter_children_with_type("Camera").nth(0).unwrap())); // Parse world - let world = try!(parse_world(tree.get_first_child_with_type_name("World").unwrap())); + let world = try!(parse_world(tree.iter_children_with_type("World").nth(0).unwrap())); // Parse root scene assembly - let assembly = try!(parse_assembly(tree.get_first_child_with_type_name("Assembly").unwrap())); + let assembly = try!(parse_assembly(tree.iter_children_with_type("Assembly").nth(0).unwrap())); // Put scene together let scene_name = if let &DataTree::Internal{ident, ..} = tree { @@ -257,16 +259,17 @@ fn parse_world(tree: &DataTree) -> Result<(f32, f32, f32), PsyParseError> { // Parse background shader let bgs = { - if tree.count_children_with_type_name("BackgroundShader") != 1 { + if tree.iter_children_with_type("BackgroundShader").count() != 1 { return Err(PsyParseError::UnknownError); } - tree.get_first_child_with_type_name("BackgroundShader").unwrap() + tree.iter_children_with_type("BackgroundShader").nth(0).unwrap() }; let bgs_type = { - if bgs.count_children_with_type_name("Type") != 1 { + if bgs.iter_children_with_type("Type").count() != 1 { return Err(PsyParseError::UnknownError); } - if let &DataTree::Leaf{contents, ..} = bgs.get_first_child_with_type_name("Type") + if let &DataTree::Leaf{contents, ..} = bgs.iter_children_with_type("Type") + .nth(0) .unwrap() { contents.trim() } else { @@ -275,8 +278,8 @@ fn parse_world(tree: &DataTree) -> Result<(f32, f32, f32), PsyParseError> { }; match bgs_type { "Color" => { - if let Some(&DataTree::Leaf{contents, ..}) = - bgs.get_first_child_with_type_name("Color") { + if let Some(&DataTree::Leaf{contents, ..}) = bgs.iter_children_with_type("Color") + .nth(0) { if let IResult::Done(_, color) = closure!(tuple!(ws_f32, ws_f32, ws_f32))(contents.trim() @@ -303,7 +306,7 @@ fn parse_world(tree: &DataTree) -> Result<(f32, f32, f32), PsyParseError> { -fn parse_matrix(contents: &str) -> Result { +pub fn parse_matrix(contents: &str) -> Result { if let IResult::Done(_, ns) = closure!(terminated!(tuple!(ws_f32, ws_f32, ws_f32, diff --git a/src/parse/psy_assembly.rs b/src/parse/psy_assembly.rs index 08732bf..72b4752 100644 --- a/src/parse/psy_assembly.rs +++ b/src/parse/psy_assembly.rs @@ -7,7 +7,7 @@ use nom::IResult; use super::DataTree; use super::basics::{ws_u32, ws_f32}; -use super::psy::PsyParseError; +use super::psy::{parse_matrix, PsyParseError}; use math::Matrix4x4; use camera::Camera; @@ -17,8 +17,8 @@ use assembly::{Assembly, AssemblyBuilder}; pub fn parse_assembly(tree: &DataTree) -> Result { let mut builder = AssemblyBuilder::new(); - if let &DataTree::Internal{ref children, ..} = tree { - for child in children { + if tree.is_internal() { + for child in tree.iter_children() { match child.type_name() { // Sub-Assembly "Assembly" => { @@ -26,9 +26,48 @@ pub fn parse_assembly(tree: &DataTree) -> Result { builder.add_assembly(ident, try!(parse_assembly(&child))); } else { // TODO: error condition of some kind, because no ident + panic!(); } } + // Instance + "Instance" => { + // Pre-conditions + if !child.is_internal() { + // TODO: proper error + panic!(); + } + + // Get data name + let name = { + if child.iter_leaf_children_with_type("Data").count() != 1 { + // TODO: proper error message + panic!(); + } + child.iter_leaf_children_with_type("Data").nth(0).unwrap().1 + }; + + // Get xforms + let mut xforms = Vec::new(); + for (_, contents) in child.iter_leaf_children_with_type("Transform") { + xforms.push(try!(parse_matrix(contents))); + } + + // Add instance + if builder.name_exists(name) { + builder.add_instance(name, Some(&xforms)); + } else { + // TODO: proper error message + panic!("Attempted to add instance for data with a name that doesn't \ + exist."); + } + } + + // MeshSurface + "MeshSurface" => { + // TODO: call mesh surface parsing function once it's written + } + _ => { // TODO: some kind of error, because not a known type name } @@ -68,34 +107,6 @@ pub fn parse_assembly(tree: &DataTree) -> Result { // assembly->add_object(child.name, parse_rectangle_light(child)); // } // - // // Instance - // else if (child.type == "Instance") { - // // Parse - // std::string name = ""; - // std::vector xforms; - // const SurfaceShader *shader = nullptr; - // for (const auto& child2: child.children) { - // if (child2.type == "Transform") { - // xforms.emplace_back(parse_matrix(child2.leaf_contents)); - // } else if (child2.type == "Data") { - // name = child2.leaf_contents; - // } else if (child2.type == "SurfaceShaderBind") { - // shader = assembly->get_surface_shader(child2.leaf_contents); - // if (shader == nullptr) { - // std::cout << "ERROR: attempted to bind surface shader that doesn't exist." << std::endl; - // } - // } - // } - // - // // Add instance - // if (assembly->object_map.count(name) != 0) { - // assembly->create_object_instance(name, xforms, shader); - // } else if (assembly->assembly_map.count(name) != 0) { - // assembly->create_assembly_instance(name, xforms, shader); - // } else { - // std::cout << "ERROR: attempted to add instace for data that doesn't exist." << std::endl; - // } - // } } } } else {