Continuing cleanup of builder and parser. Removing light factory, creating issues with function signatures and unnecessary resources for light creation

This commit is contained in:
Wito Wiala 2026-05-12 12:29:44 +01:00
parent 0c04eeb0f9
commit c659ea0f44
11 changed files with 321 additions and 287 deletions

View file

@ -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::*;

View file

@ -49,15 +49,20 @@ impl IndexMut<usize> 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<usize>,
pub area_light_name: String,
pub area_light_params: ParsedParameterVector,
pub area_light_loc: FileLoc,
pub pending_area_light: Option<PendingAreaLight>,
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, ParserError> {
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(&params.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(&params.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<Arena>,
) -> 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> {

View file

@ -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<ShapeSceneEntity>) {
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<Vec<Light>> {
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,

View file

@ -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<AsyncJob<Light>>,
pub lights: Vec<LightSceneEntity>,
pub area_lights: Vec<SceneEntity>,
}

View file

@ -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<Shape>,
alpha: Ptr<GPUFloatTexture>,
image: Ptr<Image>,
colorspace: Ptr<RGBColorSpace>,
two_sided: bool,
) -> Self;
}
impl CreateDiffuseLight for DiffuseAreaLight {
fn new(
render_from_light: Transform,
medium_interface: MediumInterface,
le: Spectrum,
scale: Float,
shape: Ptr<Shape>,
alpha: Ptr<GPUFloatTexture>,
image: Ptr<Image>,
colorspace: Ptr<RGBColorSpace>,
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))
}

View file

@ -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<Image>,
) -> Self;
}
impl CreateGoniometricLight for GoniometricLight {
fn new(
render_from_light: Transform,
medium_interface: MediumInterface,
le: Spectrum,
scale: Float,
image: Ptr<Image>,
) -> 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<Light> {
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))
}

View file

@ -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;

View file

@ -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>,
image_color_space: Ptr<RGBColorSpace>,
fov: Float,
) -> Self;
}
impl CreateProjectionLight for ProjectionLight {
fn new(
render_from_light: Transform,
medium_interface: MediumInterface,
scale: Float,
image: Arc<Image>,
image_color_space: Ptr<RGBColorSpace>,
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))
}
}

View file

@ -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()

View file

@ -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 {

View file

@ -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<Arena>,
) -> 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<Arena>,
) -> 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::<Result<_, _>>()?;
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,
&params,
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, &params, type_token.loc)
func(self.target, &type_name, params, type_token.loc)
}
}