First materials succesfully parsed

This commit is contained in:
hal8174 2025-08-19 20:38:03 +02:00
parent 9a95ca8fd7
commit c8ff77a0a9
Signed by: hal8174
SSH key fingerprint: SHA256:NN98ZYwnrreQLSOV/g+amY7C3yL/mS1heD7bi5t6PPw
5 changed files with 197 additions and 172 deletions

27
Cargo.lock generated
View file

@ -523,6 +523,26 @@ dependencies = [
"windows-sys 0.60.2", "windows-sys 0.60.2",
] ]
[[package]]
name = "const_format"
version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd"
dependencies = [
"const_format_proc_macros",
]
[[package]]
name = "const_format_proc_macros"
version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.9.4" version = "0.9.4"
@ -2291,6 +2311,7 @@ name = "ray-tracing-pbrt-scene"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap",
"const_format",
"image 0.25.6", "image 0.25.6",
"miette", "miette",
"nom 8.0.0", "nom 8.0.0",
@ -2937,6 +2958,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]] [[package]]
name = "unit-prefix" name = "unit-prefix"
version = "0.5.1" version = "0.5.1"

View file

@ -10,3 +10,4 @@ miette = { version = "7.6.0", features = ["fancy"] }
nom = "8.0.0" nom = "8.0.0"
thiserror = "2.0.12" thiserror = "2.0.12"
image = "0.25.6" image = "0.25.6"
const_format = "0.2.34"

View file

@ -1,6 +1,7 @@
use crate::tokenizer::Tokenizer; use crate::{texture::Pbrt_2d_float_texture, tokenizer::Tokenizer};
use error::SourceFile;
use material::PbrtMaterial; use material::PbrtMaterial;
use miette::{IntoDiagnostic, Result, bail, miette}; use miette::{Diagnostic, IntoDiagnostic, Result, SourceSpan, bail, miette};
use ray_tracing_core::{ use ray_tracing_core::{
affine_transform::AffineTransform, affine_transform::AffineTransform,
math::{Dir3, Pos3}, math::{Dir3, Pos3},
@ -12,6 +13,7 @@ use std::{
sync::Arc, sync::Arc,
}; };
use texture::PbrtTexture; use texture::PbrtTexture;
use thiserror::Error;
#[macro_use] #[macro_use]
mod tokenizer; mod tokenizer;
@ -642,7 +644,7 @@ enum ShapeAlpha {
#[derive(Debug)] #[derive(Debug)]
struct Shape { struct Shape {
ctm: AffineTransform, ctm: AffineTransform,
material: usize, material: Arc<dyn PbrtMaterial>,
obj: ShapeType, obj: ShapeType,
alpha: ShapeAlpha, alpha: ShapeAlpha,
} }
@ -809,7 +811,12 @@ fn inner_parse_pbrt(path: impl AsRef<Path> + std::fmt::Debug) -> Result<Pbrt> {
Statement::Shape(shape_type, shape_alpha) => { Statement::Shape(shape_type, shape_alpha) => {
pbrt.scene.shapes.push(Shape { pbrt.scene.shapes.push(Shape {
ctm: context.get_ctm(), ctm: context.get_ctm(),
material: 0, material: Arc::clone(
context
.material
.last()
.ok_or_else(|| miette!("No material specified"))?,
),
obj: shape_type, obj: shape_type,
alpha: shape_alpha, alpha: shape_alpha,
}); });

View file

@ -2,7 +2,7 @@ use ray_tracing_core::color::Color;
use crate::{ use crate::{
either::Either, either::Either,
texture::{Pbrt_2d_float_texture, Pbrt_2d_spectrum_texture}, texture::{Pbrt_2d_float_texture, Pbrt_2d_spectrum_texture, parse_rgb},
}; };
use super::*; use super::*;
@ -27,13 +27,17 @@ pub fn parse_make_named_material(
struct PbrtCoatedDiffuseMaterial { struct PbrtCoatedDiffuseMaterial {
albedo: Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>, albedo: Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
g: Either<Float, Arc<dyn Pbrt_2d_float_texture>>, g: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
maxdetph: usize, maxdepth: usize,
nsamples: usize, nsamples: usize,
thickness: Float, thickness: Float,
roughness: Either<Float, Arc<dyn Pbrt_2d_float_texture>>, roughness: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
uroughness: 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>>, vroughness: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
reflectance: Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>, reflectance: Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
eta: Either<
Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
>,
} }
impl PbrtMaterial for PbrtCoatedDiffuseMaterial {} impl PbrtMaterial for PbrtCoatedDiffuseMaterial {}
@ -51,6 +55,37 @@ struct PbrtDielectricMaterial {
impl PbrtMaterial for PbrtDielectricMaterial {} impl PbrtMaterial for PbrtDielectricMaterial {}
#[derive(Debug)]
struct PbrtDiffuseMaterial {
reflectance: Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
}
impl PbrtMaterial for PbrtDiffuseMaterial {}
fn parse_2d_float_texture(
input: &mut Tokenizer,
context: &PbrtContext,
) -> Result<Arc<dyn Pbrt_2d_float_texture>> {
let n = input.parse_parameter()?;
context
.get_texture(&n)
.ok_or_else(|| miette!("Unknown texture"))
.and_then(|t| Arc::clone(t).get_2d_float_texture())
}
fn parse_2d_spectrum_texture(
input: &mut Tokenizer,
context: &PbrtContext,
) -> Result<Arc<dyn Pbrt_2d_spectrum_texture>> {
let n = input.parse_parameter()?;
context
.get_texture(&n)
.ok_or_else(|| miette!("Unknown texture"))
.and_then(|t| Arc::clone(t).get_2d_spectrum_texture())
}
pub fn parse_material( pub fn parse_material(
input: &mut Tokenizer, input: &mut Tokenizer,
context: &PbrtContext, context: &PbrtContext,
@ -58,164 +93,84 @@ pub fn parse_material(
let material: String = input.parse_parameter()?; let material: String = input.parse_parameter()?;
match material.as_str() { match material.as_str() {
"\"coateddiffuse\"" => { "\"diffuse\"" => Ok(Arc::new(parse_dict2!(input, PbrtDiffuseMaterial;
let t = parse_dict!(input=> reflectance, Either::A(Color::black()), [
albedo, Either<Color, String>, Either::A(Color::black()); "\"rgb reflectance\"", Either::A(texture::parse_rgb(input)?);
g, Either<Float, String>, Either::A(0.0); "\"spectrum reflectance\"", Either::A(texture::parse_spectrum(input)?);
maxdepth, usize, 10; "\"texture reflectance\"", Either::B(parse_2d_spectrum_texture(input, context)?)
nsamples, usize, 1; ]
thickness, Float, 0.01; ))),
roughness, Either<Float, String>, Either::A(0.0); "\"coateddiffuse\"" => Ok(Arc::new(parse_dict2!(input, PbrtCoatedDiffuseMaterial;
uroughness, Either<Float, String>, Either::A(0.0); albedo, Either::A(Color::black()), [
vroughness, Either<Float, String>, Either::A(0.0); "\"rgb albedo\"", Either::A(texture::parse_rgb(input)?);
reflectance, Either<Color, String>, Either::A(Color::black()) "\"spectrum albedo\"", Either::A(texture::parse_spectrum(input)?);
=> "\"texture albedo\"", Either::B(parse_2d_spectrum_texture(input, context)?)
albedo, "\"rgb albedo\"", Either::A(texture::parse_rgb(input)?); ];
albedo, "\"spectrum albedo\"", Either::A(texture::parse_spectrum(input)?); g, Either::A(0.0), [
albedo, "\"texture albedo\"", Either::B(input.parse_parameter()?); "\"float g\"", Either::A(input.parse_parameter()?);
g, "\"float g\"", Either::A(input.parse_parameter()?); "\"texture g\"", Either::B(parse_2d_float_texture(input, context)?)
g, "\"texture g\"", Either::B(input.parse_parameter()?); ];
maxdepth, "\"integer maxdepth\"", input.parse_parameter()?; maxdepth, 10, ["\"integer maxdepth\"", input.parse_parameter()?];
nsamples, "\"integer nsamples\"", input.parse_parameter()?; nsamples, 1, ["\"integer nsamples\"", input.parse_parameter()?];
thickness, "\"float thickness\"", input.parse_parameter()?; thickness, 0.01, ["\"float thickness\"", input.parse_parameter()?];
roughness, "\"float roughness\"", Either::A(input.parse_parameter()?); roughness, Either::A(0.0), [
roughness, "\"texture roughness\"", Either::B(input.parse_parameter()?); "\"float roughness\"", Either::A(input.parse_parameter()?);
uroughness, "\"float uroughness\"", Either::A(input.parse_parameter()?); "\"texture roughness\"", Either::B(parse_2d_float_texture(input, context)?)
uroughness, "\"texture uroughness\"", Either::B(input.parse_parameter()?); ];
vroughness, "\"float vroughness\"", Either::A(input.parse_parameter()?); uroughness, Either::A(0.0), [
vroughness, "\"texture vroughness\"", Either::B(input.parse_parameter()?); "\"float uroughness\"", Either::A(input.parse_parameter()?);
reflectance, "\"rgb reflectance\"", Either::A(texture::parse_rgb(input)?); "\"texture uroughness\"", Either::B(parse_2d_float_texture(input, context)?)
reflectance, "\"spectrum reflectance\"", Either::A(texture::parse_spectrum(input)?); ];
reflectance, "\"texture reflectance\"", Either::B(input.parse_parameter()?) vroughness, Either::A(0.0), [
); "\"float vroughness\"", Either::A(input.parse_parameter()?);
"\"texture vroughness\"", Either::B(parse_2d_float_texture(input, context)?)
Ok(Arc::new(PbrtCoatedDiffuseMaterial { ];
albedo: t reflectance, Either::A(Color::black()), [
.albedo "\"rgb reflectance\"", Either::A(texture::parse_rgb(input)?);
.map_b(|n| { "\"spectrum reflectance\"", Either::A(texture::parse_spectrum(input)?);
context "\"texture reflectance\"", Either::B(parse_2d_spectrum_texture(input, context)?)
.get_texture(&n) ];
.ok_or_else(|| { eta, Either::A(Either::A(1.5)), [
miette!("Unknown texture for coateddiffuse material {n}") "\"float eta\"", Either::A(Either::A(input.parse_parameter()?));
}) "\"rgb eta\"", Either::B(Either::A(parse_rgb(input)?));
.and_then(|t| Arc::clone(t).get_2d_spectrum_texture()) "\"spectrum eta\"", Either::B(Either::A(texture::parse_spectrum(input)?));
}) "\"texture eta\"", {
.transpose_b()?, let n = input.parse_parameter()?;
g: t.g let t = context.get_texture(&n).ok_or_else(|| miette!("Unknown texture"))?;
.map_b(|n| { match Arc::clone(t).get_2d_spectrum_texture() {
context Ok(t) => Either::B(Either::B(t)),
.get_texture(&n) Err(_) => Either::A(Either::B(Arc::clone(t).get_2d_float_texture()?))
.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()?,
}))
} }
]
))),
"\"dielectric\"" => Ok(Arc::new(parse_dict2!(input, PbrtDielectricMaterial;
eta, Either::A(Either::A(1.5)), [
"\"float eta\"", Either::A(Either::A(input.parse_parameter()?));
"\"rgb eta\"", Either::B(Either::A(parse_rgb(input)?));
"\"spectrum eta\"", Either::B(Either::A(texture::parse_spectrum(input)?));
"\"texture eta\"", {
let n = input.parse_parameter()?;
let t = context.get_texture(&n).ok_or_else(|| miette!("Unknown texture"))?;
match Arc::clone(t).get_2d_spectrum_texture() {
Ok(t) => Either::B(Either::B(t)),
Err(_) => Either::A(Either::B(Arc::clone(t).get_2d_float_texture()?))
}
}
];
roughness, Either::A(0.0), [
"\"float roughness\"", Either::A(input.parse_parameter()?);
"\"texture roughness\"", Either::B(parse_2d_float_texture(input, context)?)
];
uroughness, Either::A(0.0), [
"\"float uroughness\"", Either::A(input.parse_parameter()?);
"\"texture uroughness\"", Either::B(parse_2d_float_texture(input, context)?)
];
vroughness, Either::A(0.0), [
"\"float vroughness\"", Either::A(input.parse_parameter()?);
"\"texture vroughness\"", Either::B(parse_2d_float_texture(input, context)?)
]
))),
_ => Err(miette!("Unknown material {material}")), _ => Err(miette!("Unknown material {material}")),
} }
} }

View file

@ -1,10 +1,15 @@
use crate::{BytesToChar, error::SourceFile}; use crate::{
BytesToChar, PbrtContext, either::Either, error::SourceFile, texture::Pbrt_2d_float_texture,
};
use const_format::concatcp;
use miette::{Diagnostic, Error, IntoDiagnostic, Report, Result, SourceSpan}; use miette::{Diagnostic, Error, IntoDiagnostic, Report, Result, SourceSpan};
use ray_tracing_core::prelude::Float;
use std::{ use std::{
fs::File, fs::File,
io::{BufReader, Bytes, Read}, io::{BufReader, Bytes, Read},
iter::Peekable, iter::Peekable,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc,
}; };
use thiserror::Error; use thiserror::Error;
@ -445,15 +450,45 @@ macro_rules! parse_dict {
}; };
} }
// macro_rules! parse_dict2_internal { macro_rules! parse_dict2 {
// () => {}; ($tokenizer:expr, $struct:path; $($name:ident, $default:expr, [$($parse_name:expr, $parsing:expr);*]);+) => {
// } {
$(
#[allow(unused_mut)]
let mut $name = None;
)+
// macro_rules! parse_dict2 { while let Some(p) = $tokenizer.next_if(|p| p.starts_with('"')).transpose()? {
// ($tokenizer:expr, $struct:expr; $($name:ident, [$($parse_name:expr, $parsing:expr);*]);+) => { match p.as_str() {
$(
$(
$parse_name => {
if $name.is_none() {
$name = Some($parsing);
} else {
return Err($crate::tokenizer::DuplicateDictEntryError {bad_bit: $tokenizer.last_span(), src: $tokenizer.get_src()}.into())
}
}
)*
)+
_ => {
return Err($crate::tokenizer::UnknownDictEntryError {bad_bit: $tokenizer.last_span(), src: $tokenizer.get_src()}.into())
}
}
}
// }; $struct {
// } $(
$name: match $name {
Some(v) => v,
None => {$default},
},
)+
}
}
};
}
#[derive(Error, Debug, Diagnostic)] #[derive(Error, Debug, Diagnostic)]
#[error("Duplicate dict entry error")] #[error("Duplicate dict entry error")]