#![allow(dead_code)] use std::result::Result; use nom; use nom::IResult; use mem_arena::MemArena; use camera::Camera; use color::{XYZ, rec709_e_to_xyz}; use light::WorldLightSource; use math::Matrix4x4; use renderer::Renderer; use scene::Scene; use scene::World; use super::basics::{ws_u32, ws_f32}; use super::DataTree; use super::psy_assembly::parse_assembly; use super::psy_light::parse_distant_disk_light; #[derive(Debug)] pub enum PsyParseError { // The first usize for all errors is their byte offset // into the psy content where they occured. UnknownError(usize), UnknownVariant(usize, &'static str), // Error message ExpectedInternalNode(usize, &'static str), // Error message ExpectedLeafNode(usize, &'static str), // Error message MissingNode(usize, &'static str), // Error message IncorrectLeafData(usize, &'static str), // Error message WrongNodeCount(usize, &'static str, usize), // Error message, sections found InstancedMissingData(usize, &'static str, String), // Error message, data name } impl PsyParseError { pub fn print(&self, psy_content: &str) { match self { &PsyParseError::UnknownError(offset) => { let line = line_count_to_byte_offset(psy_content, offset); println!( "Line {}: Unknown parse error. If you get this message, please report \ it to the developers so they can improve the error messages.", line ); } &PsyParseError::UnknownVariant(offset, error) => { let line = line_count_to_byte_offset(psy_content, offset); println!("Line {}: {}", line, error); } &PsyParseError::ExpectedInternalNode(offset, error) => { let line = line_count_to_byte_offset(psy_content, offset); println!("Line {}: {}", line, error); } &PsyParseError::ExpectedLeafNode(offset, error) => { let line = line_count_to_byte_offset(psy_content, offset); println!("Line {}: {}", line, error); } &PsyParseError::MissingNode(offset, error) => { let line = line_count_to_byte_offset(psy_content, offset); println!("Line {}: {}", line, error); } &PsyParseError::IncorrectLeafData(offset, error) => { let line = line_count_to_byte_offset(psy_content, offset); println!("Line {}: {}", line, error); } &PsyParseError::WrongNodeCount(offset, error, count) => { let line = line_count_to_byte_offset(psy_content, offset); println!("Line {}: {} Found: {}", line, error, count); } &PsyParseError::InstancedMissingData(offset, error, ref data_name) => { let line = line_count_to_byte_offset(psy_content, offset); println!("Line {}: {} Data name: '{}'", line, error, data_name); } } } } fn line_count_to_byte_offset(text: &str, offset: usize) -> usize { text[..offset].matches("\n").count() + 1 } /// Takes in a DataTree representing a Scene node and returns pub fn parse_scene<'a>( arena: &'a MemArena, tree: &'a DataTree, ) -> Result, PsyParseError> { // Verify we have the right number of each section if tree.iter_children_with_type("Output").count() != 1 { let count = tree.iter_children_with_type("Output").count(); return Err(PsyParseError::WrongNodeCount( tree.byte_offset(), "Scene should have precisely one Output \ section.", count, )); } if tree.iter_children_with_type("RenderSettings").count() != 1 { let count = tree.iter_children_with_type("RenderSettings").count(); return Err(PsyParseError::WrongNodeCount( tree.byte_offset(), "Scene should have precisely one \ RenderSettings section.", count, )); } if tree.iter_children_with_type("Camera").count() != 1 { let count = tree.iter_children_with_type("Camera").count(); return Err(PsyParseError::WrongNodeCount( tree.byte_offset(), "Scene should have precisely one Camera \ section.", count, )); } if tree.iter_children_with_type("World").count() != 1 { let count = tree.iter_children_with_type("World").count(); return Err(PsyParseError::WrongNodeCount( tree.byte_offset(), "Scene should have precisely one World section.", count, )); } if tree.iter_children_with_type("Assembly").count() != 1 { let count = tree.iter_children_with_type("Assembly").count(); return Err(PsyParseError::WrongNodeCount( tree.byte_offset(), "Scene should have precisely one Root Assembly \ section.", count, )); } // Parse output info let output_info = parse_output_info(tree.iter_children_with_type("Output").nth(0).unwrap())?; // Parse render settings let render_settings = parse_render_settings( tree.iter_children_with_type("RenderSettings") .nth(0) .unwrap(), )?; // Parse camera let camera = parse_camera( arena, tree.iter_children_with_type("Camera").nth(0).unwrap(), )?; // Parse world let world = parse_world(arena, tree.iter_children_with_type("World").nth(0).unwrap())?; // Parse root scene assembly let assembly = parse_assembly( arena, tree.iter_children_with_type("Assembly").nth(0).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, camera: camera, world: world, root: assembly, }; // Put renderer together let renderer = Renderer { output_file: output_info.clone(), resolution: ( (render_settings.0).0 as usize, (render_settings.0).1 as usize, ), spp: render_settings.1 as usize, seed: render_settings.2, scene: scene, }; return Ok(renderer); } fn parse_output_info(tree: &DataTree) -> Result { if let &DataTree::Internal { ref children, .. } = tree { let mut found_path = false; let mut path = String::new(); for child in children { match child { &DataTree::Leaf { type_name, contents, byte_offset, } if type_name == "Path" => { // Trim and validate let tc = contents.trim(); if tc.chars().count() < 2 { return Err(PsyParseError::IncorrectLeafData( byte_offset, "File path format is \ incorrect.", )); } if tc.chars().nth(0).unwrap() != '"' || tc.chars().last().unwrap() != '"' { return Err(PsyParseError::IncorrectLeafData( byte_offset, "File paths must be \ surrounded by quotes.", )); } let len = tc.len(); let tc = &tc[1..len - 1]; // Parse // TODO: proper string escaping found_path = true; path = tc.to_string(); } _ => {} } } if found_path { return Ok((path)); } else { return Err(PsyParseError::MissingNode( tree.byte_offset(), "Output section must contain a Path.", )); } } else { return Err(PsyParseError::ExpectedInternalNode( tree.byte_offset(), "Output section should be an internal \ node, containing at least a Path.", )); }; } fn parse_render_settings(tree: &DataTree) -> Result<((u32, u32), u32, u32), PsyParseError> { if let &DataTree::Internal { ref children, .. } = tree { let mut found_res = false; let mut found_spp = false; let mut res = (0, 0); let mut spp = 0; let mut seed = 0; for child in children { match child { // Resolution &DataTree::Leaf { type_name, contents, byte_offset, } if type_name == "Resolution" => { if let IResult::Done(_, (w, h)) = closure!(terminated!(tuple!(ws_u32, ws_u32), nom::eof))(contents.as_bytes()) { found_res = true; res = (w, h); } else { // Found Resolution, but its contents is not in the right format return Err(PsyParseError::IncorrectLeafData( byte_offset, "Resolution should be specified with two \ integers in the form '[width height]'.", )); } } // SamplesPerPixel &DataTree::Leaf { type_name, contents, byte_offset, } if type_name == "SamplesPerPixel" => { if let IResult::Done(_, n) = ws_u32(contents.as_bytes()) { found_spp = true; spp = n; } else { // Found SamplesPerPixel, but its contents is not in the right format return Err(PsyParseError::IncorrectLeafData( byte_offset, "SamplesPerPixel should be \ an integer specified in \ the form '[samples]'.", )); } } // Seed &DataTree::Leaf { type_name, contents, byte_offset, } if type_name == "Seed" => { if let IResult::Done(_, n) = ws_u32(contents.as_bytes()) { seed = n; } else { // Found Seed, but its contents is not in the right format return Err(PsyParseError::IncorrectLeafData( byte_offset, "Seed should be an integer \ specified in the form \ '[samples]'.", )); } } _ => {} } } if found_res && found_spp { return Ok((res, spp, seed)); } else { return Err(PsyParseError::MissingNode( tree.byte_offset(), "RenderSettings must have both Resolution and \ SamplesPerPixel specified.", )); } } else { return Err(PsyParseError::ExpectedInternalNode( tree.byte_offset(), "RenderSettings section should be an \ internal node, containing at least \ Resolution and SamplesPerPixel.", )); }; } fn parse_camera<'a>(arena: &'a MemArena, tree: &'a DataTree) -> Result, PsyParseError> { 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, byte_offset, } 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(PsyParseError::IncorrectLeafData( byte_offset, "Fov should be a decimal \ number specified in the \ form '[fov]'.", )); } } // FocalDistance &DataTree::Leaf { type_name, contents, byte_offset, } 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(PsyParseError::IncorrectLeafData( byte_offset, "FocalDistance should be a \ decimal number specified \ in the form '[fov]'.", )); } } // ApertureRadius &DataTree::Leaf { type_name, contents, byte_offset, } 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(PsyParseError::IncorrectLeafData( byte_offset, "ApertureRadius should be a \ decimal number specified \ in the form '[fov]'.", )); } } // Transform &DataTree::Leaf { type_name, contents, byte_offset, } 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(make_transform_format_error(byte_offset)); } } _ => {} } } return Ok(Camera::new( arena, mats, fovs, aperture_radii, focus_distances, )); } else { return Err(PsyParseError::ExpectedInternalNode( tree.byte_offset(), "Camera section should be an internal \ node, containing at least Fov and \ Transform.", )); } } fn parse_world<'a>(arena: &'a MemArena, tree: &'a DataTree) -> Result, PsyParseError> { if tree.is_internal() { let background_color; let mut lights: Vec<&WorldLightSource> = Vec::new(); // Parse background shader let bgs = { if tree.iter_children_with_type("BackgroundShader").count() != 1 { return Err(PsyParseError::WrongNodeCount( tree.byte_offset(), "World should have precisely one BackgroundShader section.", tree.iter_children_with_type("BackgroundShader").count(), )); } tree.iter_children_with_type("BackgroundShader") .nth(0) .unwrap() }; let bgs_type = { if bgs.iter_children_with_type("Type").count() != 1 { return Err(PsyParseError::WrongNodeCount( bgs.byte_offset(), "BackgroundShader should have \ precisely one Type specified.", bgs.iter_children_with_type("Type").count(), )); } if let &DataTree::Leaf { contents, .. } = bgs.iter_children_with_type("Type").nth(0).unwrap() { contents.trim() } else { return Err(PsyParseError::ExpectedLeafNode( bgs.byte_offset(), "BackgroundShader's Type should be a \ leaf node.", )); } }; match bgs_type { "Color" => { if let Some(&DataTree::Leaf { contents, byte_offset, .. }) = bgs.iter_children_with_type("Color").nth(0) { if let IResult::Done(_, color) = closure!(tuple!(ws_f32, ws_f32, ws_f32))(contents.trim().as_bytes()) { // TODO: proper color space management, not just assuming // rec.709. background_color = XYZ::from_tuple(rec709_e_to_xyz(color)); } else { return Err(PsyParseError::IncorrectLeafData( byte_offset, "Color should be specified \ with three decimal numbers \ in the form '[R G B]'.", )); } } else { return Err(PsyParseError::MissingNode( bgs.byte_offset(), "BackgroundShader's Type is Color, \ but no Color is specified.", )); } } _ => { return Err(PsyParseError::UnknownVariant( bgs.byte_offset(), "The specified BackgroundShader Type \ isn't a recognized type.", )) } } // Parse light sources for child in tree.iter_children() { match child { &DataTree::Internal { type_name, .. } if type_name == "DistantDiskLight" => { lights.push(arena.alloc(parse_distant_disk_light(arena, &child)?)); } _ => {} } } // Build and return the world return Ok(World { background_color: background_color, lights: arena.copy_slice(&lights), }); } else { return Err(PsyParseError::ExpectedInternalNode( tree.byte_offset(), "World section should be an internal \ node, containing at least a \ BackgroundShader.", )); } } pub 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.4, ns.8, ns.12, ns.1, ns.5, ns.9, ns.13, ns.2, ns.6, ns.10, ns.14, ns.3, ns.7, ns.11, ns.15, )); } else { return Err(PsyParseError::UnknownError(0)); } } pub fn make_transform_format_error(byte_offset: usize) -> PsyParseError { return PsyParseError::IncorrectLeafData( byte_offset, "Transform should be sixteen integers specified in \ the form '[# # # # # # # # # # # # # # # #]'.", ); }