Initial pbrt material parsing
This commit is contained in:
parent
0dfa2128dd
commit
9a95ca8fd7
7 changed files with 401 additions and 108 deletions
|
|
@ -1,7 +1,6 @@
|
|||
use crate::tokenizer::Tokenizer;
|
||||
use error::SourceFile;
|
||||
use material::PbrtMaterial;
|
||||
use miette::{Diagnostic, IntoDiagnostic, Result, SourceSpan, bail, miette};
|
||||
use miette::{IntoDiagnostic, Result, bail, miette};
|
||||
use ray_tracing_core::{
|
||||
affine_transform::AffineTransform,
|
||||
math::{Dir3, Pos3},
|
||||
|
|
@ -13,10 +12,11 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
use texture::PbrtTexture;
|
||||
use thiserror::Error;
|
||||
|
||||
#[macro_use]
|
||||
mod tokenizer;
|
||||
|
||||
mod either;
|
||||
mod error;
|
||||
mod material;
|
||||
mod texture;
|
||||
|
|
@ -372,10 +372,7 @@ fn parse_camera(tokenizer: &mut Tokenizer) -> Result<Statement> {
|
|||
}
|
||||
|
||||
impl Lexer {
|
||||
fn next(
|
||||
&mut self,
|
||||
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
|
||||
) -> Option<Result<Statement>> {
|
||||
fn next(&mut self, context: &PbrtContext) -> Option<Result<Statement>> {
|
||||
match self.input.next() {
|
||||
Some(Ok(s)) => match s.as_str() {
|
||||
"AttributeBegin" => Some(Ok(Statement::AttributeBegin)),
|
||||
|
|
@ -400,14 +397,14 @@ impl Lexer {
|
|||
"Rotate" => Some(parse_rotate(&mut self.input)),
|
||||
"Transform" => Some(parse_transform(&mut self.input).map(Statement::Transform)),
|
||||
"Texture" => Some(
|
||||
texture::parse_texture(&mut self.input, textures)
|
||||
texture::parse_texture(&mut self.input, context)
|
||||
.map(|(name, texture)| Statement::Texture(name, texture)),
|
||||
),
|
||||
"Material" => Some(
|
||||
material::parse_material(&mut self.input, textures).map(Statement::Material),
|
||||
material::parse_material(&mut self.input, context).map(Statement::Material),
|
||||
),
|
||||
"MakeNamedMaterial" => Some(
|
||||
material::parse_make_named_material(&mut self.input, textures)
|
||||
material::parse_make_named_material(&mut self.input, context)
|
||||
.map(|(name, material)| Statement::MakeNamedMaterial(name, material)),
|
||||
),
|
||||
"NamedMaterial" => Some(self.input.parse_parameter().map(Statement::NamedMaterial)),
|
||||
|
|
@ -575,23 +572,20 @@ impl Parser {
|
|||
}
|
||||
|
||||
impl Parser {
|
||||
fn next(
|
||||
&mut self,
|
||||
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
|
||||
) -> Option<Result<Statement>> {
|
||||
fn next(&mut self, context: &PbrtContext) -> Option<Result<Statement>> {
|
||||
if let Some(iter) = &mut self.inner {
|
||||
if let Some(statement) = iter.next(textures) {
|
||||
if let Some(statement) = iter.next(context) {
|
||||
return Some(statement);
|
||||
}
|
||||
self.inner = None;
|
||||
}
|
||||
|
||||
match self.iter.next(textures) {
|
||||
match self.iter.next(context) {
|
||||
Some(Ok(Statement::Include(s))) => {
|
||||
let path = self.path.parent().unwrap().join(s);
|
||||
self.inner = Some(Box::new(Parser::new(path, self.base_path.clone()).unwrap()));
|
||||
|
||||
self.next(textures)
|
||||
self.next(context)
|
||||
}
|
||||
Some(s) => Some(s),
|
||||
None => None,
|
||||
|
|
@ -679,9 +673,65 @@ struct PbrtScene {
|
|||
shapes: Vec<Shape>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PbrtContext {
|
||||
ctm: Vec<AffineTransform>,
|
||||
textures: HashMap<String, Arc<dyn PbrtTexture>>,
|
||||
material: Vec<Arc<dyn PbrtMaterial>>,
|
||||
materials: HashMap<String, Arc<dyn PbrtMaterial>>,
|
||||
}
|
||||
|
||||
impl PbrtContext {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
ctm: vec![AffineTransform::identity()],
|
||||
textures: HashMap::new(),
|
||||
material: Vec::new(),
|
||||
materials: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_ctm(&self) -> AffineTransform {
|
||||
*self.ctm.last().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_texture(&self, name: &String) -> Option<&Arc<dyn PbrtTexture>> {
|
||||
self.textures.get(name)
|
||||
}
|
||||
|
||||
pub fn get_named_material(&self, name: &String) -> Option<&Arc<dyn PbrtMaterial>> {
|
||||
self.materials.get(name)
|
||||
}
|
||||
|
||||
pub fn get_material(&self) -> Option<&Arc<dyn PbrtMaterial>> {
|
||||
self.material.last()
|
||||
}
|
||||
|
||||
fn push(&mut self) {
|
||||
self.ctm.push(*self.ctm.last().unwrap());
|
||||
|
||||
if !self.material.is_empty() {
|
||||
self.material
|
||||
.push(Arc::clone(self.material.last().unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Result<()> {
|
||||
self.ctm.pop();
|
||||
|
||||
if self.ctm.is_empty() {
|
||||
return Err(miette!("Attributes do not matcch"));
|
||||
}
|
||||
|
||||
self.material.pop();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
|
||||
// unwrap on context.last() ok because context is never empty
|
||||
let mut context_ctm = vec![AffineTransform::identity()];
|
||||
let mut context = PbrtContext::new();
|
||||
|
||||
let mut parser = Parser::new(
|
||||
path.as_ref().to_path_buf(),
|
||||
|
|
@ -697,25 +747,20 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
|
|||
|
||||
let mut named_transforms = HashMap::new();
|
||||
|
||||
let mut textures = HashMap::new();
|
||||
|
||||
loop {
|
||||
let p = parser.next(&textures).ok_or_else(|| miette!(""))??;
|
||||
let p = parser.next(&context).ok_or_else(|| miette!(""))??;
|
||||
// dbg!(&p);
|
||||
match p {
|
||||
Statement::AttributeBegin => context_ctm.push(*context_ctm.last().unwrap()),
|
||||
Statement::AttributeBegin => context.push(),
|
||||
Statement::AttributeEnd => {
|
||||
context_ctm.pop();
|
||||
if context_ctm.is_empty() {
|
||||
return Err(miette!("Attribute end does not match."));
|
||||
}
|
||||
context.pop()?;
|
||||
}
|
||||
Statement::Include(_) => unreachable!(),
|
||||
Statement::ConcatTransform(affine_transform) => {
|
||||
*context_ctm.last_mut().unwrap() *= affine_transform
|
||||
*context.ctm.last_mut().unwrap() *= affine_transform
|
||||
}
|
||||
Statement::Transform(affine_transform) => {
|
||||
*context_ctm.last_mut().unwrap() = affine_transform
|
||||
*context.ctm.last_mut().unwrap() = affine_transform
|
||||
}
|
||||
Statement::Unknown(s, _items) => {
|
||||
eprintln!("Unknown statement: {s}")
|
||||
|
|
@ -724,14 +769,14 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
|
|||
if camera.is_some() {
|
||||
return Err(miette!("The camera can only be set once."));
|
||||
}
|
||||
camera = Some((c, *context_ctm.last().unwrap()));
|
||||
named_transforms.insert(String::from("\"camera\""), *context_ctm.last().unwrap());
|
||||
camera = Some((c, context.get_ctm()));
|
||||
named_transforms.insert(String::from("\"camera\""), context.get_ctm());
|
||||
}
|
||||
Statement::CoordinateSystem(s) => {
|
||||
named_transforms.insert(s, *context_ctm.last().unwrap());
|
||||
named_transforms.insert(s, context.get_ctm());
|
||||
}
|
||||
Statement::CoordSysTransform(s) => {
|
||||
*context_ctm.last_mut().unwrap() = *named_transforms
|
||||
*context.ctm.last_mut().unwrap() = *named_transforms
|
||||
.get(&s)
|
||||
.ok_or_else(|| miette!("unknown transform"))?;
|
||||
}
|
||||
|
|
@ -744,50 +789,72 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
|
|||
|
||||
let mut pbrt = Pbrt::new(PbrtWorldSettings { camera, camera_ctm });
|
||||
|
||||
let mut context_ctm = vec![AffineTransform::identity()];
|
||||
context.ctm = vec![AffineTransform::identity()];
|
||||
|
||||
// let mut context_material = vec![];
|
||||
|
||||
while let Some(p) = parser.next(&textures).transpose()? {
|
||||
while let Some(p) = parser.next(&context).transpose()? {
|
||||
match p {
|
||||
Statement::AttributeBegin => context_ctm.push(*context_ctm.last().unwrap()),
|
||||
Statement::AttributeBegin => context.push(),
|
||||
Statement::AttributeEnd => {
|
||||
context_ctm.pop();
|
||||
context.pop();
|
||||
}
|
||||
Statement::Include(_) => unreachable!(),
|
||||
Statement::ConcatTransform(affine_transform) => {
|
||||
*context_ctm.last_mut().unwrap() *= affine_transform
|
||||
*context.ctm.last_mut().unwrap() *= affine_transform
|
||||
}
|
||||
Statement::Transform(affine_transform) => {
|
||||
*context_ctm.last_mut().unwrap() = affine_transform
|
||||
*context.ctm.last_mut().unwrap() = affine_transform
|
||||
}
|
||||
Statement::Shape(shape_type, shape_alpha) => {
|
||||
pbrt.scene.shapes.push(Shape {
|
||||
ctm: *context_ctm.last().unwrap(),
|
||||
ctm: context.get_ctm(),
|
||||
material: 0,
|
||||
obj: shape_type,
|
||||
alpha: shape_alpha,
|
||||
});
|
||||
}
|
||||
Statement::CoordinateSystem(s) => {
|
||||
named_transforms.insert(s, *context_ctm.last().unwrap());
|
||||
named_transforms.insert(s, context.get_ctm());
|
||||
}
|
||||
Statement::CoordSysTransform(s) => {
|
||||
*context_ctm.last_mut().unwrap() = *named_transforms
|
||||
*context.ctm.last_mut().unwrap() = *named_transforms
|
||||
.get(&s)
|
||||
.ok_or_else(|| miette!("unknown transform"))?;
|
||||
}
|
||||
Statement::Material(m) => {
|
||||
if context.material.is_empty() {
|
||||
context.material.push(m);
|
||||
} else {
|
||||
*context.material.last_mut().unwrap() = m;
|
||||
}
|
||||
}
|
||||
Statement::MakeNamedMaterial(n, m) => {
|
||||
context.materials.insert(n, m);
|
||||
}
|
||||
Statement::NamedMaterial(n) => {
|
||||
let m = Arc::clone(
|
||||
context
|
||||
.get_named_material(&n)
|
||||
.ok_or_else(|| miette!("Unknown named material {n}"))?,
|
||||
);
|
||||
if context.material.is_empty() {
|
||||
context.material.push(m);
|
||||
} else {
|
||||
*context.material.last_mut().unwrap() = m;
|
||||
}
|
||||
}
|
||||
Statement::Unknown(s, _items) => {
|
||||
eprintln!("Unknown statement: {s}")
|
||||
}
|
||||
Statement::Texture(name, texture) => {
|
||||
textures.insert(name, texture);
|
||||
context.textures.insert(name, texture);
|
||||
}
|
||||
s => bail!("unexpected statemnet in world settings: {s:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
dbg!(textures);
|
||||
dbg!(context);
|
||||
|
||||
Ok(pbrt)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue