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>, _loc: FileLoc, arena: &Arena, ) -> Result>> { 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) } }