More parsing code cleanup and some better error messages.
Still more to do, but this is some decent progress.
This commit is contained in:
parent
c1f8d21814
commit
331b0229b0
|
@ -76,6 +76,203 @@ pub fn ensure_close(events: &mut DataTreeReader<impl BufRead>) -> PsyResult<()>
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Range {
|
||||
Full,
|
||||
From(usize),
|
||||
To(usize),
|
||||
Range(usize, usize),
|
||||
}
|
||||
|
||||
impl Range {
|
||||
pub fn contains(self, n: usize) -> bool {
|
||||
match self {
|
||||
Range::Full => true,
|
||||
Range::From(start) => n >= start,
|
||||
Range::To(end) => n < end,
|
||||
Range::Range(start, end) => n >= start && n < end,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the value is within the upper bound of the range.
|
||||
/// Ignores any lower bound.
|
||||
pub fn contains_upper(self, n: usize) -> bool {
|
||||
match self {
|
||||
Range::Full | Range::From(_) => true,
|
||||
Range::To(end) => n < end,
|
||||
Range::Range(_, end) => n < end,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower(self) -> usize {
|
||||
match self {
|
||||
Range::Full => 0,
|
||||
Range::From(start) => start,
|
||||
Range::To(_) => 0,
|
||||
Range::Range(start, _) => start,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upper(self) -> usize {
|
||||
match self {
|
||||
Range::Full => std::usize::MAX,
|
||||
Range::From(_) => std::usize::MAX,
|
||||
Range::To(end) => end,
|
||||
Range::Range(_, end) => end,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::ops::RangeFull> for Range {
|
||||
fn from(_r: std::ops::RangeFull) -> Self {
|
||||
Range::Full
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::ops::RangeFrom<usize>> for Range {
|
||||
fn from(r: std::ops::RangeFrom<usize>) -> Self {
|
||||
Range::From(r.start)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::ops::RangeTo<usize>> for Range {
|
||||
fn from(r: std::ops::RangeTo<usize>) -> Self {
|
||||
Range::To(r.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::ops::Range<usize>> for Range {
|
||||
fn from(r: std::ops::Range<usize>) -> Self {
|
||||
Range::Range(r.start, r.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<usize> for Range {
|
||||
fn from(r: usize) -> Self {
|
||||
Range::Range(r, r + 1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Acts as an intermediary for parsing, ensuring that the right number of the
|
||||
/// right subsections are encountered. It loops over subsections, passing
|
||||
/// through the `events` object untouched, so the passed closure needs to call
|
||||
/// `next_event`.
|
||||
///
|
||||
/// Tracks a maximum of 64 different subsections.
|
||||
pub fn ensure_subsections<F, DTR: BufRead>(
|
||||
events: &mut DataTreeReader<DTR>,
|
||||
subsections: &[(&str, bool, Range)], // (type name, is leaf, valid count range)
|
||||
mut f: F,
|
||||
) -> PsyResult<()>
|
||||
where
|
||||
F: FnMut(&mut DataTreeReader<DTR>) -> PsyResult<()>,
|
||||
{
|
||||
let mut counts = [0usize; 64];
|
||||
|
||||
// Loop through our events!
|
||||
loop {
|
||||
match events.peek_event()? {
|
||||
Event::Leaf {
|
||||
type_name,
|
||||
byte_offset,
|
||||
..
|
||||
} => {
|
||||
if let Some(idx) = subsections
|
||||
.iter()
|
||||
.position(|(n, l, _)| *l == true && n == &type_name)
|
||||
{
|
||||
// Increment count and make sure we're within the valid count
|
||||
// range for this sub-sections.
|
||||
counts[idx] += 1;
|
||||
if !subsections[idx].2.contains_upper(counts[idx]) {
|
||||
return Err(PsyError::WrongNodeCount(
|
||||
byte_offset,
|
||||
format!(
|
||||
"Expected at most {} '{}' leaf nodes but found \
|
||||
at least {}.",
|
||||
subsections[idx].2.upper() - 1,
|
||||
subsections[idx].0,
|
||||
counts[idx],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// Call handler.
|
||||
f(events)?
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Event::InnerOpen {
|
||||
type_name,
|
||||
byte_offset,
|
||||
..
|
||||
} => {
|
||||
if let Some(idx) = subsections
|
||||
.iter()
|
||||
.position(|(n, l, _)| *l == false && n == &type_name)
|
||||
{
|
||||
// Increment count and make sure we're within the valid count
|
||||
// range for this sub-sections.
|
||||
counts[idx] += 1;
|
||||
if !subsections[idx].2.contains_upper(counts[idx]) {
|
||||
return Err(PsyError::WrongNodeCount(
|
||||
byte_offset,
|
||||
format!(
|
||||
"Expected at most {} internal '{}' node(s) but \
|
||||
found at least {}.",
|
||||
subsections[idx].2.upper() - 1,
|
||||
subsections[idx].0,
|
||||
counts[idx],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// Call handler.
|
||||
f(events)?
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
Event::EOF => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validation.
|
||||
for i in 0..subsections.len() {
|
||||
if !subsections[i].2.contains(counts[i]) {
|
||||
if subsections[i].1 {
|
||||
return Err(PsyError::WrongNodeCount(
|
||||
events.byte_offset(),
|
||||
format!(
|
||||
"Expected at least {} '{}' leaf node(s) but only found {}.",
|
||||
subsections[i].2.lower(),
|
||||
subsections[i].0,
|
||||
counts[i],
|
||||
),
|
||||
));
|
||||
} else {
|
||||
return Err(PsyError::WrongNodeCount(
|
||||
events.byte_offset(),
|
||||
format!(
|
||||
"Expected at least {} internal '{}' node(s) but only found {}.",
|
||||
subsections[i].2.lower(),
|
||||
subsections[i].0,
|
||||
counts[i],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ========================================================
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
296
src/parse/psy.rs
296
src/parse/psy.rs
|
@ -19,7 +19,7 @@ use crate::{
|
|||
};
|
||||
|
||||
use super::{
|
||||
parse_utils::{ensure_close, ws_f32, ws_u32},
|
||||
parse_utils::{ensure_close, ensure_subsections, ws_f32, ws_u32},
|
||||
psy_assembly::parse_assembly,
|
||||
psy_light::parse_distant_disk_light,
|
||||
psy_surface_shader::parse_surface_shader,
|
||||
|
@ -127,76 +127,76 @@ pub fn parse_scene<'a>(
|
|||
events: &mut DataTreeReader<impl BufRead>,
|
||||
_ident: Option<&str>,
|
||||
) -> PsyResult<Scene<'a>> {
|
||||
// Get output info.
|
||||
let _output_info = if let Event::InnerOpen {
|
||||
type_name: "Output",
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_output_info(events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
// Get everything except the root assembly (which comes last).
|
||||
let mut output_info = None;
|
||||
let mut render_settings = None;
|
||||
let mut shaders = None;
|
||||
let mut world = None;
|
||||
let mut camera = None;
|
||||
let valid_subsections = &[
|
||||
("Output", false, (1).into()),
|
||||
("RenderSettings", false, (1).into()),
|
||||
("Shaders", false, (1).into()),
|
||||
("World", false, (1).into()),
|
||||
("Camera", false, (1).into()),
|
||||
];
|
||||
ensure_subsections(events, valid_subsections, |events| {
|
||||
match events.next_event()? {
|
||||
Event::InnerOpen {
|
||||
type_name: "Output",
|
||||
..
|
||||
} => {
|
||||
output_info = Some(parse_output_info(events)?);
|
||||
}
|
||||
|
||||
// Get render settings.
|
||||
let _render_settings = if let Event::InnerOpen {
|
||||
type_name: "RenderSettings",
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_render_settings(events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
Event::InnerOpen {
|
||||
type_name: "RenderSettings",
|
||||
..
|
||||
} => {
|
||||
render_settings = Some(parse_render_settings(events)?);
|
||||
}
|
||||
|
||||
// Get shaders.
|
||||
let shaders = if let Event::InnerOpen {
|
||||
type_name: "Shaders",
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_shaders(arena, events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
Event::InnerOpen {
|
||||
type_name: "Shaders",
|
||||
..
|
||||
} => {
|
||||
shaders = Some(parse_shaders(arena, events)?);
|
||||
}
|
||||
|
||||
// Get world.
|
||||
let world = if let Event::InnerOpen {
|
||||
type_name: "World", ..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_world(arena, events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
Event::InnerOpen {
|
||||
type_name: "World", ..
|
||||
} => {
|
||||
world = Some(parse_world(arena, events)?);
|
||||
}
|
||||
|
||||
// Get camera.
|
||||
let camera = if let Event::InnerOpen {
|
||||
type_name: "Camera",
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_camera(arena, events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
Event::InnerOpen {
|
||||
type_name: "Camera",
|
||||
..
|
||||
} => {
|
||||
camera = Some(parse_camera(arena, events)?);
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Get the root assembly.
|
||||
let root_assembly = if let Event::InnerOpen {
|
||||
type_name: "Assembly",
|
||||
..
|
||||
} = events.next_event()?
|
||||
{
|
||||
parse_assembly(arena, events)?
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
};
|
||||
let mut root_assembly = None;
|
||||
let valid_subsections = &[("Assembly", false, (1).into())];
|
||||
ensure_subsections(events, valid_subsections, |events| {
|
||||
match events.next_event()? {
|
||||
Event::InnerOpen {
|
||||
type_name: "Assembly",
|
||||
..
|
||||
} => root_assembly = Some(parse_assembly(arena, events)?),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Make sure we're closed out properly.
|
||||
if let Event::InnerClose { .. } = events.next_event()? {
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
ensure_close(events)?;
|
||||
|
||||
// Put scene together
|
||||
// let scene_name = if let Some(name) = ident {
|
||||
|
@ -205,10 +205,10 @@ pub fn parse_scene<'a>(
|
|||
// None
|
||||
// };
|
||||
let scene = Scene {
|
||||
camera: camera,
|
||||
world: world,
|
||||
shaders: shaders,
|
||||
root_assembly: root_assembly,
|
||||
camera: camera.unwrap(),
|
||||
world: world.unwrap(),
|
||||
shaders: shaders.unwrap(),
|
||||
root_assembly: root_assembly.unwrap(),
|
||||
};
|
||||
|
||||
// // Put renderer together
|
||||
|
@ -227,9 +227,10 @@ pub fn parse_scene<'a>(
|
|||
}
|
||||
|
||||
fn parse_output_info(events: &mut DataTreeReader<impl BufRead>) -> PsyResult<String> {
|
||||
let mut found_path = false;
|
||||
let mut path = String::new();
|
||||
loop {
|
||||
|
||||
let valid_subsections = &[("Path", true, (1).into())];
|
||||
ensure_subsections(events, valid_subsections, |events| {
|
||||
match events.next_event()? {
|
||||
Event::Leaf {
|
||||
type_name: "Path",
|
||||
|
@ -253,42 +254,36 @@ fn parse_output_info(events: &mut DataTreeReader<impl BufRead>) -> PsyResult<Str
|
|||
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.
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if found_path {
|
||||
return Ok(path);
|
||||
} else {
|
||||
// return Err(PsyError::MissingNode(
|
||||
// tree.byte_offset(),
|
||||
// "Output section must contain a Path.",
|
||||
// ));
|
||||
todo!(); // Return error.
|
||||
}
|
||||
ensure_close(events)?;
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn parse_render_settings(
|
||||
events: &mut DataTreeReader<impl BufRead>,
|
||||
) -> PsyResult<((u32, u32), u32, u32)> {
|
||||
let mut found_res = false;
|
||||
let mut found_spp = false;
|
||||
let mut res = (0, 0);
|
||||
let mut spp = 0;
|
||||
let mut seed = 0;
|
||||
loop {
|
||||
|
||||
// Parse
|
||||
let valid_subsections = &[
|
||||
("Resolution", true, (1).into()),
|
||||
("SamplesPerPixel", true, (1).into()),
|
||||
("Seed", true, (..).into()),
|
||||
];
|
||||
ensure_subsections(events, valid_subsections, |events| {
|
||||
match events.next_event()? {
|
||||
// Resolution
|
||||
Event::Leaf {
|
||||
|
@ -298,7 +293,6 @@ fn parse_render_settings(
|
|||
} => {
|
||||
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
|
||||
|
@ -318,7 +312,6 @@ fn parse_render_settings(
|
|||
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
|
||||
|
@ -350,26 +343,17 @@ fn parse_render_settings(
|
|||
}
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(); // Return error.
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if found_res && found_spp {
|
||||
return Ok((res, spp, seed));
|
||||
} else {
|
||||
// return Err(PsyError::MissingNode(
|
||||
// tree.byte_offset(),
|
||||
// "RenderSettings must have both Resolution and \
|
||||
// SamplesPerPixel specified.",
|
||||
// ));
|
||||
todo!(); // Return error.
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
ensure_close(events)?;
|
||||
|
||||
Ok((res, spp, seed))
|
||||
}
|
||||
|
||||
fn parse_camera<'a>(
|
||||
|
@ -382,7 +366,13 @@ fn parse_camera<'a>(
|
|||
let mut aperture_radii = Vec::new();
|
||||
|
||||
// Parse
|
||||
loop {
|
||||
let valid_subsections = &[
|
||||
("Fov", true, (1..).into()),
|
||||
("FocalDistance", true, (1..).into()),
|
||||
("ApertureRadius", true, (1..).into()),
|
||||
("Transform", true, (1..).into()),
|
||||
];
|
||||
ensure_subsections(events, valid_subsections, |events| {
|
||||
match events.next_event()? {
|
||||
// Fov
|
||||
Event::Leaf {
|
||||
|
@ -455,15 +445,15 @@ fn parse_camera<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(); // Return error.
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
ensure_close(events)?;
|
||||
|
||||
return Ok(Camera::new(
|
||||
arena,
|
||||
|
@ -481,7 +471,11 @@ fn parse_world<'a>(
|
|||
let mut background_color = None;
|
||||
let mut lights: Vec<&dyn WorldLightSource> = Vec::new();
|
||||
|
||||
loop {
|
||||
let valid_subsections = &[
|
||||
("BackgroundShader", false, (1).into()),
|
||||
("DistantDiskLight", false, (..).into()),
|
||||
];
|
||||
ensure_subsections(events, valid_subsections, |events| {
|
||||
match events.next_event()? {
|
||||
// Parse background shader
|
||||
Event::InnerOpen {
|
||||
|
@ -496,7 +490,7 @@ fn parse_world<'a>(
|
|||
{
|
||||
contents.to_string()
|
||||
} else {
|
||||
todo!(); // Return error.
|
||||
panic!("No type specified for the BackgroundShader"); // Return error.
|
||||
};
|
||||
|
||||
match bgs_type.as_ref() {
|
||||
|
@ -504,12 +498,12 @@ fn parse_world<'a>(
|
|||
if let Event::Leaf {
|
||||
type_name: "Color",
|
||||
contents,
|
||||
..
|
||||
byte_offset,
|
||||
} = events.next_event()?
|
||||
{
|
||||
background_color = Some(parse_color(contents)?);
|
||||
background_color = Some(parse_color(byte_offset, contents)?);
|
||||
} else {
|
||||
todo!(
|
||||
panic!(
|
||||
"BackgroundShader's Type is Color, \
|
||||
but no Color is specified."
|
||||
); // Return error.
|
||||
|
@ -517,7 +511,7 @@ fn parse_world<'a>(
|
|||
}
|
||||
|
||||
_ => {
|
||||
todo!(
|
||||
panic!(
|
||||
"The specified BackgroundShader Type \
|
||||
isn't a recognized type.",
|
||||
); // Return an error.
|
||||
|
@ -541,16 +535,12 @@ fn parse_world<'a>(
|
|||
ident.as_deref(),
|
||||
)?));
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
ensure_close(events)?;
|
||||
|
||||
if background_color == None {
|
||||
todo!(); // Return error.
|
||||
|
@ -568,12 +558,13 @@ fn parse_shaders<'a>(
|
|||
events: &mut DataTreeReader<impl BufRead>,
|
||||
) -> PsyResult<HashMap<String, Box<dyn SurfaceShader>>> {
|
||||
let mut shaders = HashMap::new();
|
||||
loop {
|
||||
let valid_subsections = &[("SurfaceShader", false, (..).into())];
|
||||
ensure_subsections(events, valid_subsections, |events| {
|
||||
match events.next_event()? {
|
||||
Event::InnerOpen {
|
||||
type_name: "SurfaceShader",
|
||||
ident,
|
||||
..
|
||||
byte_offset,
|
||||
} => {
|
||||
if let Some(name) = ident {
|
||||
let name = name.to_string();
|
||||
|
@ -582,19 +573,19 @@ fn parse_shaders<'a>(
|
|||
parse_surface_shader(arena, events, Some(&name))?,
|
||||
);
|
||||
} else {
|
||||
todo!("Shader has no name."); // Return error.
|
||||
return Err(PsyError::ExpectedIdent(
|
||||
byte_offset,
|
||||
"SurfaceShader has no name.".into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(); // Return error.
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
ensure_close(events)?;
|
||||
|
||||
// Return the list of shaders.
|
||||
return Ok(shaders);
|
||||
|
@ -626,39 +617,44 @@ pub fn make_transform_format_error(byte_offset: usize) -> PsyError {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn parse_color(contents: &str) -> PsyResult<Color> {
|
||||
pub fn parse_color(byte_offset: usize, contents: &str) -> PsyResult<Color> {
|
||||
let items: Vec<_> = contents.split(',').map(|s| s.trim()).collect();
|
||||
if items.len() != 2 {
|
||||
todo!(); // Return an error.
|
||||
return Err(PsyError::IncorrectLeafData(
|
||||
byte_offset,
|
||||
"Color has invalid format.".into(),
|
||||
));
|
||||
}
|
||||
|
||||
match items[0] {
|
||||
"rec709" => {
|
||||
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 {
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
}
|
||||
|
||||
"blackbody" => {
|
||||
if let IResult::Ok((_, (temperature, factor))) = tuple((ws_f32, ws_f32))(items[1]) {
|
||||
return Ok(Color::new_blackbody(temperature, factor));
|
||||
} else {
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
}
|
||||
|
||||
"color_temperature" => {
|
||||
if let IResult::Ok((_, (temperature, factor))) = tuple((ws_f32, ws_f32))(items[1]) {
|
||||
return Ok(Color::new_temperature(temperature, factor));
|
||||
} else {
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!(); // Return an error.
|
||||
s => {
|
||||
return Err(PsyError::IncorrectLeafData(
|
||||
byte_offset,
|
||||
format!("Unrecognized color type '{}.", s),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Err(PsyError::IncorrectLeafData(
|
||||
byte_offset,
|
||||
"Color has invalid format.".into(),
|
||||
))
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use data_tree::{DataTreeReader, Event};
|
|||
use crate::scene::{Assembly, Object, ObjectData};
|
||||
|
||||
use super::{
|
||||
parse_utils::ensure_close,
|
||||
parse_utils::{ensure_close, ensure_subsections},
|
||||
psy::{parse_matrix, PsyError, PsyResult},
|
||||
psy_light::{parse_rectangle_light, parse_sphere_light},
|
||||
psy_mesh_surface::parse_mesh_surface,
|
||||
|
@ -20,115 +20,112 @@ pub fn parse_assembly<'a>(
|
|||
events: &mut DataTreeReader<impl BufRead>,
|
||||
) -> PsyResult<Assembly<'a>> {
|
||||
let mut assembly = Assembly::new();
|
||||
loop {
|
||||
match events.next_event()? {
|
||||
Event::InnerOpen {
|
||||
type_name: "Object",
|
||||
ident,
|
||||
byte_offset,
|
||||
} => {
|
||||
// Get object identifier.
|
||||
let object_ident = if let Some(id) = ident {
|
||||
id.to_string()
|
||||
} else {
|
||||
return Err(PsyError::ExpectedIdent(
|
||||
byte_offset,
|
||||
"\'Object\' types must have an identifier, but the identifier is missing."
|
||||
.into(),
|
||||
));
|
||||
};
|
||||
ensure_subsections(events, &[("Object", false, (1..).into())], |events| {
|
||||
if let Event::InnerOpen {
|
||||
type_name: "Object",
|
||||
ident,
|
||||
byte_offset,
|
||||
} = events.next_event()?
|
||||
{
|
||||
// Get object identifier.
|
||||
let object_ident = if let Some(id) = ident {
|
||||
id.to_string()
|
||||
} else {
|
||||
return Err(PsyError::ExpectedIdent(
|
||||
byte_offset,
|
||||
"\'Object\' types must have an identifier, but the identifier is missing."
|
||||
.into(),
|
||||
));
|
||||
};
|
||||
|
||||
// Collect instances.
|
||||
let mut instance_xform_idxs = Vec::new();
|
||||
while let Event::InnerOpen {
|
||||
type_name: "Instance",
|
||||
..
|
||||
} = events.peek_event()?
|
||||
{
|
||||
events.next_event();
|
||||
let xforms_start_idx = assembly.xforms.len();
|
||||
loop {
|
||||
match events.next_event()? {
|
||||
Event::Leaf {
|
||||
type_name: "Transform",
|
||||
contents,
|
||||
..
|
||||
} => {
|
||||
assembly.xforms.push(parse_matrix(contents)?);
|
||||
}
|
||||
// Collect instances.
|
||||
let mut instance_xform_idxs = Vec::new();
|
||||
while let Event::InnerOpen {
|
||||
type_name: "Instance",
|
||||
..
|
||||
} = events.peek_event()?
|
||||
{
|
||||
events.next_event()?;
|
||||
let xforms_start_idx = assembly.xforms.len();
|
||||
loop {
|
||||
match events.next_event()? {
|
||||
Event::Leaf {
|
||||
type_name: "Transform",
|
||||
contents,
|
||||
..
|
||||
} => {
|
||||
assembly.xforms.push(parse_matrix(contents)?);
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!("Instances can only contain Transforms.");
|
||||
// Return an error.
|
||||
}
|
||||
_ => {
|
||||
todo!("Instances can only contain Transforms.");
|
||||
// Return an error.
|
||||
}
|
||||
}
|
||||
|
||||
instance_xform_idxs.push(xforms_start_idx..assembly.xforms.len());
|
||||
}
|
||||
|
||||
// Get object data.
|
||||
let object_data = match events.next_event()? {
|
||||
Event::InnerOpen {
|
||||
type_name: "Assembly",
|
||||
..
|
||||
} => ObjectData::Assembly(Box::new(parse_assembly(arena, events)?)),
|
||||
|
||||
Event::InnerOpen {
|
||||
type_name: "MeshSurface",
|
||||
..
|
||||
} => ObjectData::Surface(Box::new(parse_mesh_surface(arena, events)?)),
|
||||
|
||||
Event::InnerOpen {
|
||||
type_name: "SphereLight",
|
||||
..
|
||||
} => ObjectData::Light(Box::new(parse_sphere_light(arena, events)?)),
|
||||
|
||||
Event::InnerOpen {
|
||||
type_name: "RectangleLight",
|
||||
..
|
||||
} => ObjectData::Light(Box::new(parse_rectangle_light(arena, events)?)),
|
||||
|
||||
Event::InnerClose { byte_offset } => {
|
||||
return Err(PsyError::MissingNode(
|
||||
byte_offset,
|
||||
"Object contains no object data.".into(),
|
||||
));
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(PsyError::UnknownVariant(
|
||||
byte_offset,
|
||||
"Unknown data type for Object.".into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// Close object node.
|
||||
ensure_close(events)?;
|
||||
|
||||
assembly.objects.insert(
|
||||
object_ident,
|
||||
Object {
|
||||
data: object_data,
|
||||
instance_xform_idxs: instance_xform_idxs,
|
||||
},
|
||||
);
|
||||
instance_xform_idxs.push(xforms_start_idx..assembly.xforms.len());
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
break;
|
||||
}
|
||||
// Get object data.
|
||||
let object_data = match events.next_event()? {
|
||||
Event::InnerOpen {
|
||||
type_name: "Assembly",
|
||||
..
|
||||
} => ObjectData::Assembly(Box::new(parse_assembly(arena, events)?)),
|
||||
|
||||
_ => {
|
||||
todo!(); // Return an error.
|
||||
}
|
||||
Event::InnerOpen {
|
||||
type_name: "MeshSurface",
|
||||
..
|
||||
} => ObjectData::Surface(Box::new(parse_mesh_surface(arena, events)?)),
|
||||
|
||||
Event::InnerOpen {
|
||||
type_name: "SphereLight",
|
||||
..
|
||||
} => ObjectData::Light(Box::new(parse_sphere_light(arena, events)?)),
|
||||
|
||||
Event::InnerOpen {
|
||||
type_name: "RectangleLight",
|
||||
..
|
||||
} => ObjectData::Light(Box::new(parse_rectangle_light(arena, events)?)),
|
||||
|
||||
Event::InnerClose { byte_offset } => {
|
||||
return Err(PsyError::MissingNode(
|
||||
byte_offset,
|
||||
"Object contains no object data.".into(),
|
||||
));
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(PsyError::UnknownVariant(
|
||||
byte_offset,
|
||||
"Unknown data type for Object.".into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// Close object node.
|
||||
ensure_close(events)?;
|
||||
|
||||
assembly.objects.insert(
|
||||
object_ident,
|
||||
Object {
|
||||
data: object_data,
|
||||
instance_xform_idxs: instance_xform_idxs,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
ensure_close(events)?;
|
||||
|
||||
// if !tree.is_internal() {
|
||||
// return Err(PsyError::UnknownError(tree.byte_offset()));
|
||||
|
|
|
@ -65,12 +65,7 @@ pub fn parse_distant_disk_light<'a>(
|
|||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let Ok(color) = parse_color(&contents) {
|
||||
colors.push(color);
|
||||
} else {
|
||||
// Found color, but its contents is not in the right format
|
||||
return Err(PsyError::UnknownError(byte_offset));
|
||||
}
|
||||
colors.push(parse_color(byte_offset, &contents)?);
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
|
@ -116,12 +111,7 @@ pub fn parse_sphere_light<'a>(
|
|||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let Ok(color) = parse_color(&contents) {
|
||||
colors.push(color);
|
||||
} else {
|
||||
// Found color, but its contents is not in the right format
|
||||
return Err(PsyError::UnknownError(byte_offset));
|
||||
}
|
||||
colors.push(parse_color(byte_offset, &contents)?);
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
|
@ -168,12 +158,7 @@ pub fn parse_rectangle_light<'a>(
|
|||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let Ok(color) = parse_color(&contents) {
|
||||
colors.push(color);
|
||||
} else {
|
||||
// Found color, but its contents is not in the right format
|
||||
return Err(PsyError::UnknownError(byte_offset));
|
||||
}
|
||||
colors.push(parse_color(byte_offset, &contents)?);
|
||||
}
|
||||
|
||||
Event::InnerClose { .. } => {
|
||||
|
|
|
@ -40,12 +40,7 @@ pub fn parse_surface_shader(
|
|||
byte_offset,
|
||||
} = events.next_event()?
|
||||
{
|
||||
if let Ok(color) = parse_color(contents) {
|
||||
color
|
||||
} else {
|
||||
// Found color, but its contents is not in the right format
|
||||
return Err(PsyError::UnknownError(byte_offset));
|
||||
}
|
||||
parse_color(byte_offset, contents)?
|
||||
} else {
|
||||
return Err(PsyError::MissingNode(
|
||||
events.byte_offset(),
|
||||
|
@ -76,13 +71,7 @@ pub fn parse_surface_shader(
|
|||
contents,
|
||||
byte_offset,
|
||||
} => {
|
||||
if let Ok(col) = parse_color(contents) {
|
||||
color = Some(col);
|
||||
} else {
|
||||
// Found color, but its contents is not in the right
|
||||
// format.
|
||||
return Err(PsyError::UnknownError(byte_offset));
|
||||
}
|
||||
color = Some(parse_color(byte_offset, contents)?);
|
||||
}
|
||||
|
||||
// Roughness
|
||||
|
@ -147,12 +136,7 @@ pub fn parse_surface_shader(
|
|||
byte_offset,
|
||||
} = events.next_event()?
|
||||
{
|
||||
if let Ok(color) = parse_color(contents) {
|
||||
color
|
||||
} else {
|
||||
// Found color, but its contents is not in the right format
|
||||
return Err(PsyError::UnknownError(byte_offset));
|
||||
}
|
||||
parse_color(byte_offset, contents)?
|
||||
} else {
|
||||
return Err(PsyError::MissingNode(
|
||||
events.byte_offset(),
|
||||
|
|
Loading…
Reference in New Issue
Block a user