From c8ff77a0a97644a73f1b9579458031322772d431 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Tue, 19 Aug 2025 20:38:03 +0200 Subject: [PATCH] First materials succesfully parsed --- Cargo.lock | 27 +++ ray-tracing-pbrt-scene/Cargo.toml | 1 + ray-tracing-pbrt-scene/src/lib.rs | 15 +- ray-tracing-pbrt-scene/src/material.rs | 275 ++++++++++-------------- ray-tracing-pbrt-scene/src/tokenizer.rs | 51 ++++- 5 files changed, 197 insertions(+), 172 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 842c7d9..d67629a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/ray-tracing-pbrt-scene/Cargo.toml b/ray-tracing-pbrt-scene/Cargo.toml index 87d5c9a..0fe2c6c 100644 --- a/ray-tracing-pbrt-scene/Cargo.toml +++ b/ray-tracing-pbrt-scene/Cargo.toml @@ -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" diff --git a/ray-tracing-pbrt-scene/src/lib.rs b/ray-tracing-pbrt-scene/src/lib.rs index 584f2e4..9991ea7 100644 --- a/ray-tracing-pbrt-scene/src/lib.rs +++ b/ray-tracing-pbrt-scene/src/lib.rs @@ -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, obj: ShapeType, alpha: ShapeAlpha, } @@ -809,7 +811,12 @@ fn inner_parse_pbrt(path: impl AsRef + std::fmt::Debug) -> Result { 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, }); diff --git a/ray-tracing-pbrt-scene/src/material.rs b/ray-tracing-pbrt-scene/src/material.rs index 93834c3..2714ed9 100644 --- a/ray-tracing-pbrt-scene/src/material.rs +++ b/ray-tracing-pbrt-scene/src/material.rs @@ -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>, g: Either>, - maxdetph: usize, + maxdepth: usize, nsamples: usize, thickness: Float, roughness: Either>, uroughness: Either>, vroughness: Either>, reflectance: Either>, + eta: Either< + Either>, + Either>, + >, } impl PbrtMaterial for PbrtCoatedDiffuseMaterial {} @@ -51,6 +55,37 @@ struct PbrtDielectricMaterial { impl PbrtMaterial for PbrtDielectricMaterial {} +#[derive(Debug)] +struct PbrtDiffuseMaterial { + reflectance: Either>, +} + +impl PbrtMaterial for PbrtDiffuseMaterial {} + +fn parse_2d_float_texture( + input: &mut Tokenizer, + context: &PbrtContext, +) -> Result> { + 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> { + 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, Either::A(Color::black()); - g, Either, Either::A(0.0); - maxdepth, usize, 10; - nsamples, usize, 1; - thickness, Float, 0.01; - roughness, Either, Either::A(0.0); - uroughness, Either, Either::A(0.0); - vroughness, Either, Either::A(0.0); - reflectance, Either, 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()?, - })) - } - "\"dielectric\"" => { - let t = parse_dict!(input=> - eta, Either< - Either>, - Either>, - >, Either::A(Either::A(1.5)); - roughness, Either, Either::A(0.0); - uroughness, Either, Either::A(0.0); - vroughness, Either, 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()?, - })) - } + "\"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\"" => 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}")), } } diff --git a/ray-tracing-pbrt-scene/src/tokenizer.rs b/ray-tracing-pbrt-scene/src/tokenizer.rs index b0187bf..f7ff6e8 100644 --- a/ray-tracing-pbrt-scene/src/tokenizer.rs +++ b/ray-tracing-pbrt-scene/src/tokenizer.rs @@ -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")]