Parsing some stuff.

This commit is contained in:
hal8174 2025-08-01 22:17:33 +02:00
parent 16b9c32632
commit 96a24fcc28
Signed by: hal8174
SSH key fingerprint: SHA256:NN98ZYwnrreQLSOV/g+amY7C3yL/mS1heD7bi5t6PPw
2 changed files with 371 additions and 37 deletions

View file

@ -10,5 +10,7 @@ struct Args {
fn main() -> Result<(), miette::Error> { fn main() -> Result<(), miette::Error> {
let args = Args::parse(); let args = Args::parse();
parse_pbrt_v4(args.filename) dbg!(parse_pbrt_v4(args.filename)?);
Ok(())
} }

View file

@ -117,6 +117,7 @@ enum Statement {
AttributeEnd, AttributeEnd,
Include(String), Include(String),
ConcatTransform(AffineTransform), ConcatTransform(AffineTransform),
Shape(ShapeType),
Unknown(String, Vec<String>), Unknown(String, Vec<String>),
} }
@ -169,14 +170,331 @@ fn parse_look_at(iter: &mut impl Iterator<Item = Result<String>>) -> Result<Stat
))) )))
} }
fn parse_parameter<I, T>(iter: &mut Peekable<Tokenizer<I>>) -> Result<T>
where
I: Iterator<Item = Result<char>>,
T: std::str::FromStr,
<T as 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::<T>().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::<T>().into_diagnostic()?),
}
}
fn parse_list<I, T>(iter: &mut Peekable<Tokenizer<I>>, data: &mut Vec<T>) -> Result<()>
where
I: Iterator<Item = Result<char>>,
T: std::str::FromStr,
<T as 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<I, T, P, F>(
iter: &mut Peekable<Tokenizer<I>>,
data: &mut Vec<P>,
f: F,
) -> Result<()>
where
I: Iterator<Item = Result<char>>,
T: std::str::FromStr,
<T as 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<I, T, P, F>(
iter: &mut Peekable<Tokenizer<I>>,
data: &mut Vec<P>,
f: F,
) -> Result<()>
where
I: Iterator<Item = Result<char>>,
T: std::str::FromStr,
<T as 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<I: Iterator<Item = Result<char>>>( fn parse_shape<I: Iterator<Item = Result<char>>>(
iter: &mut Peekable<Tokenizer<I>>, iter: &mut Peekable<Tokenizer<I>>,
) -> std::result::Result<Statement, Error> { ) -> std::result::Result<Statement, Error> {
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() { match shape_type.as_str() {
"sphere" => {} "\"sphere\"" => {
_ => Err(miette!("")), 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<I: Iterator<Item = Result<char>>> Lexer<I> {
} }
"LookAt" => Some(parse_look_at(&mut self.input)), "LookAt" => Some(parse_look_at(&mut self.input)),
"Identity" => Some(Ok(Statement::ConcatTransform(AffineTransform::identity()))), "Identity" => Some(Ok(Statement::ConcatTransform(AffineTransform::identity()))),
"Shape" => Some(parse_shape(&mut self.input)),
_ => { _ => {
if s.chars().any(|c| !c.is_ascii_alphabetic()) { if s.chars().any(|c| !c.is_ascii_alphabetic()) {
Some(Err(miette!("malformed identifier"))) Some(Err(miette!("malformed identifier")))
@ -218,7 +537,6 @@ impl<I: Iterator<Item = Result<char>>> Lexer<I> {
Some(Ok(Statement::Unknown(s, v))) Some(Ok(Statement::Unknown(s, v)))
} }
} }
"Shape" => Some(parse_shape(&mut self.input)),
}, },
Some(Err(e)) => Some(Err(e)), Some(Err(e)) => Some(Err(e)),
None => None, None => None,
@ -251,7 +569,6 @@ struct Parser<P> {
path: P, path: P,
inner: Option<Box<Parser<PathBuf>>>, inner: Option<Box<Parser<PathBuf>>>,
iter: Lexer<BytesToChar<Bytes<BufReader<File>>>>, iter: Lexer<BytesToChar<Bytes<BufReader<File>>>>,
ctm: AffineTransform,
} }
impl<P: AsRef<Path> + std::fmt::Debug> Parser<P> { impl<P: AsRef<Path> + std::fmt::Debug> Parser<P> {
@ -260,40 +577,29 @@ impl<P: AsRef<Path> + std::fmt::Debug> Parser<P> {
let bufreader = BufReader::new(std::fs::File::open(&path).into_diagnostic()?); let bufreader = BufReader::new(std::fs::File::open(&path).into_diagnostic()?);
Ok(Self { Ok(Self {
path, path,
ctm: AffineTransform::identity(),
inner: None, inner: None,
iter: Lexer::new(BytesToChar { iter: Lexer::new(BytesToChar {
iter: bufreader.bytes(), iter: bufreader.bytes(),
}), }),
}) })
} }
fn apply_transform(&mut self, transform: AffineTransform) {
self.ctm *= transform;
}
fn set_transform(&mut self, transform: AffineTransform) {
self.ctm = transform;
}
} }
impl<P: AsRef<Path>> Iterator for Parser<P> { impl<P: AsRef<Path>> Parser<P> {
type Item = Result<Statement>; fn next(&mut self, context: &PbrtContext) -> Option<Result<Statement>> {
fn next(&mut self) -> Option<Self::Item> {
if let Some(iter) = &mut self.inner { if let Some(iter) = &mut self.inner {
if let Some(statement) = iter.next() { if let Some(statement) = iter.next(context) {
return Some(statement); return Some(statement);
} }
self.inner = None; self.inner = None;
} }
match self.iter.next(self.ctm) { match self.iter.next(context.ctm) {
Some(Ok(Statement::Include(s))) => { Some(Ok(Statement::Include(s))) => {
let path = self.path.as_ref().parent().unwrap().join(s); let path = self.path.as_ref().parent().unwrap().join(s);
self.inner = Some(Box::new(Parser::new(path).unwrap())); self.inner = Some(Box::new(Parser::new(path).unwrap()));
self.next() self.next(context)
} }
Some(s) => Some(s), Some(s) => Some(s),
None => None, None => None,
@ -301,6 +607,7 @@ impl<P: AsRef<Path>> Iterator for Parser<P> {
} }
} }
#[derive(Debug)]
enum ShapeType { enum ShapeType {
Sphere { Sphere {
radius: Float, radius: Float,
@ -308,29 +615,50 @@ enum ShapeType {
zmax: Float, zmax: Float,
phimax: Float, phimax: Float,
}, },
TriangleMesh {
indices: Vec<usize>,
p: Vec<Pos3>,
n: Vec<Dir3>,
s: Vec<Dir3>,
uv: Vec<[Float; 2]>,
},
BilinearMesh {
p: [Pos3; 4],
uv: [[Float; 2]; 4],
},
LoopSubDiv {
levels: u32,
indices: Vec<usize>,
p: Vec<Pos3>,
},
} }
#[derive(Debug)]
struct Shape { struct Shape {
ctm: AffineTransform, ctm: AffineTransform,
material: usize, material: usize,
obj: ShapeType, obj: ShapeType,
} }
struct Pbrt { #[derive(Debug)]
pub struct Pbrt {
settings: PbrtWorldSettings, settings: PbrtWorldSettings,
scene: PbrtScene, scene: PbrtScene,
} }
impl Pbrt { impl Pbrt {
fn new() -> Self { fn new() -> Self {
Self { Self {
settings: todo!(), settings: PbrtWorldSettings {},
scene: todo!(), scene: PbrtScene { shapes: Vec::new() },
} }
} }
} }
#[derive(Debug)]
struct PbrtWorldSettings {} struct PbrtWorldSettings {}
#[derive(Debug)]
struct PbrtScene { struct PbrtScene {
shapes: Vec<Shape>, shapes: Vec<Shape>,
} }
@ -352,13 +680,15 @@ fn inner_parse_pbrt(
path: impl AsRef<Path> + std::fmt::Debug, path: impl AsRef<Path> + std::fmt::Debug,
context: Option<PbrtContext>, context: Option<PbrtContext>,
) -> Result<Pbrt> { ) -> Result<Pbrt> {
// unwrap on context.last() ok because context is never empty
let mut context = vec![context.unwrap_or(PbrtContext::new())]; let mut context = vec![context.unwrap_or(PbrtContext::new())];
let mut parser = Parser::new(path)?; let mut parser = Parser::new(path)?;
let mut pbrt = Pbrt::new(); 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 { match p {
Statement::AttributeBegin => context.push(context.last().ok_or(miette!(""))?.clone()), Statement::AttributeBegin => context.push(context.last().ok_or(miette!(""))?.clone()),
Statement::AttributeEnd => { Statement::AttributeEnd => {
@ -368,20 +698,22 @@ fn inner_parse_pbrt(
Statement::ConcatTransform(affine_transform) => { Statement::ConcatTransform(affine_transform) => {
context.last_mut().ok_or(miette!(""))?.ctm *= 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<Path> + std::fmt::Debug) -> Result<()> { pub fn parse_pbrt_v4(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
let mut tokens = 0; inner_parse_pbrt(path, None)
for token in Parser::new(path).unwrap() {
dbg!(token);
tokens += 1;
}
dbg!(tokens);
Ok(())
} }