megatype-ify
This commit is contained in:
parent
5b38b2ca33
commit
50eeeb003a
@ -17,26 +17,31 @@ pub trait DirectedEdge{
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct VertId(u32);
|
||||
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct EdgeId(u32);
|
||||
/// DirectedEdgeId refers to an EdgeId when undirected.
|
||||
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct DirectedEdgeId(u32);
|
||||
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct FaceId(u32);
|
||||
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
pub struct MeshVertId(u32);
|
||||
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
pub struct MeshFaceId(u32);
|
||||
|
||||
impl UndirectedEdge for EdgeId{
|
||||
type DirectedEdge=DirectedEdgeId;
|
||||
fn as_directed(&self,parity:bool)->DirectedEdgeId{
|
||||
DirectedEdgeId(self.0|((parity as u32)<<(u32::BITS-1)))
|
||||
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
pub struct SubmeshVertId(u32);
|
||||
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
pub struct SubmeshEdgeId(u32);
|
||||
/// DirectedEdgeId refers to an EdgeId when undirected.
|
||||
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
pub struct SubmeshDirectedEdgeId(u32);
|
||||
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
pub struct SubmeshFaceId(u32);
|
||||
|
||||
impl UndirectedEdge for SubmeshEdgeId{
|
||||
type DirectedEdge=SubmeshDirectedEdgeId;
|
||||
fn as_directed(&self,parity:bool)->SubmeshDirectedEdgeId{
|
||||
SubmeshDirectedEdgeId(self.0|((parity as u32)<<(u32::BITS-1)))
|
||||
}
|
||||
}
|
||||
impl DirectedEdge for DirectedEdgeId{
|
||||
type UndirectedEdge=EdgeId;
|
||||
fn as_undirected(&self)->EdgeId{
|
||||
EdgeId(self.0&!(1<<(u32::BITS-1)))
|
||||
impl DirectedEdge for SubmeshDirectedEdgeId{
|
||||
type UndirectedEdge=SubmeshEdgeId;
|
||||
fn as_undirected(&self)->SubmeshEdgeId{
|
||||
SubmeshEdgeId(self.0&!(1<<(u32::BITS-1)))
|
||||
}
|
||||
fn parity(&self)->bool{
|
||||
self.0&(1<<(u32::BITS-1))!=0
|
||||
@ -74,16 +79,16 @@ pub trait MeshQuery<FACE:Clone,EDGE:Clone+DirectedEdge,VERT:Clone>{
|
||||
fn vert_faces(&self,vert_id:VERT)->Cow<Vec<FACE>>;
|
||||
}
|
||||
struct FaceRefs{
|
||||
edges:Vec<DirectedEdgeId>,
|
||||
edges:Vec<SubmeshDirectedEdgeId>,
|
||||
//verts:Vec<VertId>,
|
||||
}
|
||||
struct EdgeRefs{
|
||||
faces:[FaceId;2],//left, right
|
||||
verts:[VertId;2],//bottom, top
|
||||
faces:[SubmeshFaceId;2],//left, right
|
||||
verts:[SubmeshVertId;2],//bottom, top
|
||||
}
|
||||
struct VertRefs{
|
||||
faces:Vec<FaceId>,
|
||||
edges:Vec<DirectedEdgeId>,
|
||||
faces:Vec<SubmeshFaceId>,
|
||||
edges:Vec<SubmeshDirectedEdgeId>,
|
||||
}
|
||||
struct PhysicsMeshData{
|
||||
//this contains all real and virtual faces used in both the complete mesh and convex submeshes
|
||||
@ -91,20 +96,24 @@ struct PhysicsMeshData{
|
||||
//all remaining faces are virtual to operate internal logic of the face crawler
|
||||
//and cannot be part of a physics collision
|
||||
//virtual faces are only used in convex submeshes.
|
||||
faces:Vec<Face>,
|
||||
verts:Vec<Vert>,
|
||||
faces:Vec<Face>,//MeshFaceId indexes this list
|
||||
verts:Vec<Vert>,//MeshVertId indexes this list
|
||||
}
|
||||
struct PhysicsMeshTopology{
|
||||
//mapping of local ids to PhysicsMeshData ids
|
||||
faces:Vec<FaceId>,
|
||||
verts:Vec<VertId>,
|
||||
faces:Vec<MeshFaceId>,//SubmeshFaceId indexes this list
|
||||
verts:Vec<MeshVertId>,//SubmeshVertId indexes this list
|
||||
//all ids here are local to this object
|
||||
face_topology:Vec<FaceRefs>,
|
||||
edge_topology:Vec<EdgeRefs>,
|
||||
vert_topology:Vec<VertRefs>,
|
||||
}
|
||||
#[derive(id::Id)]
|
||||
pub struct PhysicsMeshId(u32);
|
||||
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
pub struct PhysicsSubmeshId(u32);
|
||||
pub struct PhysicsMesh{
|
||||
mesh_data:PhysicsMeshData,
|
||||
data:PhysicsMeshData,
|
||||
//index 0 is the complete mesh.
|
||||
//index 1-2+ is convex submeshes.
|
||||
//Most objects in roblox maps are already convex, so the list length is 1
|
||||
@ -115,7 +124,7 @@ pub struct PhysicsMesh{
|
||||
impl PhysicsMesh{
|
||||
pub fn unit_cube()->Self{
|
||||
//go go gadget debug print mesh
|
||||
let mesh_data=PhysicsMeshData{
|
||||
let data=PhysicsMeshData{
|
||||
faces:vec![
|
||||
Face{normal:Planar64Vec3::raw( 4294967296, 0, 0),dot:Planar64::raw(4294967296)},
|
||||
Face{normal:Planar64Vec3::raw( 0, 4294967296, 0),dot:Planar64::raw(4294967296)},
|
||||
@ -136,43 +145,43 @@ impl PhysicsMesh{
|
||||
]
|
||||
};
|
||||
let mesh_topology=PhysicsMeshTopology{
|
||||
faces:(0..mesh_data.faces.len()).map(FaceId).collect(),
|
||||
verts:(0..mesh_data.verts.len()).map(VertId).collect(),
|
||||
faces:(0..data.faces.len() as u32).map(MeshFaceId::new).collect(),
|
||||
verts:(0..data.verts.len() as u32).map(MeshVertId::new).collect(),
|
||||
face_topology:vec![
|
||||
FaceRefs{edges:vec![DirectedEdgeId(9223372036854775808),DirectedEdgeId(9223372036854775809),DirectedEdgeId(9223372036854775810),DirectedEdgeId(3)]},
|
||||
FaceRefs{edges:vec![DirectedEdgeId(9223372036854775812),DirectedEdgeId(9223372036854775813),DirectedEdgeId(6),DirectedEdgeId(1)]},
|
||||
FaceRefs{edges:vec![DirectedEdgeId(7),DirectedEdgeId(2),DirectedEdgeId(9223372036854775814),DirectedEdgeId(9223372036854775816)]},
|
||||
FaceRefs{edges:vec![DirectedEdgeId(8),DirectedEdgeId(5),DirectedEdgeId(9223372036854775817),DirectedEdgeId(10)]},
|
||||
FaceRefs{edges:vec![DirectedEdgeId(9223372036854775815),DirectedEdgeId(9223372036854775818),DirectedEdgeId(11),DirectedEdgeId(9223372036854775811)]},
|
||||
FaceRefs{edges:vec![DirectedEdgeId(4),DirectedEdgeId(0),DirectedEdgeId(9223372036854775819),DirectedEdgeId(9)]}
|
||||
FaceRefs{edges:vec![SubmeshDirectedEdgeId(9223372036854775808),SubmeshDirectedEdgeId(9223372036854775809),SubmeshDirectedEdgeId(9223372036854775810),SubmeshDirectedEdgeId(3)]},
|
||||
FaceRefs{edges:vec![SubmeshDirectedEdgeId(9223372036854775812),SubmeshDirectedEdgeId(9223372036854775813),SubmeshDirectedEdgeId(6),SubmeshDirectedEdgeId(1)]},
|
||||
FaceRefs{edges:vec![SubmeshDirectedEdgeId(7),SubmeshDirectedEdgeId(2),SubmeshDirectedEdgeId(9223372036854775814),SubmeshDirectedEdgeId(9223372036854775816)]},
|
||||
FaceRefs{edges:vec![SubmeshDirectedEdgeId(8),SubmeshDirectedEdgeId(5),SubmeshDirectedEdgeId(9223372036854775817),SubmeshDirectedEdgeId(10)]},
|
||||
FaceRefs{edges:vec![SubmeshDirectedEdgeId(9223372036854775815),SubmeshDirectedEdgeId(9223372036854775818),SubmeshDirectedEdgeId(11),SubmeshDirectedEdgeId(9223372036854775811)]},
|
||||
FaceRefs{edges:vec![SubmeshDirectedEdgeId(4),SubmeshDirectedEdgeId(0),SubmeshDirectedEdgeId(9223372036854775819),SubmeshDirectedEdgeId(9)]}
|
||||
],
|
||||
edge_topology:vec![
|
||||
EdgeRefs{faces:[FaceId(0),FaceId(5)],verts:[VertId(0),VertId(1)]},
|
||||
EdgeRefs{faces:[FaceId(0),FaceId(1)],verts:[VertId(1),VertId(2)]},
|
||||
EdgeRefs{faces:[FaceId(0),FaceId(2)],verts:[VertId(2),VertId(3)]},
|
||||
EdgeRefs{faces:[FaceId(4),FaceId(0)],verts:[VertId(0),VertId(3)]},
|
||||
EdgeRefs{faces:[FaceId(1),FaceId(5)],verts:[VertId(1),VertId(4)]},
|
||||
EdgeRefs{faces:[FaceId(1),FaceId(3)],verts:[VertId(4),VertId(5)]},
|
||||
EdgeRefs{faces:[FaceId(2),FaceId(1)],verts:[VertId(2),VertId(5)]},
|
||||
EdgeRefs{faces:[FaceId(4),FaceId(2)],verts:[VertId(3),VertId(6)]},
|
||||
EdgeRefs{faces:[FaceId(2),FaceId(3)],verts:[VertId(5),VertId(6)]},
|
||||
EdgeRefs{faces:[FaceId(3),FaceId(5)],verts:[VertId(4),VertId(7)]},
|
||||
EdgeRefs{faces:[FaceId(4),FaceId(3)],verts:[VertId(6),VertId(7)]},
|
||||
EdgeRefs{faces:[FaceId(5),FaceId(4)],verts:[VertId(0),VertId(7)]}
|
||||
EdgeRefs{faces:[SubmeshFaceId(0),SubmeshFaceId(5)],verts:[SubmeshVertId(0),SubmeshVertId(1)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(0),SubmeshFaceId(1)],verts:[SubmeshVertId(1),SubmeshVertId(2)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(0),SubmeshFaceId(2)],verts:[SubmeshVertId(2),SubmeshVertId(3)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(4),SubmeshFaceId(0)],verts:[SubmeshVertId(0),SubmeshVertId(3)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(1),SubmeshFaceId(5)],verts:[SubmeshVertId(1),SubmeshVertId(4)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(1),SubmeshFaceId(3)],verts:[SubmeshVertId(4),SubmeshVertId(5)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(2),SubmeshFaceId(1)],verts:[SubmeshVertId(2),SubmeshVertId(5)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(4),SubmeshFaceId(2)],verts:[SubmeshVertId(3),SubmeshVertId(6)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(2),SubmeshFaceId(3)],verts:[SubmeshVertId(5),SubmeshVertId(6)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(3),SubmeshFaceId(5)],verts:[SubmeshVertId(4),SubmeshVertId(7)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(4),SubmeshFaceId(3)],verts:[SubmeshVertId(6),SubmeshVertId(7)]},
|
||||
EdgeRefs{faces:[SubmeshFaceId(5),SubmeshFaceId(4)],verts:[SubmeshVertId(0),SubmeshVertId(7)]}
|
||||
],
|
||||
vert_topology:vec![
|
||||
VertRefs{faces:vec![FaceId(0),FaceId(4),FaceId(5)],edges:vec![DirectedEdgeId(9223372036854775811),DirectedEdgeId(9223372036854775819),DirectedEdgeId(9223372036854775808)]},
|
||||
VertRefs{faces:vec![FaceId(0),FaceId(5),FaceId(1)],edges:vec![DirectedEdgeId(9223372036854775812),DirectedEdgeId(0),DirectedEdgeId(9223372036854775809)]},
|
||||
VertRefs{faces:vec![FaceId(0),FaceId(2),FaceId(1)],edges:vec![DirectedEdgeId(1),DirectedEdgeId(9223372036854775810),DirectedEdgeId(9223372036854775814)]},
|
||||
VertRefs{faces:vec![FaceId(0),FaceId(2),FaceId(4)],edges:vec![DirectedEdgeId(2),DirectedEdgeId(3),DirectedEdgeId(9223372036854775815)]},
|
||||
VertRefs{faces:vec![FaceId(3),FaceId(5),FaceId(1)],edges:vec![DirectedEdgeId(4),DirectedEdgeId(9223372036854775817),DirectedEdgeId(9223372036854775813)]},
|
||||
VertRefs{faces:vec![FaceId(2),FaceId(3),FaceId(1)],edges:vec![DirectedEdgeId(5),DirectedEdgeId(6),DirectedEdgeId(9223372036854775816)]},
|
||||
VertRefs{faces:vec![FaceId(2),FaceId(3),FaceId(4)],edges:vec![DirectedEdgeId(7),DirectedEdgeId(8),DirectedEdgeId(9223372036854775818)]},
|
||||
VertRefs{faces:vec![FaceId(4),FaceId(3),FaceId(5)],edges:vec![DirectedEdgeId(10),DirectedEdgeId(11),DirectedEdgeId(9)]}
|
||||
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(4),SubmeshFaceId(5)],edges:vec![SubmeshDirectedEdgeId(9223372036854775811),SubmeshDirectedEdgeId(9223372036854775819),SubmeshDirectedEdgeId(9223372036854775808)]},
|
||||
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(5),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(9223372036854775812),SubmeshDirectedEdgeId(0),SubmeshDirectedEdgeId(9223372036854775809)]},
|
||||
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(2),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(1),SubmeshDirectedEdgeId(9223372036854775810),SubmeshDirectedEdgeId(9223372036854775814)]},
|
||||
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(2),SubmeshFaceId(4)],edges:vec![SubmeshDirectedEdgeId(2),SubmeshDirectedEdgeId(3),SubmeshDirectedEdgeId(9223372036854775815)]},
|
||||
VertRefs{faces:vec![SubmeshFaceId(3),SubmeshFaceId(5),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(4),SubmeshDirectedEdgeId(9223372036854775817),SubmeshDirectedEdgeId(9223372036854775813)]},
|
||||
VertRefs{faces:vec![SubmeshFaceId(2),SubmeshFaceId(3),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(5),SubmeshDirectedEdgeId(6),SubmeshDirectedEdgeId(9223372036854775816)]},
|
||||
VertRefs{faces:vec![SubmeshFaceId(2),SubmeshFaceId(3),SubmeshFaceId(4)],edges:vec![SubmeshDirectedEdgeId(7),SubmeshDirectedEdgeId(8),SubmeshDirectedEdgeId(9223372036854775818)]},
|
||||
VertRefs{faces:vec![SubmeshFaceId(4),SubmeshFaceId(3),SubmeshFaceId(5)],edges:vec![SubmeshDirectedEdgeId(10),SubmeshDirectedEdgeId(11),SubmeshDirectedEdgeId(9)]}
|
||||
]
|
||||
};
|
||||
Self{
|
||||
mesh_data,
|
||||
data,
|
||||
submeshes:vec![mesh_topology],
|
||||
}
|
||||
}
|
||||
@ -180,12 +189,12 @@ impl PhysicsMesh{
|
||||
Self::unit_cube()
|
||||
}
|
||||
pub fn mesh_data(&self)->&PhysicsMeshData{
|
||||
&self.mesh_data
|
||||
&self.data
|
||||
}
|
||||
pub fn complete_mesh(&self)->&PhysicsMeshTopology{
|
||||
&self.submeshes[0]
|
||||
}
|
||||
pub fn convex_submeshes(&self)->&[PhysicsMeshTopology]{
|
||||
pub fn submeshes(&self)->&[PhysicsMeshTopology]{
|
||||
if self.submeshes.len()==1{
|
||||
//the complete mesh is already a convex mesh
|
||||
&self.submeshes[0..0]
|
||||
@ -193,18 +202,30 @@ impl PhysicsMesh{
|
||||
&self.submeshes[1..]
|
||||
}
|
||||
}
|
||||
pub fn submesh_view(&self,submesh_id:PhysicsSubmeshId)->PhysicsMeshView{
|
||||
PhysicsMeshView{
|
||||
data:&self.data,
|
||||
topology:&self.submeshes()[submesh_id.get() as usize],
|
||||
}
|
||||
}
|
||||
pub fn submesh_views(&self)->impl Iterator<Item=PhysicsMeshView>{
|
||||
self.submeshes().iter().map(|topology|PhysicsMeshView{
|
||||
data:&self.data,
|
||||
topology,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//mesh builder code
|
||||
#[derive(Default,Clone)]
|
||||
struct VertRefGuy{
|
||||
edges:std::collections::HashSet<DirectedEdgeId>,
|
||||
faces:std::collections::HashSet<FaceId>,
|
||||
edges:std::collections::HashSet<SubmeshDirectedEdgeId>,
|
||||
faces:std::collections::HashSet<SubmeshFaceId>,
|
||||
}
|
||||
#[derive(Clone,Hash,Eq,PartialEq)]
|
||||
struct EdgeRefVerts([VertId;2]);
|
||||
struct EdgeRefVerts([SubmeshVertId;2]);
|
||||
impl EdgeRefVerts{
|
||||
fn new(v0:VertId,v1:VertId)->(Self,bool){
|
||||
fn new(v0:SubmeshVertId,v1:SubmeshVertId)->(Self,bool){
|
||||
(if v0.0<v1.0{
|
||||
Self([v0,v1])
|
||||
}else{
|
||||
@ -212,23 +233,23 @@ impl EdgeRefVerts{
|
||||
},v0.0<v1.0)
|
||||
}
|
||||
}
|
||||
struct EdgeRefFaces([FaceId;2]);
|
||||
struct EdgeRefFaces([SubmeshFaceId;2]);
|
||||
impl EdgeRefFaces{
|
||||
fn new()->Self{
|
||||
Self([FaceId(0);2])
|
||||
Self([SubmeshFaceId(0);2])
|
||||
}
|
||||
fn push(&mut self,i:usize,face_id:FaceId){
|
||||
fn push(&mut self,i:usize,face_id:SubmeshFaceId){
|
||||
self.0[i]=face_id;
|
||||
}
|
||||
}
|
||||
struct FaceRefEdges(Vec<DirectedEdgeId>);
|
||||
struct FaceRefEdges(Vec<SubmeshDirectedEdgeId>);
|
||||
#[derive(Default)]
|
||||
struct EdgePool{
|
||||
edge_guys:Vec<(EdgeRefVerts,EdgeRefFaces)>,
|
||||
edge_id_from_guy:std::collections::HashMap<EdgeRefVerts,usize>,
|
||||
}
|
||||
impl EdgePool{
|
||||
fn push(&mut self,edge_ref_verts:EdgeRefVerts)->(&mut EdgeRefFaces,EdgeId){
|
||||
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{
|
||||
@ -237,7 +258,7 @@ impl EdgePool{
|
||||
self.edge_id_from_guy.insert(edge_ref_verts,edge_id);
|
||||
edge_id
|
||||
};
|
||||
(&mut unsafe{self.edge_guys.get_unchecked_mut(edge_id)}.1,EdgeId(edge_id))
|
||||
(&mut unsafe{self.edge_guys.get_unchecked_mut(edge_id)}.1,SubmeshEdgeId::new(edge_id as u32))
|
||||
}
|
||||
}
|
||||
impl From<&model::IndexedModel> for PhysicsMesh{
|
||||
@ -250,7 +271,7 @@ impl From<&model::IndexedModel> for PhysicsMesh{
|
||||
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=FaceId(face_i);
|
||||
let face_id=SubmeshFaceId::new(face_i);
|
||||
//one face per poly
|
||||
let mut normal=Planar64Vec3::ZERO;
|
||||
let len=poly_vertices.len();
|
||||
@ -266,7 +287,7 @@ impl From<&model::IndexedModel> for PhysicsMesh{
|
||||
(v0.x()-v1.x())*(v0.y()+v1.y()),
|
||||
);
|
||||
//get/create edge and push face into it
|
||||
let (edge_ref_verts,is_sorted)=EdgeRefVerts::new(VertId(vert0_id),VertId(vert1_id));
|
||||
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
|
||||
@ -311,108 +332,129 @@ impl From<&model::IndexedModel> for PhysicsMesh{
|
||||
}
|
||||
}
|
||||
|
||||
struct PhysicsMeshView<'a>{
|
||||
data:&'a PhysicsMeshData,
|
||||
topology:&'a PhysicsMeshTopology,
|
||||
}
|
||||
impl PhysicsMeshView<'_>{
|
||||
pub fn verts<'a>(&'a self)->impl Iterator<Item=Planar64Vec3>+'a{
|
||||
self.mesh_data.verts.iter().map(|Vert(pos)|*pos)
|
||||
self.data.verts.iter().map(|Vert(pos)|*pos)
|
||||
}
|
||||
}
|
||||
impl MeshQuery<FaceId,DirectedEdgeId,VertId> for PhysicsMesh{
|
||||
fn face_nd(&self,face_id:FaceId)->(Planar64Vec3,Planar64){
|
||||
(self.faces[face_id.0].normal,self.faces[face_id.0].dot)
|
||||
impl MeshQuery<SubmeshFaceId,SubmeshDirectedEdgeId,SubmeshVertId> for PhysicsMeshView<'_>{
|
||||
fn face_nd(&self,face_id:SubmeshFaceId)->(Planar64Vec3,Planar64){
|
||||
let face_idx=self.topology.faces[face_id.get() as usize].get() as usize;
|
||||
(self.data.faces[face_idx].normal,self.data.faces[face_idx].dot)
|
||||
}
|
||||
//ideally I never calculate the vertex position, but I have to for the graphical meshes...
|
||||
fn vert(&self,vert_id:VertId)->Planar64Vec3{
|
||||
self.verts[vert_id.0].0
|
||||
fn vert(&self,vert_id:SubmeshVertId)->Planar64Vec3{
|
||||
let vert_idx=self.topology.verts[vert_id.get() as usize].get() as usize;
|
||||
self.data.verts[vert_idx].0
|
||||
}
|
||||
fn face_edges(&self,face_id:FaceId)->Cow<Vec<DirectedEdgeId>>{
|
||||
Cow::Borrowed(&self.face_topology[face_id.0].edges)
|
||||
fn face_edges(&self,face_id:SubmeshFaceId)->Cow<Vec<SubmeshDirectedEdgeId>>{
|
||||
Cow::Borrowed(&self.topology.face_topology[face_id.get() as usize].edges)
|
||||
}
|
||||
fn edge_faces(&self,edge_id:EdgeId)->Cow<[FaceId;2]>{
|
||||
Cow::Borrowed(&self.edge_topology[edge_id.0].faces)
|
||||
fn edge_faces(&self,edge_id:SubmeshEdgeId)->Cow<[SubmeshFaceId;2]>{
|
||||
Cow::Borrowed(&self.topology.edge_topology[edge_id.get() as usize].faces)
|
||||
}
|
||||
fn edge_verts(&self,edge_id:EdgeId)->Cow<[VertId;2]>{
|
||||
Cow::Borrowed(&self.edge_topology[edge_id.0].verts)
|
||||
fn edge_verts(&self,edge_id:SubmeshEdgeId)->Cow<[SubmeshVertId;2]>{
|
||||
Cow::Borrowed(&self.topology.edge_topology[edge_id.get() as usize].verts)
|
||||
}
|
||||
fn vert_edges(&self,vert_id:VertId)->Cow<Vec<DirectedEdgeId>>{
|
||||
Cow::Borrowed(&self.vert_topology[vert_id.0].edges)
|
||||
fn vert_edges(&self,vert_id:SubmeshVertId)->Cow<Vec<SubmeshDirectedEdgeId>>{
|
||||
Cow::Borrowed(&self.topology.vert_topology[vert_id.get() as usize].edges)
|
||||
}
|
||||
fn vert_faces(&self,vert_id:VertId)->Cow<Vec<FaceId>>{
|
||||
Cow::Borrowed(&self.vert_topology[vert_id.0].faces)
|
||||
fn vert_faces(&self,vert_id:SubmeshVertId)->Cow<Vec<SubmeshFaceId>>{
|
||||
Cow::Borrowed(&self.topology.vert_topology[vert_id.get() as usize].faces)
|
||||
}
|
||||
}
|
||||
|
||||
struct PhysicsMeshView<'a>{
|
||||
mesh_data:&'a PhysicsMeshData,
|
||||
topology:&'a PhysicsMeshTopology,
|
||||
pub struct PhysicsMeshTransform<'a>{
|
||||
vertex:&'a integer::Planar64Affine3,
|
||||
normal:&'a integer::Planar64Mat3,
|
||||
det:Planar64,
|
||||
}
|
||||
impl PhysicsMeshTransform<'_>{
|
||||
pub fn new<'a>(
|
||||
vertex:&'a integer::Planar64Affine3,
|
||||
normal:&'a integer::Planar64Mat3,
|
||||
det:Planar64
|
||||
)->PhysicsMeshTransform<'a>{
|
||||
PhysicsMeshTransform{
|
||||
vertex,
|
||||
normal,
|
||||
det,
|
||||
}
|
||||
}
|
||||
struct PhysicsMeshTransform<'a>{
|
||||
transform:&'a integer::Planar64Affine3,
|
||||
normal_transform:&'a integer::Planar64Mat3,
|
||||
transform_det:Planar64,
|
||||
}
|
||||
pub struct TransformedMesh<'a>{
|
||||
mesh:PhysicsMeshView<'a>,
|
||||
view:PhysicsMeshView<'a>,
|
||||
transform:PhysicsMeshTransform<'a>,
|
||||
}
|
||||
impl TransformedMesh<'_>{
|
||||
pub fn new<'a>(
|
||||
mesh_data:&'a PhysicsMeshData,
|
||||
topology:&'a PhysicsMeshTopology,
|
||||
transform:&'a integer::Planar64Affine3,
|
||||
normal_transform:&'a integer::Planar64Mat3,
|
||||
transform_det:Planar64,
|
||||
vertex:&'a integer::Planar64Affine3,
|
||||
normal:&'a integer::Planar64Mat3,
|
||||
det:Planar64,
|
||||
)->TransformedMesh<'a>{
|
||||
TransformedMesh{
|
||||
mesh_data,
|
||||
view:PhysicsMeshView{
|
||||
data: mesh_data,
|
||||
topology,
|
||||
transform,
|
||||
normal_transform,
|
||||
transform_det,
|
||||
},
|
||||
transform:PhysicsMeshTransform{
|
||||
vertex,
|
||||
normal,
|
||||
det,
|
||||
}
|
||||
}
|
||||
fn farthest_vert(&self,dir:Planar64Vec3)->VertId{
|
||||
}
|
||||
fn farthest_vert(&self,dir:Planar64Vec3)->SubmeshVertId{
|
||||
let mut best_dot=Planar64::MIN;
|
||||
let mut best_vert=VertId(0);
|
||||
for (i,vert) in self.mesh.verts.iter().enumerate(){
|
||||
let p=self.transform.transform_point3(vert.0);
|
||||
let mut best_vert=SubmeshVertId(0);
|
||||
//this happens to be well-defined. there are no virtual virtices
|
||||
for (i,vert_id) in self.view.topology.verts.iter().enumerate(){
|
||||
let vert=self.view.data.verts[vert_id.get() as usize];
|
||||
let p=self.transform.vertex.transform_point3(vert.0);
|
||||
let d=dir.dot(p);
|
||||
if best_dot<d{
|
||||
best_dot=d;
|
||||
best_vert=VertId(i);
|
||||
best_vert=SubmeshVertId::new(i as u32);
|
||||
}
|
||||
}
|
||||
best_vert
|
||||
}
|
||||
}
|
||||
impl MeshQuery<FaceId,DirectedEdgeId,VertId> for TransformedMesh<'_>{
|
||||
fn face_nd(&self,face_id:FaceId)->(Planar64Vec3,Planar64){
|
||||
let (n,d)=self.mesh.face_nd(face_id);
|
||||
let transformed_n=*self.normal_transform*n;
|
||||
let transformed_d=d+transformed_n.dot(self.transform.translation)/self.transform_det;
|
||||
(transformed_n/self.transform_det,transformed_d)
|
||||
impl MeshQuery<SubmeshFaceId,SubmeshDirectedEdgeId,SubmeshVertId> for TransformedMesh<'_>{
|
||||
fn face_nd(&self,face_id:SubmeshFaceId)->(Planar64Vec3,Planar64){
|
||||
let (n,d)=self.view.face_nd(face_id);
|
||||
let transformed_n=*self.transform.normal*n;
|
||||
let transformed_d=d+transformed_n.dot(self.transform.vertex.translation)/self.transform.det;
|
||||
(transformed_n/self.transform.det,transformed_d)
|
||||
}
|
||||
fn vert(&self,vert_id:VertId)->Planar64Vec3{
|
||||
self.transform.transform_point3(self.mesh.vert(vert_id))
|
||||
fn vert(&self,vert_id:SubmeshVertId)->Planar64Vec3{
|
||||
self.transform.vertex.transform_point3(self.view.vert(vert_id))
|
||||
}
|
||||
#[inline]
|
||||
fn face_edges(&self,face_id:FaceId)->Cow<Vec<DirectedEdgeId>>{
|
||||
self.mesh.face_edges(face_id)
|
||||
fn face_edges(&self,face_id:SubmeshFaceId)->Cow<Vec<SubmeshDirectedEdgeId>>{
|
||||
self.view.face_edges(face_id)
|
||||
}
|
||||
#[inline]
|
||||
fn edge_faces(&self,edge_id:EdgeId)->Cow<[FaceId;2]>{
|
||||
self.mesh.edge_faces(edge_id)
|
||||
fn edge_faces(&self,edge_id:SubmeshEdgeId)->Cow<[SubmeshFaceId;2]>{
|
||||
self.view.edge_faces(edge_id)
|
||||
}
|
||||
#[inline]
|
||||
fn edge_verts(&self,edge_id:EdgeId)->Cow<[VertId;2]>{
|
||||
self.mesh.edge_verts(edge_id)
|
||||
fn edge_verts(&self,edge_id:SubmeshEdgeId)->Cow<[SubmeshVertId;2]>{
|
||||
self.view.edge_verts(edge_id)
|
||||
}
|
||||
#[inline]
|
||||
fn vert_edges(&self,vert_id:VertId)->Cow<Vec<DirectedEdgeId>>{
|
||||
self.mesh.vert_edges(vert_id)
|
||||
fn vert_edges(&self,vert_id:SubmeshVertId)->Cow<Vec<SubmeshDirectedEdgeId>>{
|
||||
self.view.vert_edges(vert_id)
|
||||
}
|
||||
#[inline]
|
||||
fn vert_faces(&self,vert_id:VertId)->Cow<Vec<FaceId>>{
|
||||
self.mesh.vert_faces(vert_id)
|
||||
fn vert_faces(&self,vert_id:SubmeshVertId)->Cow<Vec<SubmeshFaceId>>{
|
||||
self.view.vert_faces(vert_id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,12 +464,12 @@ impl MeshQuery<FaceId,DirectedEdgeId,VertId> for TransformedMesh<'_>{
|
||||
//(vertex,face)
|
||||
#[derive(Clone,Copy)]
|
||||
pub enum MinkowskiVert{
|
||||
VertVert(VertId,VertId),
|
||||
VertVert(SubmeshVertId,SubmeshVertId),
|
||||
}
|
||||
#[derive(Clone,Copy)]
|
||||
pub enum MinkowskiEdge{
|
||||
VertEdge(VertId,EdgeId),
|
||||
EdgeVert(EdgeId,VertId),
|
||||
VertEdge(SubmeshVertId,SubmeshEdgeId),
|
||||
EdgeVert(SubmeshEdgeId,SubmeshVertId),
|
||||
//EdgeEdge when edges are parallel
|
||||
}
|
||||
impl UndirectedEdge for MinkowskiEdge{
|
||||
@ -441,8 +483,8 @@ impl UndirectedEdge for MinkowskiEdge{
|
||||
}
|
||||
#[derive(Clone,Copy)]
|
||||
pub enum MinkowskiDirectedEdge{
|
||||
VertEdge(VertId,DirectedEdgeId),
|
||||
EdgeVert(DirectedEdgeId,VertId),
|
||||
VertEdge(SubmeshVertId,SubmeshDirectedEdgeId),
|
||||
EdgeVert(SubmeshDirectedEdgeId,SubmeshVertId),
|
||||
//EdgeEdge when edges are parallel
|
||||
}
|
||||
impl DirectedEdge for MinkowskiDirectedEdge{
|
||||
@ -462,9 +504,9 @@ impl DirectedEdge for MinkowskiDirectedEdge{
|
||||
}
|
||||
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub enum MinkowskiFace{
|
||||
VertFace(VertId,FaceId),
|
||||
EdgeEdge(EdgeId,EdgeId,bool),
|
||||
FaceVert(FaceId,VertId),
|
||||
VertFace(SubmeshVertId,SubmeshFaceId),
|
||||
EdgeEdge(SubmeshEdgeId,SubmeshEdgeId,bool),
|
||||
FaceVert(SubmeshFaceId,SubmeshVertId),
|
||||
//EdgeFace
|
||||
//FaceEdge
|
||||
//FaceFace
|
||||
|
168
src/physics.rs
168
src/physics.rs
@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::model_physics::{self,PhysicsMesh,TransformedMesh,MeshQuery};
|
||||
use crate::model_physics::{self,PhysicsMesh,TransformedMesh,MeshQuery,PhysicsMeshId,PhysicsSubmeshId};
|
||||
use strafesnet_common::bvh;
|
||||
use strafesnet_common::map;
|
||||
use strafesnet_common::aabb;
|
||||
@ -169,11 +169,10 @@ impl PhysicsModels{
|
||||
}
|
||||
//TODO: "statically" verify the maps don't refer to any nonexistant data, if they do delete the references.
|
||||
//then I can make these getter functions unchecked.
|
||||
fn mesh(&self,model_id:PhysicsModelId)->TransformedMesh{
|
||||
let idx=model_id.get() as usize;
|
||||
let convex_mesh_id=self.models[idx].convex_mesh_id;
|
||||
fn mesh(&self,convex_mesh_id:ConvexMeshId)->TransformedMesh{
|
||||
let model_idx=convex_mesh_id.model_id.get() as usize;
|
||||
TransformedMesh::new(
|
||||
&self.meshes[convex_mesh_id.mesh_id.get() as usize].groups[convex_mesh_id.group_id.get() as usize],
|
||||
&self.meshes[model_idx].submesh_view(convex_mesh_id.submesh_id),
|
||||
&self.models[idx].transform,
|
||||
&self.models[idx].normal_transform,
|
||||
self.models[idx].transform_det,
|
||||
@ -285,23 +284,19 @@ struct WorldState{}
|
||||
struct HitboxMesh{
|
||||
halfsize:Planar64Vec3,
|
||||
mesh:PhysicsMesh,
|
||||
transform:integer::Planar64Affine3,
|
||||
normal_transform:Planar64Mat3,
|
||||
transform_det:Planar64,
|
||||
transform:PhysicsModelTransform,
|
||||
}
|
||||
impl HitboxMesh{
|
||||
fn new(mesh:PhysicsMesh,transform:integer::Planar64Affine3)->Self{
|
||||
fn new(mesh:PhysicsMesh,vertex_transform:integer::Planar64Affine3)->Self{
|
||||
//calculate extents
|
||||
let mut aabb=aabb::Aabb::default();
|
||||
for vert in mesh.verts(){
|
||||
aabb.grow(transform.transform_point3(vert));
|
||||
for vert in mesh.complete_mesh_view().verts(){
|
||||
aabb.grow(vertex_transform.transform_point3(vert));
|
||||
}
|
||||
Self{
|
||||
halfsize:aabb.size()/2,
|
||||
mesh,
|
||||
transform,
|
||||
normal_transform:transform.matrix3.inverse_times_det().transpose(),
|
||||
transform_det:transform.matrix3.determinant(),
|
||||
transform:PhysicsModelTransform::new(vertex_transform)
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
@ -482,15 +477,11 @@ impl TryFrom<&gameplay_attributes::CollisionAttributes> for PhysicsCollisionAttr
|
||||
#[derive(id::Id)]
|
||||
struct PhysicsAttributesId(u32);
|
||||
|
||||
//id assigned to deindexed IndexedPhysicsGroup
|
||||
#[derive(id::Id)]
|
||||
struct PhysicsMeshId(u32);
|
||||
#[derive(id::Id)]
|
||||
struct PhysicsGroupId(u32);
|
||||
//unique physics meshes indexed by this
|
||||
#[derive(Debug,Clone,Copy,Eq,Hash,PartialEq)]
|
||||
struct ConvexMeshId{
|
||||
model_id:PhysicsModelId,// 1:1 with IndexedModelId
|
||||
group_id:PhysicsGroupId,// group in model
|
||||
model_id:PhysicsModelId,
|
||||
submesh_id:PhysicsSubmeshId,
|
||||
}
|
||||
#[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
|
||||
struct PhysicsModelId(u32);
|
||||
@ -504,37 +495,50 @@ impl From<ModelId> for PhysicsModelId{
|
||||
Self::new(value.get())
|
||||
}
|
||||
}
|
||||
pub struct PhysicsModelTransform{
|
||||
vertex:integer::Planar64Affine3,
|
||||
normal:integer::Planar64Mat3,
|
||||
det:Planar64,
|
||||
}
|
||||
impl PhysicsModelTransform{
|
||||
pub const fn new(vertex_transform:integer::Planar64Affine3)->Self{
|
||||
Self{
|
||||
normal:vertex_transform.matrix3.inverse_times_det().transpose(),
|
||||
det:vertex_transform.matrix3.determinant(),
|
||||
vertex:vertex_transform,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct PhysicsModel{
|
||||
//A model is a thing that has a hitbox. can be represented by a list of TreyMesh-es
|
||||
//in this iteration, all it needs is extents.
|
||||
mesh_id:PhysicsMeshId,
|
||||
//put these up on the Model (data normalization)
|
||||
attr_id:PhysicsAttributesId,
|
||||
transform:integer::Planar64Affine3,
|
||||
normal_transform:integer::Planar64Mat3,
|
||||
transform_det:Planar64,
|
||||
transform:PhysicsModelTransform,
|
||||
}
|
||||
|
||||
impl PhysicsModel{
|
||||
pub fn new(mesh_id:PhysicsMeshId,attr_id:PhysicsAttributesId,transform:integer::Planar64Affine3)->Self{
|
||||
pub const fn new(mesh_id:PhysicsMeshId,attr_id:PhysicsAttributesId,transform:PhysicsModelTransform)->Self{
|
||||
Self{
|
||||
mesh_id,
|
||||
attr_id,
|
||||
transform,
|
||||
normal_transform:transform.matrix3.inverse_times_det().transpose(),
|
||||
transform_det:transform.matrix3.determinant(),
|
||||
}
|
||||
}
|
||||
const fn transform(&self)->&PhysicsModelTransform{
|
||||
&self.transform
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Eq,Hash,PartialEq)]
|
||||
struct ContactCollision{
|
||||
face_id:model_physics::MinkowskiFace,
|
||||
model_id:PhysicsModelId,//using id to avoid lifetimes
|
||||
convex_mesh_id:ConvexMeshId,
|
||||
}
|
||||
#[derive(Debug,Clone,Eq,Hash,PartialEq)]
|
||||
struct IntersectCollision{
|
||||
model_id:PhysicsModelId,
|
||||
convex_mesh_id:ConvexMeshId,
|
||||
}
|
||||
#[derive(Debug,Clone,Eq,Hash,PartialEq)]
|
||||
enum Collision{
|
||||
@ -542,16 +546,16 @@ enum Collision{
|
||||
Intersect(IntersectCollision),
|
||||
}
|
||||
impl Collision{
|
||||
fn model_id(&self)->PhysicsModelId{
|
||||
fn convex_mesh_id(&self)->ConvexMeshId{
|
||||
match self{
|
||||
&Collision::Contact(ContactCollision{model_id,face_id:_})
|
||||
|&Collision::Intersect(IntersectCollision{model_id})=>model_id,
|
||||
&Collision::Contact(ContactCollision{convex_mesh_id,face_id:_})
|
||||
|&Collision::Intersect(IntersectCollision{convex_mesh_id})=>convex_mesh_id,
|
||||
}
|
||||
}
|
||||
fn face_id(&self)->Option<model_physics::MinkowskiFace>{
|
||||
match self{
|
||||
&Collision::Contact(ContactCollision{model_id:_,face_id})=>Some(face_id),
|
||||
&Collision::Intersect(IntersectCollision{model_id:_})=>None,
|
||||
&Collision::Contact(ContactCollision{convex_mesh_id:_,face_id})=>Some(face_id),
|
||||
&Collision::Intersect(IntersectCollision{convex_mesh_id:_})=>None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -584,7 +588,7 @@ impl TouchingState{
|
||||
}
|
||||
//add accelerators
|
||||
for contact in &self.contacts{
|
||||
match models.attr(contact.model_id){
|
||||
match models.attr(contact.convex_mesh_id.model_id){
|
||||
PhysicsCollisionAttributes::Contact{contacting,general}=>{
|
||||
match &general.accelerator{
|
||||
Some(accelerator)=>a+=accelerator.acceleration,
|
||||
@ -595,7 +599,7 @@ impl TouchingState{
|
||||
}
|
||||
}
|
||||
for intersect in &self.intersects{
|
||||
match models.attr(intersect.model_id){
|
||||
match models.attr(intersect.convex_mesh_id.model_id){
|
||||
PhysicsCollisionAttributes::Intersect{intersecting,general}=>{
|
||||
match &general.accelerator{
|
||||
Some(accelerator)=>a+=accelerator.acceleration,
|
||||
@ -636,7 +640,7 @@ impl TouchingState{
|
||||
let mut move_state=MoveState::Air;
|
||||
let mut a=gravity;
|
||||
for contact in &self.contacts{
|
||||
match models.attr(contact.model_id){
|
||||
match models.attr(contact.convex_mesh_id.model_id){
|
||||
PhysicsCollisionAttributes::Contact{contacting,general}=>{
|
||||
let normal=contact_normal(models,hitbox_mesh,contact);
|
||||
match &contacting.contact_behaviour{
|
||||
@ -674,26 +678,26 @@ impl TouchingState{
|
||||
let relative_body=VirtualBody::relative(&Body::default(),body).body(time);
|
||||
for contact in &self.contacts{
|
||||
//detect face slide off
|
||||
let model_mesh=models.mesh(contact.model_id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,hitbox_mesh);
|
||||
let model_mesh=models.mesh(contact.convex_mesh_id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
||||
collector.collect(minkowski.predict_collision_face_out(&relative_body,collector.time(),contact.face_id).map(|(face,time)|{
|
||||
TimedInstruction{
|
||||
time,
|
||||
instruction:PhysicsInstruction::CollisionEnd(
|
||||
Collision::Contact(ContactCollision{model_id:contact.model_id,face_id:contact.face_id})
|
||||
Collision::Contact(ContactCollision{convex_mesh_id:contact.convex_mesh_id,face_id:contact.face_id})
|
||||
),
|
||||
}
|
||||
}));
|
||||
}
|
||||
for intersect in &self.intersects{
|
||||
//detect model collision in reverse
|
||||
let model_mesh=models.mesh(intersect.model_id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,hitbox_mesh);
|
||||
let model_mesh=models.mesh(intersect.convex_mesh_id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
||||
collector.collect(minkowski.predict_collision_out(&relative_body,collector.time()).map(|(face,time)|{
|
||||
TimedInstruction{
|
||||
time,
|
||||
instruction:PhysicsInstruction::CollisionEnd(
|
||||
Collision::Intersect(IntersectCollision{model_id:intersect.model_id})
|
||||
Collision::Intersect(IntersectCollision{convex_mesh_id:intersect.convex_mesh_id})
|
||||
),
|
||||
}
|
||||
}));
|
||||
@ -809,7 +813,7 @@ pub struct PhysicsState{
|
||||
//random collection of contextual data that doesn't belong in PhysicsState
|
||||
pub struct PhysicsData{
|
||||
//permanent map data
|
||||
bvh:bvh::BvhNode<PhysicsModelId>,
|
||||
bvh:bvh::BvhNode<ConvexMeshId>,
|
||||
modes:gameplay_modes::Modes,
|
||||
//transient map/environment data (open world may load/unload)
|
||||
models:PhysicsModels,
|
||||
@ -939,33 +943,47 @@ impl PhysicsContext{
|
||||
});
|
||||
}
|
||||
|
||||
pub fn generate_models(&mut self,map:&map::Map){
|
||||
pub fn generate_models(&mut self,map:map::Map){
|
||||
let mut starts=Vec::new();
|
||||
let mut spawns=Vec::new();
|
||||
let mut attr_hash=HashMap::new();
|
||||
for model in &map.models{
|
||||
let mesh_id=self.models.meshes.len();
|
||||
for (model_id,model) in map.models{
|
||||
let mesh_id=self.data.models.meshes.len();
|
||||
let mut make_mesh=false;
|
||||
for model_instance in &model.instances{
|
||||
if let Ok(physics_attributes)=PhysicsCollisionAttributes::try_from(&model_instance.attributes){
|
||||
let attr_id=if let Some(&attr_id)=attr_hash.get(&physics_attributes){
|
||||
attr_id
|
||||
}else{
|
||||
let attr_id=self.models.push_attr(physics_attributes.clone());
|
||||
let attr_id=self.data.models.push_attr(physics_attributes.clone());
|
||||
attr_hash.insert(physics_attributes,attr_id);
|
||||
attr_id
|
||||
};
|
||||
let model_physics=PhysicsModel::new(mesh_id,attr_id,model_instance.transform);
|
||||
make_mesh=true;
|
||||
self.models.push_model(model_physics);
|
||||
self.data.models.push_model(model_physics);
|
||||
}
|
||||
}
|
||||
if make_mesh{
|
||||
self.models.push_mesh(PhysicsMesh::from(model));
|
||||
self.data.models.push_mesh(PhysicsMesh::from(model));
|
||||
}
|
||||
}
|
||||
self.bvh=bvh::generate_bvh(self.models.aabb_list(),|i|PhysicsModelId::new(i as u32));
|
||||
println!("Physics Objects: {}",self.models.models.len());
|
||||
let convex_mesh_aabb_list=self.data.models.models.iter()
|
||||
.enumerate().flat_map(|(model_id,model)|{
|
||||
self.data.models.meshes[model.mesh_id.get() as usize].submesh_views()
|
||||
.enumerate().map(|(submesh_id,view)|{
|
||||
let mut aabb=aabb::Aabb::default();
|
||||
for v in view.verts(){
|
||||
aabb.grow(v)
|
||||
}
|
||||
(ConvexMeshId{
|
||||
model_id:PhysicsModelId::new(model_id as u32),
|
||||
submesh_id:PhysicsSubmeshId::new(submesh_id as u32),
|
||||
},aabb)
|
||||
})
|
||||
}).collect();
|
||||
self.data.bvh=bvh::generate_bvh_node(convex_mesh_aabb_list);
|
||||
println!("Physics Objects: {}",self.data.models.models.len());
|
||||
}
|
||||
|
||||
//tickless gaming
|
||||
@ -1020,17 +1038,17 @@ impl PhysicsContext{
|
||||
//common body
|
||||
let relative_body=VirtualBody::relative(&Body::default(),&state.body).body(state.time);
|
||||
let hitbox_mesh=data.hitbox_mesh.transformed_mesh();
|
||||
data.bvh.the_tester(&aabb,&mut |id|{
|
||||
data.bvh.the_tester(&aabb,&mut |convex_mesh_id|{
|
||||
//no checks are needed because of the time limits.
|
||||
let model_mesh=data.models.mesh(id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&hitbox_mesh);
|
||||
let model_mesh=data.models.mesh(convex_mesh_id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh);
|
||||
collector.collect(minkowski.predict_collision_in(&relative_body,collector.time())
|
||||
//temp (?) code to avoid collision loops
|
||||
.map_or(None,|(face,time)|if time==state.time{None}else{Some((face,time))})
|
||||
.map(|(face,time)|{
|
||||
TimedInstruction{time,instruction:PhysicsInstruction::CollisionStart(match data.models.attr(id){
|
||||
PhysicsCollisionAttributes::Contact{contacting:_,general:_}=>Collision::Contact(ContactCollision{model_id:id,face_id:face}),
|
||||
PhysicsCollisionAttributes::Intersect{intersecting:_,general:_}=>Collision::Intersect(IntersectCollision{model_id:id}),
|
||||
TimedInstruction{time,instruction:PhysicsInstruction::CollisionStart(match data.models.attr(convex_mesh_id.model_id){
|
||||
PhysicsCollisionAttributes::Contact{contacting:_,general:_}=>Collision::Contact(ContactCollision{convex_mesh_id,face_id:face}),
|
||||
PhysicsCollisionAttributes::Intersect{intersecting:_,general:_}=>Collision::Intersect(IntersectCollision{convex_mesh_id}),
|
||||
})}
|
||||
}));
|
||||
});
|
||||
@ -1053,8 +1071,8 @@ fn jumped_velocity(models:&PhysicsModels,style:&StyleModifiers,hitbox_mesh:&Hitb
|
||||
}
|
||||
|
||||
fn contact_normal(models:&PhysicsModels,hitbox_mesh:&HitboxMesh,contact:&ContactCollision)->Planar64Vec3{
|
||||
let model_mesh=models.mesh(contact.model_id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&hitbox_mesh.transformed_mesh());
|
||||
let model_mesh=models.mesh(contact.convex_mesh_id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
||||
minkowski.face_nd(contact.face_id).0
|
||||
}
|
||||
|
||||
@ -1116,15 +1134,15 @@ fn teleport(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,sty
|
||||
}
|
||||
fn teleport_to_spawn(body:&mut Body,touching:&mut TouchingState,style:&StyleModifiers,hitbox_mesh:&HitboxMesh,mode:&gameplay_modes::Mode,models:&PhysicsModels,stage_id:gameplay_modes::StageId)->Option<MoveState>{
|
||||
let model=models.model(mode.get_spawn_model_id(stage_id)?.into());
|
||||
let point=model.transform.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(style.hitbox.halfsize.y()+Planar64::ONE/16);
|
||||
let point=model.transform.vertex.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(style.hitbox.halfsize.y()+Planar64::ONE/16);
|
||||
Some(teleport(body,touching,models,style,hitbox_mesh,point))
|
||||
}
|
||||
|
||||
fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,game:&mut ModeState,models:&PhysicsModels,mode:&gameplay_modes::Mode,style:&StyleModifiers,hitbox_mesh:&HitboxMesh,touching:&mut TouchingState,body:&mut Body,model_id:PhysicsModelId)->Option<MoveState>{
|
||||
fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,game:&mut ModeState,models:&PhysicsModels,mode:&gameplay_modes::Mode,style:&StyleModifiers,hitbox_mesh:&HitboxMesh,touching:&mut TouchingState,body:&mut Body,convex_mesh_id:ConvexMeshId)->Option<MoveState>{
|
||||
//TODO: jump count and checkpoints are always reset on teleport.
|
||||
//Map makers are expected to use tools to prevent
|
||||
//multi-boosting on JumpLimit boosters such as spawning into a SetVelocity
|
||||
if let Some(stage_element)=mode.get_element(model_id.into()){
|
||||
if let Some(stage_element)=mode.get_element(convex_mesh_id.model_id.into()){
|
||||
let stage=mode.get_stage(stage_element.stage_id)?;
|
||||
if stage_element.force||game.stage_id<stage_element.stage_id{
|
||||
//TODO: check if all checkpoints are complete up to destination stage id, otherwise set to checkpoint completion stage it
|
||||
@ -1151,23 +1169,23 @@ fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,game:&
|
||||
},
|
||||
}
|
||||
if let Some(next_checkpoint)=stage.ordered_checkpoints.get(&game.next_ordered_checkpoint_id){
|
||||
if model_id==next_checkpoint{
|
||||
if convex_mesh_id==next_checkpoint{
|
||||
//if you hit the next number in a sequence of ordered checkpoints
|
||||
//increment the current checkpoint id
|
||||
game.next_ordered_checkpoint_id=gameplay_modes::CheckpointId::new(game.next_ordered_checkpoint_id.get()+1);
|
||||
}
|
||||
}
|
||||
if stage.unordered_checkpoints.contains(model_id.into()){
|
||||
if stage.unordered_checkpoints.contains(convex_mesh_id.model_id.into()){
|
||||
//count model id in accumulated unordered checkpoints
|
||||
game.unordered_checkpoints.insert(model_id.into());
|
||||
game.unordered_checkpoints.insert(convex_mesh_id.model_id.into());
|
||||
}
|
||||
}
|
||||
match wormhole{
|
||||
&Some(gameplay_attributes::Wormhole{destination_model})=>{
|
||||
let origin_model=models.model(model_id);
|
||||
let origin_model=models.model(convex_mesh_id.model_id);
|
||||
let destination_model=models.model(destination_model.into());
|
||||
//ignore the transform for now
|
||||
Some(teleport(body,touching,models,style,hitbox_mesh,body.position-origin_model.transform.translation+destination_model.transform.translation))
|
||||
Some(teleport(body,touching,models,style,hitbox_mesh,body.position-origin_model.transform.vertex.translation+destination_model.transform.vertex.translation))
|
||||
}
|
||||
None=>None,
|
||||
}
|
||||
@ -1192,8 +1210,8 @@ fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,game:&
|
||||
}
|
||||
match ins.instruction{
|
||||
PhysicsInstruction::CollisionStart(c)=>{
|
||||
let model_id=c.model_id();
|
||||
match (data.models.attr(model_id),&c){
|
||||
let convex_mesh_id=c.convex_mesh_id();
|
||||
match (data.models.attr(convex_mesh_id.model_id),&c){
|
||||
(PhysicsCollisionAttributes::Contact{contacting,general},Collision::Contact(contact))=>{
|
||||
let mut v=state.body.velocity;
|
||||
let normal=contact_normal(&data.models,&data.hitbox_mesh,contact);
|
||||
@ -1232,7 +1250,7 @@ fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,game:&
|
||||
//check ground
|
||||
state.touching.insert(c);
|
||||
//I love making functions with 10 arguments to dodge the borrow checker
|
||||
run_teleport_behaviour(&general.wormhole,&mut state.mode_state,&data.models,&data.modes.get_mode(state.mode_state.mode_id).unwrap(),&state.style,&data.hitbox_mesh,&mut state.touching,&mut state.body,model_id);
|
||||
run_teleport_behaviour(&general.wormhole,&mut state.mode_state,&data.models,&data.modes.get_mode(state.mode_state.mode_id).unwrap(),&state.style,&data.hitbox_mesh,&mut state.touching,&mut state.body,convex_mesh_id);
|
||||
//flatten v
|
||||
state.touching.constrain_velocity(&data.models,&data.hitbox_mesh,&mut v);
|
||||
match &general.booster{
|
||||
@ -1276,13 +1294,13 @@ fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,game:&
|
||||
(PhysicsCollisionAttributes::Intersect{intersecting: _,general},Collision::Intersect(intersect))=>{
|
||||
//I think that setting the velocity to 0 was preventing surface contacts from entering an infinite loop
|
||||
state.touching.insert(c);
|
||||
run_teleport_behaviour(&general.wormhole,&mut state.mode_state,&data.models,&data.modes.get_mode(state.mode_state.mode_id).unwrap(),&state.style,&data.hitbox_mesh,&mut state.touching,&mut state.body,model_id);
|
||||
run_teleport_behaviour(&general.wormhole,&mut state.mode_state,&data.models,&data.modes.get_mode(state.mode_state.mode_id).unwrap(),&state.style,&data.hitbox_mesh,&mut state.touching,&mut state.body,convex_mesh_id);
|
||||
},
|
||||
_=>panic!("invalid pair"),
|
||||
}
|
||||
},
|
||||
PhysicsInstruction::CollisionEnd(c) => {
|
||||
match data.models.attr(c.model_id()){
|
||||
match data.models.attr(c.convex_mesh_id().model_id){
|
||||
PhysicsCollisionAttributes::Contact{contacting:_,general:_}=>{
|
||||
state.touching.remove(&c);//remove contact before calling contact_constrain_acceleration
|
||||
//check ground
|
||||
@ -1365,7 +1383,7 @@ fn run_teleport_behaviour(wormhole:&Option<gameplay_attributes::Wormhole>,game:&
|
||||
let spawn_point={
|
||||
let mode=data.modes.get_mode(state.mode_state.mode_id).unwrap();
|
||||
let stage=mode.get_stage(gameplay_modes::StageId::FIRST).unwrap();
|
||||
data.models.model(stage.spawn().into()).transform.translation
|
||||
data.models.model(stage.spawn().into()).transform.vertex.translation
|
||||
};
|
||||
set_position(&mut state.body,&mut state.touching,spawn_point);
|
||||
set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,Planar64Vec3::ZERO);
|
||||
@ -1409,7 +1427,7 @@ fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time
|
||||
let h1=HitboxMesh::roblox();
|
||||
let hitbox_mesh=h1.transformed_mesh();
|
||||
let platform_mesh=h0.transformed_mesh();
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(&platform_mesh,&hitbox_mesh);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(platform_mesh,hitbox_mesh);
|
||||
let collision=minkowski.predict_collision_in(&relative_body,Time::MAX);
|
||||
assert_eq!(collision.map(|tup|tup.1),expected_collision_time,"Incorrect time of collision");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user