forked from StrafesNET/strafe-project
Compare commits
24 Commits
point-phys
...
shaders
| Author | SHA1 | Date | |
|---|---|---|---|
| f1ac04a7db | |||
| c86824bdc1 | |||
| a7f7edef00 | |||
| 5b8e5c8899 | |||
| 14000c016e | |||
| 1c4191cfc9 | |||
| b2f067e0b4 | |||
| aec82358ee | |||
| 5da5006027 | |||
| 97a1b57b65 | |||
| a359650ff8 | |||
| 1790390055 | |||
| 49e077996d | |||
| 9bfcf0b083 | |||
| 82b3201b0a | |||
| 513414d4bd | |||
| 5c4bd4c3c7 | |||
| 92ec137f33 | |||
| 5cedf91709 | |||
| c201a1a626 | |||
| fbae4d9f80 | |||
| 9374e93801 | |||
| 0585cfe6f1 | |||
| 3d96517213 |
423
Cargo.lock
generated
423
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "strafe-client"
|
||||
version = "0.8.0"
|
||||
version = "0.9.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -2,8 +2,8 @@ use crate::integer::Planar64Vec3;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Aabb{
|
||||
pub min:Planar64Vec3,
|
||||
pub max:Planar64Vec3,
|
||||
min:Planar64Vec3,
|
||||
max:Planar64Vec3,
|
||||
}
|
||||
|
||||
impl Default for Aabb {
|
||||
@@ -28,8 +28,11 @@ impl Aabb{
|
||||
pub fn intersects(&self,aabb:&Aabb)->bool{
|
||||
(self.min.cmplt(aabb.max)&aabb.min.cmplt(self.max)).all()
|
||||
}
|
||||
pub fn size(&self)->Planar64Vec3{
|
||||
self.max-self.min
|
||||
}
|
||||
pub fn center(&self)->Planar64Vec3{
|
||||
return self.min.midpoint(self.max)
|
||||
self.min.midpoint(self.max)
|
||||
}
|
||||
//probably use floats for area & volume because we don't care about precision
|
||||
// pub fn area_weight(&self)->f32{
|
||||
|
||||
@@ -72,9 +72,9 @@ fn generate_bvh_node(boxen:Vec<(usize,Aabb)>)->BvhNode{
|
||||
sort_y.push((*i,center.y()));
|
||||
sort_z.push((*i,center.z()));
|
||||
}
|
||||
sort_x.sort_by(|tup0,tup1|tup0.1.partial_cmp(&tup1.1).unwrap());
|
||||
sort_y.sort_by(|tup0,tup1|tup0.1.partial_cmp(&tup1.1).unwrap());
|
||||
sort_z.sort_by(|tup0,tup1|tup0.1.partial_cmp(&tup1.1).unwrap());
|
||||
sort_x.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
||||
sort_y.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
||||
sort_z.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
||||
let h=n/2;
|
||||
let median_x=sort_x[h].1;
|
||||
let median_y=sort_y[h].1;
|
||||
|
||||
@@ -1,49 +1,46 @@
|
||||
use crate::physics::Body;
|
||||
use crate::model_physics::{FEV,MeshQuery};
|
||||
use crate::integer::{Time,Planar64,Planar64Vec3};
|
||||
use crate::model_physics::{FEV,MeshQuery,DirectedEdge};
|
||||
use crate::integer::{Time,Planar64};
|
||||
use crate::zeroes::zeroes2;
|
||||
|
||||
struct State<FEV>{
|
||||
fev:FEV,
|
||||
time:Time,
|
||||
}
|
||||
|
||||
enum Transition<F,E,V>{
|
||||
enum Transition<F,E:DirectedEdge,V>{
|
||||
Miss,
|
||||
Next(FEV<F,E,V>,Time),
|
||||
Hit(F,Time),
|
||||
}
|
||||
|
||||
impl<F:Copy,E:Copy,V:Copy> State<FEV<F,E,V>>{
|
||||
fn next_transition(&self,mesh:&impl MeshQuery<F,E,V>,body:&Body,time_limit:Time)->Transition<F,E,V>{
|
||||
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>{
|
||||
//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.
|
||||
let mut best_time=time_limit;
|
||||
let mut best_transtition=Transition::Miss;
|
||||
match &self.fev{
|
||||
match fev{
|
||||
&FEV::<F,E,V>::Face(face_id)=>{
|
||||
//test own face collision time, ignoring roots with zero or conflicting derivative
|
||||
//n=face.normal d=face.dot
|
||||
//n.a t^2+n.v t+n.p-d==0
|
||||
let (n,d)=mesh.face_nd(face_id);
|
||||
//TODO: use higher precision d value?
|
||||
//use the mesh transform translation instead of baking it into the d value.
|
||||
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||
let t=body.time+Time::from(t);
|
||||
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
best_time=t;
|
||||
best_transtition=Transition::Hit(face_id,t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//test each edge collision time, ignoring roots with zero or conflicting derivative
|
||||
for &(edge_id,test_face_id) in mesh.face_edges(face_id).iter(){
|
||||
let edge_n=mesh.edge_n(edge_id);
|
||||
for &directed_edge_id in mesh.face_edges(face_id).iter(){
|
||||
let edge_n=mesh.directed_edge_n(directed_edge_id);
|
||||
let n=n.cross(edge_n);
|
||||
//picking a vert randomly is terrible
|
||||
let d=n.dot(mesh.vert(mesh.edge_verts(edge_id)[0]));
|
||||
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||
let verts=mesh.edge_verts(directed_edge_id.as_undirected());
|
||||
//WARNING: d is moved out of the *2 block because of adding two vertices!
|
||||
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)){
|
||||
let t=body.time+Time::from(t);
|
||||
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
best_time=t;
|
||||
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(edge_id),t);
|
||||
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -53,26 +50,29 @@ impl<F:Copy,E:Copy,V:Copy> State<FEV<F,E,V>>{
|
||||
&FEV::<F,E,V>::Edge(edge_id)=>{
|
||||
//test each face collision time, ignoring roots with zero or conflicting derivative
|
||||
let edge_n=mesh.edge_n(edge_id);
|
||||
for &test_face_id in mesh.edge_faces(edge_id).iter(){
|
||||
let face_n=mesh.face_nd(test_face_id).0;
|
||||
let n=edge_n.cross(face_n);
|
||||
let d=n.dot(mesh.vert(mesh.edge_verts(edge_id)[0]));
|
||||
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||
let edge_verts=mesh.edge_verts(edge_id);
|
||||
let delta_pos=body.position*2-(mesh.vert(edge_verts[0])+mesh.vert(edge_verts[1]));
|
||||
for (i,&edge_face_id) in mesh.edge_faces(edge_id).iter().enumerate(){
|
||||
let face_n=mesh.face_nd(edge_face_id).0;
|
||||
//edge_n gets parity from the order of edge_faces
|
||||
let n=face_n.cross(edge_n)*((i as i64)*2-1);
|
||||
//WARNING yada yada d *2
|
||||
for t in zeroes2(n.dot(delta_pos),n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||
let t=body.time+Time::from(t);
|
||||
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
best_time=t;
|
||||
best_transtition=Transition::Next(FEV::<F,E,V>::Face(test_face_id),t);
|
||||
best_transtition=Transition::Next(FEV::<F,E,V>::Face(edge_face_id),t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//test each vertex collision time, ignoring roots with zero or conflicting derivative
|
||||
let n=mesh.edge_n(edge_id);
|
||||
for &vert_id in mesh.edge_verts(edge_id).iter(){
|
||||
let d=n.dot(mesh.vert(vert_id));
|
||||
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||
for (i,&vert_id) in edge_verts.iter().enumerate(){
|
||||
//vertex normal gets parity from vert index
|
||||
let n=edge_n*(1-2*(i as i64));
|
||||
for t in zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||
let t=body.time+Time::from(t);
|
||||
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
best_time=t;
|
||||
best_transtition=Transition::Next(FEV::<F,E,V>::Vert(vert_id),t);
|
||||
break;
|
||||
@@ -83,14 +83,14 @@ impl<F:Copy,E:Copy,V:Copy> State<FEV<F,E,V>>{
|
||||
},
|
||||
&FEV::<F,E,V>::Vert(vert_id)=>{
|
||||
//test each edge collision time, ignoring roots with zero or conflicting derivative
|
||||
for &edge_id in mesh.vert_edges(vert_id).iter(){
|
||||
let n=mesh.edge_n(edge_id);
|
||||
let d=n.dot(mesh.vert(vert_id));
|
||||
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||
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
|
||||
let n=-mesh.directed_edge_n(directed_edge_id);
|
||||
for t in zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||
let t=body.time+Time::from(t);
|
||||
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||
best_time=t;
|
||||
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(edge_id),t);
|
||||
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -100,27 +100,20 @@ impl<F:Copy,E:Copy,V:Copy> State<FEV<F,E,V>>{
|
||||
}
|
||||
best_transtition
|
||||
}
|
||||
pub enum CrawlResult<F,E:DirectedEdge,V>{
|
||||
Miss(FEV<F,E,V>),
|
||||
Hit(F,Time),
|
||||
}
|
||||
|
||||
pub fn predict_collision<F:Copy,E:Copy,V:Copy>(mesh:&impl MeshQuery<F,E,V>,relative_body:&Body,time_limit:Time)->Option<(F,Time)>{
|
||||
let mut state=State{
|
||||
fev:mesh.closest_fev(relative_body.position),
|
||||
time:relative_body.time,
|
||||
};
|
||||
//it would be possible to write down the point of closest approach...
|
||||
loop{
|
||||
match state.next_transition(mesh,relative_body,time_limit){
|
||||
Transition::Miss=>return None,
|
||||
Transition::Next(fev,time)=>(state.fev,state.time)=(fev,time),
|
||||
Transition::Hit(face,time)=>return Some((face,time)),
|
||||
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>{
|
||||
let mut time=start_time;
|
||||
for _ in 0..20{
|
||||
match next_transition(&fev,time,mesh,relative_body,time_limit){
|
||||
Transition::Miss=>return CrawlResult::Miss(fev),
|
||||
Transition::Next(next_fev,next_time)=>(fev,time)=(next_fev,next_time),
|
||||
Transition::Hit(face,time)=>return CrawlResult::Hit(face,time),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn predict_collision_end<F:Copy,E:Copy,V:Copy>(mesh:&impl MeshQuery<F,E,V>,relative_body:&Body,time_limit:Time,ignore_face_id:F)->Option<(F,Time)>{
|
||||
//imagine the mesh without the collision face
|
||||
//no algorithm needed, there is only one state and three cases (Face,Edge,None)
|
||||
//determine when it passes an edge ("sliding off" case) or if it leaves the surface directly
|
||||
//the state can be constructed from the ContactCollision directly
|
||||
None
|
||||
//TODO: fix all bugs
|
||||
println!("Too many iterations! Using default behaviour instead of crashing...");
|
||||
CrawlResult::Miss(fev)
|
||||
}
|
||||
|
||||
119
src/integer.rs
119
src/integer.rs
@@ -2,6 +2,8 @@
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
||||
pub struct Time(i64);
|
||||
impl Time{
|
||||
pub const MIN:Self=Self(i64::MIN);
|
||||
pub const MAX:Self=Self(i64::MAX);
|
||||
pub const ZERO:Self=Self(0);
|
||||
pub const ONE_SECOND:Self=Self(1_000_000_000);
|
||||
pub const ONE_MILLISECOND:Self=Self(1_000_000);
|
||||
@@ -103,23 +105,23 @@ impl Ratio64{
|
||||
None
|
||||
}else{
|
||||
let d=gcd(num.unsigned_abs(),den);
|
||||
Some(Self{num:num/d as i64,den:den/d})
|
||||
Some(Self{num:num/(d as i64),den:den/d})
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn mul_int(&self,rhs:i64)->i64{
|
||||
rhs*self.num/self.den as i64
|
||||
rhs*self.num/(self.den as i64)
|
||||
}
|
||||
#[inline]
|
||||
pub fn rhs_div_int(&self,rhs:i64)->i64{
|
||||
rhs*self.den as i64/self.num
|
||||
rhs*(self.den as i64)/self.num
|
||||
}
|
||||
#[inline]
|
||||
pub fn mul_ref(&self,rhs:&Ratio64)->Ratio64{
|
||||
let (num,den)=(self.num*rhs.num,self.den*rhs.den);
|
||||
let d=gcd(num.unsigned_abs(),den);
|
||||
Self{
|
||||
num:num/d as i64,
|
||||
num:num/(d as i64),
|
||||
den:den/d,
|
||||
}
|
||||
}
|
||||
@@ -207,8 +209,8 @@ impl TryFrom<f32> for Ratio64{
|
||||
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
||||
std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f32(value)),
|
||||
std::num::FpCategory::Subnormal
|
||||
|std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f32(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,8 +222,8 @@ impl TryFrom<f64> for Ratio64{
|
||||
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
||||
std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f64(value)),
|
||||
std::num::FpCategory::Subnormal
|
||||
|std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f64(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +234,7 @@ impl std::ops::Mul<Ratio64> for Ratio64{
|
||||
let (num,den)=(self.num*rhs.num,self.den*rhs.den);
|
||||
let d=gcd(num.unsigned_abs(),den);
|
||||
Self{
|
||||
num:num/d as i64,
|
||||
num:num/(d as i64),
|
||||
den:den/d,
|
||||
}
|
||||
}
|
||||
@@ -415,6 +417,7 @@ impl Planar64{
|
||||
pub const ZERO:Self=Self(0);
|
||||
pub const ONE:Self=Self(1<<32);
|
||||
pub const MAX:Self=Self(i64::MAX);
|
||||
pub const MIN:Self=Self(i64::MIN);
|
||||
#[inline]
|
||||
pub const fn int(num:i32)->Self{
|
||||
Self(Self::ONE.0*num as i64)
|
||||
@@ -448,7 +451,7 @@ impl Into<f32> for Planar64{
|
||||
impl From<Ratio64> for Planar64{
|
||||
#[inline]
|
||||
fn from(ratio:Ratio64)->Self{
|
||||
Self((((ratio.num as i128)<<32)/ratio.den as i128) as i64)
|
||||
Self((((ratio.num as i128)<<32)/(ratio.den as i128)) as i64)
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
@@ -456,26 +459,8 @@ pub enum Planar64TryFromFloatError{
|
||||
Nan,
|
||||
Infinite,
|
||||
Subnormal,
|
||||
HighlyNegativeExponent(i16),
|
||||
HighlyPositiveExponent(i16),
|
||||
}
|
||||
#[inline]
|
||||
fn planar64_from_mes((m,e,s):(u64,i16,i8))->Result<Planar64,Planar64TryFromFloatError>{
|
||||
let e32=e+32;
|
||||
if e32<0&&(m>>-e32)==0{//shifting m will underflow to 0
|
||||
Ok(Planar64::ZERO)
|
||||
// println!("m{} e{} s{}",m,e,s);
|
||||
// println!("f={}",(m as f64)*(2.0f64.powf(e as f64))*(s as f64));
|
||||
// Err(Planar64TryFromFloatError::HighlyNegativeExponent(e))
|
||||
}else if (64-m.leading_zeros() as i16)+e32<64{//shifting m will not overflow
|
||||
if e32<0{
|
||||
Ok(Planar64((m as i64)*(s as i64)>>-e32))
|
||||
}else{
|
||||
Ok(Planar64((m as i64)*(s as i64)<<e32))
|
||||
}
|
||||
}else{//if shifting m will overflow (prev check failed)
|
||||
Err(Planar64TryFromFloatError::HighlyPositiveExponent(e))
|
||||
}
|
||||
HighlyNegativeExponent,
|
||||
HighlyPositiveExponent,
|
||||
}
|
||||
impl TryFrom<f32> for Planar64{
|
||||
type Error=Planar64TryFromFloatError;
|
||||
@@ -485,8 +470,15 @@ impl TryFrom<f32> for Planar64{
|
||||
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
||||
std::num::FpCategory::Normal=>planar64_from_mes(integer_decode_f32(value)),
|
||||
std::num::FpCategory::Subnormal
|
||||
|std::num::FpCategory::Normal=>{
|
||||
let planar=value*PLANAR64_ONE_FLOAT32;
|
||||
if planar<(i64::MIN as f32)||(i64::MAX as f32)<planar{
|
||||
Err(Self::Error::HighlyPositiveExponent)
|
||||
}else{
|
||||
Ok(Planar64(unsafe{planar.to_int_unchecked()}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -498,8 +490,15 @@ impl TryFrom<f64> for Planar64{
|
||||
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
||||
std::num::FpCategory::Normal=>planar64_from_mes(integer_decode_f64(value)),
|
||||
std::num::FpCategory::Subnormal
|
||||
|std::num::FpCategory::Normal=>{
|
||||
let planar=value*PLANAR64_ONE_FLOAT64;
|
||||
if planar<(i64::MIN as f64)||(i64::MAX as f64)<planar{
|
||||
Err(Self::Error::HighlyPositiveExponent)
|
||||
}else{
|
||||
Ok(Planar64(unsafe{planar.to_int_unchecked()}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -569,7 +568,7 @@ impl std::ops::Div<Planar64> for Planar64{
|
||||
type Output=Planar64;
|
||||
#[inline]
|
||||
fn div(self, rhs: Planar64) -> Self::Output {
|
||||
Planar64((((self.0 as i128)<<32)/rhs.0 as i128) as i64)
|
||||
Planar64((((self.0 as i128)<<32)/(rhs.0 as i128)) as i64)
|
||||
}
|
||||
}
|
||||
// impl PartialOrd<i64> for Planar64{
|
||||
@@ -804,6 +803,17 @@ impl std::ops::Mul<Time> for Planar64Vec3{
|
||||
))
|
||||
}
|
||||
}
|
||||
impl std::ops::Div<Planar64> for Planar64Vec3{
|
||||
type Output=Planar64Vec3;
|
||||
#[inline]
|
||||
fn div(self,rhs:Planar64)->Self::Output{
|
||||
Planar64Vec3(glam::i64vec3(
|
||||
(((self.0.x as i128)<<32)/(rhs.0 as i128)) as i64,
|
||||
(((self.0.y as i128)<<32)/(rhs.0 as i128)) as i64,
|
||||
(((self.0.z as i128)<<32)/(rhs.0 as i128)) as i64,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl std::ops::Div<i64> for Planar64Vec3{
|
||||
type Output=Planar64Vec3;
|
||||
#[inline]
|
||||
@@ -833,16 +843,6 @@ impl Default for Planar64Mat3{
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::ops::Mul<Planar64Vec3> for Planar64Mat3{
|
||||
type Output=Planar64Vec3;
|
||||
#[inline]
|
||||
fn mul(self,rhs:Planar64Vec3) -> Self::Output {
|
||||
self.x_axis*rhs.x()
|
||||
+self.y_axis*rhs.y()
|
||||
+self.z_axis*rhs.z()
|
||||
}
|
||||
}
|
||||
|
||||
impl Planar64Mat3{
|
||||
#[inline]
|
||||
pub fn from_cols(x_axis:Planar64Vec3,y_axis:Planar64Vec3,z_axis:Planar64Vec3)->Self{
|
||||
@@ -860,6 +860,14 @@ impl Planar64Mat3{
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn from_diagonal(diagonal:Planar64Vec3)->Self{
|
||||
Self{
|
||||
x_axis:Planar64Vec3::raw(diagonal.0.x,0,0),
|
||||
y_axis:Planar64Vec3::raw(0,diagonal.0.y,0),
|
||||
z_axis:Planar64Vec3::raw(0,0,diagonal.0.z),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_rotation_yx(yaw:Angle32,pitch:Angle32)->Self{
|
||||
let xtheta=yaw.0 as f64*ANGLE32_TO_FLOAT64_RADIANS;
|
||||
let (xs,xc)=xtheta.sin_cos();
|
||||
@@ -906,6 +914,14 @@ impl Planar64Mat3{
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn inverse_times_det(&self)->Self{
|
||||
Self{
|
||||
x_axis:Planar64Vec3::raw(((-(self.y_axis.0.z as i128*self.z_axis.0.y as i128)+self.y_axis.0.y as i128*self.z_axis.0.z as i128)>>32) as i64,((self.x_axis.0.z as i128*self.z_axis.0.y as i128-self.x_axis.0.y as i128*self.z_axis.0.z as i128)>>32) as i64,((-(self.x_axis.0.z as i128*self.y_axis.0.y as i128)+self.x_axis.0.y as i128*self.y_axis.0.z as i128)>>32) as i64),
|
||||
y_axis:Planar64Vec3::raw(((self.y_axis.0.z as i128*self.z_axis.0.x as i128-self.y_axis.0.x as i128*self.z_axis.0.z as i128)>>32) as i64,((-(self.x_axis.0.z as i128*self.z_axis.0.x as i128)+self.x_axis.0.x as i128*self.z_axis.0.z as i128)>>32) as i64,((self.x_axis.0.z as i128*self.y_axis.0.x as i128-self.x_axis.0.x as i128*self.y_axis.0.z as i128)>>32) as i64),
|
||||
z_axis:Planar64Vec3::raw(((-(self.y_axis.0.y as i128*self.z_axis.0.x as i128)+self.y_axis.0.x as i128*self.z_axis.0.y as i128)>>32) as i64,((self.x_axis.0.y as i128*self.z_axis.0.x as i128-self.x_axis.0.x as i128*self.z_axis.0.y as i128)>>32) as i64,((-(self.x_axis.0.y as i128*self.y_axis.0.x as i128)+self.x_axis.0.x as i128*self.y_axis.0.y as i128)>>32) as i64),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn transpose(&self)->Self{
|
||||
Self{
|
||||
x_axis:Planar64Vec3::raw(self.x_axis.0.x,self.y_axis.0.x,self.z_axis.0.x),
|
||||
@@ -955,6 +971,15 @@ impl std::fmt::Display for Planar64Mat3{
|
||||
)
|
||||
}
|
||||
}
|
||||
impl std::ops::Mul<Planar64Vec3> for Planar64Mat3{
|
||||
type Output=Planar64Vec3;
|
||||
#[inline]
|
||||
fn mul(self,rhs:Planar64Vec3) -> Self::Output {
|
||||
self.x_axis*rhs.x()
|
||||
+self.y_axis*rhs.y()
|
||||
+self.z_axis*rhs.z()
|
||||
}
|
||||
}
|
||||
impl std::ops::Div<i64> for Planar64Mat3{
|
||||
type Output=Planar64Mat3;
|
||||
#[inline]
|
||||
@@ -1023,7 +1048,7 @@ impl std::fmt::Display for Planar64Affine3{
|
||||
#[test]
|
||||
fn test_sqrt(){
|
||||
let r=Planar64::int(400);
|
||||
println!("r{}",r.get());
|
||||
assert_eq!(1717986918400,r.get());
|
||||
let s=r.sqrt();
|
||||
println!("s{}",s.get());
|
||||
assert_eq!(85899345920,s.get());
|
||||
}
|
||||
@@ -14,12 +14,15 @@ fn class_is_a(class: &str, superclass: &str) -> bool {
|
||||
return false
|
||||
}
|
||||
fn recursive_collect_superclass(objects: &mut std::vec::Vec<rbx_dom_weak::types::Ref>,dom: &rbx_dom_weak::WeakDom, instance: &rbx_dom_weak::Instance, superclass: &str){
|
||||
for &referent in instance.children() {
|
||||
if let Some(c) = dom.get_by_ref(referent) {
|
||||
if class_is_a(c.class.as_str(), superclass) {
|
||||
objects.push(c.referent());//copy ref
|
||||
let mut stack=vec![instance];
|
||||
while let Some(item)=stack.pop(){
|
||||
for &referent in item.children(){
|
||||
if let Some(c)=dom.get_by_ref(referent){
|
||||
if class_is_a(c.class.as_str(),superclass){
|
||||
objects.push(c.referent());//copy ref
|
||||
}
|
||||
stack.push(c);
|
||||
}
|
||||
recursive_collect_superclass(objects,dom,c,superclass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,6 +265,18 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::Index
|
||||
{
|
||||
let model_transform=planar64_affine3_from_roblox(cf,size);
|
||||
|
||||
if model_transform.matrix3.determinant()==Planar64::ZERO{
|
||||
let mut parent_ref=object.parent();
|
||||
let mut full_path=object.name.clone();
|
||||
while let Some(parent)=dom.get_by_ref(parent_ref){
|
||||
full_path=format!("{}.{}",parent.name,full_path);
|
||||
parent_ref=parent.parent();
|
||||
}
|
||||
println!("Zero determinant CFrame at location {}",full_path);
|
||||
println!("matrix3:{}",model_transform.matrix3);
|
||||
continue;
|
||||
}
|
||||
|
||||
//push TempIndexedAttributes
|
||||
let mut force_intersecting=false;
|
||||
let mut temp_indexing_attributes=Vec::new();
|
||||
|
||||
28
src/model.rs
28
src/model.rs
@@ -11,8 +11,33 @@ pub struct IndexedVertex{
|
||||
pub struct IndexedPolygon{
|
||||
pub vertices:Vec<u32>,
|
||||
}
|
||||
pub type TextureId=u32;
|
||||
pub type ShaderId=u32;
|
||||
pub enum ShaderResource{
|
||||
Model,//pass in model attributes
|
||||
Texture(TextureId),
|
||||
Depth,//current draw depth
|
||||
Normal,
|
||||
BehindTexture,//what is drawn behind this pixel
|
||||
}
|
||||
pub enum RenderType{
|
||||
NoTexture,//simply draw the vertex color or model color or something
|
||||
Texture(TextureId),
|
||||
Material{
|
||||
texture:TextureId,
|
||||
normal:TextureId,
|
||||
},
|
||||
//GUI,
|
||||
Portal{
|
||||
transform:glam::Mat4,
|
||||
},
|
||||
Shader{
|
||||
id:ShaderId,
|
||||
resources:Vec<ShaderResource>,
|
||||
},
|
||||
}
|
||||
pub struct IndexedGroup{
|
||||
pub texture:Option<u32>,//RenderPattern? material/texture/shader/flat color
|
||||
pub texture:Option<u32>,//TODO: RenderType
|
||||
pub polys:Vec<IndexedPolygon>,
|
||||
}
|
||||
pub struct IndexedModel{
|
||||
@@ -259,7 +284,6 @@ impl IntersectingAttributes{
|
||||
}
|
||||
}
|
||||
//Spawn(u32) NO! spawns are indexed in the map header instead of marked with attibutes
|
||||
//TODO: deduplicate attributes
|
||||
pub enum CollisionAttributes{
|
||||
Decoration,//visual only
|
||||
Contact{//track whether you are contacting the object
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
487
src/physics.rs
487
src/physics.rs
@@ -43,6 +43,17 @@ pub struct Body{
|
||||
pub acceleration:Planar64Vec3,//I64 where 2^32 = 1 u/s/s
|
||||
pub time:Time,//nanoseconds x xxxxD!
|
||||
}
|
||||
impl std::ops::Neg for Body{
|
||||
type Output=Self;
|
||||
fn neg(self)->Self::Output{
|
||||
Self{
|
||||
position:self.position,
|
||||
velocity:-self.velocity,
|
||||
acceleration:self.acceleration,
|
||||
time:-self.time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//hey dumbass just use a delta
|
||||
#[derive(Clone,Debug)]
|
||||
@@ -191,6 +202,7 @@ impl PhysicsModels{
|
||||
&self.meshes[self.models[model_id].mesh_id],
|
||||
&self.models[model_id].transform,
|
||||
&self.models[model_id].normal_transform,
|
||||
self.models[model_id].transform_det,
|
||||
)
|
||||
}
|
||||
fn model(&self,model_id:usize)->&PhysicsModel{
|
||||
@@ -327,6 +339,60 @@ struct StrafeSettings{
|
||||
tick_rate:Ratio64,
|
||||
}
|
||||
|
||||
struct Hitbox{
|
||||
halfsize:Planar64Vec3,
|
||||
mesh:PhysicsMesh,
|
||||
transform:crate::integer::Planar64Affine3,
|
||||
normal_transform:Planar64Mat3,
|
||||
transform_det:Planar64,
|
||||
}
|
||||
impl Hitbox{
|
||||
fn new(mesh:PhysicsMesh,transform:crate::integer::Planar64Affine3)->Self{
|
||||
//calculate extents
|
||||
let mut aabb=crate::aabb::Aabb::default();
|
||||
for vert in mesh.verts(){
|
||||
aabb.grow(transform.transform_point3(vert));
|
||||
}
|
||||
Self{
|
||||
halfsize:aabb.size()/2,
|
||||
mesh,
|
||||
transform,
|
||||
normal_transform:transform.matrix3.inverse_times_det().transpose(),
|
||||
transform_det:transform.matrix3.determinant(),
|
||||
}
|
||||
}
|
||||
fn from_mesh_scale(mesh:PhysicsMesh,scale:Planar64Vec3)->Self{
|
||||
let matrix3=Planar64Mat3::from_diagonal(scale);
|
||||
Self{
|
||||
halfsize:scale,
|
||||
mesh,
|
||||
normal_transform:matrix3.inverse_times_det().transpose(),
|
||||
transform:crate::integer::Planar64Affine3::new(matrix3,Planar64Vec3::ZERO),
|
||||
transform_det:matrix3.determinant(),//scale.x*scale.y*scale.z but whatever
|
||||
}
|
||||
}
|
||||
fn from_mesh_scale_offset(mesh:PhysicsMesh,scale:Planar64Vec3,offset:Planar64Vec3)->Self{
|
||||
let matrix3=Planar64Mat3::from_diagonal(scale);
|
||||
Self{
|
||||
halfsize:scale,
|
||||
mesh,
|
||||
normal_transform:matrix3.inverse_times_det().transpose(),
|
||||
transform:crate::integer::Planar64Affine3::new(matrix3,offset),
|
||||
transform_det:matrix3.determinant(),
|
||||
}
|
||||
}
|
||||
fn roblox()->Self{
|
||||
Self::from_mesh_scale(PhysicsMesh::from(&crate::primitives::unit_cylinder()),Planar64Vec3::int(2,5,2)/2)
|
||||
}
|
||||
fn source()->Self{
|
||||
Self::from_mesh_scale(PhysicsMesh::from(&crate::primitives::unit_cube()),Planar64Vec3::raw(33<<28,73<<28,33<<28)/2)
|
||||
}
|
||||
#[inline]
|
||||
fn transformed_mesh(&self)->TransformedMesh{
|
||||
TransformedMesh::new(&self.mesh,&self.transform,&self.normal_transform,self.transform_det)
|
||||
}
|
||||
}
|
||||
|
||||
struct StyleModifiers{
|
||||
controls_used:u32,//controls which are allowed to pass into gameplay
|
||||
controls_mask:u32,//controls which are masked from control state (e.g. jump in scroll style)
|
||||
@@ -346,7 +412,7 @@ struct StyleModifiers{
|
||||
surf_slope:Option<Planar64>,
|
||||
rocket_force:Option<Planar64>,
|
||||
gravity:Planar64Vec3,
|
||||
hitbox_halfsize:Planar64Vec3,
|
||||
hitbox:Hitbox,
|
||||
camera_offset:Planar64Vec3,
|
||||
}
|
||||
impl std::default::Default for StyleModifiers{
|
||||
@@ -368,14 +434,14 @@ impl StyleModifiers{
|
||||
const UP_DIR:Planar64Vec3=Planar64Vec3::Y;
|
||||
const FORWARD_DIR:Planar64Vec3=Planar64Vec3::NEG_Z;
|
||||
|
||||
fn new()->Self{
|
||||
fn neo()->Self{
|
||||
Self{
|
||||
controls_used:!0,
|
||||
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:EnableStrafe::Always,
|
||||
air_accel_limit:None,
|
||||
tick_rate:Ratio64::new(128,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
tick_rate:Ratio64::new(64,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump_impulse:JumpImpulse::FromEnergy(Planar64::int(512)),
|
||||
jump_calculation:JumpCalculation::Energy,
|
||||
@@ -383,7 +449,7 @@ impl StyleModifiers{
|
||||
static_friction:Planar64::int(2),
|
||||
kinetic_friction:Planar64::int(3),//unrealistic: kinetic friction is typically lower than static
|
||||
mass:Planar64::int(1),
|
||||
mv:Planar64::int(2),
|
||||
mv:Planar64::int(3),
|
||||
rocket_force:None,
|
||||
walk_speed:Planar64::int(16),
|
||||
walk_accel:Planar64::int(80),
|
||||
@@ -392,7 +458,7 @@ impl StyleModifiers{
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),
|
||||
swim_speed:Planar64::int(12),
|
||||
surf_slope:Some(Planar64::raw(7)/8),
|
||||
hitbox_halfsize:Planar64Vec3::int(2,5,2)/2,
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
@@ -421,7 +487,7 @@ impl StyleModifiers{
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),
|
||||
swim_speed:Planar64::int(12),
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox_halfsize:Planar64Vec3::int(2,5,2)/2,
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
@@ -449,7 +515,7 @@ impl StyleModifiers{
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),
|
||||
swim_speed:Planar64::int(12),
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox_halfsize:Planar64Vec3::int(2,5,2)/2,
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
@@ -460,7 +526,7 @@ impl StyleModifiers{
|
||||
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
|
||||
strafe:Some(StrafeSettings{
|
||||
enable:EnableStrafe::Always,
|
||||
air_accel_limit:Some(Planar64::raw(150<<28)*66),
|
||||
air_accel_limit:Some(Planar64::raw(150<<28)*100),
|
||||
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||
}),
|
||||
jump_impulse:JumpImpulse::FromHeight(Planar64::raw(52<<28)),
|
||||
@@ -478,7 +544,7 @@ impl StyleModifiers{
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),//?
|
||||
swim_speed:Planar64::int(12),//?
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox_halfsize:Planar64Vec3::raw(33<<28,73<<28,33<<28)/2,
|
||||
hitbox:Hitbox::source(),
|
||||
camera_offset:Planar64Vec3::raw(0,(64<<28)-(73<<27),0),
|
||||
}
|
||||
}
|
||||
@@ -506,7 +572,7 @@ impl StyleModifiers{
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),//?
|
||||
swim_speed:Planar64::int(12),//?
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox_halfsize:Planar64Vec3::raw(33<<28,73<<28,33<<28)/2,
|
||||
hitbox:Hitbox::source(),
|
||||
camera_offset:Planar64Vec3::raw(0,(64<<28)-(73<<27),0),
|
||||
}
|
||||
}
|
||||
@@ -530,7 +596,7 @@ impl StyleModifiers{
|
||||
ladder_dot:(Planar64::int(1)/2).sqrt(),
|
||||
swim_speed:Planar64::int(12),
|
||||
surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75
|
||||
hitbox_halfsize:Planar64Vec3::int(2,5,2)/2,
|
||||
hitbox:Hitbox::roblox(),
|
||||
camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2
|
||||
}
|
||||
}
|
||||
@@ -644,6 +710,10 @@ impl StyleModifiers{
|
||||
let camera_mat=camera.simulate_move_rotation(camera.mouse.lerp(&next_mouse,time));
|
||||
camera_mat*self.get_control_dir(controls)
|
||||
}
|
||||
#[inline]
|
||||
fn mesh(&self)->TransformedMesh{
|
||||
self.hitbox.transformed_mesh()
|
||||
}
|
||||
}
|
||||
|
||||
enum MoveState{
|
||||
@@ -715,24 +785,24 @@ pub struct PhysicsModel{
|
||||
attr_id:usize,
|
||||
transform:crate::integer::Planar64Affine3,
|
||||
normal_transform:crate::integer::Planar64Mat3,
|
||||
transform_det:Planar64,
|
||||
}
|
||||
|
||||
impl PhysicsModel{
|
||||
pub fn new(mesh_id:usize,attr_id:usize,transform:crate::integer::Planar64Affine3)->Self{
|
||||
let normal_transform=transform.matrix3.inverse().transpose();
|
||||
Self{
|
||||
mesh_id,
|
||||
attr_id,
|
||||
transform,
|
||||
normal_transform,
|
||||
normal_transform:transform.matrix3.inverse_times_det().transpose(),
|
||||
transform_det:transform.matrix3.determinant(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Eq,Hash,PartialEq)]
|
||||
struct ContactCollision{
|
||||
//face_id:crate::model_physics::MinkowskiFace,
|
||||
face_id:crate::model_physics::FaceId,
|
||||
face_id:crate::model_physics::MinkowskiFace,
|
||||
model_id:usize,//using id to avoid lifetimes
|
||||
}
|
||||
#[derive(Debug,Clone,Eq,Hash,PartialEq)]
|
||||
@@ -751,7 +821,7 @@ impl Collision{
|
||||
|&Collision::Intersect(IntersectCollision{model_id})=>model_id,
|
||||
}
|
||||
}
|
||||
fn face_id(&self)->Option<crate::model_physics::FaceId>{
|
||||
fn face_id(&self)->Option<crate::model_physics::MinkowskiFace>{
|
||||
match self{
|
||||
&Collision::Contact(ContactCollision{model_id:_,face_id})=>Some(face_id),
|
||||
&Collision::Intersect(IntersectCollision{model_id:_})=>None,
|
||||
@@ -811,20 +881,20 @@ impl TouchingState{
|
||||
//add water../?
|
||||
a
|
||||
}
|
||||
fn constrain_velocity(&self,models:&PhysicsModels,velocity:&mut Planar64Vec3){
|
||||
fn constrain_velocity(&self,models:&PhysicsModels,style_mesh:&TransformedMesh,velocity:&mut Planar64Vec3){
|
||||
//TODO: trey push solve
|
||||
for contact in &self.contacts{
|
||||
let n=models.mesh(contact.model_id).face_nd(contact.face_id).0;
|
||||
let n=contact_normal(models,style_mesh,contact);
|
||||
let d=n.dot128(*velocity);
|
||||
if d<0{
|
||||
*velocity-=n*Planar64::raw(((d<<32)/n.dot128(n)) as i64);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn constrain_acceleration(&self,models:&PhysicsModels,acceleration:&mut Planar64Vec3){
|
||||
fn constrain_acceleration(&self,models:&PhysicsModels,style_mesh:&TransformedMesh,acceleration:&mut Planar64Vec3){
|
||||
//TODO: trey push solve
|
||||
for contact in &self.contacts{
|
||||
let n=models.mesh(contact.model_id).face_nd(contact.face_id).0;
|
||||
let n=contact_normal(models,style_mesh,contact);
|
||||
let d=n.dot128(*acceleration);
|
||||
if d<0{
|
||||
*acceleration-=n*Planar64::raw(((d<<32)/n.dot128(n)) as i64);
|
||||
@@ -835,30 +905,31 @@ impl TouchingState{
|
||||
//check current move conditions and use heuristics to determine
|
||||
//which ladder to climb on, which ground to walk on, etc
|
||||
//collect move state affecting objects from contacts (accelerator,water,ladder,ground)
|
||||
let style_mesh=style.mesh();
|
||||
let gravity=self.base_acceleration(models,style,camera,controls,next_mouse,time);
|
||||
let mut move_state=MoveState::Air;
|
||||
let mut a=gravity;
|
||||
for contact in &self.contacts{
|
||||
match models.attr(contact.model_id){
|
||||
PhysicsCollisionAttributes::Contact{contacting,general}=>{
|
||||
let normal=models.mesh(contact.model_id).face_nd(contact.face_id).0;
|
||||
let normal=contact_normal(models,&style_mesh,contact);
|
||||
match &contacting.contact_behaviour{
|
||||
Some(crate::model::ContactingBehaviour::Ladder(_))=>{
|
||||
//ladder walkstate
|
||||
let mut target_velocity=style.get_ladder_target_velocity(camera,controls,next_mouse,time,&normal);
|
||||
self.constrain_velocity(models,&mut target_velocity);
|
||||
self.constrain_velocity(models,&style_mesh,&mut target_velocity);
|
||||
let (walk_state,mut acceleration)=WalkState::ladder(body,style,gravity,target_velocity,contact.clone(),&normal);
|
||||
move_state=MoveState::Ladder(walk_state);
|
||||
self.constrain_acceleration(models,&mut acceleration);
|
||||
self.constrain_acceleration(models,&style_mesh,&mut acceleration);
|
||||
a=acceleration;
|
||||
},
|
||||
None=>if style.surf_slope.map_or(true,|s|normal.walkable(s,Planar64Vec3::Y)){
|
||||
//check ground
|
||||
let mut target_velocity=style.get_walk_target_velocity(camera,controls,next_mouse,time,&normal);
|
||||
self.constrain_velocity(models,&mut target_velocity);
|
||||
self.constrain_velocity(models,&style_mesh,&mut target_velocity);
|
||||
let (walk_state,mut acceleration)=WalkState::ground(body,style,gravity,target_velocity,contact.clone(),&normal);
|
||||
move_state=MoveState::Walk(walk_state);
|
||||
self.constrain_acceleration(models,&mut acceleration);
|
||||
self.constrain_acceleration(models,&style_mesh,&mut acceleration);
|
||||
a=acceleration;
|
||||
},
|
||||
_=>(),
|
||||
@@ -868,15 +939,18 @@ impl TouchingState{
|
||||
}
|
||||
}
|
||||
for intersect in &self.intersects{
|
||||
//
|
||||
//water
|
||||
}
|
||||
self.constrain_acceleration(models,&mut a);
|
||||
self.constrain_acceleration(models,&style_mesh,&mut a);
|
||||
(move_state,a)
|
||||
}
|
||||
fn predict_collision_end(&self,collector:&mut crate::instruction::InstructionCollector<PhysicsInstruction>,models:&PhysicsModels,body:&Body,time:Time){
|
||||
fn predict_collision_end(&self,collector:&mut crate::instruction::InstructionCollector<PhysicsInstruction>,models:&PhysicsModels,style_mesh:&TransformedMesh,body:&Body,time:Time){
|
||||
let relative_body=VirtualBody::relative(&Body::default(),body).body(time);
|
||||
for contact in &self.contacts{
|
||||
//detect face slide off
|
||||
collector.collect(models.mesh(contact.model_id).brute_out_face(body,collector.time(),contact.face_id).map(|(face,time)|{
|
||||
let model_mesh=models.mesh(contact.model_id);
|
||||
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&style_mesh);
|
||||
collector.collect(minkowski.predict_collision_face_out(&relative_body,collector.time(),contact.face_id).map(|(face,time)|{
|
||||
TimedInstruction{
|
||||
time,
|
||||
instruction:PhysicsInstruction::CollisionEnd(
|
||||
@@ -885,10 +959,11 @@ impl TouchingState{
|
||||
}
|
||||
}));
|
||||
}
|
||||
let relative_body=VirtualBody::relative(&Body::default(),body).body(time);
|
||||
for intersect in &self.intersects{
|
||||
//detect model collision in reverse
|
||||
collector.collect(models.mesh(intersect.model_id).brute_out(&relative_body,collector.time()).map(|(face,time)|{
|
||||
let model_mesh=models.mesh(intersect.model_id);
|
||||
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&style_mesh);
|
||||
collector.collect(minkowski.predict_collision_out(&relative_body,collector.time()).map(|(face,time)|{
|
||||
TimedInstruction{
|
||||
time,
|
||||
instruction:PhysicsInstruction::CollisionEnd(
|
||||
@@ -922,6 +997,42 @@ impl Body{
|
||||
self.velocity=self.extrapolated_velocity(time);
|
||||
self.time=time;
|
||||
}
|
||||
pub fn infinity_dir(&self)->Option<Planar64Vec3>{
|
||||
if self.velocity==Planar64Vec3::ZERO{
|
||||
if self.acceleration==Planar64Vec3::ZERO{
|
||||
None
|
||||
}else{
|
||||
Some(self.acceleration)
|
||||
}
|
||||
}else{
|
||||
Some(self.velocity)
|
||||
}
|
||||
}
|
||||
pub fn grow_aabb(&self,aabb:&mut crate::aabb::Aabb,t0:Time,t1:Time){
|
||||
aabb.grow(self.extrapolated_position(t0));
|
||||
aabb.grow(self.extrapolated_position(t1));
|
||||
//v+a*t==0
|
||||
//goober code
|
||||
if self.acceleration.x()!=Planar64::ZERO{
|
||||
let t=Time::from(-self.velocity.x()/self.acceleration.x());
|
||||
if t0<t&&t<t1{
|
||||
aabb.grow(self.extrapolated_position(t));
|
||||
}
|
||||
}
|
||||
if self.acceleration.y()!=Planar64::ZERO{
|
||||
let t=Time::from(-self.velocity.y()/self.acceleration.y());
|
||||
if t0<t&&t<t1{
|
||||
aabb.grow(self.extrapolated_position(t));
|
||||
}
|
||||
}
|
||||
if self.acceleration.z()!=Planar64::ZERO{
|
||||
let t=Time::from(-self.velocity.z()/self.acceleration.z());
|
||||
if t0<t&&t<t1{
|
||||
aabb.grow(self.extrapolated_position(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
impl std::fmt::Display for Body{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
@@ -1132,21 +1243,23 @@ impl PhysicsState {
|
||||
match &mut self.move_state{
|
||||
MoveState::Air|MoveState::Water=>self.touching.base_acceleration(&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time),
|
||||
MoveState::Walk(WalkState{state,contact,jump_direction:_})=>{
|
||||
let n=self.models.mesh(contact.model_id).face_nd(contact.face_id).0;
|
||||
let style_mesh=self.style.mesh();
|
||||
let n=contact_normal(&self.models,&style_mesh,contact);
|
||||
let gravity=self.touching.base_acceleration(&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time);
|
||||
let mut a;
|
||||
let mut v=self.style.get_walk_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time,&n);
|
||||
self.touching.constrain_velocity(&self.models,&mut v);
|
||||
self.touching.constrain_velocity(&self.models,&style_mesh,&mut v);
|
||||
let normal_accel=-n.dot(gravity)/n.length();
|
||||
(*state,a)=WalkEnum::with_target_velocity(&self.body,&self.style,v,&n,self.style.walk_speed,normal_accel);
|
||||
a
|
||||
},
|
||||
MoveState::Ladder(WalkState{state,contact,jump_direction:_})=>{
|
||||
let n=self.models.mesh(contact.model_id).face_nd(contact.face_id).0;
|
||||
let style_mesh=self.style.mesh();
|
||||
let n=contact_normal(&self.models,&style_mesh,contact);
|
||||
let gravity=self.touching.base_acceleration(&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time);
|
||||
let mut a;
|
||||
let mut v=self.style.get_ladder_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time,&n);
|
||||
self.touching.constrain_velocity(&self.models,&mut v);
|
||||
self.touching.constrain_velocity(&self.models,&style_mesh,&mut v);
|
||||
(*state,a)=WalkEnum::with_target_velocity(&self.body,&self.style,v,&n,self.style.ladder_speed,self.style.ladder_accel);
|
||||
a
|
||||
},
|
||||
@@ -1176,20 +1289,23 @@ impl crate::instruction::InstructionEmitter<PhysicsInstruction> for PhysicsState
|
||||
|
||||
collector.collect(self.next_move_instruction());
|
||||
|
||||
let style_mesh=self.style.mesh();
|
||||
//check for collision ends
|
||||
self.touching.predict_collision_end(&mut collector,&self.models,&self.body,self.time);
|
||||
self.touching.predict_collision_end(&mut collector,&self.models,&style_mesh,&self.body,self.time);
|
||||
//check for collision starts
|
||||
let mut aabb=crate::aabb::Aabb::default();
|
||||
aabb.grow(self.body.extrapolated_position(self.time));
|
||||
aabb.grow(self.body.extrapolated_position(collector.time()));
|
||||
aabb.inflate(self.style.hitbox_halfsize);
|
||||
self.body.grow_aabb(&mut aabb,self.time,collector.time());
|
||||
aabb.inflate(self.style.hitbox.halfsize);
|
||||
//common body
|
||||
let relative_body=VirtualBody::relative(&Body::default(),&self.body).body(self.time);
|
||||
self.bvh.the_tester(&aabb,&mut |id|{
|
||||
//no checks are needed because of the time limits.
|
||||
//let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(self.style.mesh,&self.models.mesh(id));
|
||||
//collector.collect(crate::face_crawler::predict_collision(&minkowski,&relative_body,collector.time()).map(|(face,time)|{
|
||||
collector.collect(self.models.mesh(id).brute_in(&relative_body,collector.time()).map(|(face,time)|{
|
||||
let model_mesh=self.models.mesh(id);
|
||||
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&style_mesh);
|
||||
collector.collect(minkowski.predict_collision_in(&relative_body,collector.time())
|
||||
//temp (?) code to avoid collision loops
|
||||
.map_or(None,|(face,time)|if time==self.time{None}else{Some((face,time))})
|
||||
.map(|(face,time)|{
|
||||
TimedInstruction{time,instruction:PhysicsInstruction::CollisionStart(match self.models.attr(id){
|
||||
PhysicsCollisionAttributes::Contact{contacting:_,general:_}=>Collision::Contact(ContactCollision{model_id:id,face_id:face}),
|
||||
PhysicsCollisionAttributes::Intersect{intersecting:_,general:_}=>Collision::Intersect(IntersectCollision{model_id:id}),
|
||||
@@ -1209,12 +1325,18 @@ fn get_walk_state(move_state:&MoveState)->Option<&WalkState>{
|
||||
|
||||
fn jumped_velocity(models:&PhysicsModels,style:&StyleModifiers,walk_state:&WalkState,v:&mut Planar64Vec3){
|
||||
let jump_dir=match &walk_state.jump_direction{
|
||||
JumpDirection::FromContactNormal=>models.mesh(walk_state.contact.model_id).face_nd(walk_state.contact.face_id).0,
|
||||
JumpDirection::FromContactNormal=>contact_normal(models,&style.mesh(),&walk_state.contact),
|
||||
&JumpDirection::Exactly(dir)=>dir,
|
||||
};
|
||||
*v=*v+jump_dir*(style.get_jump_deltav()/jump_dir.length());
|
||||
}
|
||||
|
||||
fn contact_normal(models:&PhysicsModels,style_mesh:&TransformedMesh,contact:&ContactCollision)->Planar64Vec3{
|
||||
let model_mesh=models.mesh(contact.model_id);
|
||||
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,style_mesh);
|
||||
minkowski.face_nd(contact.face_id).0
|
||||
}
|
||||
|
||||
fn set_position(body:&mut Body,touching:&mut TouchingState,point:Planar64Vec3)->Planar64Vec3{
|
||||
//test intersections at new position
|
||||
//hovering above the surface 0 units is not intersecting. you will fall into it just fine
|
||||
@@ -1225,11 +1347,11 @@ fn set_position(body:&mut Body,touching:&mut TouchingState,point:Planar64Vec3)->
|
||||
//touching.recalculate(body);
|
||||
point
|
||||
}
|
||||
fn set_velocity_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,v:Planar64Vec3)->bool{
|
||||
fn set_velocity_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,style_mesh:&TransformedMesh,v:Planar64Vec3)->bool{
|
||||
//This is not correct but is better than what I have
|
||||
let mut culled=false;
|
||||
touching.contacts.retain(|contact|{
|
||||
let n=models.mesh(contact.model_id).face_nd(contact.face_id).0;
|
||||
let n=contact_normal(models,style_mesh,contact);
|
||||
let r=n.dot(v)<=Planar64::ZERO;
|
||||
if !r{
|
||||
culled=true;
|
||||
@@ -1237,19 +1359,19 @@ fn set_velocity_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsM
|
||||
}
|
||||
r
|
||||
});
|
||||
set_velocity(body,touching,models,v);
|
||||
set_velocity(body,touching,models,style_mesh,v);
|
||||
culled
|
||||
}
|
||||
fn set_velocity(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,mut v:Planar64Vec3)->Planar64Vec3{
|
||||
touching.constrain_velocity(&models,&mut v);
|
||||
fn set_velocity(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,style_mesh:&TransformedMesh,mut v:Planar64Vec3)->Planar64Vec3{
|
||||
touching.constrain_velocity(models,style_mesh,&mut v);
|
||||
body.velocity=v;
|
||||
v
|
||||
}
|
||||
fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,a:Planar64Vec3)->bool{
|
||||
fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,style_mesh:&TransformedMesh,a:Planar64Vec3)->bool{
|
||||
//This is not correct but is better than what I have
|
||||
let mut culled=false;
|
||||
touching.contacts.retain(|contact|{
|
||||
let n=models.mesh(contact.model_id).face_nd(contact.face_id).0;
|
||||
let n=contact_normal(models,style_mesh,contact);
|
||||
let r=n.dot(a)<=Planar64::ZERO;
|
||||
if !r{
|
||||
culled=true;
|
||||
@@ -1257,23 +1379,23 @@ fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&Phys
|
||||
}
|
||||
r
|
||||
});
|
||||
set_acceleration(body,touching,models,a);
|
||||
set_acceleration(body,touching,models,style_mesh,a);
|
||||
culled
|
||||
}
|
||||
fn set_acceleration(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,mut a:Planar64Vec3)->Planar64Vec3{
|
||||
touching.constrain_acceleration(&models,&mut a);
|
||||
fn set_acceleration(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,style_mesh:&TransformedMesh,mut a:Planar64Vec3)->Planar64Vec3{
|
||||
touching.constrain_acceleration(models,style_mesh,&mut a);
|
||||
body.acceleration=a;
|
||||
a
|
||||
}
|
||||
|
||||
fn teleport(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,style:&StyleModifiers,point:Planar64Vec3)->MoveState{
|
||||
set_position(body,touching,point);
|
||||
set_acceleration(body,touching,models,style.gravity);
|
||||
set_acceleration(body,touching,models,&style.mesh(),style.gravity);
|
||||
MoveState::Air
|
||||
}
|
||||
fn teleport_to_spawn(body:&mut Body,touching:&mut TouchingState,style:&StyleModifiers,mode:&crate::model::ModeDescription,models:&PhysicsModels,stage_id:u32)->Option<MoveState>{
|
||||
let model=models.model(*mode.get_spawn_model_id(stage_id)? as usize);
|
||||
let point=model.transform.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(style.hitbox_halfsize.y()+Planar64::ONE/16);
|
||||
let point=model.transform.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(style.hitbox.halfsize.y()+Planar64::ONE/16);
|
||||
Some(teleport(body,touching,models,style,point))
|
||||
}
|
||||
|
||||
@@ -1362,41 +1484,42 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
}
|
||||
match ins.instruction{
|
||||
PhysicsInstruction::CollisionStart(c)=>{
|
||||
let style_mesh=self.style.mesh();
|
||||
let model_id=c.model_id();
|
||||
match (self.models.attr(model_id),&c){
|
||||
(PhysicsCollisionAttributes::Contact{contacting,general},Collision::Contact(contact))=>{
|
||||
let mut v=self.body.velocity;
|
||||
let normal=self.models.mesh(model_id).face_nd(contact.face_id).0;
|
||||
let normal=contact_normal(&self.models,&style_mesh,contact);
|
||||
match &contacting.contact_behaviour{
|
||||
Some(crate::model::ContactingBehaviour::Surf)=>println!("I'm surfing!"),
|
||||
Some(crate::model::ContactingBehaviour::Cling)=>println!("Unimplemented!"),
|
||||
&Some(crate::model::ContactingBehaviour::Elastic(elasticity))=>{
|
||||
let n=self.models.mesh(contact.model_id).face_nd(contact.face_id).0;
|
||||
//velocity and normal are facing opposite directions so this is inherently negative.
|
||||
let d=n.dot(v)*(Planar64::ONE+Planar64::raw(elasticity as i64+1));
|
||||
v+=n*(d/n.dot(n));
|
||||
let d=normal.dot(v)*(Planar64::ONE+Planar64::raw(elasticity as i64+1));
|
||||
v+=normal*(d/normal.dot(normal));
|
||||
},
|
||||
Some(crate::model::ContactingBehaviour::Ladder(contacting_ladder))=>{
|
||||
if contacting_ladder.sticky{
|
||||
//kill v
|
||||
//actually you could do this with a booster attribute :thinking:
|
||||
v=Planar64Vec3::ZERO;//model.velocity
|
||||
}
|
||||
//ladder walkstate
|
||||
let gravity=self.touching.base_acceleration(&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time);
|
||||
let mut target_velocity=self.style.get_ladder_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time,&normal);
|
||||
self.touching.constrain_velocity(&self.models,&mut target_velocity);
|
||||
self.touching.constrain_velocity(&self.models,&style_mesh,&mut target_velocity);
|
||||
let (walk_state,a)=WalkState::ladder(&self.body,&self.style,gravity,target_velocity,contact.clone(),&normal);
|
||||
self.move_state=MoveState::Ladder(walk_state);
|
||||
set_acceleration(&mut self.body,&self.touching,&self.models,a);
|
||||
set_acceleration(&mut self.body,&self.touching,&self.models,&style_mesh,a);
|
||||
}
|
||||
None=>if self.style.surf_slope.map_or(true,|s|self.models.mesh(model_id).face_nd(contact.face_id).0.walkable(s,Planar64Vec3::Y)){
|
||||
None=>if self.style.surf_slope.map_or(true,|s|contact_normal(&self.models,&style_mesh,contact).walkable(s,Planar64Vec3::Y)){
|
||||
//ground
|
||||
let gravity=self.touching.base_acceleration(&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time);
|
||||
let mut target_velocity=self.style.get_walk_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time,&normal);
|
||||
self.touching.constrain_velocity(&self.models,&mut target_velocity);
|
||||
self.touching.constrain_velocity(&self.models,&style_mesh,&mut target_velocity);
|
||||
let (walk_state,a)=WalkState::ground(&self.body,&self.style,gravity,target_velocity,contact.clone(),&normal);
|
||||
self.move_state=MoveState::Walk(walk_state);
|
||||
set_acceleration(&mut self.body,&self.touching,&self.models,a);
|
||||
set_acceleration(&mut self.body,&self.touching,&self.models,&style_mesh,a);
|
||||
},
|
||||
}
|
||||
//check ground
|
||||
@@ -1404,7 +1527,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
//I love making functions with 10 arguments to dodge the borrow checker
|
||||
run_teleport_behaviour(&general.teleport_behaviour,&mut self.game,&self.models,&self.modes,&self.style,&mut self.touching,&mut self.body,model_id);
|
||||
//flatten v
|
||||
self.touching.constrain_velocity(&self.models,&mut v);
|
||||
self.touching.constrain_velocity(&self.models,&style_mesh,&mut v);
|
||||
match &general.booster{
|
||||
Some(booster)=>{
|
||||
//DELETE THIS when boosters get converted to height machines
|
||||
@@ -1419,7 +1542,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
let calc_move=if self.style.get_control(StyleModifiers::CONTROL_JUMP,self.controls){
|
||||
if let Some(walk_state)=get_walk_state(&self.move_state){
|
||||
jumped_velocity(&self.models,&self.style,walk_state,&mut v);
|
||||
set_velocity_cull(&mut self.body,&mut self.touching,&self.models,v)
|
||||
set_velocity_cull(&mut self.body,&mut self.touching,&self.models,&style_mesh,v)
|
||||
}else{false}
|
||||
}else{false};
|
||||
match &general.trajectory{
|
||||
@@ -1435,13 +1558,13 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
},
|
||||
None=>(),
|
||||
}
|
||||
set_velocity(&mut self.body,&self.touching,&self.models,v);
|
||||
set_velocity(&mut self.body,&self.touching,&self.models,&style_mesh,v);
|
||||
//not sure if or is correct here
|
||||
if calc_move||Planar64::ZERO<normal.dot(v){
|
||||
(self.move_state,self.body.acceleration)=self.touching.get_move_state(&self.body,&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time);
|
||||
}
|
||||
let a=self.refresh_walk_target();
|
||||
set_acceleration(&mut self.body,&self.touching,&self.models,a);
|
||||
set_acceleration(&mut self.body,&self.touching,&self.models,&self.style.mesh(),a);
|
||||
},
|
||||
(PhysicsCollisionAttributes::Intersect{intersecting: _,general},Collision::Intersect(intersect))=>{
|
||||
//I think that setting the velocity to 0 was preventing surface contacts from entering an infinite loop
|
||||
@@ -1474,7 +1597,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
let v=self.body.velocity+control_dir*(self.style.mv-d);
|
||||
//this is wrong but will work ig
|
||||
//need to note which push planes activate in push solve and keep those
|
||||
if set_velocity_cull(&mut self.body,&mut self.touching,&self.models,v){
|
||||
if set_velocity_cull(&mut self.body,&mut self.touching,&self.models,&self.style.mesh(),v){
|
||||
(self.move_state,self.body.acceleration)=self.touching.get_move_state(&self.body,&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time);
|
||||
}
|
||||
}
|
||||
@@ -1487,11 +1610,12 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
match &mut walk_state.state{
|
||||
WalkEnum::Reached=>(),
|
||||
WalkEnum::Transient(walk_target)=>{
|
||||
let style_mesh=self.style.mesh();
|
||||
//precisely set velocity
|
||||
let a=Planar64Vec3::ZERO;//ignore gravity for now.
|
||||
set_acceleration(&mut self.body,&self.touching,&self.models,a);
|
||||
set_acceleration(&mut self.body,&self.touching,&self.models,&style_mesh,a);
|
||||
let v=walk_target.velocity;
|
||||
set_velocity(&mut self.body,&self.touching,&self.models,v);
|
||||
set_velocity(&mut self.body,&self.touching,&self.models,&style_mesh,v);
|
||||
walk_state.state=WalkEnum::Reached;
|
||||
},
|
||||
}
|
||||
@@ -1520,7 +1644,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
if let Some(walk_state)=get_walk_state(&self.move_state){
|
||||
let mut v=self.body.velocity;
|
||||
jumped_velocity(&self.models,&self.style,walk_state,&mut v);
|
||||
if set_velocity_cull(&mut self.body,&mut self.touching,&self.models,v){
|
||||
if set_velocity_cull(&mut self.body,&mut self.touching,&self.models,&self.style.mesh(),v){
|
||||
(self.move_state,self.body.acceleration)=self.touching.get_move_state(&self.body,&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time);
|
||||
}
|
||||
}
|
||||
@@ -1533,7 +1657,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
PhysicsInputInstruction::Reset => {
|
||||
//it matters which of these runs first, but I have not thought it through yet as it doesn't matter yet
|
||||
set_position(&mut self.body,&mut self.touching,self.spawn_point);
|
||||
set_velocity(&mut self.body,&self.touching,&self.models,Planar64Vec3::ZERO);
|
||||
set_velocity(&mut self.body,&self.touching,&self.models,&self.style.mesh(),Planar64Vec3::ZERO);
|
||||
(self.move_state,self.body.acceleration)=self.touching.get_move_state(&self.body,&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time);
|
||||
refresh_walk_target=false;
|
||||
},
|
||||
@@ -1541,7 +1665,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
}
|
||||
if refresh_walk_target{
|
||||
let a=self.refresh_walk_target();
|
||||
if set_acceleration_cull(&mut self.body,&mut self.touching,&self.models,a){
|
||||
if set_acceleration_cull(&mut self.body,&mut self.touching,&self.models,&self.style.mesh(),a){
|
||||
(self.move_state,self.body.acceleration)=self.touching.get_move_state(&self.body,&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time);
|
||||
}
|
||||
}
|
||||
@@ -1549,3 +1673,218 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn test_collision_axis_aligned(relative_body:Body,expected_collision_time:Option<Time>){
|
||||
let h0=Hitbox::from_mesh_scale(PhysicsMesh::from(&crate::primitives::unit_cube()),Planar64Vec3::int(5,1,5)/2);
|
||||
let h1=Hitbox::roblox();
|
||||
let hitbox_mesh=h1.transformed_mesh();
|
||||
let platform_mesh=h0.transformed_mesh();
|
||||
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&platform_mesh,&hitbox_mesh);
|
||||
let collision=minkowski.predict_collision_in(&relative_body,Time::MAX);
|
||||
assert_eq!(collision.map(|tup|tup.1),expected_collision_time,"Incorrect time of collision");
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time>){
|
||||
let h0=Hitbox::new(PhysicsMesh::from(&crate::primitives::unit_cube()),
|
||||
crate::integer::Planar64Affine3::new(
|
||||
crate::integer::Planar64Mat3::from_cols(
|
||||
Planar64Vec3::int(5,0,1)/2,
|
||||
Planar64Vec3::int(0,1,0)/2,
|
||||
Planar64Vec3::int(-1,0,5)/2,
|
||||
),
|
||||
Planar64Vec3::ZERO,
|
||||
)
|
||||
);
|
||||
let h1=Hitbox::roblox();
|
||||
let hitbox_mesh=h1.transformed_mesh();
|
||||
let platform_mesh=h0.transformed_mesh();
|
||||
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&platform_mesh,&hitbox_mesh);
|
||||
let collision=minkowski.predict_collision_in(&relative_body,Time::MAX);
|
||||
assert_eq!(collision.map(|tup|tup.1),expected_collision_time,"Incorrect time of collision");
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
fn test_collision(relative_body:Body,expected_collision_time:Option<Time>){
|
||||
test_collision_axis_aligned(relative_body.clone(),expected_collision_time);
|
||||
test_collision_rotated(relative_body,expected_collision_time);
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_degenerate(){
|
||||
test_collision(Body::new(
|
||||
Planar64Vec3::int(0,5,0),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Planar64Vec3::ZERO,
|
||||
Time::ZERO
|
||||
),Some(Time::from_secs(2)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_degenerate_east(){
|
||||
test_collision(Body::new(
|
||||
Planar64Vec3::int(3,5,0),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Planar64Vec3::ZERO,
|
||||
Time::ZERO
|
||||
),Some(Time::from_secs(2)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_degenerate_south(){
|
||||
test_collision(Body::new(
|
||||
Planar64Vec3::int(0,5,3),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Planar64Vec3::ZERO,
|
||||
Time::ZERO
|
||||
),Some(Time::from_secs(2)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_degenerate_west(){
|
||||
test_collision(Body::new(
|
||||
Planar64Vec3::int(-3,5,0),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Planar64Vec3::ZERO,
|
||||
Time::ZERO
|
||||
),Some(Time::from_secs(2)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_degenerate_north(){
|
||||
test_collision(Body::new(
|
||||
Planar64Vec3::int(0,5,-3),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Planar64Vec3::ZERO,
|
||||
Time::ZERO
|
||||
),Some(Time::from_secs(2)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_east_from_west(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(3,3,0),
|
||||
Planar64Vec3::int(100,-1,0),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_south_from_north(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(0,3,3),
|
||||
Planar64Vec3::int(0,-1,100),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_west_from_east(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(-3,3,0),
|
||||
Planar64Vec3::int(-100,-1,0),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_north_from_south(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(0,3,-3),
|
||||
Planar64Vec3::int(0,-1,-100),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_north_from_ne(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(0,6,-7)/2,
|
||||
Planar64Vec3::int(-10,-1,1),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_north_from_nw(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(0,6,-7)/2,
|
||||
Planar64Vec3::int(10,-1,1),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_east_from_se(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(7,6,0)/2,
|
||||
Planar64Vec3::int(-1,-1,-10),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_east_from_ne(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(7,6,0)/2,
|
||||
Planar64Vec3::int(-1,-1,10),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_south_from_se(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(0,6,7)/2,
|
||||
Planar64Vec3::int(-10,-1,-1),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_south_from_sw(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(0,6,7)/2,
|
||||
Planar64Vec3::int(10,-1,-1),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_west_from_se(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(-7,6,0)/2,
|
||||
Planar64Vec3::int(1,-1,-10),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_parabola_edge_west_from_ne(){
|
||||
test_collision(VirtualBody::relative(&Body::default(),&Body::new(
|
||||
Planar64Vec3::int(-7,6,0)/2,
|
||||
Planar64Vec3::int(1,-1,10),
|
||||
Planar64Vec3::int(0,-1,0),
|
||||
Time::ZERO
|
||||
)).body(Time::from_secs(-1)),Some(Time::from_secs(0)));
|
||||
}
|
||||
#[test]
|
||||
fn test_collision_oblique(){
|
||||
test_collision(Body::new(
|
||||
Planar64Vec3::int(0,5,0),
|
||||
Planar64Vec3::int(1,-64,2)/64,
|
||||
Planar64Vec3::ZERO,
|
||||
Time::ZERO
|
||||
),Some(Time::from_secs(2)));
|
||||
}
|
||||
#[test]
|
||||
fn zoom_hit_nothing(){
|
||||
test_collision(Body::new(
|
||||
Planar64Vec3::int(0,10,0),
|
||||
Planar64Vec3::int(1,0,0),
|
||||
Planar64Vec3::int(0,1,0),
|
||||
Time::ZERO
|
||||
),None);
|
||||
}
|
||||
#[test]
|
||||
fn already_inside_hit_nothing(){
|
||||
test_collision(Body::new(
|
||||
Planar64Vec3::ZERO,
|
||||
Planar64Vec3::int(1,0,0),
|
||||
Planar64Vec3::int(0,1,0),
|
||||
Time::ZERO
|
||||
),None);
|
||||
}
|
||||
@@ -175,8 +175,8 @@ impl<'a,Task:Send+'a> INWorker<'a,Task>{
|
||||
|
||||
#[test]//How to run this test with printing: cargo test --release -- --nocapture
|
||||
fn test_worker() {
|
||||
println!("hiiiii");
|
||||
// Create the worker thread
|
||||
let test_body=crate::physics::Body::new(crate::integer::Planar64Vec3::ONE,crate::integer::Planar64Vec3::ONE,crate::integer::Planar64Vec3::ONE,crate::integer::Time::ZERO);
|
||||
let worker=QRWorker::new(crate::physics::Body::default(),
|
||||
|_|crate::physics::Body::new(crate::integer::Planar64Vec3::ONE,crate::integer::Planar64Vec3::ONE,crate::integer::Planar64Vec3::ONE,crate::integer::Time::ZERO)
|
||||
);
|
||||
@@ -203,7 +203,7 @@ fn test_worker() {
|
||||
};
|
||||
worker.send(task).unwrap();
|
||||
|
||||
println!("value={}",worker.grab_clone());
|
||||
//assert_eq!(test_body,worker.grab_clone());
|
||||
|
||||
// wait long enough to see print from final task
|
||||
thread::sleep(std::time::Duration::from_millis(10));
|
||||
|
||||
@@ -9,6 +9,7 @@ pub fn zeroes2(a0:Planar64,a1:Planar64,a2:Planar64) -> Vec<Planar64>{
|
||||
let radicand=a1.get() as i128*a1.get() as i128-a2.get() as i128*a0.get() as i128*4;
|
||||
if 0<radicand {
|
||||
//start with f64 sqrt
|
||||
//failure case: 2^63 < sqrt(2^127)
|
||||
let planar_radicand=Planar64::raw(unsafe{(radicand as f64).sqrt().to_int_unchecked()});
|
||||
//TODO: one or two newtons
|
||||
//sort roots ascending and avoid taking the difference of large numbers
|
||||
@@ -28,7 +29,12 @@ pub fn zeroes2(a0:Planar64,a1:Planar64,a2:Planar64) -> Vec<Planar64>{
|
||||
pub fn zeroes1(a0:Planar64,a1:Planar64) -> Vec<Planar64> {
|
||||
if a1==Planar64::ZERO{
|
||||
return vec![];
|
||||
} else {
|
||||
return vec![-a0/a1];
|
||||
}else{
|
||||
let q=((-a0.get() as i128)<<32)/(a1.get() as i128);
|
||||
if i64::MIN as i128<=q&&q<=i64::MAX as i128{
|
||||
return vec![Planar64::raw(q as i64)];
|
||||
}else{
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user