WIP refactor to make psy parsing all streaming.
Does not build right now.
This commit is contained in:
parent
9d5bc63fa5
commit
e3e5c1412f
124
src/main.rs
124
src/main.rs
|
@ -47,6 +47,11 @@ use nom::bytes::complete::take_until;
|
|||
|
||||
use kioku::Arena;
|
||||
|
||||
use data_tree::{
|
||||
reader::{DataTreeReader, ReaderError},
|
||||
Event,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
accel::BVH4Node,
|
||||
bbox::BBox,
|
||||
|
@ -191,63 +196,86 @@ fn main() {
|
|||
println!("Parsing scene file...",);
|
||||
}
|
||||
t.tick();
|
||||
let psy_contents = if args.is_present("use_stdin") {
|
||||
// Read from stdin
|
||||
let mut input = Vec::new();
|
||||
let tmp = std::io::stdin();
|
||||
let mut stdin = tmp.lock();
|
||||
let mut buf = vec![0u8; 4096];
|
||||
loop {
|
||||
let count = stdin
|
||||
.read(&mut buf)
|
||||
.expect("Unexpected end of scene input.");
|
||||
let start = if input.len() < 11 {
|
||||
0
|
||||
} else {
|
||||
input.len() - 11
|
||||
};
|
||||
let end = input.len() + count;
|
||||
input.extend(&buf[..count]);
|
||||
// let psy_contents = if args.is_present("use_stdin") {
|
||||
// // Read from stdin
|
||||
// let mut input = Vec::new();
|
||||
// let tmp = std::io::stdin();
|
||||
// let mut stdin = tmp.lock();
|
||||
// let mut buf = vec![0u8; 4096];
|
||||
// loop {
|
||||
// let count = stdin
|
||||
// .read(&mut buf)
|
||||
// .expect("Unexpected end of scene input.");
|
||||
// let start = if input.len() < 11 {
|
||||
// 0
|
||||
// } else {
|
||||
// input.len() - 11
|
||||
// };
|
||||
// let end = input.len() + count;
|
||||
// input.extend(&buf[..count]);
|
||||
|
||||
let mut done = false;
|
||||
let mut trunc_len = 0;
|
||||
if let nom::IResult::Ok((remaining, _)) =
|
||||
take_until::<&str, &[u8], ()>("__PSY_EOF__")(&input[start..end])
|
||||
{
|
||||
done = true;
|
||||
trunc_len = input.len() - remaining.len();
|
||||
}
|
||||
if done {
|
||||
input.truncate(trunc_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
String::from_utf8(input).unwrap()
|
||||
} else {
|
||||
// Read from file
|
||||
let mut input = String::new();
|
||||
let fp = args.value_of("input").unwrap();
|
||||
let mut f = io::BufReader::new(File::open(fp).unwrap());
|
||||
let _ = f.read_to_string(&mut input);
|
||||
input
|
||||
};
|
||||
// let mut done = false;
|
||||
// let mut trunc_len = 0;
|
||||
// if let nom::IResult::Ok((remaining, _)) =
|
||||
// take_until::<&str, &[u8], ()>("__PSY_EOF__")(&input[start..end])
|
||||
// {
|
||||
// done = true;
|
||||
// trunc_len = input.len() - remaining.len();
|
||||
// }
|
||||
// if done {
|
||||
// input.truncate(trunc_len);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// String::from_utf8(input).unwrap()
|
||||
// } else {
|
||||
// // Read from file
|
||||
// let mut input = String::new();
|
||||
// let fp = args.value_of("input").unwrap();
|
||||
// let mut f = io::BufReader::new(File::open(fp).unwrap());
|
||||
// let _ = f.read_to_string(&mut input);
|
||||
// input
|
||||
// };
|
||||
|
||||
let dt = DataTree::from_str(&psy_contents).unwrap();
|
||||
if !args.is_present("serialized_output") {
|
||||
println!("\tParsed scene file in {:.3}s", t.tick());
|
||||
}
|
||||
// let dt = DataTree::from_str(&psy_contents).unwrap();
|
||||
// if !args.is_present("serialized_output") {
|
||||
// println!("\tParsed scene file in {:.3}s", t.tick());
|
||||
// }
|
||||
|
||||
let mut psy_file = io::BufReader::new(File::open(fp).unwrap());
|
||||
let mut events = DataTreeReader::new(&mut psy_file);
|
||||
|
||||
// Iterate through scenes and render them
|
||||
if let DataTree::Internal { ref children, .. } = dt {
|
||||
for child in children {
|
||||
t.tick();
|
||||
if child.type_name() == "Scene" {
|
||||
loop {
|
||||
t.tick();
|
||||
match events.next_event() {
|
||||
Ok(Event::ValidEnd) => {
|
||||
break;
|
||||
}
|
||||
|
||||
Ok(_) => {
|
||||
println!("Error: invalid scene in psy file.");
|
||||
break;
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
println!("Error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse a scene and render it.
|
||||
Ok(Event::InnerOpen {
|
||||
type_name: "Scene",
|
||||
ident,
|
||||
..
|
||||
}) => {
|
||||
if !args.is_present("serialized_output") {
|
||||
println!("Building scene...");
|
||||
}
|
||||
|
||||
let arena = Arena::new().with_block_size((1 << 20) * 4);
|
||||
let mut scene = parse_scene(&arena, child).unwrap_or_else(|e| {
|
||||
let ident = ident.into::<String>();
|
||||
let mut scene = parse_scene(&arena, &mut events, &ident).unwrap_or_else(|e| {
|
||||
e.print(&psy_contents);
|
||||
panic!("Parse error.");
|
||||
});
|
||||
|
|
871
src/parse/psy.rs
871
src/parse/psy.rs
|
@ -1,9 +1,13 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::{collections::HashMap, f32, result::Result};
|
||||
use std::{collections::HashMap, f32, io::BufRead, result::Result};
|
||||
|
||||
use nom::{combinator::all_consuming, sequence::tuple, IResult};
|
||||
|
||||
use data_tree::{
|
||||
reader::{DataTreeReader, ReaderError},
|
||||
Event,
|
||||
};
|
||||
use kioku::Arena;
|
||||
|
||||
use crate::{
|
||||
|
@ -38,6 +42,7 @@ pub enum PsyParseError {
|
|||
IncorrectLeafData(usize, &'static str), // Error message
|
||||
WrongNodeCount(usize, &'static str, usize), // Error message, sections found
|
||||
InstancedMissingData(usize, &'static str, String), // Error message, data name
|
||||
ReaderError(ReaderError),
|
||||
}
|
||||
|
||||
impl PsyParseError {
|
||||
|
@ -95,109 +100,116 @@ impl PsyParseError {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for PsyParseError {}
|
||||
|
||||
impl std::fmt::Display for PsyParseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ReaderError> for PsyParseError {
|
||||
fn from(e: ReaderError) -> Self {
|
||||
PsyParseError::ReaderError(e)
|
||||
}
|
||||
}
|
||||
|
||||
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 Arena, tree: &'a DataTree) -> Result<Scene<'a>, 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("Shaders").count() != 1 {
|
||||
let count = tree.iter_children_with_type("Shaders").count();
|
||||
return Err(PsyParseError::WrongNodeCount(
|
||||
tree.byte_offset(),
|
||||
"Scene should have precisely one Shaders 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,
|
||||
));
|
||||
}
|
||||
pub fn parse_scene<'a>(
|
||||
arena: &'a Arena,
|
||||
events: &mut DataTreeReader<impl BufRead>,
|
||||
ident: Option<&str>,
|
||||
) -> Result<Scene<'a>, PsyParseError> {
|
||||
// Get output info.
|
||||
let output_info = if let Event::InnerOpen {
|
||||
type_name: "Output",
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_output_info(events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
|
||||
// Parse output info
|
||||
let output_info = parse_output_info(tree.iter_children_with_type("Output").nth(0).unwrap())?;
|
||||
// Get render settings.
|
||||
let render_settings = if let Event::InnerOpen {
|
||||
type_name: "RenderSettings",
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_render_settings(events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
|
||||
// Parse render settings
|
||||
let render_settings = parse_render_settings(
|
||||
tree.iter_children_with_type("RenderSettings")
|
||||
.nth(0)
|
||||
.unwrap(),
|
||||
)?;
|
||||
// Get camera.
|
||||
let camera = if let Event::InnerOpen {
|
||||
type_name: "Camera",
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_camera(arena, events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
|
||||
// Parse camera
|
||||
let camera = parse_camera(
|
||||
arena,
|
||||
tree.iter_children_with_type("Camera").nth(0).unwrap(),
|
||||
)?;
|
||||
// Get shaders.
|
||||
let shaders = if let Event::InnerOpen {
|
||||
type_name: "Shaders",
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_shaders(arena, events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
|
||||
// Parse world
|
||||
let world = parse_world(arena, tree.iter_children_with_type("World").nth(0).unwrap())?;
|
||||
// Get world.
|
||||
let world = if let Event::InnerOpen {
|
||||
type_name: "World", ..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_world(arena, events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
|
||||
// Parse shaders
|
||||
let shaders = parse_shaders(tree.iter_children_with_type("Shaders").nth(0).unwrap())?;
|
||||
// Get the root assembly.
|
||||
let root_assembly = if let Event::InnerOpen {
|
||||
type_name: "Assembly",
|
||||
ident,
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_assembly(arena, events, &(ident.into::<String>()))?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
|
||||
// Parse root scene assembly
|
||||
let assembly = parse_assembly(
|
||||
arena,
|
||||
tree.iter_children_with_type("Assembly").nth(0).unwrap(),
|
||||
)?;
|
||||
// Make sure we're closed out properly.
|
||||
if let Event::InnerClose { .. } = events.next_event()? {
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
|
||||
// Put scene together
|
||||
let scene_name = if let DataTree::Internal { ident, .. } = tree {
|
||||
if let Some(name) = ident {
|
||||
Some(name.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let scene_name = if let Some(name) = ident {
|
||||
Some(name.into())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let scene = Scene {
|
||||
camera: camera,
|
||||
world: world,
|
||||
shaders: shaders,
|
||||
root_assembly: assembly,
|
||||
root_assembly: root_assembly,
|
||||
};
|
||||
|
||||
// // Put renderer together
|
||||
|
@ -215,396 +227,357 @@ pub fn parse_scene<'a>(arena: &'a Arena, tree: &'a DataTree) -> Result<Scene<'a>
|
|||
return Ok(scene);
|
||||
}
|
||||
|
||||
fn parse_output_info(tree: &DataTree) -> Result<String, PsyParseError> {
|
||||
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.ends_with('"') {
|
||||
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();
|
||||
fn parse_output_info(events: &mut DataTreeReader<impl BufRead>) -> Result<String, PsyParseError> {
|
||||
let mut found_path = false;
|
||||
let mut path = String::new();
|
||||
loop {
|
||||
match events.next_event()? {
|
||||
Event::Leaf {
|
||||
type_name: "Path",
|
||||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
// 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.ends_with('"') {
|
||||
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();
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if found_path {
|
||||
return Ok(path);
|
||||
} else {
|
||||
return Err(PsyParseError::MissingNode(
|
||||
tree.byte_offset(),
|
||||
"Output section must contain a Path.",
|
||||
));
|
||||
}
|
||||
if found_path {
|
||||
return Ok(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::Ok((_, (w, h))) =
|
||||
all_consuming(tuple((ws_u32, ws_u32)))(&contents)
|
||||
{
|
||||
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::Ok((_, n)) = all_consuming(ws_u32)(&contents) {
|
||||
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::Ok((_, n)) = all_consuming(ws_u32)(&contents) {
|
||||
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 Arena, tree: &'a DataTree) -> Result<Camera<'a>, 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::Ok((_, fov)) = all_consuming(ws_f32)(&contents) {
|
||||
fovs.push(fov * (f32::consts::PI / 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::Ok((_, fd)) = all_consuming(ws_f32)(&contents) {
|
||||
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::Ok((_, ar)) = all_consuming(ws_f32)(&contents) {
|
||||
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.",
|
||||
));
|
||||
// return Err(PsyParseError::MissingNode(
|
||||
// tree.byte_offset(),
|
||||
// "Output section must contain a Path.",
|
||||
// ));
|
||||
todo!(); // Return error.
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_world<'a>(arena: &'a Arena, tree: &'a DataTree) -> Result<World<'a>, PsyParseError> {
|
||||
if tree.is_internal() {
|
||||
let background_color;
|
||||
let mut lights: Vec<&dyn 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)
|
||||
fn parse_render_settings(
|
||||
events: &mut DataTreeReader<impl BufRead>,
|
||||
) -> Result<((u32, u32), u32, u32), PsyParseError> {
|
||||
let mut found_res = false;
|
||||
let mut found_spp = false;
|
||||
let mut res = (0, 0);
|
||||
let mut spp = 0;
|
||||
let mut seed = 0;
|
||||
loop {
|
||||
match events.next_event()? {
|
||||
// Resolution
|
||||
Event::Leaf {
|
||||
type_name: "Resolution",
|
||||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let IResult::Ok((_, (w, h))) = all_consuming(tuple((ws_u32, ws_u32)))(&contents)
|
||||
{
|
||||
if let Ok(color) = parse_color(&contents) {
|
||||
background_color = color;
|
||||
} else {
|
||||
return Err(PsyParseError::IncorrectLeafData(
|
||||
*byte_offset,
|
||||
"Color should be specified \
|
||||
with three decimal numbers \
|
||||
in the form '[R G B]'.",
|
||||
));
|
||||
}
|
||||
found_res = true;
|
||||
res = (w, h);
|
||||
} else {
|
||||
return Err(PsyParseError::MissingNode(
|
||||
bgs.byte_offset(),
|
||||
"BackgroundShader's Type is Color, \
|
||||
but no Color is specified.",
|
||||
// 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]'.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
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)?));
|
||||
// SamplesPerPixel
|
||||
DataTree::Leaf {
|
||||
type_name: "SamplesPerPixel",
|
||||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let IResult::Ok((_, n)) = all_consuming(ws_u32)(&contents) {
|
||||
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: "Seed",
|
||||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let IResult::Ok((_, n)) = all_consuming(ws_u32)(&contents) {
|
||||
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]'.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build and return the world
|
||||
return Ok(World {
|
||||
background_color: background_color,
|
||||
lights: arena.copy_slice(&lights),
|
||||
});
|
||||
if found_res && found_spp {
|
||||
return Ok((res, spp, seed));
|
||||
} else {
|
||||
return Err(PsyParseError::ExpectedInternalNode(
|
||||
tree.byte_offset(),
|
||||
"World section should be an internal \
|
||||
node, containing at least a \
|
||||
BackgroundShader.",
|
||||
));
|
||||
// return Err(PsyParseError::MissingNode(
|
||||
// tree.byte_offset(),
|
||||
// "RenderSettings must have both Resolution and \
|
||||
// SamplesPerPixel specified.",
|
||||
// ));
|
||||
todo!(); // Return error.
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_shaders<'a>(
|
||||
tree: &'a DataTree,
|
||||
) -> Result<HashMap<String, Box<dyn SurfaceShader>>, PsyParseError> {
|
||||
if tree.is_internal() {
|
||||
let mut shaders = HashMap::new();
|
||||
fn parse_camera<'a>(
|
||||
arena: &'a Arena,
|
||||
events: &mut DataTreeReader<impl BufRead>,
|
||||
) -> Result<Camera<'a>, PsyParseError> {
|
||||
let mut mats = Vec::new();
|
||||
let mut fovs = Vec::new();
|
||||
let mut focus_distances = Vec::new();
|
||||
let mut aperture_radii = Vec::new();
|
||||
|
||||
for shader_item in tree.iter_children() {
|
||||
match shader_item {
|
||||
DataTree::Internal {
|
||||
type_name,
|
||||
ident,
|
||||
children,
|
||||
byte_offset,
|
||||
} if type_name == &"SurfaceShader" => {
|
||||
if let Some(name) = ident {
|
||||
shaders.insert(name.to_string(), parse_surface_shader(shader_item)?);
|
||||
} else {
|
||||
// TODO: error.
|
||||
// Parse
|
||||
loop {
|
||||
match events.next_event()? {
|
||||
// Fov
|
||||
Event::Leaf {
|
||||
type_name: "Fov",
|
||||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let IResult::Ok((_, fov)) = all_consuming(ws_f32)(&contents) {
|
||||
fovs.push(fov * (f32::consts::PI / 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
|
||||
Event::Leaf {
|
||||
type_name: "FocalDistance",
|
||||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let IResult::Ok((_, fd)) = all_consuming(ws_f32)(&contents) {
|
||||
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
|
||||
Event::Leaf {
|
||||
type_name: "ApertureRadius",
|
||||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let IResult::Ok((_, ar)) = all_consuming(ws_f32)(&contents) {
|
||||
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
|
||||
Event::Leaf {
|
||||
type_name: "Transform",
|
||||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(Camera::new(
|
||||
arena,
|
||||
&mats,
|
||||
&fovs,
|
||||
&aperture_radii,
|
||||
&focus_distances,
|
||||
));
|
||||
}
|
||||
|
||||
fn parse_world<'a>(
|
||||
arena: &'a Arena,
|
||||
events: &mut DataTreeReader<impl BufRead>,
|
||||
) -> Result<World<'a>, PsyParseError> {
|
||||
let background_color = None;
|
||||
let mut lights: Vec<&dyn WorldLightSource> = Vec::new();
|
||||
|
||||
loop {
|
||||
match events.next_event()? {
|
||||
// Parse background shader
|
||||
Event::InnerOpen {
|
||||
type_name: "BackgroundShader",
|
||||
} => {
|
||||
let bgs_type = if let Event::Leaf {
|
||||
type_name: "Type",
|
||||
contents,
|
||||
..
|
||||
} = events.next_event()
|
||||
{
|
||||
contents.into::<String>()
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
|
||||
match bgs_type {
|
||||
"Color" => {
|
||||
if let Event::Leaf {
|
||||
type_name: "Color",
|
||||
contents,
|
||||
..
|
||||
} = events.next_event()
|
||||
{
|
||||
background_color = Some(parse_color(contents)?);
|
||||
} else {
|
||||
todo!(
|
||||
"BackgroundShader's Type is Color, \
|
||||
but no Color is specified."
|
||||
); // Return error.
|
||||
};
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(
|
||||
"The specified BackgroundShader Type \
|
||||
isn't a recognized type.",
|
||||
); // Return an error.
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
// TODO: an error.
|
||||
// Close it out.
|
||||
if let Event::InnerClose { .. } = events.next_event() {
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the list of shaders.
|
||||
return Ok(shaders);
|
||||
} else {
|
||||
return Err(PsyParseError::ExpectedInternalNode(
|
||||
tree.byte_offset(),
|
||||
"Shaders section should be an internal \
|
||||
node.",
|
||||
));
|
||||
// Parse light sources
|
||||
Event::InnerOpen {
|
||||
type_name: "DistantDiskLight",
|
||||
..
|
||||
} => {
|
||||
lights.push(arena.alloc(parse_distant_disk_light(arena, events)?));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if background_color == None {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
|
||||
// Build and return the world
|
||||
return Ok(World {
|
||||
background_color: background_color.unwrap(),
|
||||
lights: arena.copy_slice(&lights),
|
||||
});
|
||||
}
|
||||
|
||||
fn parse_shaders<'a>(
|
||||
events: &mut DataTreeReader<impl BufRead>,
|
||||
) -> Result<HashMap<String, Box<dyn SurfaceShader>>, PsyParseError> {
|
||||
let mut shaders = HashMap::new();
|
||||
loop {
|
||||
match events.next_event() {
|
||||
DataTree::Internal {
|
||||
type_name: "SurfaceShader",
|
||||
ident,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let Some(name) = ident {
|
||||
let name = name.to_string();
|
||||
shaders.insert(name, parse_surface_shader(events)?);
|
||||
} else {
|
||||
todo!("Shader has no name."); // Return error.
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the list of shaders.
|
||||
return Ok(shaders);
|
||||
}
|
||||
|
||||
pub fn parse_matrix(contents: &str) -> Result<Matrix4x4, PsyParseError> {
|
||||
|
@ -621,7 +594,7 @@ pub fn parse_matrix(contents: &str) -> Result<Matrix4x4, PsyParseError> {
|
|||
}
|
||||
}
|
||||
|
||||
return Err(PsyParseError::UnknownError(0));
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
|
||||
pub fn make_transform_format_error(byte_offset: usize) -> PsyParseError {
|
||||
|
@ -635,7 +608,7 @@ pub fn make_transform_format_error(byte_offset: usize) -> PsyParseError {
|
|||
pub fn parse_color(contents: &str) -> Result<Color, PsyParseError> {
|
||||
let items: Vec<_> = contents.split(',').map(|s| s.trim()).collect();
|
||||
if items.len() != 2 {
|
||||
return Err(PsyParseError::UnknownError(0));
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
|
||||
match items[0] {
|
||||
|
@ -643,7 +616,7 @@ pub fn parse_color(contents: &str) -> Result<Color, PsyParseError> {
|
|||
if let IResult::Ok((_, color)) = tuple((ws_f32, ws_f32, ws_f32))(items[1]) {
|
||||
return Ok(Color::new_xyz(rec709_e_to_xyz(color)));
|
||||
} else {
|
||||
return Err(PsyParseError::UnknownError(0));
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -651,7 +624,7 @@ pub fn parse_color(contents: &str) -> Result<Color, PsyParseError> {
|
|||
if let IResult::Ok((_, (temperature, factor))) = tuple((ws_f32, ws_f32))(items[1]) {
|
||||
return Ok(Color::new_blackbody(temperature, factor));
|
||||
} else {
|
||||
return Err(PsyParseError::UnknownError(0));
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -659,10 +632,12 @@ pub fn parse_color(contents: &str) -> Result<Color, PsyParseError> {
|
|||
if let IResult::Ok((_, (temperature, factor))) = tuple((ws_f32, ws_f32))(items[1]) {
|
||||
return Ok(Color::new_temperature(temperature, factor));
|
||||
} else {
|
||||
return Err(PsyParseError::UnknownError(0));
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
}
|
||||
|
||||
_ => return Err(PsyParseError::UnknownError(0)),
|
||||
_ => {
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,11 @@ use std::result::Result;
|
|||
|
||||
use kioku::Arena;
|
||||
|
||||
use data_tree::{
|
||||
reader::{DataTreeReader, ReaderError},
|
||||
Event,
|
||||
};
|
||||
|
||||
use crate::scene::{Assembly, Object, ObjectData};
|
||||
|
||||
use super::{
|
||||
|
@ -15,7 +20,8 @@ use super::{
|
|||
|
||||
pub fn parse_assembly<'a>(
|
||||
arena: &'a Arena,
|
||||
tree: &'a DataTree,
|
||||
events: &mut DataTreeReader,
|
||||
ident: Option<&str>,
|
||||
) -> Result<Assembly<'a>, PsyParseError> {
|
||||
if !tree.is_internal() {
|
||||
return Err(PsyParseError::UnknownError(tree.byte_offset()));
|
||||
|
|
|
@ -6,6 +6,11 @@ use nom::{combinator::all_consuming, sequence::tuple, IResult};
|
|||
|
||||
use kioku::Arena;
|
||||
|
||||
use data_tree::{
|
||||
reader::{DataTreeReader, ReaderError},
|
||||
Event,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
light::{DistantDiskLight, RectangleLight, SphereLight},
|
||||
math::Vector,
|
||||
|
@ -19,7 +24,8 @@ use super::{
|
|||
|
||||
pub fn parse_distant_disk_light<'a>(
|
||||
arena: &'a Arena,
|
||||
tree: &'a DataTree,
|
||||
events: &mut DataTreeReader,
|
||||
ident: Option<&str>,
|
||||
) -> Result<DistantDiskLight<'a>, PsyParseError> {
|
||||
if let DataTree::Internal { ref children, .. } = *tree {
|
||||
let mut radii = Vec::new();
|
||||
|
@ -85,7 +91,8 @@ pub fn parse_distant_disk_light<'a>(
|
|||
|
||||
pub fn parse_sphere_light<'a>(
|
||||
arena: &'a Arena,
|
||||
tree: &'a DataTree,
|
||||
events: &mut DataTreeReader,
|
||||
ident: Option<&str>,
|
||||
) -> Result<SphereLight<'a>, PsyParseError> {
|
||||
if let DataTree::Internal { ref children, .. } = *tree {
|
||||
let mut radii = Vec::new();
|
||||
|
@ -134,7 +141,8 @@ pub fn parse_sphere_light<'a>(
|
|||
|
||||
pub fn parse_rectangle_light<'a>(
|
||||
arena: &'a Arena,
|
||||
tree: &'a DataTree,
|
||||
events: &mut DataTreeReader,
|
||||
ident: Option<&str>,
|
||||
) -> Result<RectangleLight<'a>, PsyParseError> {
|
||||
if let DataTree::Internal { ref children, .. } = *tree {
|
||||
let mut dimensions = Vec::new();
|
||||
|
|
|
@ -6,6 +6,11 @@ use nom::{sequence::tuple, IResult};
|
|||
|
||||
use kioku::Arena;
|
||||
|
||||
use data_tree::{
|
||||
reader::{DataTreeReader, ReaderError},
|
||||
Event,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
math::{Normal, Point},
|
||||
surface::triangle_mesh::TriangleMesh,
|
||||
|
@ -26,7 +31,8 @@ use super::{
|
|||
|
||||
pub fn parse_mesh_surface<'a>(
|
||||
arena: &'a Arena,
|
||||
tree: &'a DataTree,
|
||||
events: &mut DataTreeReader,
|
||||
ident: Option<&str>,
|
||||
) -> Result<TriangleMesh<'a>, PsyParseError> {
|
||||
let mut verts = Vec::new(); // Vec of vecs, one for each time sample
|
||||
let mut normals = Vec::new(); // Vec of vecs, on for each time sample
|
||||
|
|
|
@ -4,6 +4,11 @@ use std::result::Result;
|
|||
|
||||
use nom::{combinator::all_consuming, IResult};
|
||||
|
||||
use data_tree::{
|
||||
reader::{DataTreeReader, ReaderError},
|
||||
Event,
|
||||
};
|
||||
|
||||
use crate::shading::{SimpleSurfaceShader, SurfaceShader};
|
||||
|
||||
use super::{
|
||||
|
@ -19,7 +24,10 @@ use super::{
|
|||
// accel: BVH,
|
||||
// }
|
||||
|
||||
pub fn parse_surface_shader(tree: &DataTree) -> Result<Box<dyn SurfaceShader>, PsyParseError> {
|
||||
pub fn parse_surface_shader(
|
||||
events: &mut DataTreeReader,
|
||||
ident: Option<&str>,
|
||||
) -> Result<Box<dyn SurfaceShader>, PsyParseError> {
|
||||
let type_name = if let Some((_, text, _)) = tree.iter_leaf_children_with_type("Type").nth(0) {
|
||||
text.trim()
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue
Block a user