Parsing some stuff.
This commit is contained in:
parent
16b9c32632
commit
96a24fcc28
2 changed files with 371 additions and 37 deletions
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ enum Statement {
|
|||
AttributeEnd,
|
||||
Include(String),
|
||||
ConcatTransform(AffineTransform),
|
||||
Shape(ShapeType),
|
||||
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>>>(
|
||||
iter: &mut Peekable<Tokenizer<I>>,
|
||||
) -> 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() {
|
||||
"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<I: Iterator<Item = Result<char>>> Lexer<I> {
|
|||
}
|
||||
"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<I: Iterator<Item = Result<char>>> Lexer<I> {
|
|||
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<P> {
|
|||
path: P,
|
||||
inner: Option<Box<Parser<PathBuf>>>,
|
||||
iter: Lexer<BytesToChar<Bytes<BufReader<File>>>>,
|
||||
ctm: AffineTransform,
|
||||
}
|
||||
|
||||
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()?);
|
||||
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<P: AsRef<Path>> Iterator for Parser<P> {
|
||||
type Item = Result<Statement>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
impl<P: AsRef<Path>> Parser<P> {
|
||||
fn next(&mut self, context: &PbrtContext) -> Option<Result<Statement>> {
|
||||
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<P: AsRef<Path>> Iterator for Parser<P> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ShapeType {
|
||||
Sphere {
|
||||
radius: Float,
|
||||
|
|
@ -308,29 +615,50 @@ enum ShapeType {
|
|||
zmax: 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 {
|
||||
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<Shape>,
|
||||
}
|
||||
|
|
@ -352,13 +680,15 @@ fn inner_parse_pbrt(
|
|||
path: impl AsRef<Path> + std::fmt::Debug,
|
||||
context: Option<PbrtContext>,
|
||||
) -> Result<Pbrt> {
|
||||
// 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<Path> + 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<Path> + std::fmt::Debug) -> Result<Pbrt> {
|
||||
inner_parse_pbrt(path, None)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue