132 lines
4.6 KiB
Rust
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)
|
|
}
|
|
}
|