megatype-ify

This commit is contained in:
Quaternions 2024-02-06 20:29:36 -08:00
parent 5b38b2ca33
commit 50eeeb003a
2 changed files with 269 additions and 209 deletions

View File

@ -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

View File

@ -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");
}