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",
]
[[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]]
name = "core-foundation"
version = "0.9.4"
@ -2291,6 +2311,7 @@ name = "ray-tracing-pbrt-scene"
version = "0.1.0"
dependencies = [
"clap",
"const_format",
"image 0.25.6",
"miette",
"nom 8.0.0",
@ -2937,6 +2958,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "unit-prefix"
version = "0.5.1"

View file

@ -10,3 +10,4 @@ miette = { version = "7.6.0", features = ["fancy"] }
nom = "8.0.0"
thiserror = "2.0.12"
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 miette::{IntoDiagnostic, Result, bail, miette};
use miette::{Diagnostic, IntoDiagnostic, Result, SourceSpan, bail, miette};
use ray_tracing_core::{
affine_transform::AffineTransform,
math::{Dir3, Pos3},
@ -12,6 +13,7 @@ use std::{
sync::Arc,
};
use texture::PbrtTexture;
use thiserror::Error;
#[macro_use]
mod tokenizer;
@ -642,7 +644,7 @@ enum ShapeAlpha {
#[derive(Debug)]
struct Shape {
ctm: AffineTransform,
material: usize,
material: Arc<dyn PbrtMaterial>,
obj: ShapeType,
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) => {
pbrt.scene.shapes.push(Shape {
ctm: context.get_ctm(),
material: 0,
material: Arc::clone(
context
.material
.last()
.ok_or_else(|| miette!("No material specified"))?,
),
obj: shape_type,
alpha: shape_alpha,
});

View file

@ -2,7 +2,7 @@ use ray_tracing_core::color::Color;
use crate::{
either::Either,
texture::{Pbrt_2d_float_texture, Pbrt_2d_spectrum_texture},
texture::{Pbrt_2d_float_texture, Pbrt_2d_spectrum_texture, parse_rgb},
};
use super::*;
@ -27,13 +27,17 @@ pub fn parse_make_named_material(
struct PbrtCoatedDiffuseMaterial {
albedo: Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
g: Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
maxdetph: usize,
maxdepth: 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>>,
eta: Either<
Either<Float, Arc<dyn Pbrt_2d_float_texture>>,
Either<Color, Arc<dyn Pbrt_2d_spectrum_texture>>,
>,
}
impl PbrtMaterial for PbrtCoatedDiffuseMaterial {}
@ -51,6 +55,37 @@ struct 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(
input: &mut Tokenizer,
context: &PbrtContext,
@ -58,164 +93,84 @@ pub fn parse_material(
let material: String = input.parse_parameter()?;
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()?)
);
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()?,
}))
"\"diffuse\"" => Ok(Arc::new(parse_dict2!(input, PbrtDiffuseMaterial;
reflectance, Either::A(Color::black()), [
"\"rgb reflectance\"", Either::A(texture::parse_rgb(input)?);
"\"spectrum reflectance\"", Either::A(texture::parse_spectrum(input)?);
"\"texture reflectance\"", Either::B(parse_2d_spectrum_texture(input, context)?)
]
))),
"\"coateddiffuse\"" => Ok(Arc::new(parse_dict2!(input, PbrtCoatedDiffuseMaterial;
albedo, Either::A(Color::black()), [
"\"rgb albedo\"", Either::A(texture::parse_rgb(input)?);
"\"spectrum albedo\"", Either::A(texture::parse_spectrum(input)?);
"\"texture albedo\"", Either::B(parse_2d_spectrum_texture(input, context)?)
];
g, Either::A(0.0), [
"\"float g\"", Either::A(input.parse_parameter()?);
"\"texture g\"", Either::B(parse_2d_float_texture(input, context)?)
];
maxdepth, 10, ["\"integer maxdepth\"", input.parse_parameter()?];
nsamples, 1, ["\"integer nsamples\"", input.parse_parameter()?];
thickness, 0.01, ["\"float thickness\"", input.parse_parameter()?];
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)?)
];
reflectance, Either::A(Color::black()), [
"\"rgb reflectance\"", Either::A(texture::parse_rgb(input)?);
"\"spectrum reflectance\"", Either::A(texture::parse_spectrum(input)?);
"\"texture reflectance\"", Either::B(parse_2d_spectrum_texture(input, context)?)
];
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()?))
}
"\"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}")),
}
}

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 ray_tracing_core::prelude::Float;
use std::{
fs::File,
io::{BufReader, Bytes, Read},
iter::Peekable,
path::{Path, PathBuf},
sync::Arc,
};
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 {
// ($tokenizer:expr, $struct:expr; $($name:ident, [$($parse_name:expr, $parsing:expr);*]);+) => {
while let Some(p) = $tokenizer.next_if(|p| p.starts_with('"')).transpose()? {
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)]
#[error("Duplicate dict entry error")]