From 96a24fcc28a9d84bb9c63ed7d438abde9a48bded Mon Sep 17 00:00:00 2001 From: hal8174 Date: Fri, 1 Aug 2025 22:17:33 +0200 Subject: [PATCH] Parsing some stuff. --- ray-tracing-pbrt-scene/examples/pbrt-test.rs | 4 +- ray-tracing-pbrt-scene/src/lib.rs | 404 +++++++++++++++++-- 2 files changed, 371 insertions(+), 37 deletions(-) diff --git a/ray-tracing-pbrt-scene/examples/pbrt-test.rs b/ray-tracing-pbrt-scene/examples/pbrt-test.rs index e654fb5..3ee80b2 100644 --- a/ray-tracing-pbrt-scene/examples/pbrt-test.rs +++ b/ray-tracing-pbrt-scene/examples/pbrt-test.rs @@ -10,5 +10,7 @@ struct Args { fn main() -> Result<(), miette::Error> { let args = Args::parse(); - parse_pbrt_v4(args.filename) + dbg!(parse_pbrt_v4(args.filename)?); + + Ok(()) } diff --git a/ray-tracing-pbrt-scene/src/lib.rs b/ray-tracing-pbrt-scene/src/lib.rs index 37e4470..a17e59e 100644 --- a/ray-tracing-pbrt-scene/src/lib.rs +++ b/ray-tracing-pbrt-scene/src/lib.rs @@ -117,6 +117,7 @@ enum Statement { AttributeEnd, Include(String), ConcatTransform(AffineTransform), + Shape(ShapeType), Unknown(String, Vec), } @@ -169,14 +170,331 @@ fn parse_look_at(iter: &mut impl Iterator>) -> Result(iter: &mut Peekable>) -> Result +where + I: Iterator>, + T: std::str::FromStr, + ::Err: + std::marker::Send + std::marker::Sync + std::error::Error + 'static, +{ + let p = iter.next().ok_or(miette!("value expected"))??; + + match p.as_str() { + "[" => { + let s = iter.next().ok_or(miette!("value expected"))??; + + let d = s.parse::().into_diagnostic()?; + + if !iter + .next() + .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]")) + { + bail!("expected closing bracket.") + } + + Ok(d) + } + s => Ok(s.parse::().into_diagnostic()?), + } +} + +fn parse_list(iter: &mut Peekable>, data: &mut Vec) -> Result<()> +where + I: Iterator>, + T: std::str::FromStr, + ::Err: + std::marker::Send + std::marker::Sync + std::error::Error + 'static, +{ + if !iter + .next() + .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "[")) + { + bail!("expected list.") + } + + while let Some(p) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p != "]")) + .transpose()? + { + data.push(p.parse().into_diagnostic()?); + } + + if !iter + .next() + .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]")) + { + bail!("expected list end.") + } + + Ok(()) +} + +fn parse_list_2( + iter: &mut Peekable>, + data: &mut Vec

, + f: F, +) -> Result<()> +where + I: Iterator>, + T: std::str::FromStr, + ::Err: + std::marker::Send + std::marker::Sync + std::error::Error + 'static, + F: Fn(T, T) -> P, +{ + if !iter + .next() + .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "[")) + { + bail!("expected list.") + } + + while let Some(pa) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p != "]")) + .transpose()? + { + if let Some(pb) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p != "]")) + .transpose()? + { + data.push(f( + pa.parse().into_diagnostic()?, + pb.parse().into_diagnostic()?, + )); + } else { + bail!("Unfinished group") + } + } + + if !iter + .next() + .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]")) + { + bail!("expected list end.") + } + + Ok(()) +} + +fn parse_list_3( + iter: &mut Peekable>, + data: &mut Vec

, + f: F, +) -> Result<()> +where + I: Iterator>, + T: std::str::FromStr, + ::Err: + std::marker::Send + std::marker::Sync + std::error::Error + 'static, + F: Fn(T, T, T) -> P, +{ + if !iter + .next() + .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "[")) + { + bail!("expected list.") + } + + while let Some(pa) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p != "]")) + .transpose()? + { + if let Some(pb) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p != "]")) + .transpose()? + { + if let Some(pc) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p != "]")) + .transpose()? + { + data.push(f( + pa.parse().into_diagnostic()?, + pb.parse().into_diagnostic()?, + pc.parse().into_diagnostic()?, + )); + } else { + bail!("Unfinished group") + } + } else { + bail!("Unfinished group") + } + } + + if !iter + .next() + .is_none_or(|p| p.is_ok_and(|p| p.as_str() == "]")) + { + bail!("expected list end.") + } + + Ok(()) +} + fn parse_shape>>( iter: &mut Peekable>, ) -> std::result::Result { - let shape_type = iter.next().ok_or(miette!(""))??; + let shape_type = iter.next().ok_or(miette!("unable to get shape type"))??; match shape_type.as_str() { - "sphere" => {} - _ => Err(miette!("")), + "\"sphere\"" => { + let mut radius = 1.0; + let zmin = -radius; + let zmax = radius; + let phimax = 360.0; + + while let Some(p) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p.starts_with('"'))) + .transpose()? + { + match p.as_str() { + "\"float radius\"" => { + radius = parse_parameter(iter)?; + } + _ => { + bail!("unknown argument {}", p) + } + } + } + + Ok(Statement::Shape(ShapeType::Sphere { + radius, + zmin, + zmax, + phimax, + })) + } + "\"trianglemesh\"" => { + let mut indices = Vec::new(); + let mut p = Vec::new(); + let mut n = Vec::new(); + let mut s = Vec::new(); + let mut uv = Vec::new(); + + while let Some(q) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p.starts_with('"'))) + .transpose()? + { + match q.as_str() { + "\"integer indices\"" => { + parse_list(iter, &mut indices)?; + } + "\"point3 P\"" => { + parse_list_3(iter, &mut p, Pos3::new)?; + } + "\"normal N\"" => { + parse_list_3(iter, &mut n, Dir3::new)?; + } + "\"vector N\"" => { + parse_list_3(iter, &mut s, Dir3::new)?; + } + "\"point2 uv\"" => { + parse_list_2(iter, &mut uv, |u, v| [u, v])?; + } + _ => { + bail!("unknown argument {}", q) + } + } + } + if p.len() < 3 { + bail!("At least 3 points required.") + } + if indices.is_empty() && p.len() != 3 { + bail!("Indices required for trianglemesh with more than 3 points.") + } + + if indices.len() % 3 != 0 { + bail!( + "number of indices must be divisible by 3. num indices: {}", + indices.len() + ) + } + + if !n.is_empty() && n.len() != p.len() { + bail!("Number of normals not equal to number of positions.") + } + + if !s.is_empty() && s.len() != p.len() { + bail!("Number of tangents not equal to number of positions.") + } + if !uv.is_empty() && uv.len() != p.len() { + bail!("Number of uvs not equal to number of positions.") + } + Ok(Statement::Shape(ShapeType::TriangleMesh { + indices, + p, + n, + s, + uv, + })) + } + "\"bilinearmesh\"" => { + let mut p = Vec::new(); + + let mut uv = Vec::new(); + + while let Some(q) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p.starts_with('"'))) + .transpose()? + { + match q.as_str() { + "\"point3 P\"" => { + parse_list_3(iter, &mut p, Pos3::new)?; + } + "\"point2 uv\"" => { + parse_list_2(iter, &mut uv, |u, v| [u, v])?; + } + _ => { + bail!("unknown argument {}", q) + } + } + } + + Ok(Statement::Shape(ShapeType::BilinearMesh { + p: [p[0], p[1], p[2], p[3]], + uv: [uv[0], uv[1], uv[2], uv[3]], + })) + } + + "\"loopsubdiv\"" => { + let mut levels = 3; + let mut indices = Vec::new(); + + let mut p = Vec::new(); + + while let Some(q) = iter + .next_if(|p| p.as_ref().is_ok_and(|p| p.starts_with('"'))) + .transpose()? + { + match q.as_str() { + "\"point3 P\"" => { + parse_list_3(iter, &mut p, Pos3::new)?; + } + "\"integer indices\"" => { + parse_list(iter, &mut indices)?; + } + "\"integer levels\"" => { + levels = parse_parameter(iter)?; + } + _ => { + bail!("unknown argument {}", q) + } + } + } + + if indices.is_empty() { + bail!("indices are a required field") + } + + if p.is_empty() { + bail!("p is a required field") + } + + Ok(Statement::Shape(ShapeType::LoopSubDiv { + levels, + indices, + p, + })) + } + _ => Err(miette!("Unknown shape {}", shape_type)), } } @@ -199,6 +517,7 @@ impl>> Lexer { } "LookAt" => Some(parse_look_at(&mut self.input)), "Identity" => Some(Ok(Statement::ConcatTransform(AffineTransform::identity()))), + "Shape" => Some(parse_shape(&mut self.input)), _ => { if s.chars().any(|c| !c.is_ascii_alphabetic()) { Some(Err(miette!("malformed identifier"))) @@ -218,7 +537,6 @@ impl>> Lexer { Some(Ok(Statement::Unknown(s, v))) } } - "Shape" => Some(parse_shape(&mut self.input)), }, Some(Err(e)) => Some(Err(e)), None => None, @@ -251,7 +569,6 @@ struct Parser

{ path: P, inner: Option>>, iter: Lexer>>>, - ctm: AffineTransform, } impl + std::fmt::Debug> Parser

{ @@ -260,40 +577,29 @@ impl + std::fmt::Debug> Parser

{ let bufreader = BufReader::new(std::fs::File::open(&path).into_diagnostic()?); Ok(Self { path, - ctm: AffineTransform::identity(), inner: None, iter: Lexer::new(BytesToChar { iter: bufreader.bytes(), }), }) } - - fn apply_transform(&mut self, transform: AffineTransform) { - self.ctm *= transform; - } - - fn set_transform(&mut self, transform: AffineTransform) { - self.ctm = transform; - } } -impl> Iterator for Parser

{ - type Item = Result; - - fn next(&mut self) -> Option { +impl> Parser

{ + fn next(&mut self, context: &PbrtContext) -> Option> { if let Some(iter) = &mut self.inner { - if let Some(statement) = iter.next() { + if let Some(statement) = iter.next(context) { return Some(statement); } self.inner = None; } - match self.iter.next(self.ctm) { + match self.iter.next(context.ctm) { Some(Ok(Statement::Include(s))) => { let path = self.path.as_ref().parent().unwrap().join(s); self.inner = Some(Box::new(Parser::new(path).unwrap())); - self.next() + self.next(context) } Some(s) => Some(s), None => None, @@ -301,6 +607,7 @@ impl> Iterator for Parser

{ } } +#[derive(Debug)] enum ShapeType { Sphere { radius: Float, @@ -308,29 +615,50 @@ enum ShapeType { zmax: Float, phimax: Float, }, + TriangleMesh { + indices: Vec, + p: Vec, + n: Vec, + s: Vec, + uv: Vec<[Float; 2]>, + }, + BilinearMesh { + p: [Pos3; 4], + uv: [[Float; 2]; 4], + }, + LoopSubDiv { + levels: u32, + indices: Vec, + p: Vec, + }, } +#[derive(Debug)] struct Shape { ctm: AffineTransform, material: usize, obj: ShapeType, } -struct Pbrt { +#[derive(Debug)] +pub struct Pbrt { settings: PbrtWorldSettings, scene: PbrtScene, } + impl Pbrt { fn new() -> Self { Self { - settings: todo!(), - scene: todo!(), + settings: PbrtWorldSettings {}, + scene: PbrtScene { shapes: Vec::new() }, } } } +#[derive(Debug)] struct PbrtWorldSettings {} +#[derive(Debug)] struct PbrtScene { shapes: Vec, } @@ -352,13 +680,15 @@ fn inner_parse_pbrt( path: impl AsRef + std::fmt::Debug, context: Option, ) -> Result { + // unwrap on context.last() ok because context is never empty let mut context = vec![context.unwrap_or(PbrtContext::new())]; let mut parser = Parser::new(path)?; let mut pbrt = Pbrt::new(); - while let Some(p) = parser.next().transpose()? { + while let Some(p) = parser.next(context.last().unwrap()).transpose()? { + // dbg!(&p); match p { Statement::AttributeBegin => context.push(context.last().ok_or(miette!(""))?.clone()), Statement::AttributeEnd => { @@ -368,20 +698,22 @@ fn inner_parse_pbrt( Statement::ConcatTransform(affine_transform) => { context.last_mut().ok_or(miette!(""))?.ctm *= affine_transform } - Statement::Unknown(_, items) => todo!(), + Statement::Shape(shape_type) => { + pbrt.scene.shapes.push(Shape { + ctm: context.last().unwrap().ctm, + material: 0, + obj: shape_type, + }); + } + Statement::Unknown(s, items) => { + eprintln!("Unknown statement: {s}") + } } } - todo!() + Ok(pbrt) } -pub fn parse_pbrt_v4(path: impl AsRef + std::fmt::Debug) -> Result<()> { - let mut tokens = 0; - for token in Parser::new(path).unwrap() { - dbg!(token); - tokens += 1; - } - dbg!(tokens); - - Ok(()) +pub fn parse_pbrt_v4(path: impl AsRef + std::fmt::Debug) -> Result { + inner_parse_pbrt(path, None) }