1 use bytemuck::{Pod, Zeroable}; 2 use nalgebra::Vector4; 3 use rapier3d::parry::math::Point; 4 use tobj::{LoadError, Model, Material}; 5 6 7 #[repr(C)] 8 #[derive(Clone, Copy, Debug)] 9 pub struct Vertex { 10 pos: [f32; 4], 11 normal: [f32; 4], 12 uv: [f32; 2], 13 } 14 15 impl Vertex { 16 pub fn position(&self) -> Point<f32> { 17 Point::<f32>::new(self.pos[0], self.pos[1], self.pos[2]) 18 } 19 pub fn from(pos: [f32; 3], nor: [f32; 3], uv: [f32; 2]) -> Vertex { 20 Vertex { 21 pos: [pos[0], pos[1], pos[2], 1.0], 22 normal: [nor[0], nor[1], nor[2], 0.0], 23 uv: [uv[0], uv[1]], 24 } 25 } 26 } 27 28 unsafe impl Pod for Vertex {} 29 unsafe impl Zeroable for Vertex {} 30 31 #[derive(Clone, Debug)] 32 pub struct RawMesh { 33 pub vertices: Vec<Vertex>, 34 pub indices: Vec<[u32; 3]>, 35 } 36 37 38 /// We use meshes in a few different places. To keep things simple, we return 39 /// the most basic, direct-to-memory version. If something fancy needs to be done 40 /// with it, the fancy stays there 41 pub fn load_obj(obj_path: &str) -> Result<RawMesh, String> { 42 43 log::info!("Loading object {}", obj_path); 44 45 // Is there no better way to translate error messages? 46 let (models, materials) = match tobj::load_obj(obj_path, true) { 47 Ok((a, b)) => {Ok((a, b))} 48 Err(load_error) => {Err(load_error.to_string())} 49 }?; 50 51 // println!("# of models: {}", models.len()); 52 // println!("# of materials: {}", materials.len()); 53 // println!("{:?}", materials); 54 55 let mut index_data: Vec<[u32; 3]> = Vec::new(); 56 let mut vertex_data = Vec::new(); 57 58 for model in models { 59 let mesh = &model.mesh; 60 61 // Cycle through the faces and chunk out the indices 62 let mut next_face = 0; 63 for f in 0..mesh.num_face_indices.len() { 64 // calculate the next chunk 65 let end = next_face + mesh.num_face_indices[f] as usize; 66 let face_indices: Vec<_> = mesh.indices[next_face..end].iter().collect(); 67 68 if face_indices.len() != 3 { 69 return Err("we only handle triangulated faces".to_string()); 70 } 71 index_data.push([*face_indices[0], *face_indices[1], *face_indices[2]]); 72 next_face = end; 73 } 74 75 if mesh.positions.len() % 3 != 0 { 76 return Err(format!("position array not % 3 : {}", mesh.positions.len())) 77 } 78 if mesh.texcoords.len() % 2 != 0 { 79 return Err(format!("position array not % 3 : {}", mesh.positions.len())) 80 } 81 if mesh.normals.is_empty() { 82 return Err(format!("It would be best if this had normals")) 83 } 84 if mesh.texcoords.is_empty() { 85 log::info!("\tMesh texture coordinates empty") 86 } 87 88 for v in 0..mesh.positions.len() / 3 { 89 let texcoords = if mesh.texcoords.len() == 0 { 90 [0.0, 0.0] 91 } else { 92 [mesh.texcoords[2 * v], mesh.texcoords[2 * v + 1]] 93 }; 94 95 vertex_data.push(Vertex::from( 96 [ 97 mesh.positions[3 * v], 98 mesh.positions[3 * v + 1], 99 mesh.positions[3 * v + 2], 100 ], 101 [ 102 mesh.normals[3 * v], 103 mesh.normals[3 * v + 1], 104 mesh.normals[3 * v + 2], 105 ], 106 texcoords, 107 )); 108 } 109 } 110 Ok(RawMesh { 111 vertices: vertex_data.to_vec(), 112 indices: index_data.to_vec(), 113 }) 114 } 115 116 // pub fn create_quad_mesh() -> RawMesh { 117 // 118 // let mut index_data: Vec<[u32; 3]> = Vec::new(); 119 // let mut vertex_data = Vec::new(); 120 // 121 // vertex_data.push(Vertex::from( 122 // [ 123 // mesh.positions[3 * v], 124 // mesh.positions[3 * v + 1], 125 // mesh.positions[3 * v + 2], 126 // ], 127 // [ 128 // mesh.normals[3 * v], 129 // mesh.normals[3 * v + 1], 130 // mesh.normals[3 * v + 2], 131 // ], 132 // [mesh.texcoords[2 * v], mesh.texcoords[2 * v + 1]], 133 // )); 134 // 135 // RawMesh { 136 // vertices: vertex_data.to_vec(), 137 // indices: index_data.to_vec(), 138 // } 139 // } 140