pbrt/src/shapes/bilinear.rs

132 lines
4.6 KiB
Rust

use crate::core::image::{HostImage, ImageIO};
use crate::core::shape::{CreateShape, ALL_BILINEAR_MESHES};
use crate::core::texture::FloatTexture;
use crate::{Arena, FileLoc, ParameterDictionary};
use anyhow::{anyhow, Result};
use log::warn;
use shared::core::shape::Shape;
use shared::shapes::{BilinearPatchMesh, BilinearPatchShape};
use shared::utils::sampling::PiecewiseConstant2D;
use shared::{Ptr, Transform};
use std::collections::HashMap;
use std::path::Path;
use std::sync::Arc;
impl CreateShape for BilinearPatchShape {
fn create(
render_from_object: Transform,
_object_from_render: Transform,
reverse_orientation: bool,
parameters: ParameterDictionary,
_float_textures: &HashMap<String, Arc<FloatTexture>>,
_loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Ptr<Shape>>> {
let mut vertex_indices = parameters.get_int_array("indices")?;
let p = parameters.get_point3f_array("P")?;
let mut uv = parameters.get_point2f_array("uv")?;
let mut n = parameters.get_normal3f_array("N")?;
let mut face_indices = parameters.get_int_array("faceIndices")?;
if vertex_indices.is_empty() {
if p.len() == 4 {
vertex_indices = vec![0, 1, 2, 3];
} else {
return Err(anyhow!(
"Vertex indices \"indices\" must be provided with bilinear patch mesh shape."
));
}
} else if vertex_indices.len() % 4 != 0 {
let excess = vertex_indices.len() % 4;
warn!(
"Number of vertex indices {} not a multiple of 4. Discarding {} excess.",
vertex_indices.len(),
excess
);
let new_len = vertex_indices.len() - excess;
vertex_indices.truncate(new_len);
}
if p.is_empty() {
return Err(anyhow!(
"Vertex positions \"P\" must be provided with bilinear patch mesh shape."
));
}
if !uv.is_empty() && uv.len() != p.len() {
warn!("Number of \"uv\"s for bilinear patch mesh must match \"P\"s. Discarding uvs.");
uv.clear();
}
if !n.is_empty() && n.len() != p.len() {
warn!("Number of \"N\"s for bilinear patch mesh must match \"P\"s. Discarding \"N\"s.");
n.clear();
}
for &idx in vertex_indices.iter() {
if idx < 0 || idx as usize >= p.len() {
return Err(anyhow!(
"Bilinear patch mesh has out-of-bounds vertex index {} ({} \"P\" values were given). Discarding this mesh.",
idx,
p.len()
));
}
}
let n_patches = vertex_indices.len() / 4;
if !face_indices.is_empty() && face_indices.len() != n_patches {
warn!(
"Number of face indices {} does not match number of bilinear patches {}. Discarding face indices.",
face_indices.len(),
n_patches
);
face_indices.clear();
}
let filename = parameters.get_one_string("emissionfilename", "")?;
let image_dist = if !filename.is_empty() {
if !uv.is_empty() {
warn!(
"\"emissionfilename\" is currently ignored for bilinear patches if \"uv\" coordinates have been provided--sorry!"
);
None
} else {
let im = HostImage::read(Path::new(&filename), None)?;
let mut img = im.image;
img.flip_y();
Some(PiecewiseConstant2D::from_image(&img.inner))
}
} else {
None
};
let host = BilinearPatchMesh::new(
&render_from_object,
reverse_orientation,
&vertex_indices,
&p,
&n,
&uv,
image_dist.as_ref(),
);
let host_arc = Arc::new(host);
let mut global_store = ALL_BILINEAR_MESHES.lock();
// let mesh_index = global_store.len() as u32;
global_store.push(host_arc.clone());
drop(global_store);
let n_patches = host_arc.n_patches;
let mesh_ptr = arena.alloc_arc(host_arc);
let mut shapes = Vec::with_capacity(n_patches as usize);
for i in 0..n_patches as i32 {
shapes.push(arena.alloc(Shape::BilinearPatch(BilinearPatchShape {
mesh: mesh_ptr,
blp_index: i,
area: 0.0,
rectangle: false,
})));
}
Ok(shapes)
}
}