Compare commits
6 Commits
master
...
recalculat
Author | SHA1 | Date | |
---|---|---|---|
da8492d559 | |||
46db92acd0 | |||
35076f5c17 | |||
63395d3928 | |||
ce47f01375 | |||
fb14e023df |
701
Cargo.lock
generated
701
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
18
Cargo.toml
18
Cargo.toml
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafe-client"
|
name = "strafe-client"
|
||||||
version = "0.10.5"
|
version = "0.10.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-client"
|
repository = "https://git.itzana.me/StrafesNET/strafe-client"
|
||||||
license = "Custom"
|
license = "Custom"
|
||||||
@ -18,17 +18,17 @@ roblox = ["dep:strafesnet_deferred_loader", "dep:strafesnet_rbx_loader"]
|
|||||||
bytemuck = { version = "1.13.1", features = ["derive"] }
|
bytemuck = { version = "1.13.1", features = ["derive"] }
|
||||||
configparser = "3.0.2"
|
configparser = "3.0.2"
|
||||||
ddsfile = "0.5.1"
|
ddsfile = "0.5.1"
|
||||||
glam = "0.29.0"
|
glam = "0.28.0"
|
||||||
id = { version = "0.1.0", registry = "strafesnet" }
|
id = { version = "0.1.0", registry = "strafesnet" }
|
||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12.1"
|
||||||
pollster = "0.3.0"
|
pollster = "0.3.0"
|
||||||
strafesnet_bsp_loader = { version = "0.2.1", registry = "strafesnet", optional = true }
|
strafesnet_bsp_loader = { version = "0.1.3", registry = "strafesnet", optional = true }
|
||||||
strafesnet_common = { version = "0.5.2", registry = "strafesnet" }
|
strafesnet_common = { version = "0.4.0", registry = "strafesnet" }
|
||||||
strafesnet_deferred_loader = { version = "0.4.0", features = ["legacy"], registry = "strafesnet", optional = true }
|
strafesnet_deferred_loader = { version = "0.3.1", features = ["legacy"], registry = "strafesnet", optional = true }
|
||||||
strafesnet_rbx_loader = { version = "0.5.1", registry = "strafesnet", optional = true }
|
strafesnet_rbx_loader = { version = "0.3.2", registry = "strafesnet", optional = true }
|
||||||
strafesnet_snf = { version = "0.2.0", registry = "strafesnet", optional = true }
|
strafesnet_snf = { version = "0.1.2", registry = "strafesnet", optional = true }
|
||||||
wgpu = "22.1.0"
|
wgpu = "22.0.0"
|
||||||
winit = "0.30.5"
|
winit = "0.30.4"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
#lto = true
|
#lto = true
|
||||||
|
@ -1,33 +1,32 @@
|
|||||||
use crate::physics::Body;
|
use crate::physics::Body;
|
||||||
use crate::model_physics::{GigaTime,FEV,MeshQuery,DirectedEdge,MinkowskiMesh,MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert};
|
use crate::model_physics::{FEV,MeshQuery,DirectedEdge};
|
||||||
use strafesnet_common::integer::{Time,Fixed,Ratio};
|
use strafesnet_common::integer::{Time,Planar64};
|
||||||
|
use strafesnet_common::zeroes::zeroes2;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Transition<F,E:DirectedEdge,V>{
|
enum Transition<F,E:DirectedEdge,V>{
|
||||||
Miss,
|
Miss,
|
||||||
Next(FEV<F,E,V>,GigaTime),
|
Next(FEV<F,E,V>,Time),
|
||||||
Hit(F,GigaTime),
|
Hit(F,Time),
|
||||||
}
|
}
|
||||||
|
|
||||||
type MinkowskiFEV=FEV<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>;
|
fn next_transition<F:Copy,E:Copy+DirectedEdge,V:Copy>(fev:&FEV<F,E,V>,time:Time,mesh:&impl MeshQuery<F,E,V>,body:&Body,time_limit:Time)->Transition<F,E,V>{
|
||||||
type MinkowskiTransition=Transition<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>;
|
|
||||||
|
|
||||||
fn next_transition(fev:&MinkowskiFEV,body_time:GigaTime,mesh:&MinkowskiMesh,body:&Body,mut best_time:GigaTime)->MinkowskiTransition{
|
|
||||||
//conflicting derivative means it crosses in the wrong direction.
|
//conflicting derivative means it crosses in the wrong direction.
|
||||||
//if the transition time is equal to an already tested transition, do not replace the current best.
|
//if the transition time is equal to an already tested transition, do not replace the current best.
|
||||||
let mut best_transition=MinkowskiTransition::Miss;
|
let mut best_time=time_limit;
|
||||||
|
let mut best_transtition=Transition::Miss;
|
||||||
match fev{
|
match fev{
|
||||||
&MinkowskiFEV::Face(face_id)=>{
|
&FEV::<F,E,V>::Face(face_id)=>{
|
||||||
//test own face collision time, ignoring roots with zero or conflicting derivative
|
//test own face collision time, ignoring roots with zero or conflicting derivative
|
||||||
//n=face.normal d=face.dot
|
//n=face.normal d=face.dot
|
||||||
//n.a t^2+n.v t+n.p-d==0
|
//n.a t^2+n.v t+n.p-d==0
|
||||||
let (n,d)=mesh.face_nd(face_id);
|
let (n,d)=mesh.face_nd(face_id);
|
||||||
//TODO: use higher precision d value?
|
//TODO: use higher precision d value?
|
||||||
//use the mesh transform translation instead of baking it into the d value.
|
//use the mesh transform translation instead of baking it into the d value.
|
||||||
for dt in Fixed::<4,128>::zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||||
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
let t=body.time+Time::from(t);
|
||||||
best_time=dt;
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_transition=MinkowskiTransition::Hit(face_id,dt);
|
best_time=t;
|
||||||
|
best_transtition=Transition::Hit(face_id,t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,18 +36,18 @@ type MinkowskiTransition=Transition<MinkowskiFace,MinkowskiDirectedEdge,Minkowsk
|
|||||||
let n=n.cross(edge_n);
|
let n=n.cross(edge_n);
|
||||||
let verts=mesh.edge_verts(directed_edge_id.as_undirected());
|
let verts=mesh.edge_verts(directed_edge_id.as_undirected());
|
||||||
//WARNING: d is moved out of the *2 block because of adding two vertices!
|
//WARNING: d is moved out of the *2 block because of adding two vertices!
|
||||||
//WARNING: precision is swept under the rug!
|
for t in zeroes2(n.dot(body.position*2-(mesh.vert(verts[0])+mesh.vert(verts[1]))),n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||||
for dt in Fixed::<4,128>::zeroes2(n.dot(body.position*2-(mesh.vert(verts[0])+mesh.vert(verts[1]))).fix_4(),n.dot(body.velocity).fix_4()*2,n.dot(body.acceleration).fix_4()){
|
let t=body.time+Time::from(t);
|
||||||
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_time=dt;
|
best_time=t;
|
||||||
best_transition=MinkowskiTransition::Next(MinkowskiFEV::Edge(directed_edge_id.as_undirected()),dt);
|
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if none:
|
//if none:
|
||||||
},
|
},
|
||||||
&MinkowskiFEV::Edge(edge_id)=>{
|
&FEV::<F,E,V>::Edge(edge_id)=>{
|
||||||
//test each face collision time, ignoring roots with zero or conflicting derivative
|
//test each face collision time, ignoring roots with zero or conflicting derivative
|
||||||
let edge_n=mesh.edge_n(edge_id);
|
let edge_n=mesh.edge_n(edge_id);
|
||||||
let edge_verts=mesh.edge_verts(edge_id);
|
let edge_verts=mesh.edge_verts(edge_id);
|
||||||
@ -58,10 +57,11 @@ type MinkowskiTransition=Transition<MinkowskiFace,MinkowskiDirectedEdge,Minkowsk
|
|||||||
//edge_n gets parity from the order of edge_faces
|
//edge_n gets parity from the order of edge_faces
|
||||||
let n=face_n.cross(edge_n)*((i as i64)*2-1);
|
let n=face_n.cross(edge_n)*((i as i64)*2-1);
|
||||||
//WARNING yada yada d *2
|
//WARNING yada yada d *2
|
||||||
for dt in Fixed::<4,128>::zeroes2(n.dot(delta_pos).fix_4(),n.dot(body.velocity).fix_4()*2,n.dot(body.acceleration).fix_4()){
|
for t in zeroes2(n.dot(delta_pos),n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||||
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
let t=body.time+Time::from(t);
|
||||||
best_time=dt;
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_transition=MinkowskiTransition::Next(MinkowskiFEV::Face(edge_face_id),dt);
|
best_time=t;
|
||||||
|
best_transtition=Transition::Next(FEV::<F,E,V>::Face(edge_face_id),t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,27 +70,27 @@ type MinkowskiTransition=Transition<MinkowskiFace,MinkowskiDirectedEdge,Minkowsk
|
|||||||
for (i,&vert_id) in edge_verts.iter().enumerate(){
|
for (i,&vert_id) in edge_verts.iter().enumerate(){
|
||||||
//vertex normal gets parity from vert index
|
//vertex normal gets parity from vert index
|
||||||
let n=edge_n*(1-2*(i as i64));
|
let n=edge_n*(1-2*(i as i64));
|
||||||
for dt in Fixed::<2,64>::zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
for t in zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||||
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
let t=body.time+Time::from(t);
|
||||||
let dt=Ratio::new(dt.num.fix_4(),dt.den.fix_4());
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_time=dt;
|
best_time=t;
|
||||||
best_transition=MinkowskiTransition::Next(MinkowskiFEV::Vert(vert_id),dt);
|
best_transtition=Transition::Next(FEV::<F,E,V>::Vert(vert_id),t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if none:
|
//if none:
|
||||||
},
|
},
|
||||||
&MinkowskiFEV::Vert(vert_id)=>{
|
&FEV::<F,E,V>::Vert(vert_id)=>{
|
||||||
//test each edge collision time, ignoring roots with zero or conflicting derivative
|
//test each edge collision time, ignoring roots with zero or conflicting derivative
|
||||||
for &directed_edge_id in mesh.vert_edges(vert_id).iter(){
|
for &directed_edge_id in mesh.vert_edges(vert_id).iter(){
|
||||||
//edge is directed away from vertex, but we want the dot product to turn out negative
|
//edge is directed away from vertex, but we want the dot product to turn out negative
|
||||||
let n=-mesh.directed_edge_n(directed_edge_id);
|
let n=-mesh.directed_edge_n(directed_edge_id);
|
||||||
for dt in Fixed::<2,64>::zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
for t in zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||||
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
let t=body.time+Time::from(t);
|
||||||
let dt=Ratio::new(dt.num.fix_4(),dt.den.fix_4());
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_time=dt;
|
best_time=t;
|
||||||
best_transition=MinkowskiTransition::Next(MinkowskiFEV::Edge(directed_edge_id.as_undirected()),dt);
|
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,26 +98,18 @@ type MinkowskiTransition=Transition<MinkowskiFace,MinkowskiDirectedEdge,Minkowsk
|
|||||||
//if none:
|
//if none:
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
best_transition
|
best_transtition
|
||||||
}
|
}
|
||||||
pub enum CrawlResult<F,E:DirectedEdge,V>{
|
pub enum CrawlResult<F,E:DirectedEdge,V>{
|
||||||
Miss(FEV<F,E,V>),
|
Miss(FEV<F,E,V>),
|
||||||
Hit(F,GigaTime),
|
Hit(F,Time),
|
||||||
}
|
}
|
||||||
type MinkowskiCrawlResult=CrawlResult<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>;
|
pub fn crawl_fev<F:Copy,E:Copy+DirectedEdge,V:Copy>(mut fev:FEV<F,E,V>,mesh:&impl MeshQuery<F,E,V>,relative_body:&Body,start_time:Time,time_limit:Time)->CrawlResult<F,E,V>{
|
||||||
pub fn crawl_fev(mut fev:MinkowskiFEV,mesh:&MinkowskiMesh,relative_body:&Body,start_time:Time,time_limit:Time)->MinkowskiCrawlResult{
|
let mut time=start_time;
|
||||||
let mut body_time={
|
|
||||||
let r=(start_time-relative_body.time).to_ratio();
|
|
||||||
Ratio::new(r.num.fix_4(),r.den.fix_4())
|
|
||||||
};
|
|
||||||
let time_limit={
|
|
||||||
let r=(time_limit-relative_body.time).to_ratio();
|
|
||||||
Ratio::new(r.num.fix_4(),r.den.fix_4())
|
|
||||||
};
|
|
||||||
for _ in 0..20{
|
for _ in 0..20{
|
||||||
match next_transition(&fev,body_time,mesh,relative_body,time_limit){
|
match next_transition(&fev,time,mesh,relative_body,time_limit){
|
||||||
Transition::Miss=>return CrawlResult::Miss(fev),
|
Transition::Miss=>return CrawlResult::Miss(fev),
|
||||||
Transition::Next(next_fev,next_time)=>(fev,body_time)=(next_fev,next_time),
|
Transition::Next(next_fev,next_time)=>(fev,time)=(next_fev,next_time),
|
||||||
Transition::Hit(face,time)=>return CrawlResult::Hit(face,time),
|
Transition::Hit(face,time)=>return CrawlResult::Hit(face,time),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
src/file.rs
11
src/file.rs
@ -22,7 +22,7 @@ impl std::error::Error for ReadError{}
|
|||||||
|
|
||||||
pub enum DataStructure{
|
pub enum DataStructure{
|
||||||
#[cfg(feature="roblox")]
|
#[cfg(feature="roblox")]
|
||||||
Roblox(strafesnet_rbx_loader::Model),
|
Roblox(strafesnet_rbx_loader::Dom),
|
||||||
#[cfg(feature="source")]
|
#[cfg(feature="source")]
|
||||||
Source(strafesnet_bsp_loader::Bsp),
|
Source(strafesnet_bsp_loader::Bsp),
|
||||||
#[cfg(feature="snf")]
|
#[cfg(feature="snf")]
|
||||||
@ -66,16 +66,13 @@ pub fn load<P:AsRef<std::path::Path>>(path:P)->Result<strafesnet_common::map::Co
|
|||||||
#[cfg(feature="snf")]
|
#[cfg(feature="snf")]
|
||||||
DataStructure::StrafesNET(map)=>Ok(map),
|
DataStructure::StrafesNET(map)=>Ok(map),
|
||||||
#[cfg(feature="roblox")]
|
#[cfg(feature="roblox")]
|
||||||
DataStructure::Roblox(model)=>{
|
DataStructure::Roblox(dom)=>{
|
||||||
let mut place=model.into_place();
|
|
||||||
place.run_scripts();
|
|
||||||
|
|
||||||
let mut loader=strafesnet_deferred_loader::roblox_legacy();
|
let mut loader=strafesnet_deferred_loader::roblox_legacy();
|
||||||
|
|
||||||
let (texture_loader,mesh_loader)=loader.get_inner_mut();
|
let (texture_loader,mesh_loader)=loader.get_inner_mut();
|
||||||
|
|
||||||
let map_step1=strafesnet_rbx_loader::convert(
|
let map_step1=strafesnet_rbx_loader::convert(
|
||||||
&place,
|
&dom,
|
||||||
|name|texture_loader.acquire_render_config_id(name),
|
|name|texture_loader.acquire_render_config_id(name),
|
||||||
|name|mesh_loader.acquire_mesh_id(name),
|
|name|mesh_loader.acquire_mesh_id(name),
|
||||||
);
|
);
|
||||||
@ -113,7 +110,7 @@ pub fn load<P:AsRef<std::path::Path>>(path:P)->Result<strafesnet_common::map::Co
|
|||||||
|name|mesh_loader.acquire_mesh_id(name),
|
|name|mesh_loader.acquire_mesh_id(name),
|
||||||
);
|
);
|
||||||
|
|
||||||
let prop_meshes=mesh_loader.load_meshes(bsp.as_ref());
|
let prop_meshes=mesh_loader.load_meshes(&bsp.as_ref());
|
||||||
|
|
||||||
let map_step2=map_step1.add_prop_meshes(
|
let map_step2=map_step1.add_prop_meshes(
|
||||||
//the type conflagulator 9000
|
//the type conflagulator 9000
|
||||||
|
@ -6,6 +6,12 @@ use strafesnet_common::model::{self, ColorId, NormalId, PolygonIter, PositionId,
|
|||||||
use wgpu::{util::DeviceExt,AstcBlock,AstcChannel};
|
use wgpu::{util::DeviceExt,AstcBlock,AstcChannel};
|
||||||
use crate::model_graphics::{self,IndexedGraphicsMeshOwnedRenderConfig,IndexedGraphicsMeshOwnedRenderConfigId,GraphicsMeshOwnedRenderConfig,GraphicsModelColor4,GraphicsModelOwned,GraphicsVertex};
|
use crate::model_graphics::{self,IndexedGraphicsMeshOwnedRenderConfig,IndexedGraphicsMeshOwnedRenderConfigId,GraphicsMeshOwnedRenderConfig,GraphicsModelColor4,GraphicsModelOwned,GraphicsVertex};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GraphicsModelUpdate{
|
||||||
|
transform:Option<glam::Mat4>,
|
||||||
|
color:Option<glam::Vec4>,
|
||||||
|
}
|
||||||
|
|
||||||
struct Indices{
|
struct Indices{
|
||||||
count:u32,
|
count:u32,
|
||||||
buf:wgpu::Buffer,
|
buf:wgpu::Buffer,
|
||||||
@ -26,6 +32,7 @@ impl Indices{
|
|||||||
}
|
}
|
||||||
struct GraphicsModel{
|
struct GraphicsModel{
|
||||||
indices:Indices,
|
indices:Indices,
|
||||||
|
model_buf:wgpu::Buffer,
|
||||||
vertex_buf:wgpu::Buffer,
|
vertex_buf:wgpu::Buffer,
|
||||||
bind_group:wgpu::BindGroup,
|
bind_group:wgpu::BindGroup,
|
||||||
instance_count:u32,
|
instance_count:u32,
|
||||||
@ -58,12 +65,12 @@ struct GraphicsCamera{
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn perspective_rh(fov_x_slope:f32,fov_y_slope:f32,z_near:f32,z_far:f32)->glam::Mat4{
|
fn perspective_rh(fov_x_slope:f32,fov_y_slope:f32,z_near:f32,z_far:f32)->glam::Mat4{
|
||||||
//glam_assert!(z_near > 0.0 && z_far > 0.0);
|
//glam_assert!(z_near > 0.0 && z_far > 0.0);
|
||||||
let r=z_far/(z_near-z_far);
|
let r=z_far / (z_near-z_far);
|
||||||
glam::Mat4::from_cols(
|
glam::Mat4::from_cols(
|
||||||
glam::Vec4::new(1.0/fov_x_slope,0.0,0.0,0.0),
|
glam::Vec4::new(1.0/fov_x_slope,0.0,0.0,0.0),
|
||||||
glam::Vec4::new(0.0,1.0/fov_y_slope,0.0,0.0),
|
glam::Vec4::new(0.0,1.0/fov_y_slope,0.0,0.0),
|
||||||
glam::Vec4::new(0.0,0.0,r,-1.0),
|
glam::Vec4::new(0.0,0.0,r,-1.0),
|
||||||
glam::Vec4::new(0.0,0.0,r*z_near,0.0),
|
glam::Vec4::new(0.0,0.0,r * z_near,0.0),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
impl GraphicsCamera{
|
impl GraphicsCamera{
|
||||||
@ -72,10 +79,10 @@ impl GraphicsCamera{
|
|||||||
}
|
}
|
||||||
pub fn world(&self,pos:glam::Vec3,angles:glam::Vec2)->glam::Mat4{
|
pub fn world(&self,pos:glam::Vec3,angles:glam::Vec2)->glam::Mat4{
|
||||||
//f32 good enough for view matrix
|
//f32 good enough for view matrix
|
||||||
glam::Mat4::from_translation(pos)*glam::Mat4::from_euler(glam::EulerRot::YXZ,angles.x,angles.y,0f32)
|
glam::Mat4::from_translation(pos) * glam::Mat4::from_euler(glam::EulerRot::YXZ,angles.x,angles.y,0f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_uniform_data(&self,pos:glam::Vec3,angles:glam::Vec2)->[f32;16*4]{
|
pub fn to_uniform_data(&self,(pos,angles):(glam::Vec3,glam::Vec2))->[f32; 16 * 4]{
|
||||||
let proj=self.proj();
|
let proj=self.proj();
|
||||||
let proj_inv=proj.inverse();
|
let proj_inv=proj.inverse();
|
||||||
let view_inv=self.world(pos,angles);
|
let view_inv=self.world(pos,angles);
|
||||||
@ -98,12 +105,6 @@ impl std::default::Default for GraphicsCamera{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FrameState{
|
|
||||||
pub body:crate::physics::Body,
|
|
||||||
pub camera:crate::physics::PhysicsCamera,
|
|
||||||
pub time:integer::Time,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GraphicsState{
|
pub struct GraphicsState{
|
||||||
pipelines:GraphicsPipelines,
|
pipelines:GraphicsPipelines,
|
||||||
bind_groups:GraphicsBindGroups,
|
bind_groups:GraphicsBindGroups,
|
||||||
@ -219,7 +220,7 @@ impl GraphicsState{
|
|||||||
//wow
|
//wow
|
||||||
let instance=GraphicsModelOwned{
|
let instance=GraphicsModelOwned{
|
||||||
transform:model.transform.into(),
|
transform:model.transform.into(),
|
||||||
normal_transform:glam::Mat3::from_cols_array_2d(&model.transform.matrix3.to_array().map(|row|row.map(Into::into))).inverse().transpose(),
|
normal_transform:Into::<glam::Mat3>::into(model.transform.matrix3).inverse().transpose(),
|
||||||
color:GraphicsModelColor4::new(model.color),
|
color:GraphicsModelColor4::new(model.color),
|
||||||
};
|
};
|
||||||
//get or create owned mesh map
|
//get or create owned mesh map
|
||||||
@ -238,9 +239,9 @@ impl GraphicsState{
|
|||||||
//create
|
//create
|
||||||
let owned_mesh_id=IndexedGraphicsMeshOwnedRenderConfigId::new(unique_render_config_models.len() as u32);
|
let owned_mesh_id=IndexedGraphicsMeshOwnedRenderConfigId::new(unique_render_config_models.len() as u32);
|
||||||
unique_render_config_models.push(IndexedGraphicsMeshOwnedRenderConfig{
|
unique_render_config_models.push(IndexedGraphicsMeshOwnedRenderConfig{
|
||||||
unique_pos:mesh.unique_pos.iter().map(|v|v.to_array().map(Into::into)).collect(),
|
unique_pos:mesh.unique_pos.iter().map(|&v|*Into::<glam::Vec3>::into(v).as_ref()).collect(),
|
||||||
unique_tex:mesh.unique_tex.iter().map(|v|*v.as_ref()).collect(),
|
unique_tex:mesh.unique_tex.iter().map(|v|*v.as_ref()).collect(),
|
||||||
unique_normal:mesh.unique_normal.iter().map(|v|v.to_array().map(Into::into)).collect(),
|
unique_normal:mesh.unique_normal.iter().map(|&v|*Into::<glam::Vec3>::into(v).as_ref()).collect(),
|
||||||
unique_color:mesh.unique_color.iter().map(|v|*v.as_ref()).collect(),
|
unique_color:mesh.unique_color.iter().map(|v|*v.as_ref()).collect(),
|
||||||
unique_vertices:mesh.unique_vertices.clone(),
|
unique_vertices:mesh.unique_vertices.clone(),
|
||||||
render_config:graphics_group.render,
|
render_config:graphics_group.render,
|
||||||
@ -506,6 +507,7 @@ impl GraphicsState{
|
|||||||
model_graphics::Indices::U16(indices)=>Indices::new(device,indices,wgpu::IndexFormat::Uint16),
|
model_graphics::Indices::U16(indices)=>Indices::new(device,indices,wgpu::IndexFormat::Uint16),
|
||||||
},
|
},
|
||||||
bind_group,
|
bind_group,
|
||||||
|
model_buf,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -814,7 +816,7 @@ impl GraphicsState{
|
|||||||
});
|
});
|
||||||
|
|
||||||
let camera=GraphicsCamera::default();
|
let camera=GraphicsCamera::default();
|
||||||
let camera_uniforms=camera.to_uniform_data(glam::Vec3::ZERO,glam::Vec2::ZERO);
|
let camera_uniforms=camera.to_uniform_data(crate::physics::PhysicsOutputState::default().extrapolate(strafesnet_common::mouse::MouseState::default()));
|
||||||
let camera_buf=device.create_buffer_init(&wgpu::util::BufferInitDescriptor{
|
let camera_buf=device.create_buffer_init(&wgpu::util::BufferInitDescriptor{
|
||||||
label:Some("Camera"),
|
label:Some("Camera"),
|
||||||
contents:bytemuck::cast_slice(&camera_uniforms),
|
contents:bytemuck::cast_slice(&camera_uniforms),
|
||||||
@ -882,17 +884,16 @@ impl GraphicsState{
|
|||||||
view:&wgpu::TextureView,
|
view:&wgpu::TextureView,
|
||||||
device:&wgpu::Device,
|
device:&wgpu::Device,
|
||||||
queue:&wgpu::Queue,
|
queue:&wgpu::Queue,
|
||||||
frame_state:FrameState,
|
physics_output:crate::physics::PhysicsOutputState,
|
||||||
|
predicted_time:integer::Time,
|
||||||
|
mouse_pos:glam::IVec2,
|
||||||
){
|
){
|
||||||
//TODO:use scheduled frame times to create beautiful smoothing simulation physics extrapolation assuming no input
|
//TODO:use scheduled frame times to create beautiful smoothing simulation physics extrapolation assuming no input
|
||||||
|
|
||||||
let mut encoder=device.create_command_encoder(&wgpu::CommandEncoderDescriptor{label:None});
|
let mut encoder=device.create_command_encoder(&wgpu::CommandEncoderDescriptor{label:None});
|
||||||
|
|
||||||
// update rotation
|
// update rotation
|
||||||
let camera_uniforms=self.camera.to_uniform_data(
|
let camera_uniforms=self.camera.to_uniform_data(physics_output.extrapolate(strafesnet_common::mouse::MouseState{pos:mouse_pos,time:predicted_time}));
|
||||||
frame_state.body.extrapolated_position(frame_state.time).map(Into::<f32>::into).to_array().into(),
|
|
||||||
frame_state.camera.simulate_move_angles(glam::IVec2::ZERO)
|
|
||||||
);
|
|
||||||
self.staging_belt
|
self.staging_belt
|
||||||
.write_buffer(
|
.write_buffer(
|
||||||
&mut encoder,
|
&mut encoder,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
use strafesnet_common::integer;
|
||||||
|
|
||||||
pub enum Instruction{
|
pub enum Instruction{
|
||||||
Render(crate::graphics::FrameState),
|
Render(crate::physics::PhysicsOutputState,integer::Time,glam::IVec2),
|
||||||
//UpdateModel(crate::graphics::GraphicsModelUpdate),
|
//UpdateModel(crate::graphics::GraphicsModelUpdate),
|
||||||
Resize(winit::dpi::PhysicalSize<u32>,crate::settings::UserSettings),
|
Resize(winit::dpi::PhysicalSize<u32>,crate::settings::UserSettings),
|
||||||
ChangeMap(strafesnet_common::map::CompleteMap),
|
ChangeMap(strafesnet_common::map::CompleteMap),
|
||||||
@ -20,7 +22,7 @@ pub fn new<'a>(
|
|||||||
surface:wgpu::Surface<'a>,
|
surface:wgpu::Surface<'a>,
|
||||||
device:wgpu::Device,
|
device:wgpu::Device,
|
||||||
queue:wgpu::Queue,
|
queue:wgpu::Queue,
|
||||||
)->crate::compat_worker::INWorker<'a,Instruction>{
|
)->crate::compat_worker::INWorker<'a,Instruction>{
|
||||||
let mut resize=None;
|
let mut resize=None;
|
||||||
crate::compat_worker::INWorker::new(move |ins:Instruction|{
|
crate::compat_worker::INWorker::new(move |ins:Instruction|{
|
||||||
match ins{
|
match ins{
|
||||||
@ -31,16 +33,18 @@ pub fn new<'a>(
|
|||||||
Instruction::Resize(size,user_settings)=>{
|
Instruction::Resize(size,user_settings)=>{
|
||||||
resize=Some((size,user_settings));
|
resize=Some((size,user_settings));
|
||||||
}
|
}
|
||||||
Instruction::Render(frame_state)=>{
|
Instruction::Render(physics_output,predicted_time,mouse_pos)=>{
|
||||||
if let Some((size,user_settings))=resize.take(){
|
if let Some((size,user_settings))=&resize{
|
||||||
println!("Resizing to {:?}",size);
|
println!("Resizing to {:?}",size);
|
||||||
let t0=std::time::Instant::now();
|
let t0=std::time::Instant::now();
|
||||||
config.width=size.width.max(1);
|
config.width=size.width.max(1);
|
||||||
config.height=size.height.max(1);
|
config.height=size.height.max(1);
|
||||||
surface.configure(&device,&config);
|
surface.configure(&device,&config);
|
||||||
graphics.resize(&device,&config,&user_settings);
|
graphics.resize(&device,&config,user_settings);
|
||||||
println!("Resize took {:?}",t0.elapsed());
|
println!("Resize took {:?}",t0.elapsed());
|
||||||
}
|
}
|
||||||
|
//clear every time w/e
|
||||||
|
resize=None;
|
||||||
//this has to go deeper somehow
|
//this has to go deeper somehow
|
||||||
let frame=match surface.get_current_texture(){
|
let frame=match surface.get_current_texture(){
|
||||||
Ok(frame)=>frame,
|
Ok(frame)=>frame,
|
||||||
@ -56,7 +60,7 @@ pub fn new<'a>(
|
|||||||
..wgpu::TextureViewDescriptor::default()
|
..wgpu::TextureViewDescriptor::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
graphics.render(&view,&device,&queue,frame_state);
|
graphics.render(&view,&device,&queue,physics_output,predicted_time,mouse_pos);
|
||||||
|
|
||||||
frame.present();
|
frame.present();
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use std::borrow::{Borrow,Cow};
|
use std::borrow::{Borrow,Cow};
|
||||||
use std::collections::{HashSet,HashMap};
|
use std::collections::{HashSet,HashMap};
|
||||||
use strafesnet_common::integer::vec3::Vector3;
|
|
||||||
use strafesnet_common::model::{self,MeshId,PolygonIter};
|
use strafesnet_common::model::{self,MeshId,PolygonIter};
|
||||||
use strafesnet_common::integer::{self,vec3,Fixed,Planar64,Planar64Vec3,Ratio};
|
use strafesnet_common::zeroes;
|
||||||
|
use strafesnet_common::integer::{self,Planar64,Planar64Vec3};
|
||||||
|
|
||||||
pub trait UndirectedEdge{
|
pub trait UndirectedEdge{
|
||||||
type DirectedEdge:Copy+DirectedEdge;
|
type DirectedEdge:Copy+DirectedEdge;
|
||||||
fn as_directed(&self,parity:bool)->Self::DirectedEdge;
|
fn as_directed(&self,parity:bool)->Self::DirectedEdge;
|
||||||
}
|
}
|
||||||
pub trait DirectedEdge{
|
pub trait DirectedEdge{
|
||||||
type UndirectedEdge:Copy+std::fmt::Debug+UndirectedEdge;
|
type UndirectedEdge:Copy+UndirectedEdge;
|
||||||
fn as_undirected(&self)->Self::UndirectedEdge;
|
fn as_undirected(&self)->Self::UndirectedEdge;
|
||||||
fn parity(&self)->bool;
|
fn parity(&self)->bool;
|
||||||
//this is stupid but may work fine
|
//this is stupid but may work fine
|
||||||
@ -50,7 +50,6 @@ impl DirectedEdge for SubmeshDirectedEdgeId{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Vertex <-> Edge <-> Face -> Collide
|
//Vertex <-> Edge <-> Face -> Collide
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum FEV<F,E:DirectedEdge,V>{
|
pub enum FEV<F,E:DirectedEdge,V>{
|
||||||
Face(F),
|
Face(F),
|
||||||
Edge(E::UndirectedEdge),
|
Edge(E::UndirectedEdge),
|
||||||
@ -65,9 +64,6 @@ struct Face{
|
|||||||
}
|
}
|
||||||
struct Vert(Planar64Vec3);
|
struct Vert(Planar64Vec3);
|
||||||
pub trait MeshQuery<FACE:Clone,EDGE:Clone+DirectedEdge,VERT:Clone>{
|
pub trait MeshQuery<FACE:Clone,EDGE:Clone+DirectedEdge,VERT:Clone>{
|
||||||
// Vertex must be Planar64Vec3 because it represents an actual position
|
|
||||||
type Normal;
|
|
||||||
type Offset;
|
|
||||||
fn edge_n(&self,edge_id:EDGE::UndirectedEdge)->Planar64Vec3{
|
fn edge_n(&self,edge_id:EDGE::UndirectedEdge)->Planar64Vec3{
|
||||||
let verts=self.edge_verts(edge_id);
|
let verts=self.edge_verts(edge_id);
|
||||||
self.vert(verts[1].clone())-self.vert(verts[0].clone())
|
self.vert(verts[1].clone())-self.vert(verts[0].clone())
|
||||||
@ -77,7 +73,7 @@ pub trait MeshQuery<FACE:Clone,EDGE:Clone+DirectedEdge,VERT:Clone>{
|
|||||||
(self.vert(verts[1].clone())-self.vert(verts[0].clone()))*((directed_edge_id.parity() as i64)*2-1)
|
(self.vert(verts[1].clone())-self.vert(verts[0].clone()))*((directed_edge_id.parity() as i64)*2-1)
|
||||||
}
|
}
|
||||||
fn vert(&self,vert_id:VERT)->Planar64Vec3;
|
fn vert(&self,vert_id:VERT)->Planar64Vec3;
|
||||||
fn face_nd(&self,face_id:FACE)->(Self::Normal,Self::Offset);
|
fn face_nd(&self,face_id:FACE)->(Planar64Vec3,Planar64);
|
||||||
fn face_edges(&self,face_id:FACE)->Cow<Vec<EDGE>>;
|
fn face_edges(&self,face_id:FACE)->Cow<Vec<EDGE>>;
|
||||||
fn edge_faces(&self,edge_id:EDGE::UndirectedEdge)->Cow<[FACE;2]>;
|
fn edge_faces(&self,edge_id:EDGE::UndirectedEdge)->Cow<[FACE;2]>;
|
||||||
fn edge_verts(&self,edge_id:EDGE::UndirectedEdge)->Cow<[VERT;2]>;
|
fn edge_verts(&self,edge_id:EDGE::UndirectedEdge)->Cow<[VERT;2]>;
|
||||||
@ -141,22 +137,22 @@ impl PhysicsMesh{
|
|||||||
//go go gadget debug print mesh
|
//go go gadget debug print mesh
|
||||||
let data=PhysicsMeshData{
|
let data=PhysicsMeshData{
|
||||||
faces:vec![
|
faces:vec![
|
||||||
Face{normal:vec3::raw_xyz( 4294967296, 0, 0),dot:Planar64::raw(4294967296)},
|
Face{normal:Planar64Vec3::raw_xyz( 4294967296, 0, 0),dot:Planar64::raw(4294967296)},
|
||||||
Face{normal:vec3::raw_xyz( 0, 4294967296, 0),dot:Planar64::raw(4294967296)},
|
Face{normal:Planar64Vec3::raw_xyz( 0, 4294967296, 0),dot:Planar64::raw(4294967296)},
|
||||||
Face{normal:vec3::raw_xyz( 0, 0, 4294967296),dot:Planar64::raw(4294967296)},
|
Face{normal:Planar64Vec3::raw_xyz( 0, 0, 4294967296),dot:Planar64::raw(4294967296)},
|
||||||
Face{normal:vec3::raw_xyz(-4294967296, 0, 0),dot:Planar64::raw(4294967296)},
|
Face{normal:Planar64Vec3::raw_xyz(-4294967296, 0, 0),dot:Planar64::raw(4294967296)},
|
||||||
Face{normal:vec3::raw_xyz( 0,-4294967296, 0),dot:Planar64::raw(4294967296)},
|
Face{normal:Planar64Vec3::raw_xyz( 0,-4294967296, 0),dot:Planar64::raw(4294967296)},
|
||||||
Face{normal:vec3::raw_xyz( 0, 0,-4294967296),dot:Planar64::raw(4294967296)}
|
Face{normal:Planar64Vec3::raw_xyz( 0, 0,-4294967296),dot:Planar64::raw(4294967296)}
|
||||||
],
|
],
|
||||||
verts:vec![
|
verts:vec![
|
||||||
Vert(vec3::raw_xyz( 4294967296,-4294967296,-4294967296)),
|
Vert(Planar64Vec3::raw_xyz( 4294967296,-4294967296,-4294967296)),
|
||||||
Vert(vec3::raw_xyz( 4294967296, 4294967296,-4294967296)),
|
Vert(Planar64Vec3::raw_xyz( 4294967296, 4294967296,-4294967296)),
|
||||||
Vert(vec3::raw_xyz( 4294967296, 4294967296, 4294967296)),
|
Vert(Planar64Vec3::raw_xyz( 4294967296, 4294967296, 4294967296)),
|
||||||
Vert(vec3::raw_xyz( 4294967296,-4294967296, 4294967296)),
|
Vert(Planar64Vec3::raw_xyz( 4294967296,-4294967296, 4294967296)),
|
||||||
Vert(vec3::raw_xyz(-4294967296, 4294967296,-4294967296)),
|
Vert(Planar64Vec3::raw_xyz(-4294967296, 4294967296,-4294967296)),
|
||||||
Vert(vec3::raw_xyz(-4294967296, 4294967296, 4294967296)),
|
Vert(Planar64Vec3::raw_xyz(-4294967296, 4294967296, 4294967296)),
|
||||||
Vert(vec3::raw_xyz(-4294967296,-4294967296, 4294967296)),
|
Vert(Planar64Vec3::raw_xyz(-4294967296,-4294967296, 4294967296)),
|
||||||
Vert(vec3::raw_xyz(-4294967296,-4294967296,-4294967296))
|
Vert(Planar64Vec3::raw_xyz(-4294967296,-4294967296,-4294967296))
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
let mesh_topology=PhysicsMeshTopology{
|
let mesh_topology=PhysicsMeshTopology{
|
||||||
@ -334,7 +330,7 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
|
|||||||
for poly_vertices in polygon_group.polys(){
|
for poly_vertices in polygon_group.polys(){
|
||||||
let submesh_face_id=SubmeshFaceId::new(submesh_faces.len() as u32);
|
let submesh_face_id=SubmeshFaceId::new(submesh_faces.len() as u32);
|
||||||
//one face per poly
|
//one face per poly
|
||||||
let mut normal=Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO]);
|
let mut normal=Planar64Vec3::ZERO;
|
||||||
let len=poly_vertices.len();
|
let len=poly_vertices.len();
|
||||||
let face_edges=poly_vertices.into_iter().enumerate().map(|(i,vert_id)|{
|
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 vert0_id=MeshVertId::new(mesh.unique_vertices[vert_id.get() as usize].pos.get() as u32);
|
||||||
@ -345,11 +341,11 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
|
|||||||
//https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal (Newell's Method)
|
//https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal (Newell's Method)
|
||||||
let v0=mesh.unique_pos[vert0_id.get() as usize];
|
let v0=mesh.unique_pos[vert0_id.get() as usize];
|
||||||
let v1=mesh.unique_pos[vert1_id.get() as usize];
|
let v1=mesh.unique_pos[vert1_id.get() as usize];
|
||||||
normal+=Vector3::new([
|
normal+=Planar64Vec3::new(
|
||||||
(v0.y-v1.y)*(v0.z+v1.z),
|
(v0.y()-v1.y())*(v0.z()+v1.z()),
|
||||||
(v0.z-v1.z)*(v0.x+v1.x),
|
(v0.z()-v1.z())*(v0.x()+v1.x()),
|
||||||
(v0.x-v1.x)*(v0.y+v1.y),
|
(v0.x()-v1.x())*(v0.y()+v1.y()),
|
||||||
]);
|
);
|
||||||
//get/create edge and push face into it
|
//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_verts,is_sorted)=EdgeRefVerts::new(submesh_vert0_id,submesh_vert1_id);
|
||||||
let (edge_ref_faces,edge_id)=edge_pool.push(edge_ref_verts);
|
let (edge_ref_faces,edge_id)=edge_pool.push(edge_ref_verts);
|
||||||
@ -366,16 +362,14 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
|
|||||||
//return directed_edge_id
|
//return directed_edge_id
|
||||||
edge_id.as_directed(is_sorted)
|
edge_id.as_directed(is_sorted)
|
||||||
}).collect();
|
}).collect();
|
||||||
let mut dot=Fixed::ZERO;
|
//choose precision loss randomly idk
|
||||||
// find the average dot
|
normal=normal/len as i64;
|
||||||
|
let mut dot=Planar64::ZERO;
|
||||||
for &v in poly_vertices{
|
for &v in poly_vertices{
|
||||||
dot+=normal.dot(mesh.unique_pos[mesh.unique_vertices[v.get() as usize].pos.get() as usize]);
|
dot+=normal.dot(mesh.unique_pos[mesh.unique_vertices[v.get() as usize].pos.get() as usize]);
|
||||||
}
|
}
|
||||||
//assume face hash is stable, and there are no flush faces...
|
//assume face hash is stable, and there are no flush faces...
|
||||||
let face=Face{
|
let face=Face{normal,dot:dot/len as i64};
|
||||||
normal:(normal/len as i64).divide().fix_1(),
|
|
||||||
dot:(dot/(len*len) as i64).fix_1(),
|
|
||||||
};
|
|
||||||
let face_id=match face_id_from_face.get(&face){
|
let face_id=match face_id_from_face.get(&face){
|
||||||
Some(&face_id)=>face_id,
|
Some(&face_id)=>face_id,
|
||||||
None=>{
|
None=>{
|
||||||
@ -422,8 +416,6 @@ pub struct PhysicsMeshView<'a>{
|
|||||||
topology:&'a PhysicsMeshTopology,
|
topology:&'a PhysicsMeshTopology,
|
||||||
}
|
}
|
||||||
impl MeshQuery<SubmeshFaceId,SubmeshDirectedEdgeId,SubmeshVertId> for PhysicsMeshView<'_>{
|
impl MeshQuery<SubmeshFaceId,SubmeshDirectedEdgeId,SubmeshVertId> for PhysicsMeshView<'_>{
|
||||||
type Normal=Planar64Vec3;
|
|
||||||
type Offset=Planar64;
|
|
||||||
fn face_nd(&self,face_id:SubmeshFaceId)->(Planar64Vec3,Planar64){
|
fn face_nd(&self,face_id:SubmeshFaceId)->(Planar64Vec3,Planar64){
|
||||||
let face_idx=self.topology.faces[face_id.get() as usize].get() as usize;
|
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)
|
(self.data.faces[face_idx].normal,self.data.faces[face_idx].dot)
|
||||||
@ -452,14 +444,14 @@ impl MeshQuery<SubmeshFaceId,SubmeshDirectedEdgeId,SubmeshVertId> for PhysicsMes
|
|||||||
|
|
||||||
pub struct PhysicsMeshTransform{
|
pub struct PhysicsMeshTransform{
|
||||||
pub vertex:integer::Planar64Affine3,
|
pub vertex:integer::Planar64Affine3,
|
||||||
pub normal:integer::mat3::Matrix3<Fixed<2,64>>,
|
pub normal:integer::Planar64Mat3,
|
||||||
pub det:Fixed<3,96>,
|
pub det:Planar64,
|
||||||
}
|
}
|
||||||
impl PhysicsMeshTransform{
|
impl PhysicsMeshTransform{
|
||||||
pub fn new(transform:integer::Planar64Affine3)->Self{
|
pub const fn new(transform:integer::Planar64Affine3)->Self{
|
||||||
Self{
|
Self{
|
||||||
normal:transform.matrix3.adjugate().transpose(),
|
normal:transform.matrix3.inverse_times_det().transpose(),
|
||||||
det:transform.matrix3.det(),
|
det:transform.matrix3.determinant(),
|
||||||
vertex:transform,
|
vertex:transform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,7 +462,7 @@ pub struct TransformedMesh<'a>{
|
|||||||
transform:&'a PhysicsMeshTransform,
|
transform:&'a PhysicsMeshTransform,
|
||||||
}
|
}
|
||||||
impl TransformedMesh<'_>{
|
impl TransformedMesh<'_>{
|
||||||
pub const fn new<'a>(
|
pub fn new<'a>(
|
||||||
view:PhysicsMeshView<'a>,
|
view:PhysicsMeshView<'a>,
|
||||||
transform:&'a PhysicsMeshTransform,
|
transform:&'a PhysicsMeshTransform,
|
||||||
)->TransformedMesh<'a>{
|
)->TransformedMesh<'a>{
|
||||||
@ -479,33 +471,33 @@ impl TransformedMesh<'_>{
|
|||||||
transform,
|
transform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn verts<'a>(&'a self)->impl Iterator<Item=vec3::Vector3<Fixed<2,64>>>+'a{
|
pub fn verts<'a>(&'a self)->impl Iterator<Item=Planar64Vec3>+'a{
|
||||||
self.view.data.verts.iter().map(|&Vert(pos)|self.transform.vertex.transform_point3(pos))
|
self.view.data.verts.iter().map(|&Vert(pos)|self.transform.vertex.transform_point3(pos))
|
||||||
}
|
}
|
||||||
fn farthest_vert(&self,dir:Planar64Vec3)->SubmeshVertId{
|
fn farthest_vert(&self,dir:Planar64Vec3)->SubmeshVertId{
|
||||||
|
let mut best_dot=Planar64::MIN;
|
||||||
|
let mut best_vert=SubmeshVertId(0);
|
||||||
//this happens to be well-defined. there are no virtual virtices
|
//this happens to be well-defined. there are no virtual virtices
|
||||||
SubmeshVertId::new(
|
for (i,vert_id) in self.view.topology.verts.iter().enumerate(){
|
||||||
self.view.topology.verts.iter()
|
let p=self.transform.vertex.transform_point3(self.view.data.verts[vert_id.get() as usize].0);
|
||||||
.enumerate()
|
let d=dir.dot(p);
|
||||||
.max_by_key(|(_,&vert_id)|
|
if best_dot<d{
|
||||||
dir.dot(self.transform.vertex.transform_point3(self.view.data.verts[vert_id.get() as usize].0))
|
best_dot=d;
|
||||||
)
|
best_vert=SubmeshVertId::new(i as u32);
|
||||||
//assume there is more than zero vertices.
|
}
|
||||||
.unwrap().0 as u32
|
}
|
||||||
)
|
best_vert
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MeshQuery<SubmeshFaceId,SubmeshDirectedEdgeId,SubmeshVertId> for TransformedMesh<'_>{
|
impl MeshQuery<SubmeshFaceId,SubmeshDirectedEdgeId,SubmeshVertId> for TransformedMesh<'_>{
|
||||||
type Normal=Vector3<Fixed<3,96>>;
|
fn face_nd(&self,face_id:SubmeshFaceId)->(Planar64Vec3,Planar64){
|
||||||
type Offset=Fixed<4,128>;
|
|
||||||
fn face_nd(&self,face_id:SubmeshFaceId)->(Self::Normal,Self::Offset){
|
|
||||||
let (n,d)=self.view.face_nd(face_id);
|
let (n,d)=self.view.face_nd(face_id);
|
||||||
let transformed_n=self.transform.normal*n;
|
let transformed_n=self.transform.normal*n;
|
||||||
let transformed_d=d*self.transform.det+transformed_n.dot(self.transform.vertex.translation);
|
let transformed_d=d+transformed_n.dot(self.transform.vertex.translation)/self.transform.det;
|
||||||
(transformed_n,transformed_d)
|
(transformed_n/self.transform.det,transformed_d)
|
||||||
}
|
}
|
||||||
fn vert(&self,vert_id:SubmeshVertId)->Planar64Vec3{
|
fn vert(&self,vert_id:SubmeshVertId)->Planar64Vec3{
|
||||||
self.transform.vertex.transform_point3(self.view.vert(vert_id)).fix_1()
|
self.transform.vertex.transform_point3(self.view.vert(vert_id))
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn face_edges(&self,face_id:SubmeshFaceId)->Cow<Vec<SubmeshDirectedEdgeId>>{
|
fn face_edges(&self,face_id:SubmeshFaceId)->Cow<Vec<SubmeshDirectedEdgeId>>{
|
||||||
@ -533,11 +525,11 @@ impl MeshQuery<SubmeshFaceId,SubmeshDirectedEdgeId,SubmeshVertId> for Transforme
|
|||||||
//(face,vertex)
|
//(face,vertex)
|
||||||
//(edge,edge)
|
//(edge,edge)
|
||||||
//(vertex,face)
|
//(vertex,face)
|
||||||
#[derive(Clone,Copy,Debug)]
|
#[derive(Clone,Copy)]
|
||||||
pub enum MinkowskiVert{
|
pub enum MinkowskiVert{
|
||||||
VertVert(SubmeshVertId,SubmeshVertId),
|
VertVert(SubmeshVertId,SubmeshVertId),
|
||||||
}
|
}
|
||||||
#[derive(Clone,Copy,Debug)]
|
#[derive(Clone,Copy)]
|
||||||
pub enum MinkowskiEdge{
|
pub enum MinkowskiEdge{
|
||||||
VertEdge(SubmeshVertId,SubmeshEdgeId),
|
VertEdge(SubmeshVertId,SubmeshEdgeId),
|
||||||
EdgeVert(SubmeshEdgeId,SubmeshVertId),
|
EdgeVert(SubmeshEdgeId,SubmeshVertId),
|
||||||
@ -552,7 +544,7 @@ impl UndirectedEdge for MinkowskiEdge{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Clone,Copy,Debug)]
|
#[derive(Clone,Copy)]
|
||||||
pub enum MinkowskiDirectedEdge{
|
pub enum MinkowskiDirectedEdge{
|
||||||
VertEdge(SubmeshVertId,SubmeshDirectedEdgeId),
|
VertEdge(SubmeshVertId,SubmeshDirectedEdgeId),
|
||||||
EdgeVert(SubmeshDirectedEdgeId,SubmeshVertId),
|
EdgeVert(SubmeshDirectedEdgeId,SubmeshVertId),
|
||||||
@ -573,7 +565,7 @@ impl DirectedEdge for MinkowskiDirectedEdge{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
|
||||||
pub enum MinkowskiFace{
|
pub enum MinkowskiFace{
|
||||||
VertFace(SubmeshVertId,SubmeshFaceId),
|
VertFace(SubmeshVertId,SubmeshFaceId),
|
||||||
EdgeEdge(SubmeshEdgeId,SubmeshEdgeId,bool),
|
EdgeEdge(SubmeshEdgeId,SubmeshEdgeId,bool),
|
||||||
@ -589,7 +581,6 @@ pub struct MinkowskiMesh<'a>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//infinity fev algorithm state transition
|
//infinity fev algorithm state transition
|
||||||
#[derive(Debug)]
|
|
||||||
enum Transition{
|
enum Transition{
|
||||||
Done,//found closest vert, no edges are better
|
Done,//found closest vert, no edges are better
|
||||||
Vert(MinkowskiVert),//transition to vert
|
Vert(MinkowskiVert),//transition to vert
|
||||||
@ -599,8 +590,6 @@ enum EV{
|
|||||||
Edge(MinkowskiEdge),
|
Edge(MinkowskiEdge),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type GigaTime=Ratio<Fixed<4,128>,Fixed<4,128>>;
|
|
||||||
|
|
||||||
impl MinkowskiMesh<'_>{
|
impl MinkowskiMesh<'_>{
|
||||||
pub fn minkowski_sum<'a>(mesh0:TransformedMesh<'a>,mesh1:TransformedMesh<'a>)->MinkowskiMesh<'a>{
|
pub fn minkowski_sum<'a>(mesh0:TransformedMesh<'a>,mesh1:TransformedMesh<'a>)->MinkowskiMesh<'a>{
|
||||||
MinkowskiMesh{
|
MinkowskiMesh{
|
||||||
@ -611,7 +600,7 @@ impl MinkowskiMesh<'_>{
|
|||||||
fn farthest_vert(&self,dir:Planar64Vec3)->MinkowskiVert{
|
fn farthest_vert(&self,dir:Planar64Vec3)->MinkowskiVert{
|
||||||
MinkowskiVert::VertVert(self.mesh0.farthest_vert(dir),self.mesh1.farthest_vert(-dir))
|
MinkowskiVert::VertVert(self.mesh0.farthest_vert(dir),self.mesh1.farthest_vert(-dir))
|
||||||
}
|
}
|
||||||
fn next_transition_vert(&self,vert_id:MinkowskiVert,best_distance_squared:&mut Fixed<2,64>,infinity_dir:Planar64Vec3,point:Planar64Vec3)->Transition{
|
fn next_transition_vert(&self,vert_id:MinkowskiVert,best_distance_squared:&mut Planar64,infinity_dir:Planar64Vec3,point:Planar64Vec3)->Transition{
|
||||||
let mut best_transition=Transition::Done;
|
let mut best_transition=Transition::Done;
|
||||||
for &directed_edge_id in self.vert_edges(vert_id).iter(){
|
for &directed_edge_id in self.vert_edges(vert_id).iter(){
|
||||||
let edge_n=self.directed_edge_n(directed_edge_id);
|
let edge_n=self.directed_edge_n(directed_edge_id);
|
||||||
@ -621,7 +610,7 @@ impl MinkowskiMesh<'_>{
|
|||||||
let test_vert_id=edge_verts[directed_edge_id.parity() as usize];
|
let test_vert_id=edge_verts[directed_edge_id.parity() as usize];
|
||||||
//test if it's closer
|
//test if it's closer
|
||||||
let diff=point-self.vert(test_vert_id);
|
let diff=point-self.vert(test_vert_id);
|
||||||
if edge_n.dot(infinity_dir).is_zero(){
|
if zeroes::zeroes1(edge_n.dot(diff),edge_n.dot(infinity_dir)).len()==0{
|
||||||
let distance_squared=diff.dot(diff);
|
let distance_squared=diff.dot(diff);
|
||||||
if distance_squared<*best_distance_squared{
|
if distance_squared<*best_distance_squared{
|
||||||
best_transition=Transition::Vert(test_vert_id);
|
best_transition=Transition::Vert(test_vert_id);
|
||||||
@ -631,21 +620,21 @@ impl MinkowskiMesh<'_>{
|
|||||||
}
|
}
|
||||||
best_transition
|
best_transition
|
||||||
}
|
}
|
||||||
fn final_ev(&self,vert_id:MinkowskiVert,best_distance_squared:&mut Fixed<2,64>,infinity_dir:Planar64Vec3,point:Planar64Vec3)->EV{
|
fn final_ev(&self,vert_id:MinkowskiVert,best_distance_squared:&mut Planar64,infinity_dir:Planar64Vec3,point:Planar64Vec3)->EV{
|
||||||
let mut best_transition=EV::Vert(vert_id);
|
let mut best_transition=EV::Vert(vert_id);
|
||||||
let diff=point-self.vert(vert_id);
|
let diff=point-self.vert(vert_id);
|
||||||
for &directed_edge_id in self.vert_edges(vert_id).iter(){
|
for &directed_edge_id in self.vert_edges(vert_id).iter(){
|
||||||
let edge_n=self.directed_edge_n(directed_edge_id);
|
let edge_n=self.directed_edge_n(directed_edge_id);
|
||||||
//is boundary uncrossable by a crawl from infinity
|
//is boundary uncrossable by a crawl from infinity
|
||||||
//check if time of collision is outside Time::MIN..Time::MAX
|
//check if time of collision is outside Time::MIN..Time::MAX
|
||||||
if edge_n.dot(infinity_dir).is_zero(){
|
|
||||||
let d=edge_n.dot(diff);
|
let d=edge_n.dot(diff);
|
||||||
|
if zeroes::zeroes1(d,edge_n.dot(infinity_dir)).len()==0{
|
||||||
//test the edge
|
//test the edge
|
||||||
let edge_nn=edge_n.dot(edge_n);
|
let edge_nn=edge_n.dot(edge_n);
|
||||||
if !d.is_negative()&&d<=edge_nn{
|
if Planar64::ZERO<=d&&d<=edge_nn{
|
||||||
let distance_squared={
|
let distance_squared={
|
||||||
let c=diff.cross(edge_n);
|
let c=diff.cross(edge_n);
|
||||||
(c.dot(c)/edge_nn).divide().fix_2()
|
c.dot(c)/edge_nn
|
||||||
};
|
};
|
||||||
if distance_squared<=*best_distance_squared{
|
if distance_squared<=*best_distance_squared{
|
||||||
best_transition=EV::Edge(directed_edge_id.as_undirected());
|
best_transition=EV::Edge(directed_edge_id.as_undirected());
|
||||||
@ -691,7 +680,7 @@ impl MinkowskiMesh<'_>{
|
|||||||
let boundary_d=boundary_n.dot(delta_pos);
|
let boundary_d=boundary_n.dot(delta_pos);
|
||||||
//check if time of collision is outside Time::MIN..Time::MAX
|
//check if time of collision is outside Time::MIN..Time::MAX
|
||||||
//infinity_dir can always be treated as a velocity
|
//infinity_dir can always be treated as a velocity
|
||||||
if !boundary_d.is_positive()&&boundary_n.dot(infinity_dir).is_zero(){
|
if (boundary_d)<=Planar64::ZERO&&zeroes::zeroes1(boundary_d,boundary_n.dot(infinity_dir)*2).len()==0{
|
||||||
//both faces cannot pass this condition, return early if one does.
|
//both faces cannot pass this condition, return early if one does.
|
||||||
return FEV::<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>::Face(face_id);
|
return FEV::<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>::Face(face_id);
|
||||||
}
|
}
|
||||||
@ -705,16 +694,15 @@ impl MinkowskiMesh<'_>{
|
|||||||
let infinity_fev=self.infinity_fev(-dir,infinity_body.position);
|
let infinity_fev=self.infinity_fev(-dir,infinity_body.position);
|
||||||
//a line is simpler to solve than a parabola
|
//a line is simpler to solve than a parabola
|
||||||
infinity_body.velocity=dir;
|
infinity_body.velocity=dir;
|
||||||
infinity_body.acceleration=vec3::ZERO;
|
infinity_body.acceleration=Planar64Vec3::ZERO;
|
||||||
//crawl in from negative infinity along a tangent line to get the closest fev
|
//crawl in from negative infinity along a tangent line to get the closest fev
|
||||||
// TODO: change crawl_fev args to delta time? Optional values?
|
match crate::face_crawler::crawl_fev(infinity_fev,self,&infinity_body,integer::Time::MIN,infinity_body.time){
|
||||||
match crate::face_crawler::crawl_fev(infinity_fev,self,&infinity_body,integer::Time::MIN/4,infinity_body.time){
|
|
||||||
crate::face_crawler::CrawlResult::Miss(fev)=>Some(fev),
|
crate::face_crawler::CrawlResult::Miss(fev)=>Some(fev),
|
||||||
crate::face_crawler::CrawlResult::Hit(_,_)=>None,
|
crate::face_crawler::CrawlResult::Hit(_,_)=>None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn predict_collision_in(&self,relative_body:&crate::physics::Body,time_limit:integer::Time)->Option<(MinkowskiFace,GigaTime)>{
|
pub fn predict_collision_in(&self,relative_body:&crate::physics::Body,time_limit:integer::Time)->Option<(MinkowskiFace,integer::Time)>{
|
||||||
self.closest_fev_not_inside(relative_body.clone()).map_or(None,|fev|{
|
self.closest_fev_not_inside(relative_body.clone()).map_or(None,|fev|{
|
||||||
//continue forwards along the body parabola
|
//continue forwards along the body parabola
|
||||||
match crate::face_crawler::crawl_fev(fev,self,relative_body,relative_body.time,time_limit){
|
match crate::face_crawler::crawl_fev(fev,self,relative_body,relative_body.time,time_limit){
|
||||||
@ -723,7 +711,7 @@ impl MinkowskiMesh<'_>{
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn predict_collision_out(&self,relative_body:&crate::physics::Body,time_limit:integer::Time)->Option<(MinkowskiFace,GigaTime)>{
|
pub fn predict_collision_out(&self,relative_body:&crate::physics::Body,time_limit:integer::Time)->Option<(MinkowskiFace,integer::Time)>{
|
||||||
//create an extrapolated body at time_limit
|
//create an extrapolated body at time_limit
|
||||||
let infinity_body=crate::physics::Body::new(
|
let infinity_body=crate::physics::Body::new(
|
||||||
relative_body.extrapolated_position(time_limit),
|
relative_body.extrapolated_position(time_limit),
|
||||||
@ -739,13 +727,10 @@ impl MinkowskiMesh<'_>{
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn predict_collision_face_out(&self,relative_body:&crate::physics::Body,time_limit:integer::Time,contact_face_id:MinkowskiFace)->Option<(MinkowskiEdge,GigaTime)>{
|
pub fn predict_collision_face_out(&self,relative_body:&crate::physics::Body,time_limit:integer::Time,contact_face_id:MinkowskiFace)->Option<(MinkowskiEdge,integer::Time)>{
|
||||||
//no algorithm needed, there is only one state and two cases (Edge,None)
|
//no algorithm needed, there is only one state and two cases (Edge,None)
|
||||||
//determine when it passes an edge ("sliding off" case)
|
//determine when it passes an edge ("sliding off" case)
|
||||||
let mut best_time={
|
let mut best_time=time_limit;
|
||||||
let r=(time_limit-relative_body.time).to_ratio();
|
|
||||||
Ratio::new(r.num.fix_4(),r.den.fix_4())
|
|
||||||
};
|
|
||||||
let mut best_edge=None;
|
let mut best_edge=None;
|
||||||
let face_n=self.face_nd(contact_face_id).0;
|
let face_n=self.face_nd(contact_face_id).0;
|
||||||
for &directed_edge_id in self.face_edges(contact_face_id).iter(){
|
for &directed_edge_id in self.face_edges(contact_face_id).iter(){
|
||||||
@ -755,10 +740,10 @@ impl MinkowskiMesh<'_>{
|
|||||||
let verts=self.edge_verts(directed_edge_id.as_undirected());
|
let verts=self.edge_verts(directed_edge_id.as_undirected());
|
||||||
let d=n.dot(self.vert(verts[0])+self.vert(verts[1]));
|
let d=n.dot(self.vert(verts[0])+self.vert(verts[1]));
|
||||||
//WARNING! d outside of *2
|
//WARNING! d outside of *2
|
||||||
//WARNING: truncated precision
|
for t in zeroes::zeroes2((n.dot(relative_body.position))*2-d,n.dot(relative_body.velocity)*2,n.dot(relative_body.acceleration)){
|
||||||
for dt in Fixed::<4,128>::zeroes2(((n.dot(relative_body.position))*2-d).fix_4(),n.dot(relative_body.velocity).fix_4()*2,n.dot(relative_body.acceleration).fix_4()){
|
let t=relative_body.time+integer::Time::from(t);
|
||||||
if Ratio::new(Planar64::ZERO,Planar64::EPSILON).le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(relative_body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
if relative_body.time<t&&t<best_time&&n.dot(relative_body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_time=dt;
|
best_time=t;
|
||||||
best_edge=Some(directed_edge_id);
|
best_edge=Some(directed_edge_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -766,15 +751,15 @@ impl MinkowskiMesh<'_>{
|
|||||||
}
|
}
|
||||||
best_edge.map(|e|(e.as_undirected(),best_time))
|
best_edge.map(|e|(e.as_undirected(),best_time))
|
||||||
}
|
}
|
||||||
fn infinity_in(&self,infinity_body:crate::physics::Body)->Option<(MinkowskiFace,GigaTime)>{
|
fn infinity_in(&self,infinity_body:crate::physics::Body)->Option<(MinkowskiFace,integer::Time)>{
|
||||||
let infinity_fev=self.infinity_fev(-infinity_body.velocity,infinity_body.position);
|
let infinity_fev=self.infinity_fev(-infinity_body.velocity,infinity_body.position);
|
||||||
match crate::face_crawler::crawl_fev(infinity_fev,self,&infinity_body,integer::Time::MIN/4,infinity_body.time){
|
match crate::face_crawler::crawl_fev(infinity_fev,self,&infinity_body,integer::Time::MIN,infinity_body.time){
|
||||||
crate::face_crawler::CrawlResult::Miss(_)=>None,
|
crate::face_crawler::CrawlResult::Miss(_)=>None,
|
||||||
crate::face_crawler::CrawlResult::Hit(face,time)=>Some((face,time)),
|
crate::face_crawler::CrawlResult::Hit(face,time)=>Some((face,time)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_point_in_mesh(&self,point:Planar64Vec3)->bool{
|
pub fn is_point_in_mesh(&self,point:Planar64Vec3)->bool{
|
||||||
let infinity_body=crate::physics::Body::new(point,vec3::Y,vec3::ZERO,integer::Time::ZERO);
|
let infinity_body=crate::physics::Body::new(point,Planar64Vec3::Y,Planar64Vec3::ZERO,integer::Time::ZERO);
|
||||||
//movement must escape the mesh forwards and backwards in time,
|
//movement must escape the mesh forwards and backwards in time,
|
||||||
//otherwise the point is not inside the mesh
|
//otherwise the point is not inside the mesh
|
||||||
self.infinity_in(infinity_body)
|
self.infinity_in(infinity_body)
|
||||||
@ -785,9 +770,7 @@ impl MinkowskiMesh<'_>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MeshQuery<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert> for MinkowskiMesh<'_>{
|
impl MeshQuery<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert> for MinkowskiMesh<'_>{
|
||||||
type Normal=Vector3<Fixed<3,96>>;
|
fn face_nd(&self,face_id:MinkowskiFace)->(Planar64Vec3,Planar64){
|
||||||
type Offset=Fixed<4,128>;
|
|
||||||
fn face_nd(&self,face_id:MinkowskiFace)->(Self::Normal,Self::Offset){
|
|
||||||
match face_id{
|
match face_id{
|
||||||
MinkowskiFace::VertFace(v0,f1)=>{
|
MinkowskiFace::VertFace(v0,f1)=>{
|
||||||
let (n,d)=self.mesh1.face_nd(f1);
|
let (n,d)=self.mesh1.face_nd(f1);
|
||||||
@ -801,7 +784,7 @@ impl MeshQuery<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert> for MinkowskiM
|
|||||||
let n=edge0_n.cross(edge1_n);
|
let n=edge0_n.cross(edge1_n);
|
||||||
let e0d=n.dot(self.mesh0.vert(e0v0)+self.mesh0.vert(e0v1));
|
let e0d=n.dot(self.mesh0.vert(e0v0)+self.mesh0.vert(e0v1));
|
||||||
let e1d=n.dot(self.mesh1.vert(e1v0)+self.mesh1.vert(e1v1));
|
let e1d=n.dot(self.mesh1.vert(e1v0)+self.mesh1.vert(e1v1));
|
||||||
((n*(parity as i64*4-2)).fix_3(),((e0d-e1d)*(parity as i64*2-1)).fix_4())
|
(n*(parity as i64*4-2),(e0d-e1d)*(parity as i64*2-1))
|
||||||
},
|
},
|
||||||
MinkowskiFace::FaceVert(f0,v1)=>{
|
MinkowskiFace::FaceVert(f0,v1)=>{
|
||||||
let (n,d)=self.mesh0.face_nd(f0);
|
let (n,d)=self.mesh0.face_nd(f0);
|
||||||
@ -850,18 +833,17 @@ impl MeshQuery<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert> for MinkowskiM
|
|||||||
let &[e1f0,e1f1]=self.mesh1.edge_faces(e1).borrow();
|
let &[e1f0,e1f1]=self.mesh1.edge_faces(e1).borrow();
|
||||||
Cow::Owned([(e1f1,false),(e1f0,true)].map(|(edge_face_id1,face_parity)|{
|
Cow::Owned([(e1f1,false),(e1f0,true)].map(|(edge_face_id1,face_parity)|{
|
||||||
let mut best_edge=None;
|
let mut best_edge=None;
|
||||||
let mut best_d:Ratio<Fixed<8,256>,Fixed<8,256>>=Ratio::new(Fixed::ZERO,Fixed::ONE);
|
let mut best_d=Planar64::ZERO;
|
||||||
let edge_face1_n=self.mesh1.face_nd(edge_face_id1).0;
|
let edge_face1_n=self.mesh1.face_nd(edge_face_id1).0;
|
||||||
let edge_face1_nn=edge_face1_n.dot(edge_face1_n);
|
let edge_face1_nn=edge_face1_n.dot(edge_face1_n);
|
||||||
for &directed_edge_id0 in v0e.iter(){
|
for &directed_edge_id0 in v0e.iter(){
|
||||||
let edge0_n=self.mesh0.directed_edge_n(directed_edge_id0);
|
let edge0_n=self.mesh0.directed_edge_n(directed_edge_id0);
|
||||||
//must be behind other face.
|
//must be behind other face.
|
||||||
let d=edge_face1_n.dot(edge0_n);
|
let d=edge_face1_n.dot(edge0_n);
|
||||||
if d.is_negative(){
|
if d<Planar64::ZERO{
|
||||||
let edge0_nn=edge0_n.dot(edge0_n);
|
let edge0_nn=edge0_n.dot(edge0_n);
|
||||||
// Assume not every number is huge
|
//divide by zero???
|
||||||
// TODO: revisit this
|
let dd=d*d/(edge_face1_nn*edge0_nn);
|
||||||
let dd=(d*d)/(edge_face1_nn*edge0_nn);
|
|
||||||
if best_d<dd{
|
if best_d<dd{
|
||||||
best_d=dd;
|
best_d=dd;
|
||||||
best_edge=Some(directed_edge_id0);
|
best_edge=Some(directed_edge_id0);
|
||||||
@ -880,15 +862,15 @@ impl MeshQuery<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert> for MinkowskiM
|
|||||||
let &[e0f0,e0f1]=self.mesh0.edge_faces(e0).borrow();
|
let &[e0f0,e0f1]=self.mesh0.edge_faces(e0).borrow();
|
||||||
Cow::Owned([(e0f0,true),(e0f1,false)].map(|(edge_face_id0,face_parity)|{
|
Cow::Owned([(e0f0,true),(e0f1,false)].map(|(edge_face_id0,face_parity)|{
|
||||||
let mut best_edge=None;
|
let mut best_edge=None;
|
||||||
let mut best_d:Ratio<Fixed<8,256>,Fixed<8,256>>=Ratio::new(Fixed::ZERO,Fixed::ONE);
|
let mut best_d=Planar64::ZERO;
|
||||||
let edge_face0_n=self.mesh0.face_nd(edge_face_id0).0;
|
let edge_face0_n=self.mesh0.face_nd(edge_face_id0).0;
|
||||||
let edge_face0_nn=edge_face0_n.dot(edge_face0_n);
|
let edge_face0_nn=edge_face0_n.dot(edge_face0_n);
|
||||||
for &directed_edge_id1 in v1e.iter(){
|
for &directed_edge_id1 in v1e.iter(){
|
||||||
let edge1_n=self.mesh1.directed_edge_n(directed_edge_id1);
|
let edge1_n=self.mesh1.directed_edge_n(directed_edge_id1);
|
||||||
let d=edge_face0_n.dot(edge1_n);
|
let d=edge_face0_n.dot(edge1_n);
|
||||||
if d.is_negative(){
|
if d<Planar64::ZERO{
|
||||||
let edge1_nn=edge1_n.dot(edge1_n);
|
let edge1_nn=edge1_n.dot(edge1_n);
|
||||||
let dd=(d*d)/(edge_face0_nn*edge1_nn);
|
let dd=d*d/(edge_face0_nn*edge1_nn);
|
||||||
if best_d<dd{
|
if best_d<dd{
|
||||||
best_d=dd;
|
best_d=dd;
|
||||||
best_edge=Some(directed_edge_id1);
|
best_edge=Some(directed_edge_id1);
|
||||||
@ -924,20 +906,19 @@ impl MeshQuery<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert> for MinkowskiM
|
|||||||
//detect shared volume when the other mesh is mirrored along a test edge dir
|
//detect shared volume when the other mesh is mirrored along a test edge dir
|
||||||
let v0f=self.mesh0.vert_faces(v0);
|
let v0f=self.mesh0.vert_faces(v0);
|
||||||
let v1f=self.mesh1.vert_faces(v1);
|
let v1f=self.mesh1.vert_faces(v1);
|
||||||
let v0f_n:Vec<_>=v0f.iter().map(|&face_id|self.mesh0.face_nd(face_id).0).collect();
|
let v0f_n:Vec<Planar64Vec3>=v0f.iter().map(|&face_id|self.mesh0.face_nd(face_id).0).collect();
|
||||||
let v1f_n:Vec<_>=v1f.iter().map(|&face_id|self.mesh1.face_nd(face_id).0).collect();
|
let v1f_n:Vec<Planar64Vec3>=v1f.iter().map(|&face_id|self.mesh1.face_nd(face_id).0).collect();
|
||||||
let the_len=v0f.len()+v1f.len();
|
let the_len=v0f.len()+v1f.len();
|
||||||
for &directed_edge_id in self.mesh0.vert_edges(v0).iter(){
|
for &directed_edge_id in self.mesh0.vert_edges(v0).iter(){
|
||||||
let n=self.mesh0.directed_edge_n(directed_edge_id);
|
let n=self.mesh0.directed_edge_n(directed_edge_id);
|
||||||
let nn=n.dot(n);
|
let nn=n.dot(n);
|
||||||
// TODO: there's gotta be a better way to do this
|
|
||||||
//make a set of faces
|
//make a set of faces
|
||||||
let mut face_normals=Vec::with_capacity(the_len);
|
let mut face_normals=Vec::with_capacity(the_len);
|
||||||
//add mesh0 faces as-is
|
//add mesh0 faces as-is
|
||||||
face_normals.clone_from(&v0f_n);
|
face_normals.clone_from(&v0f_n);
|
||||||
for face_n in &v1f_n{
|
for face_n in &v1f_n{
|
||||||
//add reflected mesh1 faces
|
//add reflected mesh1 faces
|
||||||
face_normals.push(*face_n-(n*face_n.dot(n)*2/nn).divide().fix_3());
|
face_normals.push(*face_n-n*(face_n.dot(n)*2/nn));
|
||||||
}
|
}
|
||||||
if is_empty_volume(face_normals){
|
if is_empty_volume(face_normals){
|
||||||
edges.push(MinkowskiDirectedEdge::EdgeVert(directed_edge_id,v1));
|
edges.push(MinkowskiDirectedEdge::EdgeVert(directed_edge_id,v1));
|
||||||
@ -949,7 +930,7 @@ impl MeshQuery<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert> for MinkowskiM
|
|||||||
let mut face_normals=Vec::with_capacity(the_len);
|
let mut face_normals=Vec::with_capacity(the_len);
|
||||||
face_normals.clone_from(&v1f_n);
|
face_normals.clone_from(&v1f_n);
|
||||||
for face_n in &v0f_n{
|
for face_n in &v0f_n{
|
||||||
face_normals.push(*face_n-(n*face_n.dot(n)*2/nn).divide().fix_3());
|
face_normals.push(*face_n-n*(face_n.dot(n)*2/nn));
|
||||||
}
|
}
|
||||||
if is_empty_volume(face_normals){
|
if is_empty_volume(face_normals){
|
||||||
edges.push(MinkowskiDirectedEdge::VertEdge(v0,directed_edge_id));
|
edges.push(MinkowskiDirectedEdge::VertEdge(v0,directed_edge_id));
|
||||||
@ -964,7 +945,7 @@ impl MeshQuery<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert> for MinkowskiM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty_volume(normals:Vec<Vector3<Fixed<3,96>>>)->bool{
|
fn is_empty_volume(normals:Vec<Planar64Vec3>)->bool{
|
||||||
let len=normals.len();
|
let len=normals.len();
|
||||||
for i in 0..len-1{
|
for i in 0..len-1{
|
||||||
for j in i+1..len{
|
for j in i+1..len{
|
||||||
@ -972,10 +953,9 @@ fn is_empty_volume(normals:Vec<Vector3<Fixed<3,96>>>)->bool{
|
|||||||
let mut d_comp=None;
|
let mut d_comp=None;
|
||||||
for k in 0..len{
|
for k in 0..len{
|
||||||
if k!=i&&k!=j{
|
if k!=i&&k!=j{
|
||||||
let d=n.dot(normals[k]).is_negative();
|
let d=n.dot(normals[k]);
|
||||||
if let Some(comp)=&d_comp{
|
if let Some(comp)=&d_comp{
|
||||||
// This is testing if d_comp*d < 0
|
if *comp*d<Planar64::ZERO{
|
||||||
if comp^d{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@ -990,8 +970,8 @@ fn is_empty_volume(normals:Vec<Vector3<Fixed<3,96>>>)->bool{
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_empty_volume(){
|
fn test_is_empty_volume(){
|
||||||
assert!(!is_empty_volume([vec3::X.fix_3(),vec3::Y.fix_3(),vec3::Z.fix_3()].to_vec()));
|
assert!(!is_empty_volume([Planar64Vec3::X,Planar64Vec3::Y,Planar64Vec3::Z].to_vec()));
|
||||||
assert!(is_empty_volume([vec3::X.fix_3(),vec3::Y.fix_3(),vec3::Z.fix_3(),vec3::NEG_X.fix_3()].to_vec()));
|
assert!(is_empty_volume([Planar64Vec3::X,Planar64Vec3::Y,Planar64Vec3::Z,Planar64Vec3::NEG_X].to_vec()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
414
src/physics.rs
414
src/physics.rs
@ -11,7 +11,7 @@ use strafesnet_common::gameplay_modes::{self,StageId};
|
|||||||
use strafesnet_common::gameplay_style::{self,StyleModifiers};
|
use strafesnet_common::gameplay_style::{self,StyleModifiers};
|
||||||
use strafesnet_common::controls_bitflag::Controls;
|
use strafesnet_common::controls_bitflag::Controls;
|
||||||
use strafesnet_common::instruction::{self,InstructionEmitter,InstructionConsumer,TimedInstruction};
|
use strafesnet_common::instruction::{self,InstructionEmitter,InstructionConsumer,TimedInstruction};
|
||||||
use strafesnet_common::integer::{self,vec3,mat3,Time,Planar64,Planar64Vec3,Planar64Mat3,Angle32,Ratio64Vec2};
|
use strafesnet_common::integer::{self,Time,Planar64,Planar64Vec3,Planar64Mat3,Angle32,Ratio64Vec2};
|
||||||
use gameplay::ModeState;
|
use gameplay::ModeState;
|
||||||
|
|
||||||
//external influence
|
//external influence
|
||||||
@ -22,8 +22,8 @@ use strafesnet_common::physics::Instruction as PhysicsInputInstruction;
|
|||||||
//when the physics asks itself what happens next, this is how it's represented
|
//when the physics asks itself what happens next, this is how it's represented
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum PhysicsInternalInstruction{
|
enum PhysicsInternalInstruction{
|
||||||
CollisionStart(Collision,model_physics::GigaTime),
|
CollisionStart(Collision),
|
||||||
CollisionEnd(Collision,model_physics::GigaTime),
|
CollisionEnd(Collision),
|
||||||
StrafeTick,
|
StrafeTick,
|
||||||
ReachWalkTargetVelocity,
|
ReachWalkTargetVelocity,
|
||||||
// Water,
|
// Water,
|
||||||
@ -36,7 +36,7 @@ enum PhysicsInstruction{
|
|||||||
Input(PhysicsInputInstruction),
|
Input(PhysicsInputInstruction),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone,Copy,Debug,Hash)]
|
#[derive(Clone,Copy,Debug,Default,Hash)]
|
||||||
pub struct Body{
|
pub struct Body{
|
||||||
pub position:Planar64Vec3,//I64 where 2^32 = 1 u
|
pub position:Planar64Vec3,//I64 where 2^32 = 1 u
|
||||||
pub velocity:Planar64Vec3,//I64 where 2^32 = 1 u/s
|
pub velocity:Planar64Vec3,//I64 where 2^32 = 1 u/s
|
||||||
@ -124,13 +124,13 @@ struct ContactMoveState{
|
|||||||
}
|
}
|
||||||
impl TransientAcceleration{
|
impl TransientAcceleration{
|
||||||
fn with_target_diff(target_diff:Planar64Vec3,accel:Planar64,time:Time)->Self{
|
fn with_target_diff(target_diff:Planar64Vec3,accel:Planar64,time:Time)->Self{
|
||||||
if target_diff==vec3::ZERO{
|
if target_diff==Planar64Vec3::ZERO{
|
||||||
TransientAcceleration::Reached
|
TransientAcceleration::Reached
|
||||||
}else{
|
}else{
|
||||||
//normal friction acceleration is clippedAcceleration.dot(normal)*friction
|
//normal friction acceleration is clippedAcceleration.dot(normal)*friction
|
||||||
TransientAcceleration::Reachable{
|
TransientAcceleration::Reachable{
|
||||||
acceleration:target_diff.with_length(accel).divide().fix_1(),
|
acceleration:target_diff.with_length(accel),
|
||||||
time:time+Time::from((target_diff.length()/accel).divide().fix_1())
|
time:time+Time::from(target_diff.length()/accel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ impl TransientAcceleration{
|
|||||||
}
|
}
|
||||||
fn acceleration(&self)->Planar64Vec3{
|
fn acceleration(&self)->Planar64Vec3{
|
||||||
match self{
|
match self{
|
||||||
TransientAcceleration::Reached=>vec3::ZERO,
|
TransientAcceleration::Reached=>Planar64Vec3::ZERO,
|
||||||
&TransientAcceleration::Reachable{acceleration,time:_}=>acceleration,
|
&TransientAcceleration::Reachable{acceleration,time:_}=>acceleration,
|
||||||
&TransientAcceleration::Unreachable{acceleration}=>acceleration,
|
&TransientAcceleration::Unreachable{acceleration}=>acceleration,
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ impl ContactMoveState{
|
|||||||
Self{
|
Self{
|
||||||
target:TransientAcceleration::ground(walk_settings,body,gravity,target_velocity),
|
target:TransientAcceleration::ground(walk_settings,body,gravity,target_velocity),
|
||||||
contact,
|
contact,
|
||||||
jump_direction:JumpDirection::Exactly(vec3::Y),
|
jump_direction:JumpDirection::Exactly(Planar64Vec3::Y),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn ladder(ladder_settings:&gameplay_style::LadderSettings,body:&Body,gravity:Planar64Vec3,target_velocity:Planar64Vec3,contact:ContactCollision)->Self{
|
fn ladder(ladder_settings:&gameplay_style::LadderSettings,body:&Body,gravity:Planar64Vec3,target_velocity:Planar64Vec3,contact:ContactCollision)->Self{
|
||||||
@ -296,7 +296,7 @@ impl PhysicsCamera{
|
|||||||
let ay=Angle32::clamp_from_i64(a.y)
|
let ay=Angle32::clamp_from_i64(a.y)
|
||||||
//clamp to actual vertical cam limit
|
//clamp to actual vertical cam limit
|
||||||
.clamp(Self::ANGLE_PITCH_LOWER_LIMIT,Self::ANGLE_PITCH_UPPER_LIMIT);
|
.clamp(Self::ANGLE_PITCH_LOWER_LIMIT,Self::ANGLE_PITCH_UPPER_LIMIT);
|
||||||
mat3::from_rotation_yx(ax,ay)
|
Planar64Mat3::from_rotation_yx(ax,ay)
|
||||||
}
|
}
|
||||||
fn rotation(&self)->Planar64Mat3{
|
fn rotation(&self)->Planar64Mat3{
|
||||||
self.get_rotation(self.clamped_mouse_pos)
|
self.get_rotation(self.clamped_mouse_pos)
|
||||||
@ -306,7 +306,7 @@ impl PhysicsCamera{
|
|||||||
}
|
}
|
||||||
fn get_rotation_y(&self,mouse_pos_x:i32)->Planar64Mat3{
|
fn get_rotation_y(&self,mouse_pos_x:i32)->Planar64Mat3{
|
||||||
let ax=-self.sensitivity.x.mul_int(mouse_pos_x as i64);
|
let ax=-self.sensitivity.x.mul_int(mouse_pos_x as i64);
|
||||||
mat3::from_rotation_y(Angle32::wrap_from_i64(ax))
|
Planar64Mat3::from_rotation_y(Angle32::wrap_from_i64(ax))
|
||||||
}
|
}
|
||||||
fn rotation_y(&self)->Planar64Mat3{
|
fn rotation_y(&self)->Planar64Mat3{
|
||||||
self.get_rotation_y(self.clamped_mouse_pos.x)
|
self.get_rotation_y(self.clamped_mouse_pos.x)
|
||||||
@ -410,16 +410,16 @@ impl HitboxMesh{
|
|||||||
let transform=PhysicsMeshTransform::new(transform);
|
let transform=PhysicsMeshTransform::new(transform);
|
||||||
let transformed_mesh=TransformedMesh::new(mesh.complete_mesh_view(),&transform);
|
let transformed_mesh=TransformedMesh::new(mesh.complete_mesh_view(),&transform);
|
||||||
for vert in transformed_mesh.verts(){
|
for vert in transformed_mesh.verts(){
|
||||||
aabb.grow(vert.fix_1());
|
aabb.grow(vert);
|
||||||
}
|
}
|
||||||
Self{
|
Self{
|
||||||
halfsize:aabb.size()>>1,
|
halfsize:aabb.size()/2,
|
||||||
mesh,
|
mesh,
|
||||||
transform,
|
transform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn transformed_mesh(&self)->TransformedMesh{
|
fn transformed_mesh(&self)->TransformedMesh{
|
||||||
TransformedMesh::new(self.mesh.complete_mesh_view(),&self.transform)
|
TransformedMesh::new(self.mesh.complete_mesh_view(),&self.transform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -438,7 +438,7 @@ impl StyleHelper for StyleModifiers{
|
|||||||
|
|
||||||
fn get_control_dir(&self,controls:Controls)->Planar64Vec3{
|
fn get_control_dir(&self,controls:Controls)->Planar64Vec3{
|
||||||
//don't get fancy just do it
|
//don't get fancy just do it
|
||||||
let mut control_dir:Planar64Vec3=vec3::ZERO;
|
let mut control_dir:Planar64Vec3 = Planar64Vec3::ZERO;
|
||||||
//Apply mask after held check so you can require non-allowed keys to be held for some reason
|
//Apply mask after held check so you can require non-allowed keys to be held for some reason
|
||||||
let controls=controls.intersection(self.controls_mask);
|
let controls=controls.intersection(self.controls_mask);
|
||||||
if controls.contains(Controls::MoveForward){
|
if controls.contains(Controls::MoveForward){
|
||||||
@ -463,22 +463,19 @@ impl StyleHelper for StyleModifiers{
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_y_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{
|
fn get_y_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{
|
||||||
(camera.rotation_y()*self.get_control_dir(controls)).fix_1()
|
camera.rotation_y()*self.get_control_dir(controls)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_propulsion_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{
|
fn get_propulsion_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{
|
||||||
//don't interpolate this! discrete mouse movement, constant acceleration
|
//don't interpolate this! discrete mouse movement, constant acceleration
|
||||||
(camera.rotation()*self.get_control_dir(controls)).fix_1()
|
camera.rotation()*self.get_control_dir(controls)
|
||||||
}
|
}
|
||||||
fn calculate_mesh(&self)->HitboxMesh{
|
fn calculate_mesh(&self)->HitboxMesh{
|
||||||
let mesh=match self.hitbox.mesh{
|
let mesh=match self.hitbox.mesh{
|
||||||
gameplay_style::HitboxMesh::Box=>PhysicsMesh::unit_cube(),
|
gameplay_style::HitboxMesh::Box=>PhysicsMesh::unit_cube(),
|
||||||
gameplay_style::HitboxMesh::Cylinder=>PhysicsMesh::unit_cylinder(),
|
gameplay_style::HitboxMesh::Cylinder=>PhysicsMesh::unit_cylinder(),
|
||||||
};
|
};
|
||||||
let transform=integer::Planar64Affine3::new(
|
let transform=integer::Planar64Affine3::new(Planar64Mat3::from_diagonal(self.hitbox.halfsize),Planar64Vec3::ZERO);
|
||||||
mat3::from_diagonal(self.hitbox.halfsize),
|
|
||||||
vec3::ZERO
|
|
||||||
);
|
|
||||||
HitboxMesh::new(mesh,transform)
|
HitboxMesh::new(mesh,transform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -494,7 +491,7 @@ impl MoveState{
|
|||||||
//call this after state.move_state is changed
|
//call this after state.move_state is changed
|
||||||
fn apply_enum(&self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
|
fn apply_enum(&self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){
|
||||||
match self{
|
match self{
|
||||||
MoveState::Fly=>body.acceleration=vec3::ZERO,
|
MoveState::Fly=>body.acceleration=Planar64Vec3::ZERO,
|
||||||
MoveState::Air=>{
|
MoveState::Air=>{
|
||||||
//calculate base acceleration
|
//calculate base acceleration
|
||||||
let a=touching.base_acceleration(models,style,camera,input_state);
|
let a=touching.base_acceleration(models,style,camera,input_state);
|
||||||
@ -616,6 +613,19 @@ impl MoveState{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone,Default)]
|
||||||
|
pub struct PhysicsOutputState{
|
||||||
|
body:Body,
|
||||||
|
camera:PhysicsCamera,
|
||||||
|
camera_offset:Planar64Vec3,
|
||||||
|
mouse_pos:glam::IVec2,
|
||||||
|
}
|
||||||
|
impl PhysicsOutputState{
|
||||||
|
pub fn extrapolate(&self,mouse:MouseState)->(glam::Vec3,glam::Vec2){
|
||||||
|
((self.body.extrapolated_position(mouse.time)+self.camera_offset).into(),self.camera.simulate_move_angles(mouse.pos-self.mouse_pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone,Hash,Eq,PartialEq)]
|
#[derive(Clone,Hash,Eq,PartialEq)]
|
||||||
enum PhysicsCollisionAttributes{
|
enum PhysicsCollisionAttributes{
|
||||||
Contact(gameplay_attributes::ContactAttributes),
|
Contact(gameplay_attributes::ContactAttributes),
|
||||||
@ -769,9 +779,9 @@ impl TouchingState{
|
|||||||
//TODO: trey push solve
|
//TODO: trey push solve
|
||||||
for contact in &self.contacts{
|
for contact in &self.contacts{
|
||||||
let n=contact_normal(models,hitbox_mesh,contact);
|
let n=contact_normal(models,hitbox_mesh,contact);
|
||||||
let d=n.dot(*velocity);
|
let d=n.dot128(*velocity);
|
||||||
if d.is_negative(){
|
if d<0{
|
||||||
*velocity-=(n*d/n.length_squared()).divide().fix_1();
|
*velocity-=n*Planar64::raw(((d<<32)/n.dot128(n)) as i64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -779,24 +789,23 @@ impl TouchingState{
|
|||||||
//TODO: trey push solve
|
//TODO: trey push solve
|
||||||
for contact in &self.contacts{
|
for contact in &self.contacts{
|
||||||
let n=contact_normal(models,hitbox_mesh,contact);
|
let n=contact_normal(models,hitbox_mesh,contact);
|
||||||
let d=n.dot(*acceleration);
|
let d=n.dot128(*acceleration);
|
||||||
if d.is_negative(){
|
if d<0{
|
||||||
*acceleration-=(n*d/n.length_squared()).divide().fix_1();
|
*acceleration-=n*Planar64::raw(((d<<32)/n.dot128(n)) as i64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<PhysicsInternalInstruction>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,time:Time){
|
fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<PhysicsInternalInstruction>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,time:Time){
|
||||||
let relative_body=VirtualBody::relative(&Body::ZERO,body).body(time);
|
let relative_body=VirtualBody::relative(&Body::default(),body).body(time);
|
||||||
for contact in &self.contacts{
|
for contact in &self.contacts{
|
||||||
//detect face slide off
|
//detect face slide off
|
||||||
let model_mesh=models.contact_mesh(contact);
|
let model_mesh=models.contact_mesh(contact);
|
||||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
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)|{
|
collector.collect(minkowski.predict_collision_face_out(&relative_body,collector.time(),contact.face_id).map(|(_face,time)|{
|
||||||
TimedInstruction{
|
TimedInstruction{
|
||||||
time:relative_body.time+time.into(),
|
time,
|
||||||
instruction:PhysicsInternalInstruction::CollisionEnd(
|
instruction:PhysicsInternalInstruction::CollisionEnd(
|
||||||
Collision::Contact(*contact),
|
Collision::Contact(*contact)
|
||||||
time
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -807,10 +816,9 @@ impl TouchingState{
|
|||||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
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)|{
|
collector.collect(minkowski.predict_collision_out(&relative_body,collector.time()).map(|(_face,time)|{
|
||||||
TimedInstruction{
|
TimedInstruction{
|
||||||
time:relative_body.time+time.into(),
|
time,
|
||||||
instruction:PhysicsInternalInstruction::CollisionEnd(
|
instruction:PhysicsInternalInstruction::CollisionEnd(
|
||||||
Collision::Intersect(*intersect),
|
Collision::Intersect(*intersect)
|
||||||
time
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -819,7 +827,6 @@ impl TouchingState{
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Body{
|
impl Body{
|
||||||
pub const ZERO:Self=Self::new(vec3::ZERO,vec3::ZERO,vec3::ZERO,Time::ZERO);
|
|
||||||
pub const fn new(position:Planar64Vec3,velocity:Planar64Vec3,acceleration:Planar64Vec3,time:Time)->Self{
|
pub const fn new(position:Planar64Vec3,velocity:Planar64Vec3,acceleration:Planar64Vec3,time:Time)->Self{
|
||||||
Self{
|
Self{
|
||||||
position,
|
position,
|
||||||
@ -830,63 +837,20 @@ impl Body{
|
|||||||
}
|
}
|
||||||
pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{
|
pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{
|
||||||
let dt=time-self.time;
|
let dt=time-self.time;
|
||||||
self.position
|
self.position+self.velocity*dt+self.acceleration*(dt*dt/2)
|
||||||
+(self.velocity*dt).map(|elem|elem.divide().fix_1())
|
|
||||||
+self.acceleration.map(|elem|(dt*dt*elem/2).divide().fix_1())
|
|
||||||
}
|
}
|
||||||
pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{
|
pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{
|
||||||
let dt=time-self.time;
|
let dt=time-self.time;
|
||||||
self.velocity+(self.acceleration*dt).map(|elem|elem.divide().fix_1())
|
self.velocity+self.acceleration*dt
|
||||||
}
|
}
|
||||||
pub fn advance_time(&mut self,time:Time){
|
pub fn advance_time(&mut self,time:Time){
|
||||||
self.position=self.extrapolated_position(time);
|
self.position=self.extrapolated_position(time);
|
||||||
self.velocity=self.extrapolated_velocity(time);
|
self.velocity=self.extrapolated_velocity(time);
|
||||||
self.time=time;
|
self.time=time;
|
||||||
}
|
}
|
||||||
pub fn extrapolated_position_ratio_dt<Num,Den,N1,D1,N2,N3,D2,N4,T1>(&self,dt:integer::Ratio<Num,Den>)->Planar64Vec3
|
|
||||||
where
|
|
||||||
// Why?
|
|
||||||
// All of this can be removed with const generics because the type can be specified as
|
|
||||||
// Ratio<Fixed<N,NF>,Fixed<D,DF>>
|
|
||||||
// which is known to implement all the necessary traits
|
|
||||||
Num:Copy,
|
|
||||||
Den:Copy+core::ops::Mul<i64,Output=D1>,
|
|
||||||
D1:Copy,
|
|
||||||
Num:core::ops::Mul<Planar64,Output=N1>,
|
|
||||||
Planar64:core::ops::Mul<D1,Output=N2>,
|
|
||||||
N1:core::ops::Add<N2,Output=N3>,
|
|
||||||
Num:core::ops::Mul<N3,Output=N4>,
|
|
||||||
Den:core::ops::Mul<D1,Output=D2>,
|
|
||||||
D2:Copy,
|
|
||||||
Planar64:core::ops::Mul<D2,Output=N4>,
|
|
||||||
N4:integer::Divide<D2,Output=T1>,
|
|
||||||
T1:integer::Fix<Planar64>,
|
|
||||||
{
|
|
||||||
// a*dt^2/2 + v*dt + p
|
|
||||||
// (a*dt/2+v)*dt+p
|
|
||||||
(self.acceleration.map(|elem|dt*elem/2)+self.velocity).map(|elem|dt.mul_ratio(elem))
|
|
||||||
.map(|elem|elem.divide().fix())+self.position
|
|
||||||
}
|
|
||||||
pub fn extrapolated_velocity_ratio_dt<Num,Den,N1,T1>(&self,dt:integer::Ratio<Num,Den>)->Planar64Vec3
|
|
||||||
where
|
|
||||||
Num:Copy,
|
|
||||||
Den:Copy,
|
|
||||||
Num:core::ops::Mul<Planar64,Output=N1>,
|
|
||||||
Planar64:core::ops::Mul<Den,Output=N1>,
|
|
||||||
N1:integer::Divide<Den,Output=T1>,
|
|
||||||
T1:integer::Fix<Planar64>,
|
|
||||||
{
|
|
||||||
// a*dt + v
|
|
||||||
self.acceleration.map(|elem|(dt*elem).divide().fix())+self.velocity
|
|
||||||
}
|
|
||||||
pub fn advance_time_ratio_dt(&mut self,dt:model_physics::GigaTime){
|
|
||||||
self.position=self.extrapolated_position_ratio_dt(dt);
|
|
||||||
self.velocity=self.extrapolated_velocity_ratio_dt(dt);
|
|
||||||
self.time+=dt.into();
|
|
||||||
}
|
|
||||||
pub fn infinity_dir(&self)->Option<Planar64Vec3>{
|
pub fn infinity_dir(&self)->Option<Planar64Vec3>{
|
||||||
if self.velocity==vec3::ZERO{
|
if self.velocity==Planar64Vec3::ZERO{
|
||||||
if self.acceleration==vec3::ZERO{
|
if self.acceleration==Planar64Vec3::ZERO{
|
||||||
None
|
None
|
||||||
}else{
|
}else{
|
||||||
Some(self.acceleration)
|
Some(self.acceleration)
|
||||||
@ -900,22 +864,22 @@ impl Body{
|
|||||||
aabb.grow(self.extrapolated_position(t1));
|
aabb.grow(self.extrapolated_position(t1));
|
||||||
//v+a*t==0
|
//v+a*t==0
|
||||||
//goober code
|
//goober code
|
||||||
if !self.acceleration.x.is_zero(){
|
if self.acceleration.x()!=Planar64::ZERO{
|
||||||
let t=-self.velocity.x/self.acceleration.x;
|
let t=Time::from(-self.velocity.x()/self.acceleration.x());
|
||||||
if t0.to_ratio().lt_ratio(t)&&t.lt_ratio(t1.to_ratio()){
|
if t0<t&&t<t1{
|
||||||
aabb.grow(self.extrapolated_position_ratio_dt(t));
|
aabb.grow(self.extrapolated_position(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !self.acceleration.y.is_zero(){
|
if self.acceleration.y()!=Planar64::ZERO{
|
||||||
let t=-self.velocity.y/self.acceleration.y;
|
let t=Time::from(-self.velocity.y()/self.acceleration.y());
|
||||||
if t0.to_ratio().lt_ratio(t)&&t.lt_ratio(t1.to_ratio()){
|
if t0<t&&t<t1{
|
||||||
aabb.grow(self.extrapolated_position_ratio_dt(t));
|
aabb.grow(self.extrapolated_position(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !self.acceleration.z.is_zero(){
|
if self.acceleration.z()!=Planar64::ZERO{
|
||||||
let t=-self.velocity.z/self.acceleration.z;
|
let t=Time::from(-self.velocity.z()/self.acceleration.z());
|
||||||
if t0.to_ratio().lt_ratio(t)&&t.lt_ratio(t1.to_ratio()){
|
if t0<t&&t<t1{
|
||||||
aabb.grow(self.extrapolated_position_ratio_dt(t));
|
aabb.grow(self.extrapolated_position(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -958,7 +922,7 @@ impl VirtualBody<'_>{
|
|||||||
pub struct PhysicsState{
|
pub struct PhysicsState{
|
||||||
time:Time,
|
time:Time,
|
||||||
body:Body,
|
body:Body,
|
||||||
_world:WorldState,//currently there is only one state the world can be in
|
world:WorldState,//currently there is only one state the world can be in
|
||||||
touching:TouchingState,
|
touching:TouchingState,
|
||||||
//camera must exist in state because wormholes modify the camera, also camera punch
|
//camera must exist in state because wormholes modify the camera, also camera punch
|
||||||
camera:PhysicsCamera,
|
camera:PhysicsCamera,
|
||||||
@ -988,14 +952,14 @@ pub struct PhysicsData{
|
|||||||
impl Default for PhysicsState{
|
impl Default for PhysicsState{
|
||||||
fn default()->Self{
|
fn default()->Self{
|
||||||
Self{
|
Self{
|
||||||
body:Body::new(vec3::int(0,50,0),vec3::int(0,0,0),vec3::int(0,-100,0),Time::ZERO),
|
body:Body::new(Planar64Vec3::int(0,50,0),Planar64Vec3::int(0,0,0),Planar64Vec3::int(0,-100,0),Time::ZERO),
|
||||||
time:Time::ZERO,
|
time:Time::ZERO,
|
||||||
style:StyleModifiers::default(),
|
style:StyleModifiers::default(),
|
||||||
touching:TouchingState::default(),
|
touching:TouchingState::default(),
|
||||||
move_state:MoveState::Air,
|
move_state:MoveState::Air,
|
||||||
camera:PhysicsCamera::default(),
|
camera:PhysicsCamera::default(),
|
||||||
input_state:InputState::default(),
|
input_state:InputState::default(),
|
||||||
_world:WorldState{},
|
world:WorldState{},
|
||||||
mode_state:ModeState::default(),
|
mode_state:ModeState::default(),
|
||||||
run:run::Run::new(),
|
run:run::Run::new(),
|
||||||
}
|
}
|
||||||
@ -1083,15 +1047,14 @@ impl instruction::InstructionEmitter<PhysicsInternalInstruction> for PhysicsCont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl PhysicsContext{
|
impl PhysicsContext{
|
||||||
pub fn camera_body(&self)->Body{
|
pub const fn output(&self)->PhysicsOutputState{
|
||||||
Body{
|
PhysicsOutputState{
|
||||||
position:self.state.body.position+self.state.style.camera_offset,
|
body:self.state.body,
|
||||||
..self.state.body
|
camera:self.state.camera,
|
||||||
|
camera_offset:self.state.style.camera_offset,
|
||||||
|
mouse_pos:self.state.input_state.mouse.pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const fn camera(&self)->PhysicsCamera{
|
|
||||||
self.state.camera
|
|
||||||
}
|
|
||||||
pub const fn get_next_mouse(&self)->&MouseState{
|
pub const fn get_next_mouse(&self)->&MouseState{
|
||||||
self.state.input_state.get_next_mouse()
|
self.state.input_state.get_next_mouse()
|
||||||
}
|
}
|
||||||
@ -1203,7 +1166,7 @@ impl PhysicsContext{
|
|||||||
let mut aabb=aabb::Aabb::default();
|
let mut aabb=aabb::Aabb::default();
|
||||||
let transformed_mesh=TransformedMesh::new(view,transform);
|
let transformed_mesh=TransformedMesh::new(view,transform);
|
||||||
for v in transformed_mesh.verts(){
|
for v in transformed_mesh.verts(){
|
||||||
aabb.grow(v.fix_1());
|
aabb.grow(v);
|
||||||
}
|
}
|
||||||
(ConvexMeshId{
|
(ConvexMeshId{
|
||||||
model_id,
|
model_id,
|
||||||
@ -1278,15 +1241,12 @@ impl PhysicsContext{
|
|||||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,data.hitbox_mesh.transformed_mesh());
|
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,data.hitbox_mesh.transformed_mesh());
|
||||||
collector.collect(minkowski.predict_collision_in(relative_body,collector.time())
|
collector.collect(minkowski.predict_collision_in(relative_body,collector.time())
|
||||||
//temp (?) code to avoid collision loops
|
//temp (?) code to avoid collision loops
|
||||||
.map_or(None,|(face,dt)|{
|
.map_or(None,|(face,time)|if time<=state.time{None}else{Some((face,time))})
|
||||||
let time=relative_body.time+dt.into();
|
.map(|(face,time)|
|
||||||
if time<=state.time{None}else{Some((time,face,dt))}})
|
|
||||||
.map(|(time,face,dt)|
|
|
||||||
TimedInstruction{
|
TimedInstruction{
|
||||||
time,
|
time,
|
||||||
instruction:PhysicsInternalInstruction::CollisionStart(
|
instruction:PhysicsInternalInstruction::CollisionStart(
|
||||||
Collision::new(convex_mesh_id,face),
|
Collision::new(convex_mesh_id,face)
|
||||||
dt
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -1299,8 +1259,7 @@ impl PhysicsContext{
|
|||||||
fn contact_normal(models:&PhysicsModels,hitbox_mesh:&HitboxMesh,contact:&ContactCollision)->Planar64Vec3{
|
fn contact_normal(models:&PhysicsModels,hitbox_mesh:&HitboxMesh,contact:&ContactCollision)->Planar64Vec3{
|
||||||
let model_mesh=models.contact_mesh(contact);
|
let model_mesh=models.contact_mesh(contact);
|
||||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
||||||
// TODO: normalize to i64::MAX>>1
|
minkowski.face_nd(contact.face_id).0
|
||||||
minkowski.face_nd(contact.face_id).0.fix_1()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recalculate_touching(
|
fn recalculate_touching(
|
||||||
@ -1384,12 +1343,12 @@ fn set_velocity_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsM
|
|||||||
let mut culled=false;
|
let mut culled=false;
|
||||||
touching.contacts.retain(|contact|{
|
touching.contacts.retain(|contact|{
|
||||||
let n=contact_normal(models,hitbox_mesh,contact);
|
let n=contact_normal(models,hitbox_mesh,contact);
|
||||||
let r=n.dot(v).is_positive();
|
let r=n.dot(v)<=Planar64::ZERO;
|
||||||
if r{
|
if !r{
|
||||||
culled=true;
|
culled=true;
|
||||||
println!("set_velocity_cull contact={:?}",contact);
|
println!("set_velocity_cull contact={:?}",contact);
|
||||||
}
|
}
|
||||||
!r
|
r
|
||||||
});
|
});
|
||||||
set_velocity(body,touching,models,hitbox_mesh,v);
|
set_velocity(body,touching,models,hitbox_mesh,v);
|
||||||
culled
|
culled
|
||||||
@ -1403,12 +1362,12 @@ fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&Phys
|
|||||||
let mut culled=false;
|
let mut culled=false;
|
||||||
touching.contacts.retain(|contact|{
|
touching.contacts.retain(|contact|{
|
||||||
let n=contact_normal(models,hitbox_mesh,contact);
|
let n=contact_normal(models,hitbox_mesh,contact);
|
||||||
let r=n.dot(a).is_positive();
|
let r=n.dot(a)<=Planar64::ZERO;
|
||||||
if r{
|
if !r{
|
||||||
culled=true;
|
culled=true;
|
||||||
println!("set_acceleration_cull contact={:?}",contact);
|
println!("set_acceleration_cull contact={:?}",contact);
|
||||||
}
|
}
|
||||||
!r
|
r
|
||||||
});
|
});
|
||||||
set_acceleration(body,touching,models,hitbox_mesh,a);
|
set_acceleration(body,touching,models,hitbox_mesh,a);
|
||||||
culled
|
culled
|
||||||
@ -1456,10 +1415,8 @@ fn teleport_to_spawn(
|
|||||||
input_state:&InputState,
|
input_state:&InputState,
|
||||||
time:Time,
|
time:Time,
|
||||||
)->Result<(),TeleportToSpawnError>{
|
)->Result<(),TeleportToSpawnError>{
|
||||||
const EPSILON:Planar64=Planar64::raw((1<<32)/16);
|
|
||||||
let transform=models.get_model_transform(stage.spawn()).ok_or(TeleportToSpawnError::NoModel)?;
|
let transform=models.get_model_transform(stage.spawn()).ok_or(TeleportToSpawnError::NoModel)?;
|
||||||
//TODO: transform.vertex.matrix3.col(1)+transform.vertex.translation
|
let point=transform.vertex.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(style.hitbox.halfsize.y()+Planar64::ONE/16);
|
||||||
let point=transform.vertex.transform_point3(vec3::Y).fix_1()+Planar64Vec3::new([Planar64::ZERO,style.hitbox.halfsize.y+EPSILON,Planar64::ZERO]);
|
|
||||||
teleport(point,move_state,body,touching,run,mode_state,Some(mode),models,hitbox_mesh,bvh,style,camera,input_state,time);
|
teleport(point,move_state,body,touching,run,mode_state,Some(mode),models,hitbox_mesh,bvh,style,camera,input_state,time);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1527,9 +1484,9 @@ fn run_teleport_behaviour(
|
|||||||
match stage_element.behaviour(){
|
match stage_element.behaviour(){
|
||||||
gameplay_modes::StageElementBehaviour::SpawnAt=>(),
|
gameplay_modes::StageElementBehaviour::SpawnAt=>(),
|
||||||
gameplay_modes::StageElementBehaviour::Trigger
|
gameplay_modes::StageElementBehaviour::Trigger
|
||||||
|gameplay_modes::StageElementBehaviour::Teleport=>if let Some(mode_state_stage)=mode.get_stage(mode_state.get_stage_id()){
|
|gameplay_modes::StageElementBehaviour::Teleport=>{
|
||||||
//I guess this is correct behaviour when trying to teleport to a non-existent spawn but it's still weird
|
//I guess this is correct behaviour when trying to teleport to a non-existent spawn but it's still weird
|
||||||
let _=teleport_to_spawn(mode_state_stage,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time);
|
let _=teleport_to_spawn(stage,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time);
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
gameplay_modes::StageElementBehaviour::Platform=>(),
|
gameplay_modes::StageElementBehaviour::Platform=>(),
|
||||||
@ -1580,7 +1537,7 @@ fn collision_start_contact(
|
|||||||
Some(gameplay_attributes::ContactingBehaviour::Surf)=>println!("I'm surfing!"),
|
Some(gameplay_attributes::ContactingBehaviour::Surf)=>println!("I'm surfing!"),
|
||||||
Some(gameplay_attributes::ContactingBehaviour::Cling)=>println!("Unimplemented!"),
|
Some(gameplay_attributes::ContactingBehaviour::Cling)=>println!("Unimplemented!"),
|
||||||
&Some(gameplay_attributes::ContactingBehaviour::Elastic(elasticity))=>{
|
&Some(gameplay_attributes::ContactingBehaviour::Elastic(elasticity))=>{
|
||||||
let reflected_velocity=body.velocity+((body.velocity-incident_velocity)*Planar64::raw(elasticity as i64+1)).fix_1();
|
let reflected_velocity=body.velocity+(body.velocity-incident_velocity)*Planar64::raw(elasticity as i64+1);
|
||||||
set_velocity(body,touching,models,hitbox_mesh,reflected_velocity);
|
set_velocity(body,touching,models,hitbox_mesh,reflected_velocity);
|
||||||
},
|
},
|
||||||
Some(gameplay_attributes::ContactingBehaviour::Ladder(contacting_ladder))=>
|
Some(gameplay_attributes::ContactingBehaviour::Ladder(contacting_ladder))=>
|
||||||
@ -1589,7 +1546,7 @@ fn collision_start_contact(
|
|||||||
//kill v
|
//kill v
|
||||||
//actually you could do this with a booster attribute :thinking:
|
//actually you could do this with a booster attribute :thinking:
|
||||||
//it's a little bit different because maybe you want to chain ladders together
|
//it's a little bit different because maybe you want to chain ladders together
|
||||||
set_velocity(body,touching,models,hitbox_mesh,vec3::ZERO);//model.velocity
|
set_velocity(body,touching,models,hitbox_mesh,Planar64Vec3::ZERO);//model.velocity
|
||||||
}
|
}
|
||||||
//ladder walkstate
|
//ladder walkstate
|
||||||
let (gravity,target_velocity)=ladder_things(ladder_settings,&contact,touching,models,hitbox_mesh,style,camera,input_state);
|
let (gravity,target_velocity)=ladder_things(ladder_settings,&contact,touching,models,hitbox_mesh,style,camera,input_state);
|
||||||
@ -1598,7 +1555,7 @@ fn collision_start_contact(
|
|||||||
},
|
},
|
||||||
Some(gameplay_attributes::ContactingBehaviour::NoJump)=>todo!("nyi"),
|
Some(gameplay_attributes::ContactingBehaviour::NoJump)=>todo!("nyi"),
|
||||||
None=>if let Some(walk_settings)=&style.walk{
|
None=>if let Some(walk_settings)=&style.walk{
|
||||||
if walk_settings.is_slope_walkable(contact_normal(models,hitbox_mesh,&contact),vec3::Y){
|
if walk_settings.is_slope_walkable(contact_normal(models,hitbox_mesh,&contact),Planar64Vec3::Y){
|
||||||
//ground
|
//ground
|
||||||
let (gravity,target_velocity)=ground_things(walk_settings,&contact,touching,models,hitbox_mesh,style,camera,input_state);
|
let (gravity,target_velocity)=ground_things(walk_settings,&contact,touching,models,hitbox_mesh,style,camera,input_state);
|
||||||
let walk_state=ContactMoveState::ground(walk_settings,body,gravity,target_velocity,contact);
|
let walk_state=ContactMoveState::ground(walk_settings,body,gravity,target_velocity,contact);
|
||||||
@ -1726,20 +1683,17 @@ fn collision_end_intersect(
|
|||||||
}
|
}
|
||||||
fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction<PhysicsInternalInstruction>){
|
fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction<PhysicsInternalInstruction>){
|
||||||
state.time=ins.time;
|
state.time=ins.time;
|
||||||
let (should_advance_body,goober_time)=match ins.instruction{
|
let should_advance_body=match ins.instruction{
|
||||||
PhysicsInternalInstruction::CollisionStart(_,dt)
|
PhysicsInternalInstruction::CollisionStart(_)
|
||||||
|PhysicsInternalInstruction::CollisionEnd(_,dt)=>(true,Some(dt)),
|
|PhysicsInternalInstruction::CollisionEnd(_)
|
||||||
PhysicsInternalInstruction::StrafeTick
|
|PhysicsInternalInstruction::StrafeTick
|
||||||
|PhysicsInternalInstruction::ReachWalkTargetVelocity=>(true,None),
|
|PhysicsInternalInstruction::ReachWalkTargetVelocity=>true,
|
||||||
};
|
};
|
||||||
if should_advance_body{
|
if should_advance_body{
|
||||||
match goober_time{
|
state.body.advance_time(state.time);
|
||||||
Some(dt)=>state.body.advance_time_ratio_dt(dt),
|
|
||||||
None=>state.body.advance_time(state.time),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
match ins.instruction{
|
match ins.instruction{
|
||||||
PhysicsInternalInstruction::CollisionStart(collision,_)=>{
|
PhysicsInternalInstruction::CollisionStart(collision)=>{
|
||||||
let mode=data.modes.get_mode(state.mode_state.get_mode_id());
|
let mode=data.modes.get_mode(state.mode_state.get_mode_id());
|
||||||
match collision{
|
match collision{
|
||||||
Collision::Contact(contact)=>collision_start_contact(
|
Collision::Contact(contact)=>collision_start_contact(
|
||||||
@ -1760,7 +1714,7 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PhysicsInternalInstruction::CollisionEnd(collision,_)=>match collision{
|
PhysicsInternalInstruction::CollisionEnd(collision)=>match collision{
|
||||||
Collision::Contact(contact)=>collision_end_contact(
|
Collision::Contact(contact)=>collision_end_contact(
|
||||||
&mut state.move_state,&mut state.body,&mut state.touching,&data.models,&data.hitbox_mesh,&state.style,&state.camera,&state.input_state,
|
&mut state.move_state,&mut state.body,&mut state.touching,&data.models,&data.hitbox_mesh,&state.style,&state.camera,&state.input_state,
|
||||||
data.models.contact_attr(contact.model_id),
|
data.models.contact_attr(contact.model_id),
|
||||||
@ -1782,9 +1736,9 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
|
|||||||
if strafe_settings.activates(controls){
|
if strafe_settings.activates(controls){
|
||||||
let masked_controls=strafe_settings.mask(controls);
|
let masked_controls=strafe_settings.mask(controls);
|
||||||
let control_dir=state.style.get_control_dir(masked_controls);
|
let control_dir=state.style.get_control_dir(masked_controls);
|
||||||
if control_dir!=vec3::ZERO{
|
if control_dir!=Planar64Vec3::ZERO{
|
||||||
let camera_mat=state.camera.simulate_move_rotation_y(state.input_state.lerp_delta(state.time).x);
|
let camera_mat=state.camera.simulate_move_rotation_y(state.input_state.lerp_delta(state.time).x);
|
||||||
if let Some(ticked_velocity)=strafe_settings.tick_velocity(state.body.velocity,(camera_mat*control_dir).with_length(Planar64::ONE).divide().fix_1()){
|
if let Some(ticked_velocity)=strafe_settings.tick_velocity(state.body.velocity,(camera_mat*control_dir).with_length(Planar64::ONE)){
|
||||||
//this is wrong but will work ig
|
//this is wrong but will work ig
|
||||||
//need to note which push planes activate in push solve and keep those
|
//need to note which push planes activate in push solve and keep those
|
||||||
state.cull_velocity(data,ticked_velocity);
|
state.cull_velocity(data,ticked_velocity);
|
||||||
@ -1808,7 +1762,7 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
|
|||||||
//we know that the acceleration is precisely zero because the walk target is known to be reachable
|
//we know that the acceleration is precisely zero because the walk target is known to be reachable
|
||||||
//which means that gravity can be fully cancelled
|
//which means that gravity can be fully cancelled
|
||||||
//ignore moving platforms for now
|
//ignore moving platforms for now
|
||||||
set_acceleration(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,vec3::ZERO);
|
set_acceleration(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,Planar64Vec3::ZERO);
|
||||||
walk_state.target=TransientAcceleration::Reached;
|
walk_state.target=TransientAcceleration::Reached;
|
||||||
},
|
},
|
||||||
//you are not supposed to reach an unreachable walk target!
|
//you are not supposed to reach an unreachable walk target!
|
||||||
@ -1903,9 +1857,9 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
|||||||
data.models.get_model_transform(mode.get_start().into()).map(|transform|
|
data.models.get_model_transform(mode.get_start().into()).map(|transform|
|
||||||
transform.vertex.translation
|
transform.vertex.translation
|
||||||
)
|
)
|
||||||
).unwrap_or(vec3::ZERO);
|
).unwrap_or(Planar64Vec3::ZERO);
|
||||||
set_position(spawn_point,&mut state.move_state,&mut state.body,&mut state.touching,&mut state.run,&mut state.mode_state,mode,&data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state,state.time);
|
set_position(spawn_point,&mut state.move_state,&mut state.body,&mut state.touching,&mut state.run,&mut state.mode_state,mode,&data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state,state.time);
|
||||||
set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,vec3::ZERO);
|
set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,Planar64Vec3::ZERO);
|
||||||
state.set_move_state(data,MoveState::Air);
|
state.set_move_state(data,MoveState::Air);
|
||||||
b_refresh_walk_target=false;
|
b_refresh_walk_target=false;
|
||||||
}
|
}
|
||||||
@ -1942,7 +1896,6 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
|||||||
if b_refresh_walk_target{
|
if b_refresh_walk_target{
|
||||||
state.apply_input_and_body(data);
|
state.apply_input_and_body(data);
|
||||||
state.cull_velocity(data,state.body.velocity);
|
state.cull_velocity(data,state.body.velocity);
|
||||||
//also check if accelerating away from surface
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1956,7 +1909,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
|||||||
_=>println!("{}|{:?}",ins.time,ins.instruction),
|
_=>println!("{}|{:?}",ins.time,ins.instruction),
|
||||||
}
|
}
|
||||||
if ins.time<state.time{
|
if ins.time<state.time{
|
||||||
println!("@@@@ Time travel warning! state.time={} ins.time={}\nInstruction={:?}",state.time,ins.time,ins.instruction);
|
println!("@@@@ Time travel warning! {:?}",ins);
|
||||||
}
|
}
|
||||||
//idle is special, it is specifically a no-op to get Internal events to catch up to real time
|
//idle is special, it is specifically a no-op to get Internal events to catch up to real time
|
||||||
match ins.instruction{
|
match ins.instruction{
|
||||||
@ -1968,216 +1921,215 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test{
|
mod test{
|
||||||
use strafesnet_common::integer::{vec3::{self,int as int3},mat3};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
fn test_collision_axis_aligned(relative_body:Body,expected_collision_time:Option<Time>){
|
fn test_collision_axis_aligned(relative_body:Body,expected_collision_time:Option<Time>){
|
||||||
let h0=HitboxMesh::new(PhysicsMesh::unit_cube(),integer::Planar64Affine3::new(mat3::from_diagonal(int3(5,1,5)>>1),vec3::ZERO));
|
let h0=HitboxMesh::new(PhysicsMesh::unit_cube(),integer::Planar64Affine3::new(Planar64Mat3::from_diagonal(Planar64Vec3::int(5,1,5)/2),Planar64Vec3::ZERO));
|
||||||
let h1=StyleModifiers::roblox_bhop().calculate_mesh();
|
let h1=StyleModifiers::roblox_bhop().calculate_mesh();
|
||||||
let hitbox_mesh=h1.transformed_mesh();
|
let hitbox_mesh=h1.transformed_mesh();
|
||||||
let platform_mesh=h0.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::from_secs(10));
|
let collision=minkowski.predict_collision_in(&relative_body,Time::MAX);
|
||||||
assert_eq!(collision.map(|tup|relative_body.time+tup.1.into()),expected_collision_time,"Incorrect time of collision");
|
assert_eq!(collision.map(|tup|tup.1),expected_collision_time,"Incorrect time of collision");
|
||||||
}
|
}
|
||||||
fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time>){
|
fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time>){
|
||||||
let h0=HitboxMesh::new(PhysicsMesh::unit_cube(),
|
let h0=HitboxMesh::new(PhysicsMesh::unit_cube(),
|
||||||
integer::Planar64Affine3::new(
|
integer::Planar64Affine3::new(
|
||||||
integer::Planar64Mat3::from_cols([
|
integer::Planar64Mat3::from_cols(
|
||||||
int3(5,0,1)>>1,
|
Planar64Vec3::int(5,0,1)/2,
|
||||||
int3(0,1,0)>>1,
|
Planar64Vec3::int(0,1,0)/2,
|
||||||
int3(-1,0,5)>>1,
|
Planar64Vec3::int(-1,0,5)/2,
|
||||||
]),
|
|
||||||
vec3::ZERO
|
|
||||||
),
|
),
|
||||||
|
Planar64Vec3::ZERO,
|
||||||
|
)
|
||||||
);
|
);
|
||||||
let h1=StyleModifiers::roblox_bhop().calculate_mesh();
|
let h1=StyleModifiers::roblox_bhop().calculate_mesh();
|
||||||
let hitbox_mesh=h1.transformed_mesh();
|
let hitbox_mesh=h1.transformed_mesh();
|
||||||
let platform_mesh=h0.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::from_secs(10));
|
let collision=minkowski.predict_collision_in(&relative_body,Time::MAX);
|
||||||
assert_eq!(collision.map(|tup|relative_body.time+tup.1.into()),expected_collision_time,"Incorrect time of collision");
|
assert_eq!(collision.map(|tup|tup.1),expected_collision_time,"Incorrect time of collision");
|
||||||
}
|
}
|
||||||
fn test_collision(relative_body:Body,expected_collision_time:Option<Time>){
|
fn test_collision(relative_body:Body,expected_collision_time:Option<Time>){
|
||||||
test_collision_axis_aligned(relative_body.clone(),expected_collision_time);
|
test_collision_axis_aligned(relative_body.clone(),expected_collision_time);
|
||||||
test_collision_rotated(relative_body,expected_collision_time);
|
test_collision_rotated(relative_body,expected_collision_time);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_degenerate_straight_down(){
|
fn test_collision_degenerate(){
|
||||||
test_collision(Body::new(
|
test_collision(Body::new(
|
||||||
int3(0,5,0),
|
Planar64Vec3::int(0,5,0),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
vec3::ZERO,
|
Planar64Vec3::ZERO,
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
),Some(Time::from_secs(2)));
|
),Some(Time::from_secs(2)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_degenerate_east(){
|
fn test_collision_degenerate_east(){
|
||||||
test_collision(Body::new(
|
test_collision(Body::new(
|
||||||
int3(3,5,0),
|
Planar64Vec3::int(3,5,0),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
vec3::ZERO,
|
Planar64Vec3::ZERO,
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
),Some(Time::from_secs(2)));
|
),Some(Time::from_secs(2)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_degenerate_south(){
|
fn test_collision_degenerate_south(){
|
||||||
test_collision(Body::new(
|
test_collision(Body::new(
|
||||||
int3(0,5,3),
|
Planar64Vec3::int(0,5,3),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
vec3::ZERO,
|
Planar64Vec3::ZERO,
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
),Some(Time::from_secs(2)));
|
),Some(Time::from_secs(2)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_degenerate_west(){
|
fn test_collision_degenerate_west(){
|
||||||
test_collision(Body::new(
|
test_collision(Body::new(
|
||||||
int3(-3,5,0),
|
Planar64Vec3::int(-3,5,0),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
vec3::ZERO,
|
Planar64Vec3::ZERO,
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
),Some(Time::from_secs(2)));
|
),Some(Time::from_secs(2)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_degenerate_north(){
|
fn test_collision_degenerate_north(){
|
||||||
test_collision(Body::new(
|
test_collision(Body::new(
|
||||||
int3(0,5,-3),
|
Planar64Vec3::int(0,5,-3),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
vec3::ZERO,
|
Planar64Vec3::ZERO,
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
),Some(Time::from_secs(2)));
|
),Some(Time::from_secs(2)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_east_from_west(){
|
fn test_collision_parabola_edge_east_from_west(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(3,3,0),
|
Planar64Vec3::int(3,3,0),
|
||||||
int3(100,-1,0),
|
Planar64Vec3::int(100,-1,0),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_south_from_north(){
|
fn test_collision_parabola_edge_south_from_north(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(0,3,3),
|
Planar64Vec3::int(0,3,3),
|
||||||
int3(0,-1,100),
|
Planar64Vec3::int(0,-1,100),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_west_from_east(){
|
fn test_collision_parabola_edge_west_from_east(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(-3,3,0),
|
Planar64Vec3::int(-3,3,0),
|
||||||
int3(-100,-1,0),
|
Planar64Vec3::int(-100,-1,0),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_north_from_south(){
|
fn test_collision_parabola_edge_north_from_south(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(0,3,-3),
|
Planar64Vec3::int(0,3,-3),
|
||||||
int3(0,-1,-100),
|
Planar64Vec3::int(0,-1,-100),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_north_from_ne(){
|
fn test_collision_parabola_edge_north_from_ne(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(0,6,-7)>>1,
|
Planar64Vec3::int(0,6,-7)/2,
|
||||||
int3(-10,-1,1),
|
Planar64Vec3::int(-10,-1,1),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_north_from_nw(){
|
fn test_collision_parabola_edge_north_from_nw(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(0,6,-7)>>1,
|
Planar64Vec3::int(0,6,-7)/2,
|
||||||
int3(10,-1,1),
|
Planar64Vec3::int(10,-1,1),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_east_from_se(){
|
fn test_collision_parabola_edge_east_from_se(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(7,6,0)>>1,
|
Planar64Vec3::int(7,6,0)/2,
|
||||||
int3(-1,-1,-10),
|
Planar64Vec3::int(-1,-1,-10),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_east_from_ne(){
|
fn test_collision_parabola_edge_east_from_ne(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(7,6,0)>>1,
|
Planar64Vec3::int(7,6,0)/2,
|
||||||
int3(-1,-1,10),
|
Planar64Vec3::int(-1,-1,10),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_south_from_se(){
|
fn test_collision_parabola_edge_south_from_se(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(0,6,7)>>1,
|
Planar64Vec3::int(0,6,7)/2,
|
||||||
int3(-10,-1,-1),
|
Planar64Vec3::int(-10,-1,-1),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_south_from_sw(){
|
fn test_collision_parabola_edge_south_from_sw(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(0,6,7)>>1,
|
Planar64Vec3::int(0,6,7)/2,
|
||||||
int3(10,-1,-1),
|
Planar64Vec3::int(10,-1,-1),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_west_from_se(){
|
fn test_collision_parabola_edge_west_from_se(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(-7,6,0)>>1,
|
Planar64Vec3::int(-7,6,0)/2,
|
||||||
int3(1,-1,-10),
|
Planar64Vec3::int(1,-1,-10),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_parabola_edge_west_from_ne(){
|
fn test_collision_parabola_edge_west_from_ne(){
|
||||||
test_collision(VirtualBody::relative(&Body::ZERO,&Body::new(
|
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||||
int3(-7,6,0)>>1,
|
Planar64Vec3::int(-7,6,0)/2,
|
||||||
int3(1,-1,10),
|
Planar64Vec3::int(1,-1,10),
|
||||||
int3(0,-1,0),
|
Planar64Vec3::int(0,-1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_oblique(){
|
fn test_collision_oblique(){
|
||||||
test_collision(Body::new(
|
test_collision(Body::new(
|
||||||
int3(0,5,0),
|
Planar64Vec3::int(0,5,0),
|
||||||
int3(1,-64,2)>>6,// /64
|
Planar64Vec3::int(1,-64,2)/64,
|
||||||
vec3::ZERO,
|
Planar64Vec3::ZERO,
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
),Some(Time::from_secs(2)));
|
),Some(Time::from_secs(2)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn zoom_hit_nothing(){
|
fn zoom_hit_nothing(){
|
||||||
test_collision(Body::new(
|
test_collision(Body::new(
|
||||||
int3(0,10,0),
|
Planar64Vec3::int(0,10,0),
|
||||||
int3(1,0,0),
|
Planar64Vec3::int(1,0,0),
|
||||||
int3(0,1,0),
|
Planar64Vec3::int(0,1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
),None);
|
),None);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn already_inside_hit_nothing(){
|
fn already_inside_hit_nothing(){
|
||||||
test_collision(Body::new(
|
test_collision(Body::new(
|
||||||
vec3::ZERO,
|
Planar64Vec3::ZERO,
|
||||||
int3(1,0,0),
|
Planar64Vec3::int(1,0,0),
|
||||||
int3(0,1,0),
|
Planar64Vec3::int(0,1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
),None);
|
),None);
|
||||||
}
|
}
|
||||||
|
@ -180,12 +180,8 @@ impl MouseInterpolator{
|
|||||||
self.empty_queue();
|
self.empty_queue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_frame_state(&self,time:Time)->crate::graphics::FrameState{
|
pub fn get_render_stuff(&self,time:Time)->(crate::physics::PhysicsOutputState,Time,glam::IVec2){
|
||||||
crate::graphics::FrameState{
|
(self.physics.output(),self.timer.time(time),self.physics.get_next_mouse().pos)
|
||||||
body:self.physics.camera_body(),
|
|
||||||
camera:self.physics.camera(),
|
|
||||||
time:self.timer.time(time),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn change_map(&mut self,time:Time,map:&strafesnet_common::map::CompleteMap){
|
pub fn change_map(&mut self,time:Time,map:&strafesnet_common::map::CompleteMap){
|
||||||
//dump any pending interpolation state
|
//dump any pending interpolation state
|
||||||
@ -225,8 +221,8 @@ pub fn new<'a>(
|
|||||||
interpolator.handle_instruction(&ins);
|
interpolator.handle_instruction(&ins);
|
||||||
match ins.instruction{
|
match ins.instruction{
|
||||||
Instruction::Render=>{
|
Instruction::Render=>{
|
||||||
let frame_state=interpolator.get_frame_state(ins.time);
|
let (physics_output,time,mouse_pos)=interpolator.get_render_stuff(ins.time);
|
||||||
graphics_worker.send(crate::graphics_worker::Instruction::Render(frame_state)).unwrap();
|
graphics_worker.send(crate::graphics_worker::Instruction::Render(physics_output,time,mouse_pos)).unwrap();
|
||||||
},
|
},
|
||||||
Instruction::Resize(size)=>{
|
Instruction::Resize(size)=>{
|
||||||
graphics_worker.send(crate::graphics_worker::Instruction::Resize(size,interpolator.user_settings().clone())).unwrap();
|
graphics_worker.send(crate::graphics_worker::Instruction::Resize(size,interpolator.user_settings().clone())).unwrap();
|
||||||
|
@ -181,9 +181,9 @@ mod test{
|
|||||||
#[test]//How to run this test with printing: cargo test --release -- --nocapture
|
#[test]//How to run this test with printing: cargo test --release -- --nocapture
|
||||||
fn test_worker() {
|
fn test_worker() {
|
||||||
// Create the worker thread
|
// Create the worker thread
|
||||||
let test_body=physics::Body::new(integer::vec3::ONE,integer::vec3::ONE,integer::vec3::ONE,integer::Time::ZERO);
|
let test_body=physics::Body::new(integer::Planar64Vec3::ONE,integer::Planar64Vec3::ONE,integer::Planar64Vec3::ONE,integer::Time::ZERO);
|
||||||
let worker=QRWorker::new(physics::Body::ZERO,
|
let worker=QRWorker::new(physics::Body::default(),
|
||||||
|_|physics::Body::new(integer::vec3::ONE,integer::vec3::ONE,integer::vec3::ONE,integer::Time::ZERO)
|
|_|physics::Body::new(integer::Planar64Vec3::ONE,integer::Planar64Vec3::ONE,integer::Planar64Vec3::ONE,integer::Time::ZERO)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send tasks to the worker
|
// Send tasks to the worker
|
||||||
|
Loading…
Reference in New Issue
Block a user