From f412874317d1f2610c45009d887cc6d788d4e708 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 7 Feb 2024 20:52:32 -0800 Subject: [PATCH] physics mesh builder rewrite --- src/model_physics.rs | 207 ++++++++++++++++++++++++++----------------- 1 file changed, 127 insertions(+), 80 deletions(-) diff --git a/src/model_physics.rs b/src/model_physics.rs index 5a47fec..aed4165 100644 --- a/src/model_physics.rs +++ b/src/model_physics.rs @@ -1,5 +1,6 @@ use std::borrow::{Borrow,Cow}; -use strafesnet_common::model; +use std::collections::{HashSet,HashMap}; +use strafesnet_common::model::{self,PolygonIter}; use strafesnet_common::zeroes; use strafesnet_common::integer::{self,Planar64,Planar64Vec3}; @@ -56,6 +57,7 @@ pub enum FEV{ } //use Unit32 #[repr(C)] for map files +#[derive(Clone,Hash,Eq,PartialEq)] struct Face{ normal:Planar64Vec3, dot:Planar64, @@ -188,21 +190,28 @@ impl PhysicsMesh{ pub fn unit_cylinder()->Self{ Self::unit_cube() } - pub fn mesh_data(&self)->&PhysicsMeshData{ + #[inline] + pub const fn mesh_data(&self)->&PhysicsMeshData{ &self.data } - pub fn complete_mesh(&self)->&PhysicsMeshTopology{ + #[inline] + pub const fn complete_mesh(&self)->&PhysicsMeshTopology{ &self.submeshes[0] } - pub fn submeshes(&self)->&[PhysicsMeshTopology]{ - if self.submeshes.len()==1{ - //the complete mesh is already a convex mesh - &self.submeshes[0..0] - }else{ - &self.submeshes[1..] + #[inline] + pub const fn complete_mesh_view(&self)->PhysicsMeshView{ + PhysicsMeshView{ + data:&self.data, + topology:self.complete_mesh(), } } - pub fn submesh_view(&self,submesh_id:PhysicsSubmeshId)->PhysicsMeshView{ + #[inline] + pub const fn submeshes(&self)->&[PhysicsMeshTopology]{ + //the complete mesh is already a convex mesh when len()==1, len()==2 is invalid but will still work + &self.submeshes[self.submeshes.len().saturating_sub(1).min(1)..] + } + #[inline] + pub const fn submesh_view(&self,submesh_id:PhysicsSubmeshId)->PhysicsMeshView{ PhysicsMeshView{ data:&self.data, topology:&self.submeshes()[submesh_id.get() as usize], @@ -219,13 +228,13 @@ impl PhysicsMesh{ //mesh builder code #[derive(Default,Clone)] struct VertRefGuy{ - edges:std::collections::HashSet, - faces:std::collections::HashSet, + edges:HashSet, + faces:HashSet, } #[derive(Clone,Hash,Eq,PartialEq)] struct EdgeRefVerts([SubmeshVertId;2]); impl EdgeRefVerts{ - fn new(v0:SubmeshVertId,v1:SubmeshVertId)->(Self,bool){ + const fn new(v0:SubmeshVertId,v1:SubmeshVertId)->(Self,bool){ (if v0.0Self{ + const fn new()->Self{ Self([SubmeshFaceId(0);2]) } - fn push(&mut self,i:usize,face_id:SubmeshFaceId){ + const fn push(&mut self,i:usize,face_id:SubmeshFaceId){ self.0[i]=face_id; } } @@ -246,88 +255,126 @@ struct FaceRefEdges(Vec); #[derive(Default)] struct EdgePool{ edge_guys:Vec<(EdgeRefVerts,EdgeRefFaces)>, - edge_id_from_guy:std::collections::HashMap, + edge_id_from_guy:HashMap, } impl EdgePool{ fn push(&mut self,edge_ref_verts:EdgeRefVerts)->(&mut EdgeRefFaces,SubmeshEdgeId){ let edge_id=if let Some(&edge_id)=self.edge_id_from_guy.get(&edge_ref_verts){ edge_id }else{ - let edge_id=self.edge_guys.len(); + let edge_id=SubmeshEdgeId::new(self.edge_guys.len() as u32); self.edge_guys.push((edge_ref_verts.clone(),EdgeRefFaces::new())); self.edge_id_from_guy.insert(edge_ref_verts,edge_id); edge_id }; - (&mut unsafe{self.edge_guys.get_unchecked_mut(edge_id)}.1,SubmeshEdgeId::new(edge_id as u32)) + (&mut unsafe{self.edge_guys.get_unchecked_mut(edge_id.get() as usize)}.1,edge_id) } } impl From<&model::Mesh> for PhysicsMesh{ - fn from(indexed_model:&model::Mesh)->Self{ - assert!(indexed_model.unique_pos.len()!=0,"Mesh cannot have 0 vertices"); - let verts=indexed_model.unique_pos.iter().map(|v|Vert(v.clone())).collect(); - let mut vert_ref_guys=vec![VertRefGuy::default();indexed_model.unique_pos.len()]; - let mut edge_pool=EdgePool::default(); - let mut face_i=0; + fn from(mesh:&model::Mesh)->Self{ + assert!(mesh.unique_pos.len()!=0,"Mesh cannot have 0 vertices"); + let verts=mesh.unique_pos.into_iter().map(Vert).collect(); let mut faces=Vec::new(); - let mut face_ref_guys=Vec::new(); - for group in &indexed_model.polygon_groups{for poly_vertices in group.polys(){ - let face_id=SubmeshFaceId::new(face_i); - //one face per poly - let mut normal=Planar64Vec3::ZERO; - let len=poly_vertices.len(); - let face_edges=poly_vertices.iter().enumerate().map(|(i,&vert_id)|{ - let vert0_id=indexed_model.unique_vertices[vert_id.get() as usize].pos.get() as usize; - let vert1_id=indexed_model.unique_vertices[poly_vertices[(i+1)%len].get() as usize].pos.get() as usize; - //https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal (Newell's Method) - let v0=indexed_model.unique_pos[vert0_id]; - let v1=indexed_model.unique_pos[vert1_id]; - normal+=Planar64Vec3::new( - (v0.y()-v1.y())*(v0.z()+v1.z()), - (v0.z()-v1.z())*(v0.x()+v1.x()), - (v0.x()-v1.x())*(v0.y()+v1.y()), - ); - //get/create edge and push face into it - let (edge_ref_verts,is_sorted)=EdgeRefVerts::new(SubmeshVertId::new(vert0_id as u32),SubmeshVertId::new(vert1_id as u32)); - let (edge_ref_faces,edge_id)=edge_pool.push(edge_ref_verts); - //polygon vertices as assumed to be listed clockwise - //populate the edge face on the left or right depending on how the edge vertices got sorted - edge_ref_faces.push(!is_sorted as usize,face_id); - //index edges & face into vertices - { - let vert_ref_guy=unsafe{vert_ref_guys.get_unchecked_mut(vert0_id)}; - vert_ref_guy.edges.insert(edge_id.as_directed(is_sorted)); - vert_ref_guy.faces.insert(face_id); - unsafe{vert_ref_guys.get_unchecked_mut(vert1_id)}.edges.insert(edge_id.as_directed(!is_sorted)); + let mut face_id_from_face=HashMap::new(); + let submeshes=mesh.physics_groups.iter().enumerate().map(|(submesh_id,physics_group)|{ + //construct submesh + let mut submesh_faces=Vec::new();//these contain a map from submeshId->meshId + let mut submesh_verts=Vec::new(); + let mut submesh_vert_id_from_mesh_vert_id=HashMap::::new(); + //lazy closure + let get_submesh_vert_id=|vert_id:MeshVertId|{ + if let Some(&submesh_vert_id)=submesh_vert_id_from_mesh_vert_id.get(&vert_id){ + submesh_vert_id + }else{ + let submesh_vert_id=SubmeshVertId::new(vert_id.get() as u32); + submesh_vert_id_from_mesh_vert_id.insert(vert_id,submesh_vert_id); + submesh_vert_id + } + }; + let mut edge_pool=EdgePool::default(); + let mut vert_ref_guys=vec![VertRefGuy::default();mesh.unique_pos.len()]; + let mut face_ref_guys=Vec::new(); + let submesh_id=PhysicsSubmeshId::new(submesh_id as u32); + for polygon_group_id in &physics_group.groups{ + let polygon_group=mesh.polygon_groups[polygon_group_id.get() as usize]; + for poly_vertices in polygon_group.polys(){ + let submesh_face_id=SubmeshFaceId::new(submesh_faces.len() as u32); + //one face per poly + let mut normal=Planar64Vec3::ZERO; + let len=poly_vertices.len(); + let face_edges=poly_vertices.into_iter().enumerate().map(|(i,vert_id)|{ + let vert0_id=MeshVertId::new(mesh.unique_vertices[vert_id.get() as usize].pos.get() as u32); + let vert1_id=MeshVertId::new(mesh.unique_vertices[poly_vertices[(i+1)%len].get() as usize].pos.get() as u32); + //index submesh verts + let submesh_vert0_id=get_submesh_vert_id(vert0_id); + let submesh_vert1_id=get_submesh_vert_id(vert1_id); + //https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal (Newell's Method) + let v0=mesh.unique_pos[vert0_id.get() as usize]; + let v1=mesh.unique_pos[vert1_id.get() as usize]; + normal+=Planar64Vec3::new( + (v0.y()-v1.y())*(v0.z()+v1.z()), + (v0.z()-v1.z())*(v0.x()+v1.x()), + (v0.x()-v1.x())*(v0.y()+v1.y()), + ); + //get/create edge and push face into it + let (edge_ref_verts,is_sorted)=EdgeRefVerts::new(submesh_vert0_id,submesh_vert1_id); + let (edge_ref_faces,edge_id)=edge_pool.push(edge_ref_verts); + //polygon vertices as assumed to be listed clockwise + //populate the edge face on the left or right depending on how the edge vertices got sorted + edge_ref_faces.push(!is_sorted as usize,submesh_face_id); + //index edges & face into vertices + { + let vert_ref_guy=unsafe{vert_ref_guys.get_unchecked_mut(submesh_vert0_id.get() as usize)}; + vert_ref_guy.edges.insert(edge_id.as_directed(is_sorted)); + vert_ref_guy.faces.insert(submesh_face_id); + unsafe{vert_ref_guys.get_unchecked_mut(submesh_vert1_id.get() as usize)}.edges.insert(edge_id.as_directed(!is_sorted)); + } + //return directed_edge_id + edge_id.as_directed(is_sorted) + }).collect(); + //choose precision loss randomly idk + normal=normal/len as i64; + let mut dot=Planar64::ZERO; + for &v in poly_vertices{ + dot+=normal.dot(mesh.unique_pos[mesh.unique_vertices[v.get() as usize].pos.get() as usize]); + } + let face=Face{normal,dot:dot/len as i64}; + let face_id=match face_id_from_face.get(&face){ + Some(&face_id)=>face_id, + None=>{ + let face_id=MeshFaceId::new(faces.len() as u32); + face_id_from_face.insert(face,face_id); + faces.push(face); + face_id + } + }; + submesh_faces.push(face_id); + face_ref_guys.push(FaceRefEdges(face_edges)); } - //return directed_edge_id - edge_id.as_directed(is_sorted) - }).collect(); - //choose precision loss randomly idk - normal=normal/len as i64; - let mut dot=Planar64::ZERO; - for &v in poly_vertices{ - dot+=normal.dot(indexed_model.unique_pos[indexed_model.unique_vertices[v.get() as usize].pos.get() as usize]); } - faces.push(Face{normal,dot:dot/len as i64}); - face_ref_guys.push(FaceRefEdges(face_edges)); - face_i+=1; - }} - //conceivably faces, edges, and vertices exist now + PhysicsMeshTopology{ + faces:submesh_faces, + verts:submesh_verts, + face_topology:face_ref_guys.into_iter().map(|face_ref_guy|{ + FaceRefs{edges:face_ref_guy.0} + }).collect(), + edge_topology:edge_pool.edge_guys.into_iter().map(|(edge_ref_verts,edge_ref_faces)| + EdgeRefs{faces:edge_ref_faces.0,verts:edge_ref_verts.0} + ).collect(), + vert_topology:vert_ref_guys.into_iter().map(|vert_ref_guy| + VertRefs{ + edges:vert_ref_guy.edges.into_iter().collect(), + faces:vert_ref_guy.faces.into_iter().collect(), + } + ).collect(), + } + }).collect(); Self{ - faces, - verts, - face_topology:face_ref_guys.into_iter().map(|face_ref_guy|{ - FaceRefs{edges:face_ref_guy.0} - }).collect(), - edge_topology:edge_pool.edge_guys.into_iter().map(|(edge_ref_verts,edge_ref_faces)| - EdgeRefs{faces:edge_ref_faces.0,verts:edge_ref_verts.0} - ).collect(), - vert_topology:vert_ref_guys.into_iter().map(|vert_ref_guy| - VertRefs{ - edges:vert_ref_guy.edges.into_iter().collect(), - faces:vert_ref_guy.faces.into_iter().collect(), - } - ).collect(), + data:PhysicsMeshData{ + faces, + verts, + }, + submeshes, } } }