Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5250a0178f | |||
| 828c35dab6 | |||
| 0abf467eca | |||
| 5e819faf70 | |||
| 8c574812ff | |||
| be7abc7df0 | |||
| f2bd9152d2 | |||
| d1d29884e6 | |||
| df55d17a15 | |||
| af99de9a20 | |||
| b8ab427f3f | |||
| fe2478ce79 | |||
| ddd1a9a88c | |||
| a69fca99dd | |||
| 23ae2d3321 | |||
| ddc724a803 | |||
| 8565669166 | |||
| 0416f002ac | |||
| d8043a9265 | |||
| bf1d7cb20f | |||
| 1d2afcc364 | |||
| a5941e24ef | |||
| bcffafdc09 | |||
| 17788d5373 | |||
| c86824bdc1 | |||
| a7f7edef00 | |||
| 5b8e5c8899 | |||
| 14000c016e | |||
| 1c4191cfc9 | |||
| b2f067e0b4 | |||
| aec82358ee | |||
| 5da5006027 | |||
| 97a1b57b65 | |||
| a359650ff8 | |||
| 1790390055 | |||
| 49e077996d | |||
| 9bfcf0b083 | |||
| 82b3201b0a | |||
| 513414d4bd | |||
| 5c4bd4c3c7 | |||
| 92ec137f33 | |||
| 5cedf91709 | |||
| c201a1a626 | |||
| fbae4d9f80 | |||
| 9374e93801 | |||
| 0585cfe6f1 | |||
| 3d96517213 |
519
Cargo.lock
generated
519
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,8 @@ rbx_binary = "0.7.1"
|
|||||||
rbx_dom_weak = "2.5.0"
|
rbx_dom_weak = "2.5.0"
|
||||||
rbx_reflection_database = "0.2.7"
|
rbx_reflection_database = "0.2.7"
|
||||||
rbx_xml = "0.13.1"
|
rbx_xml = "0.13.1"
|
||||||
|
vbsp = "0.5.0"
|
||||||
|
vmdl = "0.1.1"
|
||||||
wgpu = "0.18.0"
|
wgpu = "0.18.0"
|
||||||
winit = { version = "0.29.2", features = ["rwh_05"] }
|
winit = { version = "0.29.2", features = ["rwh_05"] }
|
||||||
|
|
||||||
|
|||||||
@@ -72,9 +72,9 @@ fn generate_bvh_node(boxen:Vec<(usize,Aabb)>)->BvhNode{
|
|||||||
sort_y.push((*i,center.y()));
|
sort_y.push((*i,center.y()));
|
||||||
sort_z.push((*i,center.z()));
|
sort_z.push((*i,center.z()));
|
||||||
}
|
}
|
||||||
sort_x.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.partial_cmp(&tup1.1).unwrap());
|
sort_y.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
||||||
sort_z.sort_by(|tup0,tup1|tup0.1.partial_cmp(&tup1.1).unwrap());
|
sort_z.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
||||||
let h=n/2;
|
let h=n/2;
|
||||||
let median_x=sort_x[h].1;
|
let median_x=sort_x[h].1;
|
||||||
let median_y=sort_y[h].1;
|
let median_y=sort_y[h].1;
|
||||||
|
|||||||
@@ -3,16 +3,13 @@ use crate::model_physics::{FEV,MeshQuery,DirectedEdge};
|
|||||||
use crate::integer::{Time,Planar64};
|
use crate::integer::{Time,Planar64};
|
||||||
use crate::zeroes::zeroes2;
|
use crate::zeroes::zeroes2;
|
||||||
|
|
||||||
#[derive(Debug)]
|
enum Transition<F,E:DirectedEdge,V>{
|
||||||
enum Transition<F,E:DirectedEdge,V>
|
|
||||||
where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
|
|
||||||
Miss,
|
Miss,
|
||||||
Next(FEV<F,E,V>,Time),
|
Next(FEV<F,E,V>,Time),
|
||||||
Hit(F,Time),
|
Hit(F,Time),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_transition<F:Copy+std::fmt::Debug,E:Copy+DirectedEdge+std::fmt::Debug,V:Copy+std::fmt::Debug>(fev:&FEV<F,E,V>,time:Time,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>{
|
||||||
where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
|
|
||||||
//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_time=time_limit;
|
let mut best_time=time_limit;
|
||||||
@@ -23,10 +20,10 @@ where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
|
|||||||
//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);
|
||||||
println!("Face n={} d={}",n,d);
|
//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)){
|
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);
|
let t=body.time+Time::from(t);
|
||||||
println!("dt={} low={} upp={} into={}",t-body.time,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{
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_time=t;
|
best_time=t;
|
||||||
best_transtition=Transition::Hit(face_id,t);
|
best_transtition=Transition::Hit(face_id,t);
|
||||||
@@ -38,12 +35,9 @@ where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
|
|||||||
let edge_n=mesh.directed_edge_n(directed_edge_id);
|
let edge_n=mesh.directed_edge_n(directed_edge_id);
|
||||||
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());
|
||||||
let d=n.dot(mesh.vert(verts[0])+mesh.vert(verts[1]));
|
|
||||||
println!("Face Edge boundary_n={} boundary_d={}",n,d/2);
|
|
||||||
//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!
|
||||||
for t in zeroes2(n.dot(body.position)*2-d,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
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);
|
let t=body.time+Time::from(t);
|
||||||
println!("dt={} low={} upp={} into={}",t-body.time,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{
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_time=t;
|
best_time=t;
|
||||||
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
||||||
@@ -57,17 +51,14 @@ where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
|
|||||||
//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);
|
||||||
let vert_sum=mesh.vert(edge_verts[0])+mesh.vert(edge_verts[1]);
|
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(){
|
for (i,&edge_face_id) in mesh.edge_faces(edge_id).iter().enumerate(){
|
||||||
let face_n=mesh.face_nd(edge_face_id).0;
|
let face_n=mesh.face_nd(edge_face_id).0;
|
||||||
//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);
|
||||||
let d=n.dot(vert_sum);
|
|
||||||
println!("Edge Face={:?} boundary_n={} boundary_d={}",edge_face_id,n,d/2);
|
|
||||||
//WARNING yada yada d *2
|
//WARNING yada yada d *2
|
||||||
for t in zeroes2((n.dot(body.position))*2-d,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
for t in zeroes2(n.dot(delta_pos),n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||||
let t=body.time+Time::from(t);
|
let t=body.time+Time::from(t);
|
||||||
println!("dt={} low={} upp={} into={}",t-body.time,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{
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_time=t;
|
best_time=t;
|
||||||
best_transtition=Transition::Next(FEV::<F,E,V>::Face(edge_face_id),t);
|
best_transtition=Transition::Next(FEV::<F,E,V>::Face(edge_face_id),t);
|
||||||
@@ -79,11 +70,8 @@ where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
|
|||||||
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));
|
||||||
let d=n.dot(mesh.vert(vert_id));
|
for t in zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||||
println!("Edge Vert boundary_n={} boundary_d={}",n,d);
|
|
||||||
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);
|
let t=body.time+Time::from(t);
|
||||||
println!("dt={} low={} upp={} into={}",t-body.time,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{
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_time=t;
|
best_time=t;
|
||||||
best_transtition=Transition::Next(FEV::<F,E,V>::Vert(vert_id),t);
|
best_transtition=Transition::Next(FEV::<F,E,V>::Vert(vert_id),t);
|
||||||
@@ -98,11 +86,8 @@ where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
|
|||||||
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);
|
||||||
let d=n.dot(mesh.vert(vert_id));
|
for t in zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
||||||
println!("Vert Edge={:?} boundary_n={} boundary_d={}",directed_edge_id,n,d);
|
|
||||||
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);
|
let t=body.time+Time::from(t);
|
||||||
println!("dt={} low={} upp={} into={}",t-body.time,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{
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
||||||
best_time=t;
|
best_time=t;
|
||||||
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
||||||
@@ -119,19 +104,9 @@ pub enum CrawlResult<F,E:DirectedEdge,V>{
|
|||||||
Miss(FEV<F,E,V>),
|
Miss(FEV<F,E,V>),
|
||||||
Hit(F,Time),
|
Hit(F,Time),
|
||||||
}
|
}
|
||||||
pub fn crawl_fev<F:Copy+std::fmt::Debug,E:Copy+std::fmt::Debug+DirectedEdge,V:Copy+std::fmt::Debug>(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<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>{
|
||||||
where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
|
|
||||||
let mut time=start_time;
|
let mut time=start_time;
|
||||||
for _ in 0..20{
|
for _ in 0..20{
|
||||||
println!("@ fev={:?} time={}",fev,time);
|
|
||||||
match &fev{
|
|
||||||
&FEV::Face(face_id)=>{
|
|
||||||
let a=mesh.face_nd(face_id);
|
|
||||||
println!("face_n={}",a.0);
|
|
||||||
},
|
|
||||||
&FEV::Edge(edge_id)=>println!("edge_n={} verts={:?}",mesh.edge_n(edge_id),mesh.edge_verts(edge_id)),
|
|
||||||
&FEV::Vert(vert_id)=>println!("vert={}",mesh.vert(vert_id)),
|
|
||||||
}
|
|
||||||
match next_transition(&fev,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,time)=(next_fev,next_time),
|
Transition::Next(next_fev,next_time)=>(fev,time)=(next_fev,next_time),
|
||||||
|
|||||||
@@ -152,11 +152,14 @@ impl GraphicsState{
|
|||||||
let mut texture_loading_threads=Vec::new();
|
let mut texture_loading_threads=Vec::new();
|
||||||
let num_textures=indexed_models.textures.len();
|
let num_textures=indexed_models.textures.len();
|
||||||
for (i,texture_id) in indexed_models.textures.into_iter().enumerate(){
|
for (i,texture_id) in indexed_models.textures.into_iter().enumerate(){
|
||||||
if let Ok(mut file) = std::fs::File::open(std::path::Path::new(&format!("textures/{}.dds",texture_id))){
|
let path=std::path::PathBuf::from(format!("textures/{}.dds",texture_id));
|
||||||
|
if let Ok(mut file) = std::fs::File::open(path.clone()){
|
||||||
double_map.insert(i as u32, texture_loading_threads.len() as u32);
|
double_map.insert(i as u32, texture_loading_threads.len() as u32);
|
||||||
texture_loading_threads.push((texture_id,std::thread::spawn(move ||{
|
texture_loading_threads.push((texture_id,std::thread::spawn(move ||{
|
||||||
ddsfile::Dds::read(&mut file).unwrap()
|
ddsfile::Dds::read(&mut file).unwrap()
|
||||||
})));
|
})));
|
||||||
|
}else{
|
||||||
|
//println!("missing texture path={:?}",path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,23 +105,23 @@ impl Ratio64{
|
|||||||
None
|
None
|
||||||
}else{
|
}else{
|
||||||
let d=gcd(num.unsigned_abs(),den);
|
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]
|
#[inline]
|
||||||
pub fn mul_int(&self,rhs:i64)->i64{
|
pub fn mul_int(&self,rhs:i64)->i64{
|
||||||
rhs*self.num/self.den as i64
|
rhs*self.num/(self.den as i64)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rhs_div_int(&self,rhs:i64)->i64{
|
pub fn rhs_div_int(&self,rhs:i64)->i64{
|
||||||
rhs*self.den as i64/self.num
|
rhs*(self.den as i64)/self.num
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_ref(&self,rhs:&Ratio64)->Ratio64{
|
pub fn mul_ref(&self,rhs:&Ratio64)->Ratio64{
|
||||||
let (num,den)=(self.num*rhs.num,self.den*rhs.den);
|
let (num,den)=(self.num*rhs.num,self.den*rhs.den);
|
||||||
let d=gcd(num.unsigned_abs(),den);
|
let d=gcd(num.unsigned_abs(),den);
|
||||||
Self{
|
Self{
|
||||||
num:num/d as i64,
|
num:num/(d as i64),
|
||||||
den:den/d,
|
den:den/d,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,8 +209,8 @@ impl TryFrom<f32> for Ratio64{
|
|||||||
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||||
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||||
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||||
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
std::num::FpCategory::Subnormal
|
||||||
std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f32(value)),
|
|std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f32(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,8 +222,8 @@ impl TryFrom<f64> for Ratio64{
|
|||||||
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||||
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||||
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||||
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
std::num::FpCategory::Subnormal
|
||||||
std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f64(value)),
|
|std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f64(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,7 +234,7 @@ impl std::ops::Mul<Ratio64> for Ratio64{
|
|||||||
let (num,den)=(self.num*rhs.num,self.den*rhs.den);
|
let (num,den)=(self.num*rhs.num,self.den*rhs.den);
|
||||||
let d=gcd(num.unsigned_abs(),den);
|
let d=gcd(num.unsigned_abs(),den);
|
||||||
Self{
|
Self{
|
||||||
num:num/d as i64,
|
num:num/(d as i64),
|
||||||
den:den/d,
|
den:den/d,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,7 +411,7 @@ impl TryFrom<[f32;3]> for Unit32Vec3{
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
///[-1.0,1.0] = [-2^32,2^32]
|
///[-1.0,1.0] = [-2^32,2^32]
|
||||||
#[derive(Clone,Copy,Debug,Hash,Eq,Ord,PartialEq,PartialOrd)]
|
#[derive(Clone,Copy,Hash,Eq,Ord,PartialEq,PartialOrd)]
|
||||||
pub struct Planar64(i64);
|
pub struct Planar64(i64);
|
||||||
impl Planar64{
|
impl Planar64{
|
||||||
pub const ZERO:Self=Self(0);
|
pub const ZERO:Self=Self(0);
|
||||||
@@ -451,7 +451,7 @@ impl Into<f32> for Planar64{
|
|||||||
impl From<Ratio64> for Planar64{
|
impl From<Ratio64> for Planar64{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(ratio:Ratio64)->Self{
|
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)]
|
#[derive(Debug)]
|
||||||
@@ -459,26 +459,8 @@ pub enum Planar64TryFromFloatError{
|
|||||||
Nan,
|
Nan,
|
||||||
Infinite,
|
Infinite,
|
||||||
Subnormal,
|
Subnormal,
|
||||||
HighlyNegativeExponent(i16),
|
HighlyNegativeExponent,
|
||||||
HighlyPositiveExponent(i16),
|
HighlyPositiveExponent,
|
||||||
}
|
|
||||||
#[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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl TryFrom<f32> for Planar64{
|
impl TryFrom<f32> for Planar64{
|
||||||
type Error=Planar64TryFromFloatError;
|
type Error=Planar64TryFromFloatError;
|
||||||
@@ -488,8 +470,15 @@ impl TryFrom<f32> for Planar64{
|
|||||||
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||||
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||||
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||||
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
std::num::FpCategory::Subnormal
|
||||||
std::num::FpCategory::Normal=>planar64_from_mes(integer_decode_f32(value)),
|
|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()}))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -501,8 +490,15 @@ impl TryFrom<f64> for Planar64{
|
|||||||
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||||
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||||
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||||
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
std::num::FpCategory::Subnormal
|
||||||
std::num::FpCategory::Normal=>planar64_from_mes(integer_decode_f64(value)),
|
|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()}))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -572,7 +568,7 @@ impl std::ops::Div<Planar64> for Planar64{
|
|||||||
type Output=Planar64;
|
type Output=Planar64;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div(self, rhs: Planar64) -> Self::Output {
|
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{
|
// impl PartialOrd<i64> for Planar64{
|
||||||
@@ -583,7 +579,7 @@ impl std::ops::Div<Planar64> for Planar64{
|
|||||||
|
|
||||||
|
|
||||||
///[-1.0,1.0] = [-2^32,2^32]
|
///[-1.0,1.0] = [-2^32,2^32]
|
||||||
#[derive(Clone,Copy,Debug,Default,Hash,Eq,PartialEq)]
|
#[derive(Clone,Copy,Default,Hash,Eq,PartialEq)]
|
||||||
pub struct Planar64Vec3(glam::I64Vec3);
|
pub struct Planar64Vec3(glam::I64Vec3);
|
||||||
impl Planar64Vec3{
|
impl Planar64Vec3{
|
||||||
pub const ZERO:Self=Planar64Vec3(glam::I64Vec3::ZERO);
|
pub const ZERO:Self=Planar64Vec3(glam::I64Vec3::ZERO);
|
||||||
@@ -807,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{
|
impl std::ops::Div<i64> for Planar64Vec3{
|
||||||
type Output=Planar64Vec3;
|
type Output=Planar64Vec3;
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
235
src/load_bsp.rs
Normal file
235
src/load_bsp.rs
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
const VALVE_SCALE:f32=1.0/16.0;
|
||||||
|
fn valve_transform(v:[f32;3])->crate::integer::Planar64Vec3{
|
||||||
|
crate::integer::Planar64Vec3::try_from([v[0]*VALVE_SCALE,v[2]*VALVE_SCALE,-v[1]*VALVE_SCALE]).unwrap()
|
||||||
|
}
|
||||||
|
pub fn generate_indexed_models<R:std::io::Read+std::io::Seek>(input:&mut R)->Result<crate::model::IndexedModelInstances,vbsp::BspError>{
|
||||||
|
let mut s=Vec::new();
|
||||||
|
|
||||||
|
match input.read_to_end(&mut s){
|
||||||
|
Ok(_)=>(),
|
||||||
|
Err(e)=>println!("load_bsp::generate_indexed_models read_to_end failed: {:?}",e),
|
||||||
|
}
|
||||||
|
|
||||||
|
match vbsp::Bsp::read(s.as_slice()){
|
||||||
|
Ok(bsp)=>{
|
||||||
|
let mut spawn_point=crate::integer::Planar64Vec3::ZERO;
|
||||||
|
|
||||||
|
let vertices: Vec<_> = bsp
|
||||||
|
.vertices
|
||||||
|
.iter()
|
||||||
|
.map(|vertex|<[f32;3]>::from(vertex.position))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut name_from_texture_id=Vec::new();
|
||||||
|
let mut texture_id_from_name=std::collections::HashMap::new();
|
||||||
|
|
||||||
|
let mut models=bsp.models().map(|world_model|{
|
||||||
|
//non-deduplicated
|
||||||
|
let mut spam_pos=Vec::new();
|
||||||
|
let mut spam_tex=Vec::new();
|
||||||
|
let mut spam_normal=Vec::new();
|
||||||
|
let mut spam_vertices=Vec::new();
|
||||||
|
let groups=world_model.faces()
|
||||||
|
.filter(|face| face.is_visible())//TODO: look at this
|
||||||
|
.map(|face|{
|
||||||
|
let face_texture=face.texture();
|
||||||
|
let face_texture_data=face_texture.texture_data();
|
||||||
|
let (texture_u,texture_v)=(glam::Vec3A::from_slice(&face_texture.texture_transforms_u[0..3]),glam::Vec3A::from_slice(&face_texture.texture_transforms_v[0..3]));
|
||||||
|
let texture_offset=glam::vec2(face_texture.texture_transforms_u[3],face_texture.texture_transforms_v[3]);
|
||||||
|
let texture_size=glam::vec2(face_texture_data.width as f32,face_texture_data.height as f32);
|
||||||
|
|
||||||
|
//texture
|
||||||
|
let texture_id=if let Some(&texture_id)=texture_id_from_name.get(face_texture_data.name()){
|
||||||
|
texture_id
|
||||||
|
}else{
|
||||||
|
let texture_id=name_from_texture_id.len() as u32;
|
||||||
|
texture_id_from_name.insert(face_texture_data.name().to_string(),texture_id);
|
||||||
|
name_from_texture_id.push(face_texture_data.name().to_string());
|
||||||
|
texture_id
|
||||||
|
};
|
||||||
|
|
||||||
|
//normal
|
||||||
|
let normal=face.normal();
|
||||||
|
let normal_idx=spam_normal.len() as u32;
|
||||||
|
spam_normal.push(valve_transform(<[f32;3]>::from(normal)));
|
||||||
|
let mut vertices:Vec<u32>=face.vertex_indexes().map(|vertex_index|{
|
||||||
|
let pos=glam::Vec3A::from_array(vertices[vertex_index as usize]);
|
||||||
|
let pos_idx=spam_pos.len();
|
||||||
|
spam_pos.push(valve_transform(vertices[vertex_index as usize]));
|
||||||
|
|
||||||
|
//calculate texture coordinates
|
||||||
|
let tex=(glam::vec2(pos.dot(texture_u),pos.dot(texture_v))+texture_offset)/texture_size;
|
||||||
|
let tex_idx=spam_tex.len() as u32;
|
||||||
|
spam_tex.push(tex);
|
||||||
|
|
||||||
|
let i=spam_vertices.len() as u32;
|
||||||
|
spam_vertices.push(crate::model::IndexedVertex{
|
||||||
|
pos: pos_idx as u32,
|
||||||
|
tex: tex_idx as u32,
|
||||||
|
normal: normal_idx,
|
||||||
|
color: 0,
|
||||||
|
});
|
||||||
|
i
|
||||||
|
}).collect();
|
||||||
|
vertices.reverse();
|
||||||
|
crate::model::IndexedGroup{
|
||||||
|
texture:Some(texture_id),
|
||||||
|
polys:vec![crate::model::IndexedPolygon{vertices}],
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
crate::model::IndexedModel{
|
||||||
|
unique_pos:spam_pos,
|
||||||
|
unique_tex:spam_tex,
|
||||||
|
unique_normal:spam_normal,
|
||||||
|
unique_color:vec![glam::Vec4::ONE],
|
||||||
|
unique_vertices:spam_vertices,
|
||||||
|
groups,
|
||||||
|
instances:vec![crate::model::ModelInstance{
|
||||||
|
attributes:crate::model::CollisionAttributes::Decoration,
|
||||||
|
transform:crate::integer::Planar64Affine3::new(
|
||||||
|
crate::integer::Planar64Mat3::default(),
|
||||||
|
valve_transform(<[f32;3]>::from(world_model.origin))
|
||||||
|
),
|
||||||
|
..Default::default()
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
//dedupe prop models
|
||||||
|
let mut model_dedupe=std::collections::HashSet::new();
|
||||||
|
for prop in bsp.static_props(){
|
||||||
|
model_dedupe.insert(prop.model());
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate unique meshes
|
||||||
|
let mut model_map=std::collections::HashMap::with_capacity(model_dedupe.len());
|
||||||
|
let mut prop_models=Vec::new();
|
||||||
|
for model_name in model_dedupe{
|
||||||
|
let model_name_lower=model_name.to_lowercase();
|
||||||
|
//.mdl, .vvd, .dx90.vtx
|
||||||
|
let mut path=std::path::PathBuf::from(model_name_lower.as_str());
|
||||||
|
let file_name=std::path::PathBuf::from(path.file_stem().unwrap());
|
||||||
|
path.pop();
|
||||||
|
path.push(file_name);
|
||||||
|
let mut vvd_path=path.clone();
|
||||||
|
let mut vtx_path=path.clone();
|
||||||
|
vvd_path.set_extension("vvd");
|
||||||
|
vtx_path.set_extension("dx90.vtx");
|
||||||
|
match (bsp.pack.get(model_name_lower.as_str()),bsp.pack.get(vvd_path.as_os_str().to_str().unwrap()),bsp.pack.get(vtx_path.as_os_str().to_str().unwrap())){
|
||||||
|
(Ok(Some(mdl_file)),Ok(Some(vvd_file)),Ok(Some(vtx_file)))=>{
|
||||||
|
match (vmdl::mdl::Mdl::read(mdl_file.as_ref()),vmdl::vvd::Vvd::read(vvd_file.as_ref()),vmdl::vtx::Vtx::read(vtx_file.as_ref())){
|
||||||
|
(Ok(mdl),Ok(vvd),Ok(vtx))=>{
|
||||||
|
let model=vmdl::Model::from_parts(mdl,vtx,vvd);
|
||||||
|
let texture_paths=model.texture_directories();
|
||||||
|
if texture_paths.len()!=1{
|
||||||
|
println!("WARNING: multiple texture paths");
|
||||||
|
}
|
||||||
|
let skin=model.skin_tables().nth(0).unwrap();
|
||||||
|
|
||||||
|
let mut spam_pos=Vec::with_capacity(model.vertices().len());
|
||||||
|
let mut spam_normal=Vec::with_capacity(model.vertices().len());
|
||||||
|
let mut spam_tex=Vec::with_capacity(model.vertices().len());
|
||||||
|
let mut spam_vertices=Vec::with_capacity(model.vertices().len());
|
||||||
|
for (i,vertex) in model.vertices().iter().enumerate(){
|
||||||
|
spam_pos.push(valve_transform(<[f32;3]>::from(vertex.position)));
|
||||||
|
spam_normal.push(valve_transform(<[f32;3]>::from(vertex.normal)));
|
||||||
|
spam_tex.push(glam::Vec2::from_array(vertex.texture_coordinates));
|
||||||
|
spam_vertices.push(crate::model::IndexedVertex{
|
||||||
|
pos:i as u32,
|
||||||
|
tex:i as u32,
|
||||||
|
normal:i as u32,
|
||||||
|
color:0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let model_id=prop_models.len();
|
||||||
|
model_map.insert(model_name,model_id);
|
||||||
|
prop_models.push(crate::model::IndexedModel{
|
||||||
|
unique_pos:spam_pos,
|
||||||
|
unique_normal:spam_normal,
|
||||||
|
unique_tex:spam_tex,
|
||||||
|
unique_color:vec![glam::Vec4::ONE],
|
||||||
|
unique_vertices:spam_vertices,
|
||||||
|
groups:model.meshes().map(|mesh|{
|
||||||
|
let texture=if let (Some(texture_path),Some(texture_name))=(texture_paths.get(0),skin.texture(mesh.material_index())){
|
||||||
|
let mut path=std::path::PathBuf::from(texture_path.as_str());
|
||||||
|
path.push(texture_name);
|
||||||
|
let texture_location=path.as_os_str().to_str().unwrap();
|
||||||
|
let texture_id=if let Some(&texture_id)=texture_id_from_name.get(texture_location){
|
||||||
|
texture_id
|
||||||
|
}else{
|
||||||
|
println!("texture! {}",texture_location);
|
||||||
|
let texture_id=name_from_texture_id.len() as u32;
|
||||||
|
texture_id_from_name.insert(texture_location.to_string(),texture_id);
|
||||||
|
name_from_texture_id.push(texture_location.to_string());
|
||||||
|
texture_id
|
||||||
|
};
|
||||||
|
Some(texture_id)
|
||||||
|
}else{
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::model::IndexedGroup{
|
||||||
|
texture,
|
||||||
|
polys:{
|
||||||
|
//looking at the code, it would seem that the strips are pre-deindexed into triangle lists when calling this function
|
||||||
|
mesh.vertex_strip_indices().map(|strip|{
|
||||||
|
strip.collect::<Vec<usize>>().chunks(3).map(|tri|{
|
||||||
|
crate::model::IndexedPolygon{vertices:vec![tri[0] as u32,tri[1] as u32,tri[2] as u32]}
|
||||||
|
}).collect::<Vec<crate::model::IndexedPolygon>>()
|
||||||
|
}).flatten().collect()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}).collect(),
|
||||||
|
instances:Vec::new(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_=>println!("model_name={} error",model_name),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_=>println!("no model name={}",model_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate model instances
|
||||||
|
for prop in bsp.static_props(){
|
||||||
|
let placement=prop.as_prop_placement();
|
||||||
|
if let Some(&model_index)=model_map.get(placement.model){
|
||||||
|
prop_models[model_index].instances.push(crate::model::ModelInstance{
|
||||||
|
transform:crate::integer::Planar64Affine3::new(
|
||||||
|
crate::integer::Planar64Mat3::try_from(
|
||||||
|
glam::Mat3A::from_diagonal(glam::Vec3::splat(placement.scale))
|
||||||
|
//TODO: figure this out
|
||||||
|
*glam::Mat3A::from_quat(glam::Quat::from_xyzw(
|
||||||
|
placement.rotation.v.x,//b
|
||||||
|
placement.rotation.v.y,//c
|
||||||
|
placement.rotation.v.z,//d
|
||||||
|
placement.rotation.s,//a
|
||||||
|
))
|
||||||
|
).unwrap(),
|
||||||
|
valve_transform(<[f32;3]>::from(placement.origin)),
|
||||||
|
),
|
||||||
|
attributes:crate::model::CollisionAttributes::Decoration,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
//println!("model not found {}",placement.model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//actually add the prop models
|
||||||
|
prop_models.append(&mut models);
|
||||||
|
|
||||||
|
Ok(crate::model::IndexedModelInstances{
|
||||||
|
textures:name_from_texture_id,
|
||||||
|
models:prop_models,
|
||||||
|
spawn_point,
|
||||||
|
modes:Vec::new(),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Err(e)=>{
|
||||||
|
println!("rotten {:?}",e);
|
||||||
|
Err(e)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,12 +14,15 @@ fn class_is_a(class: &str, superclass: &str) -> bool {
|
|||||||
return false
|
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){
|
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() {
|
let mut stack=vec![instance];
|
||||||
if let Some(c) = dom.get_by_ref(referent) {
|
while let Some(item)=stack.pop(){
|
||||||
if class_is_a(c.class.as_str(), superclass) {
|
for &referent in item.children(){
|
||||||
objects.push(c.referent());//copy ref
|
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);
|
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
|
//push TempIndexedAttributes
|
||||||
let mut force_intersecting=false;
|
let mut force_intersecting=false;
|
||||||
let mut temp_indexing_attributes=Vec::new();
|
let mut temp_indexing_attributes=Vec::new();
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ mod graphics;
|
|||||||
mod settings;
|
mod settings;
|
||||||
mod primitives;
|
mod primitives;
|
||||||
mod instruction;
|
mod instruction;
|
||||||
|
mod load_bsp;
|
||||||
mod load_roblox;
|
mod load_roblox;
|
||||||
mod face_crawler;
|
mod face_crawler;
|
||||||
mod compat_worker;
|
mod compat_worker;
|
||||||
@@ -46,7 +47,7 @@ fn load_file(path: std::path::PathBuf)->Option<model::IndexedModelInstances>{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
//b"VBSP"=>Some(load_bsp::generate_indexed_models(input)),
|
b"VBSP"=>load_bsp::generate_indexed_models(&mut input).ok(),
|
||||||
//b"SNFM"=>Some(sniffer::generate_indexed_models(input)),
|
//b"SNFM"=>Some(sniffer::generate_indexed_models(input)),
|
||||||
//b"SNFB"=>Some(sniffer::load_bot(input)),
|
//b"SNFB"=>Some(sniffer::load_bot(input)),
|
||||||
other=>{
|
other=>{
|
||||||
|
|||||||
@@ -259,7 +259,6 @@ impl IntersectingAttributes{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Spawn(u32) NO! spawns are indexed in the map header instead of marked with attibutes
|
//Spawn(u32) NO! spawns are indexed in the map header instead of marked with attibutes
|
||||||
//TODO: deduplicate attributes
|
|
||||||
pub enum CollisionAttributes{
|
pub enum CollisionAttributes{
|
||||||
Decoration,//visual only
|
Decoration,//visual only
|
||||||
Contact{//track whether you are contacting the object
|
Contact{//track whether you are contacting the object
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ impl DirectedEdge for DirectedEdgeId{
|
|||||||
pub struct FaceId(usize);
|
pub struct FaceId(usize);
|
||||||
|
|
||||||
//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),
|
||||||
@@ -48,12 +47,10 @@ pub enum FEV<F,E:DirectedEdge,V>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//use Unit32 #[repr(C)] for map files
|
//use Unit32 #[repr(C)] for map files
|
||||||
#[derive(Debug)]
|
|
||||||
struct Face{
|
struct Face{
|
||||||
normal:Planar64Vec3,
|
normal:Planar64Vec3,
|
||||||
dot:Planar64,
|
dot:Planar64,
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
|
||||||
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>{
|
||||||
fn edge_n(&self,edge_id:EDGE::UndirectedEdge)->Planar64Vec3{
|
fn edge_n(&self,edge_id:EDGE::UndirectedEdge)->Planar64Vec3{
|
||||||
@@ -72,22 +69,18 @@ pub trait MeshQuery<FACE:Clone,EDGE:Clone+DirectedEdge,VERT:Clone>{
|
|||||||
fn vert_edges(&self,vert_id:VERT)->Cow<Vec<EDGE>>;
|
fn vert_edges(&self,vert_id:VERT)->Cow<Vec<EDGE>>;
|
||||||
fn vert_faces(&self,vert_id:VERT)->Cow<Vec<FACE>>;
|
fn vert_faces(&self,vert_id:VERT)->Cow<Vec<FACE>>;
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
|
||||||
struct FaceRefs{
|
struct FaceRefs{
|
||||||
edges:Vec<DirectedEdgeId>,
|
edges:Vec<DirectedEdgeId>,
|
||||||
//verts:Vec<VertId>,
|
//verts:Vec<VertId>,
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
|
||||||
struct EdgeRefs{
|
struct EdgeRefs{
|
||||||
faces:[FaceId;2],//left, right
|
faces:[FaceId;2],//left, right
|
||||||
verts:[VertId;2],//bottom, top
|
verts:[VertId;2],//bottom, top
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
|
||||||
struct VertRefs{
|
struct VertRefs{
|
||||||
faces:Vec<FaceId>,
|
faces:Vec<FaceId>,
|
||||||
edges:Vec<DirectedEdgeId>,
|
edges:Vec<DirectedEdgeId>,
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PhysicsMesh{
|
pub struct PhysicsMesh{
|
||||||
faces:Vec<Face>,
|
faces:Vec<Face>,
|
||||||
verts:Vec<Vert>,
|
verts:Vec<Vert>,
|
||||||
@@ -245,17 +238,20 @@ pub struct TransformedMesh<'a>{
|
|||||||
mesh:&'a PhysicsMesh,
|
mesh:&'a PhysicsMesh,
|
||||||
transform:&'a crate::integer::Planar64Affine3,
|
transform:&'a crate::integer::Planar64Affine3,
|
||||||
normal_transform:&'a crate::integer::Planar64Mat3,
|
normal_transform:&'a crate::integer::Planar64Mat3,
|
||||||
|
transform_det:Planar64,
|
||||||
}
|
}
|
||||||
impl TransformedMesh<'_>{
|
impl TransformedMesh<'_>{
|
||||||
pub fn new<'a>(
|
pub fn new<'a>(
|
||||||
mesh:&'a PhysicsMesh,
|
mesh:&'a PhysicsMesh,
|
||||||
transform:&'a crate::integer::Planar64Affine3,
|
transform:&'a crate::integer::Planar64Affine3,
|
||||||
normal_transform:&'a crate::integer::Planar64Mat3,
|
normal_transform:&'a crate::integer::Planar64Mat3,
|
||||||
|
transform_det:Planar64,
|
||||||
)->TransformedMesh<'a>{
|
)->TransformedMesh<'a>{
|
||||||
TransformedMesh{
|
TransformedMesh{
|
||||||
mesh,
|
mesh,
|
||||||
transform,
|
transform,
|
||||||
normal_transform,
|
normal_transform,
|
||||||
|
transform_det,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn farthest_vert(&self,dir:Planar64Vec3)->VertId{
|
fn farthest_vert(&self,dir:Planar64Vec3)->VertId{
|
||||||
@@ -276,8 +272,8 @@ impl MeshQuery<FaceId,DirectedEdgeId,VertId> for TransformedMesh<'_>{
|
|||||||
fn face_nd(&self,face_id:FaceId)->(Planar64Vec3,Planar64){
|
fn face_nd(&self,face_id:FaceId)->(Planar64Vec3,Planar64){
|
||||||
let (n,d)=self.mesh.face_nd(face_id);
|
let (n,d)=self.mesh.face_nd(face_id);
|
||||||
let transformed_n=*self.normal_transform*n;
|
let transformed_n=*self.normal_transform*n;
|
||||||
let transformed_d=Planar64::raw(((transformed_n.dot128(self.transform.matrix3*(n*d))<<32)/n.dot128(n)) as i64)+transformed_n.dot(self.transform.translation);
|
let transformed_d=d+transformed_n.dot(self.transform.translation)/self.transform_det;
|
||||||
(transformed_n,transformed_d)
|
(transformed_n/self.transform_det,transformed_d)
|
||||||
}
|
}
|
||||||
fn vert(&self,vert_id:VertId)->Planar64Vec3{
|
fn vert(&self,vert_id:VertId)->Planar64Vec3{
|
||||||
self.transform.transform_point3(self.mesh.vert(vert_id))
|
self.transform.transform_point3(self.mesh.vert(vert_id))
|
||||||
@@ -308,11 +304,11 @@ impl MeshQuery<FaceId,DirectedEdgeId,VertId> for TransformedMesh<'_>{
|
|||||||
//(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(VertId,VertId),
|
VertVert(VertId,VertId),
|
||||||
}
|
}
|
||||||
#[derive(Clone,Copy,Debug)]
|
#[derive(Clone,Copy)]
|
||||||
pub enum MinkowskiEdge{
|
pub enum MinkowskiEdge{
|
||||||
VertEdge(VertId,EdgeId),
|
VertEdge(VertId,EdgeId),
|
||||||
EdgeVert(EdgeId,VertId),
|
EdgeVert(EdgeId,VertId),
|
||||||
@@ -327,7 +323,7 @@ impl UndirectedEdge for MinkowskiEdge{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Clone,Copy,Debug)]
|
#[derive(Clone,Copy)]
|
||||||
pub enum MinkowskiDirectedEdge{
|
pub enum MinkowskiDirectedEdge{
|
||||||
VertEdge(VertId,DirectedEdgeId),
|
VertEdge(VertId,DirectedEdgeId),
|
||||||
EdgeVert(DirectedEdgeId,VertId),
|
EdgeVert(DirectedEdgeId,VertId),
|
||||||
@@ -348,7 +344,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(VertId,FaceId),
|
VertFace(VertId,FaceId),
|
||||||
EdgeEdge(EdgeId,EdgeId,bool),
|
EdgeEdge(EdgeId,EdgeId,bool),
|
||||||
@@ -388,12 +384,12 @@ impl MinkowskiMesh<'_>{
|
|||||||
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
|
||||||
if infinity_dir.dot(edge_n)==Planar64::ZERO{
|
let edge_verts=self.edge_verts(directed_edge_id.as_undirected());
|
||||||
let edge_verts=self.edge_verts(directed_edge_id.as_undirected());
|
//select opposite vertex
|
||||||
//select opposite vertex
|
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 crate::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);
|
||||||
@@ -409,9 +405,10 @@ impl MinkowskiMesh<'_>{
|
|||||||
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
|
||||||
if infinity_dir.dot(edge_n)==Planar64::ZERO{
|
//check if time of collision is outside Time::MIN..Time::MAX
|
||||||
|
let d=edge_n.dot(diff);
|
||||||
|
if crate::zeroes::zeroes1(d,edge_n.dot(infinity_dir)).len()==0{
|
||||||
//test the edge
|
//test the edge
|
||||||
let d=diff.dot(edge_n);
|
|
||||||
let edge_nn=edge_n.dot(edge_n);
|
let edge_nn=edge_n.dot(edge_n);
|
||||||
if Planar64::ZERO<=d&&d<=edge_nn{
|
if Planar64::ZERO<=d&&d<=edge_nn{
|
||||||
let distance_squared={
|
let distance_squared={
|
||||||
@@ -441,7 +438,6 @@ impl MinkowskiMesh<'_>{
|
|||||||
}
|
}
|
||||||
/// This function drops a vertex down to an edge or a face if the path from infinity did not cross any vertex-edge boundaries but the point is supposed to have already crossed a boundary down from a vertex
|
/// This function drops a vertex down to an edge or a face if the path from infinity did not cross any vertex-edge boundaries but the point is supposed to have already crossed a boundary down from a vertex
|
||||||
fn infinity_fev(&self,infinity_dir:Planar64Vec3,point:Planar64Vec3)->FEV::<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>{
|
fn infinity_fev(&self,infinity_dir:Planar64Vec3,point:Planar64Vec3)->FEV::<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>{
|
||||||
println!("infinity_fev dir={} point={}",infinity_dir,point);
|
|
||||||
//start on any vertex
|
//start on any vertex
|
||||||
//cross uncrossable vertex-edge boundaries until you find the closest vertex or edge
|
//cross uncrossable vertex-edge boundaries until you find the closest vertex or edge
|
||||||
//cross edge-face boundary if it's uncrossable
|
//cross edge-face boundary if it's uncrossable
|
||||||
@@ -449,37 +445,21 @@ impl MinkowskiMesh<'_>{
|
|||||||
//if a vert is returned, it is the closest point to the infinity point
|
//if a vert is returned, it is the closest point to the infinity point
|
||||||
EV::Vert(vert_id)=>FEV::<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>::Vert(vert_id),
|
EV::Vert(vert_id)=>FEV::<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>::Vert(vert_id),
|
||||||
EV::Edge(edge_id)=>{
|
EV::Edge(edge_id)=>{
|
||||||
println!("fix edge edge_id={:?}",edge_id);
|
|
||||||
match edge_id{
|
|
||||||
MinkowskiEdge::VertEdge(v0,e1)=>{
|
|
||||||
println!("v0={}",self.mesh0.vert(v0));
|
|
||||||
for face_id1 in self.mesh1.edge_faces(e1).iter(){
|
|
||||||
println!("e1 face_n={}",self.mesh1.face_nd(*face_id1).0);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MinkowskiEdge::EdgeVert(e0,v1)=>{
|
|
||||||
println!("v1={}",self.mesh1.vert(v1));
|
|
||||||
for face_id0 in self.mesh0.edge_faces(e0).iter(){
|
|
||||||
println!("e0 face_n={}",self.mesh0.face_nd(*face_id0).0);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
//cross to face if the boundary is not crossable and we are on the wrong side
|
//cross to face if the boundary is not crossable and we are on the wrong side
|
||||||
let edge_n=self.edge_n(edge_id);
|
let edge_n=self.edge_n(edge_id);
|
||||||
println!("edge_n={}",edge_n);
|
// point is multiplied by two because vert_sum sums two vertices.
|
||||||
let vert_sum={
|
let delta_pos=point*2-{
|
||||||
let &[v0,v1]=self.edge_verts(edge_id).borrow();
|
let &[v0,v1]=self.edge_verts(edge_id).borrow();
|
||||||
self.vert(v0)+self.vert(v1)
|
self.vert(v0)+self.vert(v1)
|
||||||
};
|
};
|
||||||
for (i,&face_id) in self.edge_faces(edge_id).iter().enumerate(){
|
for (i,&face_id) in self.edge_faces(edge_id).iter().enumerate(){
|
||||||
let face_n=self.face_nd(face_id).0;
|
let face_n=self.face_nd(face_id).0;
|
||||||
println!("face_id={:?} face_n={}",face_id,face_n);
|
|
||||||
//edge-face boundary nd, n facing out of the face towards the edge
|
//edge-face boundary nd, n facing out of the face towards the edge
|
||||||
let boundary_n=face_n.cross(edge_n)*(i as i64*2-1);
|
let boundary_n=face_n.cross(edge_n)*(i as i64*2-1);
|
||||||
let boundary_d=boundary_n.dot(vert_sum);
|
let boundary_d=boundary_n.dot(delta_pos);
|
||||||
println!("dot={} boundary_n={} boundary_d={} point_d={}",infinity_dir.dot(boundary_n),boundary_n,boundary_d,point.dot(boundary_n)*2);
|
//check if time of collision is outside Time::MIN..Time::MAX
|
||||||
// point.dot(boundary_n) is multiplied by two because vert_sum sums two vertices.
|
//infinity_dir can always be treated as a velocity
|
||||||
if infinity_dir.dot(boundary_n)==Planar64::ZERO&&point.dot(boundary_n)*2<=boundary_d{
|
if (boundary_d)<=Planar64::ZERO&&crate::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);
|
||||||
}
|
}
|
||||||
@@ -503,7 +483,6 @@ impl MinkowskiMesh<'_>{
|
|||||||
}
|
}
|
||||||
pub fn predict_collision_in(&self,relative_body:&crate::physics::Body,time_limit:crate::integer::Time)->Option<(MinkowskiFace,crate::integer::Time)>{
|
pub fn predict_collision_in(&self,relative_body:&crate::physics::Body,time_limit:crate::integer::Time)->Option<(MinkowskiFace,crate::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|{
|
||||||
println!("@@@BEGIN REAL CRAWL@@@");
|
|
||||||
//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){
|
||||||
crate::face_crawler::CrawlResult::Miss(_)=>None,
|
crate::face_crawler::CrawlResult::Miss(_)=>None,
|
||||||
@@ -625,6 +604,7 @@ impl MeshQuery<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert> for MinkowskiM
|
|||||||
let d=edge_face1_n.dot(edge0_n);
|
let d=edge_face1_n.dot(edge0_n);
|
||||||
if d<Planar64::ZERO{
|
if d<Planar64::ZERO{
|
||||||
let edge0_nn=edge0_n.dot(edge0_n);
|
let edge0_nn=edge0_n.dot(edge0_n);
|
||||||
|
//divide by zero???
|
||||||
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;
|
||||||
@@ -761,4 +741,4 @@ fn build_me_a_cube(){
|
|||||||
let unit_cube=crate::primitives::unit_cube();
|
let unit_cube=crate::primitives::unit_cube();
|
||||||
let mesh=PhysicsMesh::from(&unit_cube);
|
let mesh=PhysicsMesh::from(&unit_cube);
|
||||||
//println!("mesh={:?}",mesh);
|
//println!("mesh={:?}",mesh);
|
||||||
}
|
}
|
||||||
@@ -202,6 +202,7 @@ impl PhysicsModels{
|
|||||||
&self.meshes[self.models[model_id].mesh_id],
|
&self.meshes[self.models[model_id].mesh_id],
|
||||||
&self.models[model_id].transform,
|
&self.models[model_id].transform,
|
||||||
&self.models[model_id].normal_transform,
|
&self.models[model_id].normal_transform,
|
||||||
|
self.models[model_id].transform_det,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn model(&self,model_id:usize)->&PhysicsModel{
|
fn model(&self,model_id:usize)->&PhysicsModel{
|
||||||
@@ -343,11 +344,11 @@ struct Hitbox{
|
|||||||
mesh:PhysicsMesh,
|
mesh:PhysicsMesh,
|
||||||
transform:crate::integer::Planar64Affine3,
|
transform:crate::integer::Planar64Affine3,
|
||||||
normal_transform:Planar64Mat3,
|
normal_transform:Planar64Mat3,
|
||||||
|
transform_det:Planar64,
|
||||||
}
|
}
|
||||||
impl Hitbox{
|
impl Hitbox{
|
||||||
fn new(mesh:PhysicsMesh,transform:crate::integer::Planar64Affine3)->Self{
|
fn new(mesh:PhysicsMesh,transform:crate::integer::Planar64Affine3)->Self{
|
||||||
//calculate extents
|
//calculate extents
|
||||||
let normal_transform=transform.matrix3.inverse_times_det().transpose();
|
|
||||||
let mut aabb=crate::aabb::Aabb::default();
|
let mut aabb=crate::aabb::Aabb::default();
|
||||||
for vert in mesh.verts(){
|
for vert in mesh.verts(){
|
||||||
aabb.grow(transform.transform_point3(vert));
|
aabb.grow(transform.transform_point3(vert));
|
||||||
@@ -356,23 +357,28 @@ impl Hitbox{
|
|||||||
halfsize:aabb.size()/2,
|
halfsize:aabb.size()/2,
|
||||||
mesh,
|
mesh,
|
||||||
transform,
|
transform,
|
||||||
normal_transform,
|
normal_transform:transform.matrix3.inverse_times_det().transpose(),
|
||||||
|
transform_det:transform.matrix3.determinant(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn from_mesh_scale(mesh:PhysicsMesh,scale:Planar64Vec3)->Self{
|
fn from_mesh_scale(mesh:PhysicsMesh,scale:Planar64Vec3)->Self{
|
||||||
|
let matrix3=Planar64Mat3::from_diagonal(scale);
|
||||||
Self{
|
Self{
|
||||||
halfsize:scale,
|
halfsize:scale,
|
||||||
mesh,
|
mesh,
|
||||||
transform:crate::integer::Planar64Affine3::new(Planar64Mat3::from_diagonal(scale),Planar64Vec3::ZERO),
|
normal_transform:matrix3.inverse_times_det().transpose(),
|
||||||
normal_transform:Planar64Mat3::from_diagonal(scale).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{
|
fn from_mesh_scale_offset(mesh:PhysicsMesh,scale:Planar64Vec3,offset:Planar64Vec3)->Self{
|
||||||
|
let matrix3=Planar64Mat3::from_diagonal(scale);
|
||||||
Self{
|
Self{
|
||||||
halfsize:scale,
|
halfsize:scale,
|
||||||
mesh,
|
mesh,
|
||||||
transform:crate::integer::Planar64Affine3::new(Planar64Mat3::from_diagonal(scale),offset),
|
normal_transform:matrix3.inverse_times_det().transpose(),
|
||||||
normal_transform:Planar64Mat3::from_diagonal(scale).inverse_times_det().transpose(),
|
transform:crate::integer::Planar64Affine3::new(matrix3,offset),
|
||||||
|
transform_det:matrix3.determinant(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn roblox()->Self{
|
fn roblox()->Self{
|
||||||
@@ -383,7 +389,7 @@ impl Hitbox{
|
|||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn transformed_mesh(&self)->TransformedMesh{
|
fn transformed_mesh(&self)->TransformedMesh{
|
||||||
TransformedMesh::new(&self.mesh,&self.transform,&self.normal_transform)
|
TransformedMesh::new(&self.mesh,&self.transform,&self.normal_transform,self.transform_det)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,7 +526,7 @@ impl StyleModifiers{
|
|||||||
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
|
controls_mask:!0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
|
||||||
strafe:Some(StrafeSettings{
|
strafe:Some(StrafeSettings{
|
||||||
enable:EnableStrafe::Always,
|
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(),
|
tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
|
||||||
}),
|
}),
|
||||||
jump_impulse:JumpImpulse::FromHeight(Planar64::raw(52<<28)),
|
jump_impulse:JumpImpulse::FromHeight(Planar64::raw(52<<28)),
|
||||||
@@ -779,16 +785,17 @@ pub struct PhysicsModel{
|
|||||||
attr_id:usize,
|
attr_id:usize,
|
||||||
transform:crate::integer::Planar64Affine3,
|
transform:crate::integer::Planar64Affine3,
|
||||||
normal_transform:crate::integer::Planar64Mat3,
|
normal_transform:crate::integer::Planar64Mat3,
|
||||||
|
transform_det:Planar64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PhysicsModel{
|
impl PhysicsModel{
|
||||||
pub fn new(mesh_id:usize,attr_id:usize,transform:crate::integer::Planar64Affine3)->Self{
|
pub fn new(mesh_id:usize,attr_id:usize,transform:crate::integer::Planar64Affine3)->Self{
|
||||||
let normal_transform=transform.matrix3.inverse_times_det().transpose();
|
|
||||||
Self{
|
Self{
|
||||||
mesh_id,
|
mesh_id,
|
||||||
attr_id,
|
attr_id,
|
||||||
transform,
|
transform,
|
||||||
normal_transform,
|
normal_transform:transform.matrix3.inverse_times_det().transpose(),
|
||||||
|
transform_det:transform.matrix3.determinant(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -956,7 +963,6 @@ impl TouchingState{
|
|||||||
//detect model collision in reverse
|
//detect model collision in reverse
|
||||||
let model_mesh=models.mesh(intersect.model_id);
|
let model_mesh=models.mesh(intersect.model_id);
|
||||||
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&style_mesh);
|
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&style_mesh);
|
||||||
println!("### predict_collision_out id={} body={} time_limit={}",intersect.model_id,relative_body,collector.time());
|
|
||||||
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,
|
time,
|
||||||
@@ -1296,7 +1302,6 @@ impl crate::instruction::InstructionEmitter<PhysicsInstruction> for PhysicsState
|
|||||||
//no checks are needed because of the time limits.
|
//no checks are needed because of the time limits.
|
||||||
let model_mesh=self.models.mesh(id);
|
let model_mesh=self.models.mesh(id);
|
||||||
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&style_mesh);
|
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&style_mesh);
|
||||||
println!("### predict_collision_in id={} body={} time_limit={}",id,relative_body,collector.time());
|
|
||||||
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,time)|if time==self.time{None}else{Some((face,time))})
|
.map_or(None,|(face,time)|if time==self.time{None}else{Some((face,time))})
|
||||||
@@ -1671,7 +1676,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
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=Hitbox::from_mesh_scale(PhysicsMesh::from(&crate::primitives::unit_cube()),Planar64Vec3::int(256,1,256)/2);
|
let h0=Hitbox::from_mesh_scale(PhysicsMesh::from(&crate::primitives::unit_cube()),Planar64Vec3::int(5,1,5)/2);
|
||||||
let h1=Hitbox::roblox();
|
let h1=Hitbox::roblox();
|
||||||
let hitbox_mesh=h1.transformed_mesh();
|
let hitbox_mesh=h1.transformed_mesh();
|
||||||
let platform_mesh=h0.transformed_mesh();
|
let platform_mesh=h0.transformed_mesh();
|
||||||
@@ -1684,9 +1689,9 @@ fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time
|
|||||||
let h0=Hitbox::new(PhysicsMesh::from(&crate::primitives::unit_cube()),
|
let h0=Hitbox::new(PhysicsMesh::from(&crate::primitives::unit_cube()),
|
||||||
crate::integer::Planar64Affine3::new(
|
crate::integer::Planar64Affine3::new(
|
||||||
crate::integer::Planar64Mat3::from_cols(
|
crate::integer::Planar64Mat3::from_cols(
|
||||||
Planar64Vec3::int(256,0,1)/2,
|
Planar64Vec3::int(5,0,1)/2,
|
||||||
Planar64Vec3::int(0,1,0)/2,
|
Planar64Vec3::int(0,1,0)/2,
|
||||||
Planar64Vec3::int(-1,0,256)/2,
|
Planar64Vec3::int(-1,0,5)/2,
|
||||||
),
|
),
|
||||||
Planar64Vec3::ZERO,
|
Planar64Vec3::ZERO,
|
||||||
)
|
)
|
||||||
@@ -1866,42 +1871,6 @@ fn test_collision_oblique(){
|
|||||||
),Some(Time::from_secs(2)));
|
),Some(Time::from_secs(2)));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collision_oblique_north(){
|
|
||||||
test_collision(Body::new(
|
|
||||||
Planar64Vec3::int(0,4,0),
|
|
||||||
Planar64Vec3::int(0,-1,-1),
|
|
||||||
Planar64Vec3::int(0,-1,0),
|
|
||||||
Time::ZERO
|
|
||||||
),Some(Time::from_nanos(732050807)));
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_collision_oblique_east(){
|
|
||||||
test_collision(Body::new(
|
|
||||||
Planar64Vec3::int(0,4,0),
|
|
||||||
Planar64Vec3::int(1,-1,0),
|
|
||||||
Planar64Vec3::int(0,-1,0),
|
|
||||||
Time::ZERO
|
|
||||||
),Some(Time::from_nanos(732050807)));
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_collision_oblique_south(){
|
|
||||||
test_collision(Body::new(
|
|
||||||
Planar64Vec3::int(0,4,0),
|
|
||||||
Planar64Vec3::int(0,-1,1),
|
|
||||||
Planar64Vec3::int(0,-1,0),
|
|
||||||
Time::ZERO
|
|
||||||
),Some(Time::from_nanos(732050807)));
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_collision_oblique_west(){
|
|
||||||
test_collision(Body::new(
|
|
||||||
Planar64Vec3::int(0,4,0),
|
|
||||||
Planar64Vec3::int(-1,-1,0),
|
|
||||||
Planar64Vec3::int(0,-1,0),
|
|
||||||
Time::ZERO
|
|
||||||
),Some(Time::from_nanos(732050807)));
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn zoom_hit_nothing(){
|
fn zoom_hit_nothing(){
|
||||||
test_collision(Body::new(
|
test_collision(Body::new(
|
||||||
Planar64Vec3::int(0,10,0),
|
Planar64Vec3::int(0,10,0),
|
||||||
@@ -1918,4 +1887,4 @@ fn already_inside_hit_nothing(){
|
|||||||
Planar64Vec3::int(0,1,0),
|
Planar64Vec3::int(0,1,0),
|
||||||
Time::ZERO
|
Time::ZERO
|
||||||
),None);
|
),None);
|
||||||
}
|
}
|
||||||
@@ -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;
|
let radicand=a1.get() as i128*a1.get() as i128-a2.get() as i128*a0.get() as i128*4;
|
||||||
if 0<radicand {
|
if 0<radicand {
|
||||||
//start with f64 sqrt
|
//start with f64 sqrt
|
||||||
|
//failure case: 2^63 < sqrt(2^127)
|
||||||
let planar_radicand=Planar64::raw(unsafe{(radicand as f64).sqrt().to_int_unchecked()});
|
let planar_radicand=Planar64::raw(unsafe{(radicand as f64).sqrt().to_int_unchecked()});
|
||||||
//TODO: one or two newtons
|
//TODO: one or two newtons
|
||||||
//sort roots ascending and avoid taking the difference of large numbers
|
//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> {
|
pub fn zeroes1(a0:Planar64,a1:Planar64) -> Vec<Planar64> {
|
||||||
if a1==Planar64::ZERO{
|
if a1==Planar64::ZERO{
|
||||||
return vec![];
|
return vec![];
|
||||||
} else {
|
}else{
|
||||||
return vec![-a0/a1];
|
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![];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
[camera]
|
[camera]
|
||||||
sensitivity_x=49192
|
sensitivity_x=98384
|
||||||
#sensitivity_x=98384
|
|
||||||
fov_y=1.0
|
fov_y=1.0
|
||||||
#fov_x_from_y_ratio=1.33333333333333333333333333333333
|
#fov_x_from_y_ratio=1.33333333333333333333333333333333
|
||||||
Reference in New Issue
Block a user