diff --git a/src/core/camera.rs b/src/core/camera.rs index 43e5c6d..8b70809 100644 --- a/src/core/camera.rs +++ b/src/core/camera.rs @@ -2,8 +2,8 @@ use crate::cameras::realistic::RealisticCameraHost; use crate::core::image::ImageMetadata; use crate::core::image::{Image, ImageIO}; use crate::globals::get_options; +use crate::utils::read_float_file; use crate::utils::{Arena, FileLoc, ParameterDictionary}; -use crate::utils::{Upload, read_float_file}; use anyhow::{Result, anyhow}; use shared::Ptr; use shared::cameras::*; diff --git a/src/core/scene/builder.rs b/src/core/scene/builder.rs index a30ff24..cb7320a 100644 --- a/src/core/scene/builder.rs +++ b/src/core/scene/builder.rs @@ -49,15 +49,20 @@ impl IndexMut for TransformSet { } } +#[derive(Clone, Debug)] +struct PendingAreaLight { + name: String, + params: ParsedParameterVector, + loc: FileLoc, +} + #[derive(Default, Debug, Clone)] struct GraphicsState { pub current_inside_medium: String, pub current_outside_medium: String, pub current_material_name: String, pub current_material_index: Option, - pub area_light_name: String, - pub area_light_params: ParsedParameterVector, - pub area_light_loc: FileLoc, + pub pending_area_light: Option, pub shape_attributes: ParsedParameterVector, pub light_attributes: ParsedParameterVector, pub material_attributes: ParsedParameterVector, @@ -191,7 +196,7 @@ impl BasicSceneBuilder { fn make_params( &self, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: &FileLoc, ) -> Result { ParameterDictionary::new(params.clone(), self.graphics_state.color_space.clone()) @@ -333,7 +338,7 @@ impl ParserTarget for BasicSceneBuilder { fn camera( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError> { self.verify_options("Camera", &loc)?; @@ -357,7 +362,7 @@ impl ParserTarget for BasicSceneBuilder { CameraTransform::from_world(animated_world_from_cam, rendering_space); self.render_from_world = camera_from_world.t[0]; - let parameters = self.make_params(¶ms.clone(), &loc)?; + let parameters = self.make_params(params, &loc)?; self.current_camera = Some(CameraSceneEntity { base: SceneEntity { @@ -405,7 +410,7 @@ impl ParserTarget for BasicSceneBuilder { fn pixel_filter( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError> { self.verify_options("PixelFilter", &loc)?; @@ -421,12 +426,12 @@ impl ParserTarget for BasicSceneBuilder { fn film( &mut self, type_name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError> { self.verify_options("Film", &loc)?; let parameters = self.make_params(params, &loc)?; - self.current_filter = Some(SceneEntity { + self.current_film = Some(SceneEntity { name: type_name.to_string(), loc, parameters, @@ -437,7 +442,7 @@ impl ParserTarget for BasicSceneBuilder { fn accelerator( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError> { self.verify_options("Accelerator", &loc)?; @@ -453,7 +458,7 @@ impl ParserTarget for BasicSceneBuilder { fn integrator( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError> { self.verify_options("Integrator", &loc)?; @@ -469,7 +474,7 @@ impl ParserTarget for BasicSceneBuilder { fn make_named_medium( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError> { self.verify_world("MakeNamedMaterial", &loc)?; @@ -509,11 +514,11 @@ impl ParserTarget for BasicSceneBuilder { fn sampler( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError> { self.verify_options("Sampler", &loc)?; - let parameters = self.make_params(¶ms.clone(), &loc)?; + let parameters = self.make_params(params, &loc)?; self.current_sampler = Some(SceneEntity { name: name.to_string(), loc, @@ -631,7 +636,7 @@ impl ParserTarget for BasicSceneBuilder { orig_name: &str, type_name: &str, tex_name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, arena: Arc, ) -> Result<(), ParserError> { @@ -693,7 +698,7 @@ impl ParserTarget for BasicSceneBuilder { fn material( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError> { self.verify_world("material", &loc); @@ -708,7 +713,7 @@ impl ParserTarget for BasicSceneBuilder { fn make_named_material( &mut self, _name: &str, - _params: &ParsedParameterVector, + _params: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { todo!() @@ -720,28 +725,114 @@ impl ParserTarget for BasicSceneBuilder { fn light_source( &mut self, - _name: &str, - _params: &ParsedParameterVector, - _loc: FileLoc, + name: &str, + params: ParsedParameterVector, + loc: FileLoc, ) -> Result<(), ParserError> { + self.verify_world("LightSource", &loc)?; + let dict = ParameterDictionary::from_array( + params.clone(), + &self.graphics_state.medium_attributes, + self.graphics_state.color_space.clone() + )?; + + let render_from_light = AnimatedTransform::new( + &self.graphics_state.ctm.t[0], + self.graphics_state.transform_start_time, + &self.graphics_state.ctm.t[1], + self.graphics_state.transform_end_time, + ); + + let entity = LightSceneEntity { + transformed_base: TransformedSceneEntity { + base: SceneEntity { + name: name.to_string(), + loc, + parameters: dict, + }, + render_from_object: render_from_light, + }, + medium: self.graphics_state.current_outside_medium.clone(), + }; + + self.scene.add_light(entity); Ok(()) + } fn area_light_source( &mut self, - _name: &str, - _params: &ParsedParameterVector, - _loc: FileLoc, + name: &str, + params: ParsedParameterVector, + loc: FileLoc, ) -> Result<(), ParserError> { + self.verify_world("AreaLightSource", &loc)?; + self.graphics_state.pending_area_light = Some(PendingAreaLight { + name: name.to_string(), + params: params.clone(), + loc, + }); Ok(()) } fn shape( &mut self, - _name: &str, - _params: &ParsedParameterVector, - _loc: FileLoc, + name: &str, + params: ParsedParameterVector, + loc: FileLoc, ) -> Result<(), ParserError> { + self.verify_world("Shape", &loc)?; + + let dict = ParameterDictionary::from_array( + params.clone(), + &self.graphics_state.shape_attributes, + self.graphics_state.color_space.clone() + )?; + + let render_from_object = self.graphics_state.ctm[0]; + let object_from_render = render_from_object.inverse(); + + let light_index = if let Some(ref al) = self.graphics_state.pending_area_light { + let al_dict = self.make_params(al.params.clone(), &al.loc)?; + let light_entity = SceneEntity { + name: al.name.clone(), + loc: al.loc.clone(), + parameters: al_dict + }; + Some(self.scene.add_area_light(light_entity)) + } else { + None + }; + + let material = if !self.graphics_state.current_material_name.is_empty() { + MaterialRef::Name(self.graphics_state.current_material_name.clone()) + } else if let Some(idx) = self.graphics_state.current_material_index { + MaterialRef::Index(idx) + } else { + MaterialRef::None + }; + + let entity = ShapeSceneEntity { + base: SceneEntity { + name: name.to_string(), + loc, + parameters: dict + }, + render_from_object: Arc::new(render_from_object), + object_from_render: Arc::new(object_from_render), + reverse_orientation: self.graphics_state.reverse_orientation, + material, + light_index, + inside_medium: self.graphics_state.current_inside_medium.clone(), + outside_medium: self.graphics_state.current_outside_medium.clone(), + }; + + if self.active_instance_definition.is_some() { + self.active_instance_definition.as_mut().unwrap().shapes.push(entity) + } else { + self.scene.add_shape(entity); + } + Ok(()) } fn object_begin(&mut self, _name: &str, _loc: FileLoc) -> Result<(), ParserError> { diff --git a/src/core/scene/scene.rs b/src/core/scene/scene.rs index ae387cf..6ca9fda 100644 --- a/src/core/scene/scene.rs +++ b/src/core/scene/scene.rs @@ -4,6 +4,7 @@ use crate::core::camera::CameraFactory; use crate::core::film::FilmFactory; use crate::core::filter::FilterFactory; use crate::core::image::{Image, io::ImageIO}; +use crate::core::light::LightFactory; use crate::core::material::MaterialFactory; use crate::core::primitive::{CreateGeometricPrimitive, CreateSimplePrimitive}; use crate::core::sampler::SamplerFactory; @@ -16,7 +17,7 @@ use crate::{Arena, FileLoc}; use anyhow::{Result, anyhow}; use parking_lot::Mutex; use rayon::prelude::*; -use shared::core::camera::Camera; +use shared::core::camera::{CameraTransform, Camera}; use shared::core::color::LINEAR; use shared::core::film::Film; use shared::core::filter::Filter; @@ -313,6 +314,14 @@ impl BasicScene { state.area_lights.len() - 1 } + pub fn add_light(&self, light: LightSceneEntity) { + self.light_state.lock().lights.push(light); + } + + pub fn add_shape(&self, shape: ShapeSceneEntity) { + self.shapes.lock().push(shape); + } + pub fn add_shapes(&self, new_shapes: Vec) { self.shapes.lock().extend(new_shapes); } @@ -489,6 +498,32 @@ impl BasicScene { Ok((named_materials, materials)) } + pub fn create_lights( + &self, + camera_transform: &CameraTransform, + arena: &mut Arena, + ) -> Result> { + let state = self.light_state.lock(); + + state.lights.par_iter().map(|entity| { + let render_from_light = entity.transformed_base.render_from_object.start_transform; + let medium = self.get_medium( + &entity.medium, + &entity.transformed_base.base.loc, + ); + + Light::create( + &entity.transformed_base.base.name, + &entity.transformed_base.base.parameters, + render_from_light, + camera_transform, + medium.map(|m| *m), + &entity.transformed_base.base.loc, + arena, + ) + }).collect() + } + pub fn create_aggregate( &self, textures: &NamedTextures, diff --git a/src/core/scene/state.rs b/src/core/scene/state.rs index 70300f7..68f161e 100644 --- a/src/core/scene/state.rs +++ b/src/core/scene/state.rs @@ -1,4 +1,4 @@ -use super::{SceneEntity, TextureSceneEntity}; +use super::{SceneEntity, TextureSceneEntity, LightSceneEntity}; use crate::core::image::Image; use crate::core::texture::{FloatTexture, SpectrumTexture}; use crate::utils::parallel::AsyncJob; @@ -29,7 +29,7 @@ pub struct MaterialState { #[derive(Debug, Default)] pub struct LightState { - pub light_jobs: Vec>, + pub lights: Vec, pub area_lights: Vec, } diff --git a/src/lights/diffuse.rs b/src/lights/diffuse.rs index 21b7374..c53f339 100644 --- a/src/lights/diffuse.rs +++ b/src/lights/diffuse.rs @@ -8,7 +8,7 @@ use crate::utils::{Arena, FileLoc, ParameterDictionary, Upload, resolve_filename use anyhow::{Result, anyhow}; use shared::core::geometry::Point2i; use shared::core::light::{Light, LightBase, LightType}; -use shared::core::medium::{Medium, MediumInterface}; +use shared::core::medium::Medium; use shared::core::shape::{Shape, ShapeTrait}; use shared::core::spectrum::Spectrum; use shared::core::texture::GPUFloatTexture; @@ -18,89 +18,6 @@ use shared::spectra::RGBColorSpace; use shared::utils::{Ptr, Transform}; use shared::{Float, PI}; -pub trait CreateDiffuseLight { - fn new( - render_from_light: Transform, - medium_interface: MediumInterface, - le: Spectrum, - scale: Float, - shape: Ptr, - alpha: Ptr, - image: Ptr, - colorspace: Ptr, - two_sided: bool, - ) -> Self; -} - -impl CreateDiffuseLight for DiffuseAreaLight { - fn new( - render_from_light: Transform, - medium_interface: MediumInterface, - le: Spectrum, - scale: Float, - shape: Ptr, - alpha: Ptr, - image: Ptr, - colorspace: Ptr, - two_sided: bool, - ) -> Self { - let is_constant_zero = match &*alpha { - GPUFloatTexture::Constant(tex) => tex.evaluate(&TextureEvalContext::default()) == 0.0, - _ => false, - }; - - let (light_type, stored_alpha) = if is_constant_zero { - (LightType::DeltaPosition, None) - } else { - (LightType::Area, Some(alpha)) - }; - - let base = LightBase::new(light_type, render_from_light, medium_interface); - - let lemit = lookup_spectrum(&le); - - if !image.is_null() { - let desc = image - .get_channel_desc(&["R", "G", "B"]) - .expect("Image used for DiffuseAreaLight doesn't have R, G, B channels"); - - assert_eq!(3, desc.size(), "Image channel description size mismatch"); - assert!( - desc.is_identity(), - "Image channel description is not identity" - ); - - assert!( - !colorspace.is_null(), - "Image provided but ColorSpace is missing" - ); - } - - let is_triangle_or_bilinear = - matches!(*shape, Shape::Triangle(_) | Shape::BilinearPatch(_)); - if render_from_light.has_scale(None) && !is_triangle_or_bilinear { - println!( - "Scaling detected in rendering to light space transformation! \ - The system has numerous assumptions, implicit and explicit, \ - that this transform will have no scale factors in it. \ - Proceed at your own risk; your image may have errors." - ); - } - - Self { - base, - area: shape.area(), - image: Ptr::from(image.device()), - colorspace, - shape, - alpha: stored_alpha.expect("Could not retrieve texture"), - lemit: Ptr::from(&lemit.device()), - two_sided, - scale, - } - } -} - impl CreateLight for DiffuseAreaLight { fn create( render_from_light: Transform, @@ -186,17 +103,61 @@ impl CreateLight for DiffuseAreaLight { scale *= phi_v / k_e; } - let specific = DiffuseAreaLight::new( - render_from_light, - medium.into(), - *l_for_scale, + let alpha_ptr = alpha.upload(arena); + let is_constant_zero = match &*alpha_ptr { + GPUFloatTexture::Constant(tex) => tex.evaluate(&TextureEvalContext::default()) == 0.0, + _ => false, + }; + + let (light_type, stored_alpha) = if is_constant_zero { + (LightType::DeltaPosition, None) + } else { + (LightType::Area, Some(alpha)) + }; + + let base = LightBase::new(light_type, render_from_light, medium.into()); + if let Some(ref img) = image { + let desc = img + .get_channel_desc(&["R", "G", "B"]) + .expect("Image used for DiffuseAreaLight doesn't have R, G, B channels"); + assert_eq!(3, desc.size()); + assert!(desc.is_identity()); + assert!( + image_color_space.is_some(), + "Image provided but ColorSpace is missing" + ); + } + + let is_triangle_or_bilinear = + matches!(*shape, Shape::Triangle(_) | Shape::BilinearPatch(_)); + if render_from_light.has_scale(None) && !is_triangle_or_bilinear { + println!( + "Scaling detected in rendering to light space transformation! \ + Proceed at your own risk; your image may have errors." + ); + } + + let shape_ptr = shape.upload(arena); + let image_ptr = image + .as_ref() + .map(|img| arena.alloc(*img.device())) + .unwrap_or(Ptr::null()); + let colorspace_ptr = image_color_space + .map(|cs| cs.upload(arena)) + .unwrap_or(Ptr::null()); + let lemit_ptr = arena.alloc(lookup_spectrum(l_for_scale).device()); + + let specific = DiffuseAreaLight { + base, + area: shape.area(), + shape: shape_ptr, + alpha: alpha_ptr, + image: image_ptr, + colorspace: colorspace_ptr, + lemit: lemit_ptr, + two_sided, scale, - shape.upload(arena), - alpha.upload(arena), - Ptr::from(&image.unwrap()), - image_color_space.upload(arena), - true, - ); + }; Ok(Light::DiffuseArea(specific)) } diff --git a/src/lights/goniometric.rs b/src/lights/goniometric.rs index ddc57cd..72c3796 100644 --- a/src/lights/goniometric.rs +++ b/src/lights/goniometric.rs @@ -5,11 +5,11 @@ use crate::core::light::{CreateLight, lookup_spectrum}; use crate::core::spectrum::spectrum_to_photometric; use crate::core::texture::FloatTexture; use crate::utils::sampling::PiecewiseConstant2D; -use crate::utils::{Arena, FileLoc, ParameterDictionary, resolve_filename}; +use crate::utils::{Arena, FileLoc, ParameterDictionary, Upload, resolve_filename}; use anyhow::{Result, anyhow}; use shared::core::geometry::Point2i; use shared::core::light::{Light, LightBase, LightType}; -use shared::core::medium::{Medium, MediumInterface}; +use shared::core::medium::Medium; use shared::core::shape::Shape; use shared::core::spectrum::Spectrum; use shared::core::texture::SpectrumType; @@ -18,42 +18,6 @@ use shared::spectra::RGBColorSpace; use shared::utils::{Ptr, Transform}; use shared::{Float, PI}; -pub trait CreateGoniometricLight { - fn new( - render_from_light: Transform, - medium_interface: MediumInterface, - le: Spectrum, - scale: Float, - image: Ptr, - ) -> Self; -} - -impl CreateGoniometricLight for GoniometricLight { - fn new( - render_from_light: Transform, - medium_interface: MediumInterface, - le: Spectrum, - scale: Float, - image: Ptr, - ) -> Self { - let base = LightBase::new( - LightType::DeltaPosition, - render_from_light, - medium_interface, - ); - - let iemit = lookup_spectrum(&le); - let distrib = PiecewiseConstant2D::from_image(&image); - Self { - base, - iemit: Ptr::from(&iemit.device()), - scale, - image: Ptr::from(image.device()), - distrib: Ptr::from(&distrib.device), - } - } -} - impl CreateLight for GoniometricLight { fn create( render_from_light: Transform, @@ -63,7 +27,7 @@ impl CreateLight for GoniometricLight { _shape: &Shape, _alpha_text: &FloatTexture, colorspace: Option<&RGBColorSpace>, - _arena: &Arena, + arena: &Arena, ) -> Result { let i = params .get_one_spectrum( @@ -116,8 +80,30 @@ impl CreateLight for GoniometricLight { .expect("Could not create transform for GoniometricLight"); let final_render_from_light = render_from_light * t; - let specific = - GoniometricLight::new(final_render_from_light, medium.into(), i, scale, image); + let base = LightBase::new( + LightType::DeltaPosition, + final_render_from_light, + medium.into(), + ); + + let iemit = lookup_spectrum(&i); + + let image_ptr = if !image.is_null() { + let distrib = PiecewiseConstant2D::from_image(&image); + let distrib_ptr = distrib.upload(arena); + let img_ptr = image.upload(arena); + (img_ptr, distrib_ptr) + } else { + (Ptr::null(), Ptr::null()) + }; + + let specific = GoniometricLight { + base, + iemit: arena.alloc(iemit.device()), + scale, + image: image_ptr.0, + distrib: image_ptr.1, + }; Ok(Light::Goniometric(specific)) } diff --git a/src/lights/mod.rs b/src/lights/mod.rs index 8445aa2..e347ad8 100644 --- a/src/lights/mod.rs +++ b/src/lights/mod.rs @@ -7,12 +7,9 @@ pub mod projection; pub mod sampler; pub mod spot; -pub use diffuse::CreateDiffuseLight; pub use distant::CreateDistantLight; -pub use goniometric::CreateGoniometricLight; pub use infinite::{ CreateImageInfiniteLight, CreatePortalInfiniteLight, CreateUniformInfiniteLight, }; pub use point::CreatePointLight; -pub use projection::CreateProjectionLight; pub use spot::CreateSpotLight; diff --git a/src/lights/projection.rs b/src/lights/projection.rs index 2e63831..f10d1b0 100644 --- a/src/lights/projection.rs +++ b/src/lights/projection.rs @@ -10,88 +10,14 @@ use shared::core::geometry::{ Bounds2f, Point2f, Point2i, Point3f, Vector3f, VectorLike, cos_theta, }; use shared::core::light::{Light, LightBase, LightType}; -use shared::core::medium::{Medium, MediumInterface}; +use shared::core::medium::Medium; use shared::core::shape::Shape; use shared::core::spectrum::Spectrum; use shared::lights::ProjectionLight; use shared::spectra::RGBColorSpace; +use shared::utils::Transform; use shared::utils::math::{radians, square}; -use shared::utils::{Ptr, Transform}; use std::path::Path; -use std::sync::Arc; - -pub trait CreateProjectionLight { - fn new( - render_from_light: Transform, - medium_interface: MediumInterface, - scale: Float, - image: Arc, - image_color_space: Ptr, - fov: Float, - ) -> Self; -} - -impl CreateProjectionLight for ProjectionLight { - fn new( - render_from_light: Transform, - medium_interface: MediumInterface, - scale: Float, - image: Arc, - image_color_space: Ptr, - fov: Float, - ) -> Self { - let base = LightBase::new( - LightType::DeltaPosition, - render_from_light, - medium_interface, - ); - - let opposite = (radians(fov) / 2.0).tan(); - let res = image.resolution(); - let aspect = res.x() as Float / res.y() as Float; - let aspect_ratio = if aspect > 1.0 { aspect } else { 1.0 / aspect }; - let a = 4.0 * square(opposite) * aspect_ratio; - let screen_bounds = if aspect > 1.0 { - Bounds2f::from_points(Point2f::new(-aspect, -1.0), Point2f::new(aspect, 1.0)) - } else { - Bounds2f::from_points( - Point2f::new(-1.0, -1.0 / aspect), - Point2f::new(1.0, 1.0 / aspect), - ) - }; - - let hither = 1e-3; - let screen_from_light = Transform::perspective(fov, hither, 1e30).unwrap(); - let light_from_screen = screen_from_light.inverse(); - - let dwda = |p: Point2f| { - let w = - Vector3f::from(light_from_screen.apply_to_point(Point3f::new(p.x(), p.y(), 0.0))); - cos_theta(w.normalize()).powi(3) - }; - - let d = image.get_sampling_distribution(dwda, screen_bounds); - let distrib = PiecewiseConstant2D::from_slice( - d.as_slice(), - d.x_size() as usize, - d.y_size() as usize, - screen_bounds, - ); - - Self { - base, - image: Ptr::from(image.device()), - image_color_space, - distrib: Ptr::from(&distrib.device), - screen_bounds, - screen_from_light, - light_from_screen, - scale, - hither, - a, - } - } -} impl CreateLight for ProjectionLight { fn create( @@ -155,15 +81,53 @@ impl CreateLight for ProjectionLight { let flip = Transform::scale(1., -1., 1.); let render_from_light_flip = render_from_light * flip; - let specific = ProjectionLight::new( - render_from_light_flip, - medium.into(), - scale, - Arc::new(image), - colorspace.upload(arena), - fov, + let base = LightBase::new(LightType::DeltaPosition, render_from_light, medium.into()); + + let opposite = (radians(fov) / 2.0).tan(); + let res = image.resolution(); + let aspect = res.x() as Float / res.y() as Float; + let aspect_ratio = if aspect > 1.0 { aspect } else { 1.0 / aspect }; + let a = 4.0 * square(opposite) * aspect_ratio; + let screen_bounds = if aspect > 1.0 { + Bounds2f::from_points(Point2f::new(-aspect, -1.0), Point2f::new(aspect, 1.0)) + } else { + Bounds2f::from_points( + Point2f::new(-1.0, -1.0 / aspect), + Point2f::new(1.0, 1.0 / aspect), + ) + }; + + let hither = 1e-3; + let screen_from_light = Transform::perspective(fov, hither, 1e30).unwrap(); + let light_from_screen = screen_from_light.inverse(); + + let dwda = |p: Point2f| { + let w = + Vector3f::from(light_from_screen.apply_to_point(Point3f::new(p.x(), p.y(), 0.0))); + cos_theta(w.normalize()).powi(3) + }; + + let d = image.get_sampling_distribution(dwda, screen_bounds); + let distrib = PiecewiseConstant2D::from_slice( + d.as_slice(), + d.x_size() as usize, + d.y_size() as usize, + screen_bounds, ); + let specific = ProjectionLight { + base, + image: image.upload(arena), + image_color_space: colorspace.upload(arena), + distrib: distrib.upload(arena), + screen_bounds, + screen_from_light, + light_from_screen, + scale, + hither, + a, + }; + Ok(Light::Projection(specific)) } } diff --git a/src/shapes/triangle.rs b/src/shapes/triangle.rs index 65865f5..f280a2a 100644 --- a/src/shapes/triangle.rs +++ b/src/shapes/triangle.rs @@ -29,7 +29,7 @@ impl CreateShape for TriangleShape { if vertex_indices.is_empty() { if p.len() == 3 { } else { - return bail!("Vertex indices \"indices\" must be provided with triangle mesh."); + bail!("Vertex indices \"indices\" must be provided with triangle mesh."); } } else if vertex_indices.len() % 3 != 0 { let excess = vertex_indices.len() % 3; @@ -43,7 +43,7 @@ impl CreateShape for TriangleShape { } if p.is_empty() { - return bail!("Vertex positions \"P\" must be provided with triangle mesh."); + bail!("Vertex positions \"P\" must be provided with triangle mesh."); } if !uvs.is_empty() && uvs.len() != p.len() { @@ -64,7 +64,7 @@ impl CreateShape for TriangleShape { for (_, &index) in vertex_indices.iter().enumerate() { // Check for negative indices (if keeping i32) or out of bounds if index < 0 || index as usize >= p.len() { - return bail!( + bail!( "TriangleMesh has out-of-bounds vertex index {} ({} \"P\" values were given). Discarding this mesh.", index, p.len() diff --git a/src/utils/backend.rs b/src/utils/backend.rs index b9654d1..89ddc0a 100644 --- a/src/utils/backend.rs +++ b/src/utils/backend.rs @@ -138,7 +138,7 @@ pub mod vulkan { fn inner() -> &'static VulkanAllocatorInner { VK_ALLOCATOR .get() - .expect("Vulkan not initialized — call init_vulkan() before Arena::default()") + .expect("Vulkan not initialized — call init_vulkan() before arena creation") } impl Default for VulkanAllocator { diff --git a/src/utils/parser.rs b/src/utils/parser.rs index 943e441..ae95c79 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -66,37 +66,37 @@ pub trait ParserTarget { fn pixel_filter( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn film( &mut self, type_name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn accelerator( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn integrator( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn camera( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn make_named_medium( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn medium_interface( @@ -108,7 +108,7 @@ pub trait ParserTarget { fn sampler( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; @@ -127,20 +127,20 @@ pub trait ParserTarget { name: &str, type_name: &str, tex_name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, arena: Arc, ) -> Result<(), ParserError>; fn material( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn make_named_material( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn named_material(&mut self, name: &str, loc: FileLoc) -> Result<(), ParserError>; @@ -148,20 +148,20 @@ pub trait ParserTarget { fn light_source( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn area_light_source( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn shape( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, loc: FileLoc, ) -> Result<(), ParserError>; fn reverse_orientation(&mut self, loc: FileLoc) -> Result<(), ParserError>; @@ -594,7 +594,7 @@ impl ParserTarget for FormattingParserTarget { fn shape( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { println!( @@ -609,7 +609,7 @@ impl ParserTarget for FormattingParserTarget { fn material( &mut self, name: &str, - params: &ParsedParameterVector, + params: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { println!( @@ -626,7 +626,7 @@ impl ParserTarget for FormattingParserTarget { name: &str, type_name: &str, tex_name: &str, - _params: &ParsedParameterVector, + _params: ParsedParameterVector, _loc: FileLoc, _arena: Arc, ) -> Result<(), ParserError> { @@ -658,7 +658,7 @@ impl ParserTarget for FormattingParserTarget { fn pixel_filter( &mut self, _n: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -666,7 +666,7 @@ impl ParserTarget for FormattingParserTarget { fn film( &mut self, _t: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -674,7 +674,7 @@ impl ParserTarget for FormattingParserTarget { fn accelerator( &mut self, _n: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -682,7 +682,7 @@ impl ParserTarget for FormattingParserTarget { fn integrator( &mut self, _n: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -690,7 +690,7 @@ impl ParserTarget for FormattingParserTarget { fn camera( &mut self, _n: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -698,7 +698,7 @@ impl ParserTarget for FormattingParserTarget { fn make_named_medium( &mut self, _n: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -709,7 +709,7 @@ impl ParserTarget for FormattingParserTarget { fn sampler( &mut self, _n: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -725,7 +725,7 @@ impl ParserTarget for FormattingParserTarget { fn make_named_material( &mut self, _n: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -736,7 +736,7 @@ impl ParserTarget for FormattingParserTarget { fn light_source( &mut self, _n: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -744,7 +744,7 @@ impl ParserTarget for FormattingParserTarget { fn area_light_source( &mut self, _n: &str, - _p: &ParsedParameterVector, + _p: ParsedParameterVector, _loc: FileLoc, ) -> Result<(), ParserError> { Ok(()) @@ -1093,7 +1093,7 @@ impl<'a> SceneParser<'a> { .collect::>()?; self.target.look_at( v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], token.loc, - ); + )?; } _ => { return Err(ParserError::Generic( @@ -1186,7 +1186,7 @@ impl<'a> SceneParser<'a> { let ax = self.expect_float()?; let ay = self.expect_float()?; let az = self.expect_float()?; - self.target.rotate(angle, ax, ay, az, token.loc); + self.target.rotate(angle, ax, ay, az, token.loc)?; } _ => { return Err(ParserError::Generic( @@ -1203,7 +1203,7 @@ impl<'a> SceneParser<'a> { let x = self.expect_float()?; let y = self.expect_float()?; let z = self.expect_float()?; - self.target.scale(x, y, z, token.loc); + self.target.scale(x, y, z, token.loc)?; } _ => { return Err(ParserError::Generic( @@ -1245,7 +1245,7 @@ impl<'a> SceneParser<'a> { &name, &type_name, &tex_name, - ¶ms, + params, token.loc, arena.clone(), )?; @@ -1310,7 +1310,7 @@ impl<'a> SceneParser<'a> { F: FnMut( &mut dyn ParserTarget, &str, - &ParsedParameterVector, + ParsedParameterVector, FileLoc, ) -> Result<(), ParserError>, { @@ -1322,6 +1322,6 @@ impl<'a> SceneParser<'a> { }; let params = self.parse_parameters()?; - func(self.target, &type_name, ¶ms, type_token.loc) + func(self.target, &type_name, params, type_token.loc) } }