use bytemuck::{Pod, Zeroable}; use nalgebra::Vector4; use rapier3d::parry::math::Point; use tobj::{LoadError, Model, Material}; #[repr(C)] #[derive(Clone, Copy, Debug)] pub struct Vertex { pos: [f32; 4], normal: [f32; 4], uv: [f32; 2], } impl Vertex { pub fn position(&self) -> Point { Point::::new(self.pos[0], self.pos[1], self.pos[2]) } pub fn from(pos: [f32; 3], nor: [f32; 3], uv: [f32; 2]) -> Vertex { Vertex { pos: [pos[0], pos[1], pos[2], 1.0], normal: [nor[0], nor[1], nor[2], 0.0], uv: [uv[0], uv[1]], } } } unsafe impl Pod for Vertex {} unsafe impl Zeroable for Vertex {} #[derive(Clone, Debug)] pub struct RawMesh { pub vertices: Vec, pub indices: Vec<[u32; 3]>, } /// We use meshes in a few different places. To keep things simple, we return /// the most basic, direct-to-memory version. If something fancy needs to be done /// with it, the fancy stays there pub fn load_obj(obj_path: &str) -> Result { log::info!("Loading object {}", obj_path); // Is there no better way to translate error messages? let (models, materials) = match tobj::load_obj(obj_path, true) { Ok((a, b)) => {Ok((a, b))} Err(load_error) => {Err(load_error.to_string())} }?; // println!("# of models: {}", models.len()); // println!("# of materials: {}", materials.len()); // println!("{:?}", materials); let mut index_data: Vec<[u32; 3]> = Vec::new(); let mut vertex_data = Vec::new(); for model in models { let mesh = &model.mesh; // Cycle through the faces and chunk out the indices let mut next_face = 0; for f in 0..mesh.num_face_indices.len() { // calculate the next chunk let end = next_face + mesh.num_face_indices[f] as usize; let face_indices: Vec<_> = mesh.indices[next_face..end].iter().collect(); if face_indices.len() != 3 { return Err("we only handle triangulated faces".to_string()); } index_data.push([*face_indices[0], *face_indices[1], *face_indices[2]]); next_face = end; } if mesh.positions.len() % 3 != 0 { return Err(format!("position array not % 3 : {}", mesh.positions.len())) } if mesh.texcoords.len() % 2 != 0 { return Err(format!("position array not % 3 : {}", mesh.positions.len())) } if mesh.normals.is_empty() { return Err(format!("It would be best if this had normals")) } if mesh.texcoords.is_empty() { log::info!("\tMesh texture coordinates empty") } for v in 0..mesh.positions.len() / 3 { let texcoords = if mesh.texcoords.len() == 0 { [0.0, 0.0] } else { [mesh.texcoords[2 * v], mesh.texcoords[2 * v + 1]] }; vertex_data.push(Vertex::from( [ mesh.positions[3 * v], mesh.positions[3 * v + 1], mesh.positions[3 * v + 2], ], [ mesh.normals[3 * v], mesh.normals[3 * v + 1], mesh.normals[3 * v + 2], ], texcoords, )); } } Ok(RawMesh { vertices: vertex_data.to_vec(), indices: index_data.to_vec(), }) }