Initial pbrt material parsing
This commit is contained in:
parent
0dfa2128dd
commit
9a95ca8fd7
7 changed files with 401 additions and 108 deletions
30
ray-tracing-pbrt-scene/src/either.rs
Normal file
30
ray-tracing-pbrt-scene/src/either.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#[derive(Debug)]
|
||||
pub enum Either<A, B> {
|
||||
A(A),
|
||||
B(B),
|
||||
}
|
||||
|
||||
impl<A, B> Either<A, B> {
|
||||
pub fn map_a<C>(self, f: impl FnOnce(A) -> C) -> Either<C, B> {
|
||||
match self {
|
||||
Either::A(a) => Either::A(f(a)),
|
||||
Either::B(b) => Either::B(b),
|
||||
}
|
||||
}
|
||||
pub fn map_b<C>(self, f: impl FnOnce(B) -> C) -> Either<A, C> {
|
||||
match self {
|
||||
Either::A(a) => Either::A(a),
|
||||
Either::B(b) => Either::B(f(b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, E> Either<A, Result<B, E>> {
|
||||
pub fn transpose_b(self) -> Result<Either<A, B>, E> {
|
||||
match self {
|
||||
Either::A(a) => Ok(Either::A(a)),
|
||||
Either::B(Ok(b)) => Ok(Either::B(b)),
|
||||
Either::B(Err(e)) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
use ray_tracing_core::color::Color;
|
||||
|
||||
use crate::{
|
||||
either::Either,
|
||||
texture::{Pbrt_2d_float_texture, Pbrt_2d_spectrum_texture},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub trait PbrtMaterial: std::fmt::Debug + Send + Sync {}
|
||||
|
||||
pub fn parse_make_named_material(
|
||||
input: &mut Tokenizer,
|
||||
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
|
||||
context: &PbrtContext,
|
||||
) -> Result<(String, Arc<dyn PbrtMaterial>)> {
|
||||
let name = input.parse_next()?;
|
||||
|
||||
|
|
@ -13,16 +20,202 @@ pub fn parse_make_named_material(
|
|||
"first element of make named material dict has to be type"
|
||||
));
|
||||
}
|
||||
Ok((name, parse_material(input, textures)?))
|
||||
Ok((name, parse_material(input, context)?))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PbrtCoatedDiffuseMaterial {
|
||||
albedo: Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
|
||||
g: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
maxdetph: usize,
|
||||
nsamples: usize,
|
||||
thickness: Float,
|
||||
roughness: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
uroughness: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
vroughness: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
reflectance: Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
|
||||
}
|
||||
|
||||
impl PbrtMaterial for PbrtCoatedDiffuseMaterial {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PbrtDielectricMaterial {
|
||||
eta: Either<
|
||||
Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
|
||||
>,
|
||||
roughness: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
uroughness: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
vroughness: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
}
|
||||
|
||||
impl PbrtMaterial for PbrtDielectricMaterial {}
|
||||
|
||||
pub fn parse_material(
|
||||
input: &mut Tokenizer,
|
||||
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
|
||||
context: &PbrtContext,
|
||||
) -> Result<Arc<dyn PbrtMaterial>> {
|
||||
let material: String = input.parse_parameter()?;
|
||||
|
||||
dbg!(material);
|
||||
match material.as_str() {
|
||||
"\"coateddiffuse\"" => {
|
||||
let t = parse_dict!(input=>
|
||||
albedo, Either<Color, String>, Either::A(Color::black());
|
||||
g, Either<Float, String>, Either::A(0.0);
|
||||
maxdepth, usize, 10;
|
||||
nsamples, usize, 1;
|
||||
thickness, Float, 0.01;
|
||||
roughness, Either<Float, String>, Either::A(0.0);
|
||||
uroughness, Either<Float, String>, Either::A(0.0);
|
||||
vroughness, Either<Float, String>, Either::A(0.0);
|
||||
reflectance, Either<Color, String>, Either::A(Color::black())
|
||||
=>
|
||||
albedo, "\"rgb albedo\"", Either::A(texture::parse_rgb(input)?);
|
||||
albedo, "\"spectrum albedo\"", Either::A(texture::parse_spectrum(input)?);
|
||||
albedo, "\"texture albedo\"", Either::B(input.parse_parameter()?);
|
||||
g, "\"float g\"", Either::A(input.parse_parameter()?);
|
||||
g, "\"texture g\"", Either::B(input.parse_parameter()?);
|
||||
maxdepth, "\"integer maxdepth\"", input.parse_parameter()?;
|
||||
nsamples, "\"integer nsamples\"", input.parse_parameter()?;
|
||||
thickness, "\"float thickness\"", input.parse_parameter()?;
|
||||
roughness, "\"float roughness\"", Either::A(input.parse_parameter()?);
|
||||
roughness, "\"texture roughness\"", Either::B(input.parse_parameter()?);
|
||||
uroughness, "\"float uroughness\"", Either::A(input.parse_parameter()?);
|
||||
uroughness, "\"texture uroughness\"", Either::B(input.parse_parameter()?);
|
||||
vroughness, "\"float vroughness\"", Either::A(input.parse_parameter()?);
|
||||
vroughness, "\"texture vroughness\"", Either::B(input.parse_parameter()?);
|
||||
reflectance, "\"rgb reflectance\"", Either::A(texture::parse_rgb(input)?);
|
||||
reflectance, "\"spectrum reflectance\"", Either::A(texture::parse_spectrum(input)?);
|
||||
reflectance, "\"texture reflectance\"", Either::B(input.parse_parameter()?)
|
||||
);
|
||||
|
||||
todo!()
|
||||
Ok(Arc::new(PbrtCoatedDiffuseMaterial {
|
||||
albedo: t
|
||||
.albedo
|
||||
.map_b(|n| {
|
||||
context
|
||||
.get_texture(&n)
|
||||
.ok_or_else(|| {
|
||||
miette!("Unknown texture for coateddiffuse material {n}")
|
||||
})
|
||||
.and_then(|t| Arc::clone(t).get_2d_spectrum_texture())
|
||||
})
|
||||
.transpose_b()?,
|
||||
g: t.g
|
||||
.map_b(|n| {
|
||||
context
|
||||
.get_texture(&n)
|
||||
.ok_or_else(|| {
|
||||
miette!("Unknown texture for coateddiffuse material {n}")
|
||||
})
|
||||
.and_then(|t| Arc::clone(t).get_2d_float_texture())
|
||||
})
|
||||
.transpose_b()?,
|
||||
maxdetph: t.maxdepth,
|
||||
nsamples: t.nsamples,
|
||||
thickness: t.thickness,
|
||||
roughness: t
|
||||
.roughness
|
||||
.map_b(|n| {
|
||||
context
|
||||
.get_texture(&n)
|
||||
.ok_or_else(|| {
|
||||
miette!("Unknown texture for coateddiffuse material {n}")
|
||||
})
|
||||
.and_then(|t| Arc::clone(t).get_2d_float_texture())
|
||||
})
|
||||
.transpose_b()?,
|
||||
uroughness: t
|
||||
.uroughness
|
||||
.map_b(|n| {
|
||||
context
|
||||
.get_texture(&n)
|
||||
.ok_or_else(|| {
|
||||
miette!("Unknown texture for coateddiffuse material {n}")
|
||||
})
|
||||
.and_then(|t| Arc::clone(t).get_2d_float_texture())
|
||||
})
|
||||
.transpose_b()?,
|
||||
vroughness: t
|
||||
.vroughness
|
||||
.map_b(|n| {
|
||||
context
|
||||
.get_texture(&n)
|
||||
.ok_or_else(|| {
|
||||
miette!("Unknown texture for coateddiffuse material {n}")
|
||||
})
|
||||
.and_then(|t| Arc::clone(t).get_2d_float_texture())
|
||||
})
|
||||
.transpose_b()?,
|
||||
reflectance: t
|
||||
.reflectance
|
||||
.map_b(|n| {
|
||||
context
|
||||
.get_texture(&n)
|
||||
.ok_or_else(|| {
|
||||
miette!("Unknown texture for coateddiffuse material {n}")
|
||||
})
|
||||
.and_then(|t| Arc::clone(t).get_2d_spectrum_texture())
|
||||
})
|
||||
.transpose_b()?,
|
||||
}))
|
||||
}
|
||||
"\"dielectric\"" => {
|
||||
let t = parse_dict!(input=>
|
||||
eta, Either<
|
||||
Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
|
||||
>, Either::A(Either::A(1.5));
|
||||
roughness, Either<Float, String>, Either::A(0.0);
|
||||
uroughness, Either<Float, String>, Either::A(0.0);
|
||||
vroughness, Either<Float, String>, Either::A(0.0)
|
||||
=>
|
||||
eta, "\"float eta\"", Either::A(Either::A(input.parse_parameter()?));
|
||||
roughness, "\"float roughness\"", Either::A(input.parse_parameter()?);
|
||||
roughness, "\"texture roughness\"", Either::B(input.parse_parameter()?);
|
||||
uroughness, "\"float uroughness\"", Either::A(input.parse_parameter()?);
|
||||
uroughness, "\"texture uroughness\"", Either::B(input.parse_parameter()?);
|
||||
vroughness, "\"float vroughness\"", Either::A(input.parse_parameter()?);
|
||||
vroughness, "\"texture vroughness\"", Either::B(input.parse_parameter()?)
|
||||
);
|
||||
|
||||
Ok(Arc::new(PbrtDielectricMaterial {
|
||||
eta: Either::A(Either::A(1.5)),
|
||||
roughness: t
|
||||
.roughness
|
||||
.map_b(|n| {
|
||||
context
|
||||
.get_texture(&n)
|
||||
.ok_or_else(|| {
|
||||
miette!("Unknown texture for coateddiffuse material {n}")
|
||||
})
|
||||
.and_then(|t| Arc::clone(t).get_2d_float_texture())
|
||||
})
|
||||
.transpose_b()?,
|
||||
uroughness: t
|
||||
.uroughness
|
||||
.map_b(|n| {
|
||||
context
|
||||
.get_texture(&n)
|
||||
.ok_or_else(|| {
|
||||
miette!("Unknown texture for coateddiffuse material {n}")
|
||||
})
|
||||
.and_then(|t| Arc::clone(t).get_2d_float_texture())
|
||||
})
|
||||
.transpose_b()?,
|
||||
vroughness: t
|
||||
.vroughness
|
||||
.map_b(|n| {
|
||||
context
|
||||
.get_texture(&n)
|
||||
.ok_or_else(|| {
|
||||
miette!("Unknown texture for coateddiffuse material {n}")
|
||||
})
|
||||
.and_then(|t| Arc::clone(t).get_2d_float_texture())
|
||||
})
|
||||
.transpose_b()?,
|
||||
}))
|
||||
}
|
||||
_ => Err(miette!("Unknown material {material}")),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use ray_tracing_core::{affine_transform::AffineTransform, color::Color, prelude:
|
|||
use scale::SpectrumScaleTexture2d;
|
||||
use std::{collections::HashMap, ops::Deref, sync::Arc};
|
||||
|
||||
use crate::tokenizer::Tokenizer;
|
||||
use crate::{PbrtContext, either::Either, tokenizer::Tokenizer};
|
||||
|
||||
mod checkerboard;
|
||||
mod imagemap;
|
||||
|
|
@ -56,18 +56,18 @@ impl TextureMapping {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_spectrum(input: &mut Tokenizer) -> Result<Color> {
|
||||
pub fn parse_spectrum(input: &mut Tokenizer) -> Result<Color> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parse_rgb(input: &mut Tokenizer) -> Result<Color> {
|
||||
pub fn parse_rgb(input: &mut Tokenizer) -> Result<Color> {
|
||||
let t = input.parse_list()?;
|
||||
Ok(Color::new(t[0], t[1], t[2]))
|
||||
}
|
||||
|
||||
fn parse_float_texture(
|
||||
input: &mut Tokenizer,
|
||||
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
|
||||
context: &PbrtContext,
|
||||
) -> Result<Arc<dyn PbrtTexture>> {
|
||||
let texture_class: String = input.parse_next()?;
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ fn parse_float_texture(
|
|||
|
||||
fn parse_spectrum_texture(
|
||||
input: &mut Tokenizer,
|
||||
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
|
||||
context: &PbrtContext,
|
||||
) -> Result<Arc<dyn PbrtTexture>> {
|
||||
let texture_class: String = input.parse_next()?;
|
||||
match texture_class.as_str() {
|
||||
|
|
@ -89,8 +89,8 @@ fn parse_spectrum_texture(
|
|||
udelta, Float, 0.0;
|
||||
vdelta, Float, 0.0;
|
||||
dimension, TextureDimension, TextureDimension::D2;
|
||||
tex1, ValueTexture<Color, String>, ValueTexture::Value(Color::white());
|
||||
tex2, ValueTexture<Color, String>, ValueTexture::Value(Color::black())
|
||||
tex1, Either<Color, String>, Either::A(Color::white());
|
||||
tex2, Either<Color, String>, Either::A(Color::black())
|
||||
=>
|
||||
mapping, "\"string mapping\"", TextureMapping::new(input.parse_parameter()?)?;
|
||||
uscale, "\"float uscale\"", input.parse_parameter()?;
|
||||
|
|
@ -98,12 +98,12 @@ fn parse_spectrum_texture(
|
|||
udelta, "\"float udelta\"", input.parse_parameter()?;
|
||||
vdelta, "\"float vdelta\"", input.parse_parameter()?;
|
||||
dimension, "\"integer dimension\"", TextureDimension::new(input.parse_parameter()?)?;
|
||||
tex1, "\"rgb tex1\"", ValueTexture::Value(parse_rgb(input)?);
|
||||
tex1, "\"spectrum tex1\"", ValueTexture::Value(parse_spectrum(input)?);
|
||||
tex1, "\"texture tex1\"", ValueTexture::Texture(input.parse_parameter()?);
|
||||
tex2, "\"rgb tex2\"", ValueTexture::Value(parse_rgb(input)?);
|
||||
tex2, "\"spectrum tex2\"", ValueTexture::Value(parse_spectrum(input)?);
|
||||
tex2, "\"texture tex2\"", ValueTexture::Texture(input.parse_parameter()?)
|
||||
tex1, "\"rgb tex1\"", Either::A(parse_rgb(input)?);
|
||||
tex1, "\"spectrum tex1\"", Either::A(parse_spectrum(input)?);
|
||||
tex1, "\"texture tex1\"", Either::B(input.parse_parameter()?);
|
||||
tex2, "\"rgb tex2\"", Either::A(parse_rgb(input)?);
|
||||
tex2, "\"spectrum tex2\"", Either::A(parse_spectrum(input)?);
|
||||
tex2, "\"texture tex2\"", Either::B(input.parse_parameter()?)
|
||||
|
||||
);
|
||||
|
||||
|
|
@ -114,22 +114,22 @@ fn parse_spectrum_texture(
|
|||
mapping,
|
||||
tex: [
|
||||
match t.tex1 {
|
||||
ValueTexture::Value(v) => ValueTexture::Value(v),
|
||||
ValueTexture::Texture(name) => ValueTexture::Texture(
|
||||
Either::A(v) => Either::A(v),
|
||||
Either::B(name) => Either::B(
|
||||
Arc::clone(
|
||||
textures
|
||||
.get(&name)
|
||||
context
|
||||
.get_texture(&name)
|
||||
.ok_or_else(|| miette!("unable to find texture"))?,
|
||||
)
|
||||
.get_2d_spectrum_texture()?,
|
||||
),
|
||||
},
|
||||
match t.tex2 {
|
||||
ValueTexture::Value(v) => ValueTexture::Value(v),
|
||||
ValueTexture::Texture(name) => ValueTexture::Texture(
|
||||
Either::A(v) => Either::A(v),
|
||||
Either::B(name) => Either::B(
|
||||
Arc::clone(
|
||||
textures
|
||||
.get(&name)
|
||||
context
|
||||
.get_texture(&name)
|
||||
.ok_or_else(|| miette!("unable to find texture"))?,
|
||||
)
|
||||
.get_2d_spectrum_texture()?,
|
||||
|
|
@ -182,34 +182,34 @@ fn parse_spectrum_texture(
|
|||
}
|
||||
"\"scale\"" => {
|
||||
let t = parse_dict!(input =>
|
||||
tex, ValueTexture<Color, String>, ValueTexture::Value(Color::white());
|
||||
scale, ValueTexture<Float, String>, ValueTexture::Value(1.0)
|
||||
tex, Either<Color, String>, Either::A(Color::white());
|
||||
scale, Either<Float, String>, Either::A(1.0)
|
||||
=>
|
||||
tex, "\"rgb tex\"", ValueTexture::Value(parse_rgb(input)?);
|
||||
tex, "\"spectrum tex\"", ValueTexture::Value(parse_spectrum(input)?);
|
||||
tex, "\"texture tex\"", ValueTexture::Texture(input.parse_parameter()?);
|
||||
scale, "\"float scale\"", ValueTexture::Value(input.parse_parameter()?);
|
||||
scale, "\"texture scale\"", ValueTexture::Texture(input.parse_parameter()?)
|
||||
tex, "\"rgb tex\"", Either::A(parse_rgb(input)?);
|
||||
tex, "\"spectrum tex\"", Either::A(parse_spectrum(input)?);
|
||||
tex, "\"texture tex\"", Either::B(input.parse_parameter()?);
|
||||
scale, "\"float scale\"", Either::A(input.parse_parameter()?);
|
||||
scale, "\"texture scale\"", Either::B(input.parse_parameter()?)
|
||||
);
|
||||
|
||||
Ok(Arc::new(SpectrumScaleTexture2d {
|
||||
tex: match t.tex {
|
||||
ValueTexture::Value(v) => ValueTexture::Value(v),
|
||||
ValueTexture::Texture(t) => ValueTexture::Texture(
|
||||
Either::A(v) => Either::A(v),
|
||||
Either::B(t) => Either::B(
|
||||
Arc::clone(
|
||||
textures
|
||||
.get(&t)
|
||||
context
|
||||
.get_texture(&t)
|
||||
.ok_or_else(|| miette!("Unable to find texture scale"))?,
|
||||
)
|
||||
.get_2d_spectrum_texture()?,
|
||||
),
|
||||
},
|
||||
scale: match t.scale {
|
||||
ValueTexture::Value(v) => ValueTexture::Value(v),
|
||||
ValueTexture::Texture(t) => ValueTexture::Texture(
|
||||
Either::A(v) => Either::A(v),
|
||||
Either::B(t) => Either::B(
|
||||
Arc::clone(
|
||||
textures
|
||||
.get(&t)
|
||||
context
|
||||
.get_texture(&t)
|
||||
.ok_or_else(|| miette!("Unable to find texture scale"))?,
|
||||
)
|
||||
.get_2d_float_texture()?,
|
||||
|
|
@ -223,14 +223,14 @@ fn parse_spectrum_texture(
|
|||
|
||||
pub fn parse_texture(
|
||||
input: &mut Tokenizer,
|
||||
textures: &HashMap<String, Arc<dyn PbrtTexture>>,
|
||||
context: &PbrtContext,
|
||||
) -> Result<(String, Arc<dyn PbrtTexture>)> {
|
||||
let texture_name: String = input.parse_next()?;
|
||||
let texture_type: String = input.parse_next()?;
|
||||
|
||||
match texture_type.as_str() {
|
||||
"\"spectrum\"" => parse_spectrum_texture(input, textures).map(|t| (texture_name, t)),
|
||||
"\"float\"" => parse_float_texture(input, textures).map(|t| (texture_name, t)),
|
||||
"\"spectrum\"" => parse_spectrum_texture(input, context).map(|t| (texture_name, t)),
|
||||
"\"float\"" => parse_float_texture(input, context).map(|t| (texture_name, t)),
|
||||
_ => Err(miette!("Texture type has to be spectrum or float")),
|
||||
}
|
||||
}
|
||||
|
|
@ -267,9 +267,3 @@ impl UVMapping {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ValueTexture<V, T> {
|
||||
Value(V),
|
||||
Texture(T),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use super::*;
|
|||
#[derive(Debug)]
|
||||
pub(super) struct FloatCheckerboardTexture2d {
|
||||
pub(super) mapping: UVMapping,
|
||||
pub(super) tex: [ValueTexture<Float, Arc<dyn Pbrt_2d_float_texture>>; 2],
|
||||
pub(super) tex: [Either<Float, Arc<dyn Pbrt_2d_float_texture>>; 2],
|
||||
}
|
||||
|
||||
impl Pbrt_2d_float_texture for FloatCheckerboardTexture2d {
|
||||
|
|
@ -21,8 +21,8 @@ impl Pbrt_2d_float_texture for FloatCheckerboardTexture2d {
|
|||
};
|
||||
|
||||
match &self.tex[even as usize] {
|
||||
ValueTexture::Value(v) => *v,
|
||||
ValueTexture::Texture(t) => t.get(u, v),
|
||||
Either::A(v) => *v,
|
||||
Either::B(t) => t.get(u, v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ impl PbrtTexture for FloatCheckerboardTexture2d {
|
|||
#[derive(Debug)]
|
||||
pub(super) struct SpectrumCheckerboardTexture2d {
|
||||
pub(super) mapping: UVMapping,
|
||||
pub(super) tex: [ValueTexture<Color, Arc<dyn Pbrt_2d_spectrum_texture>>; 2],
|
||||
pub(super) tex: [Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>; 2],
|
||||
}
|
||||
|
||||
impl Pbrt_2d_spectrum_texture for SpectrumCheckerboardTexture2d {
|
||||
|
|
@ -61,8 +61,8 @@ impl Pbrt_2d_spectrum_texture for SpectrumCheckerboardTexture2d {
|
|||
};
|
||||
|
||||
match &self.tex[even as usize] {
|
||||
ValueTexture::Value(v) => *v,
|
||||
ValueTexture::Texture(t) => t.get(u, v),
|
||||
Either::A(v) => *v,
|
||||
Either::B(t) => t.get(u, v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use super::*;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct SpectrumScaleTexture2d {
|
||||
pub(super) tex: ValueTexture<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
|
||||
pub(super) scale: ValueTexture<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
pub(super) tex: Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
|
||||
pub(super) scale: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
|
||||
}
|
||||
|
||||
impl PbrtTexture for SpectrumScaleTexture2d {
|
||||
|
|
@ -23,13 +23,13 @@ impl PbrtTexture for SpectrumScaleTexture2d {
|
|||
impl Pbrt_2d_spectrum_texture for SpectrumScaleTexture2d {
|
||||
fn get(&self, u: Float, v: Float) -> Color {
|
||||
let x = match &self.tex {
|
||||
ValueTexture::Value(x) => *x,
|
||||
ValueTexture::Texture(t) => t.get(u, v),
|
||||
Either::A(x) => *x,
|
||||
Either::B(t) => t.get(u, v),
|
||||
};
|
||||
|
||||
let s = match &self.scale {
|
||||
ValueTexture::Value(s) => *s,
|
||||
ValueTexture::Texture(t) => t.get(u, v),
|
||||
Either::A(s) => *s,
|
||||
Either::B(t) => t.get(u, v),
|
||||
};
|
||||
|
||||
x * s
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use miette::{Diagnostic, Error, IntoDiagnostic, Report, Result, SourceSpan, bail, miette};
|
||||
use crate::{BytesToChar, error::SourceFile};
|
||||
use miette::{Diagnostic, Error, IntoDiagnostic, Report, Result, SourceSpan};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufReader, Bytes, Read},
|
||||
|
|
@ -7,8 +8,6 @@ use std::{
|
|||
};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{BytesToChar, SourceFile};
|
||||
|
||||
pub struct Tokenizer {
|
||||
inner: InnerTokenizer,
|
||||
path: PathBuf,
|
||||
|
|
@ -446,6 +445,16 @@ macro_rules! parse_dict {
|
|||
};
|
||||
}
|
||||
|
||||
// macro_rules! parse_dict2_internal {
|
||||
// () => {};
|
||||
// }
|
||||
|
||||
// macro_rules! parse_dict2 {
|
||||
// ($tokenizer:expr, $struct:expr; $($name:ident, [$($parse_name:expr, $parsing:expr);*]);+) => {
|
||||
|
||||
// };
|
||||
// }
|
||||
|
||||
#[derive(Error, Debug, Diagnostic)]
|
||||
#[error("Duplicate dict entry error")]
|
||||
#[diagnostic(help("multiple dict entries with the same key"))]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue