Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
204dce366f | |||
99301bb990 | |||
28ffc82ac0 | |||
792c386008 | |||
151b99c3e6 | |||
b0e0bda101 | |||
510aef07a8 | |||
2c07673b7d | |||
2a73f8a469 | |||
4023ae60b1 | |||
1016f95b48 | |||
c0769abc1b | |||
74eefcb78f | |||
f770f5ac7b | |||
5b710b531e | |||
a77b2fd78f | |||
915d6c67cd | |||
9b7101cbea | |||
e67b29148e | |||
384b42f1ff | |||
aceae11d42 | |||
5123573822 | |||
49a5acf73b | |||
ba2d40970b |
engine
lib
strafe-client/src
@ -484,6 +484,9 @@ impl TransformedMesh<'_>{
|
|||||||
pub fn verts<'a>(&'a self)->impl Iterator<Item=vec3::Vector3<Fixed<2,64>>>+'a{
|
pub fn verts<'a>(&'a self)->impl Iterator<Item=vec3::Vector3<Fixed<2,64>>>+'a{
|
||||||
self.view.data.verts.iter().map(|&Vert(pos)|self.transform.vertex.transform_point3(pos))
|
self.view.data.verts.iter().map(|&Vert(pos)|self.transform.vertex.transform_point3(pos))
|
||||||
}
|
}
|
||||||
|
pub fn faces(&self)->impl Iterator<Item=SubmeshFaceId>{
|
||||||
|
(0..self.view.topology.faces.len() as u32).map(SubmeshFaceId::new)
|
||||||
|
}
|
||||||
fn farthest_vert(&self,dir:Planar64Vec3)->SubmeshVertId{
|
fn farthest_vert(&self,dir:Planar64Vec3)->SubmeshVertId{
|
||||||
//this happens to be well-defined. there are no virtual virtices
|
//this happens to be well-defined. there are no virtual virtices
|
||||||
SubmeshVertId::new(
|
SubmeshVertId::new(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::collections::{HashMap,HashSet};
|
use std::collections::{HashMap,HashSet};
|
||||||
|
use crate::model::DirectedEdge;
|
||||||
use crate::model::{self as model_physics,PhysicsMesh,PhysicsMeshTransform,TransformedMesh,MeshQuery,PhysicsMeshId,PhysicsSubmeshId};
|
use crate::model::{self as model_physics,PhysicsMesh,PhysicsMeshTransform,TransformedMesh,MeshQuery,PhysicsMeshId,PhysicsSubmeshId};
|
||||||
use strafesnet_common::bvh;
|
use strafesnet_common::bvh;
|
||||||
use strafesnet_common::map;
|
use strafesnet_common::map;
|
||||||
@ -280,7 +281,8 @@ impl PhysicsCamera{
|
|||||||
.clamp(Self::ANGLE_PITCH_LOWER_LIMIT,Self::ANGLE_PITCH_UPPER_LIMIT);
|
.clamp(Self::ANGLE_PITCH_LOWER_LIMIT,Self::ANGLE_PITCH_UPPER_LIMIT);
|
||||||
mat3::from_rotation_yx(ax,ay)
|
mat3::from_rotation_yx(ax,ay)
|
||||||
}
|
}
|
||||||
fn rotation(&self)->Planar64Mat3{
|
#[inline]
|
||||||
|
pub fn rotation(&self)->Planar64Mat3{
|
||||||
self.get_rotation(self.clamped_mouse_pos)
|
self.get_rotation(self.clamped_mouse_pos)
|
||||||
}
|
}
|
||||||
fn simulate_move_rotation(&self,mouse_delta:glam::IVec2)->Planar64Mat3{
|
fn simulate_move_rotation(&self,mouse_delta:glam::IVec2)->Planar64Mat3{
|
||||||
@ -980,6 +982,34 @@ impl PhysicsContext<'_>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl PhysicsData{
|
impl PhysicsData{
|
||||||
|
pub fn trace_ray(&self,ray:strafesnet_common::ray::Ray)->Option<ModelId>{
|
||||||
|
let (_time,convex_mesh_id)=self.bvh.sample_ray(&ray,Time::ZERO,Time::MAX/4,|&model,ray|{
|
||||||
|
let mesh=self.models.mesh(model);
|
||||||
|
// brute force trace every face
|
||||||
|
mesh.faces().filter_map(|face_id|{
|
||||||
|
let (n,d)=mesh.face_nd(face_id);
|
||||||
|
// trace ray onto face
|
||||||
|
// n.(o+d*t)==n.p
|
||||||
|
// n.o + n.d * t == n.p
|
||||||
|
// t == (n.p - n.o)/n.d
|
||||||
|
let nd=n.dot(ray.direction);
|
||||||
|
if nd.is_zero(){
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let t=(d-n.dot(ray.origin))/nd;
|
||||||
|
// check if point of intersection is behind face edges
|
||||||
|
// *2 because average of 2 vertices
|
||||||
|
let p=ray.extrapolate(t)*2;
|
||||||
|
mesh.face_edges(face_id).iter().all(|&directed_edge_id|{
|
||||||
|
let edge_n=mesh.directed_edge_n(directed_edge_id);
|
||||||
|
let cross_n=edge_n.cross(n);
|
||||||
|
let &[vert0,vert1]=mesh.edge_verts(directed_edge_id.as_undirected()).as_ref();
|
||||||
|
cross_n.dot(p)<cross_n.dot(mesh.vert(vert0)+mesh.vert(vert1))
|
||||||
|
}).then(||t)
|
||||||
|
}).min().map(Into::into)
|
||||||
|
})?;
|
||||||
|
Some(convex_mesh_id.model_id.into())
|
||||||
|
}
|
||||||
/// use with caution, this is the only non-instruction way to mess with physics
|
/// use with caution, this is the only non-instruction way to mess with physics
|
||||||
pub fn generate_models(&mut self,map:&map::CompleteMap){
|
pub fn generate_models(&mut self,map:&map::CompleteMap){
|
||||||
let mut modes=map.modes.clone();
|
let mut modes=map.modes.clone();
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use strafesnet_common::integer::{self,vec3::{self,Vector3},Fixed,Planar64,Planar64Vec3,Ratio};
|
use strafesnet_common::integer::vec3::{self,Vector3};
|
||||||
|
use strafesnet_common::integer::{Fixed,Planar64Vec3,Ratio};
|
||||||
|
use strafesnet_common::ray::Ray;
|
||||||
|
|
||||||
// This algorithm is based on Lua code
|
// This algorithm is based on Lua code
|
||||||
// written by Trey Reynolds in 2021
|
// written by Trey Reynolds in 2021
|
||||||
@ -12,24 +14,6 @@ type Conts<'a>=arrayvec::ArrayVec<&'a Contact,4>;
|
|||||||
// hack to allow comparing ratios to zero
|
// hack to allow comparing ratios to zero
|
||||||
const RATIO_ZERO:Ratio<Fixed<1,32>,Fixed<1,32>>=Ratio::new(Fixed::ZERO,Fixed::EPSILON);
|
const RATIO_ZERO:Ratio<Fixed<1,32>,Fixed<1,32>>=Ratio::new(Fixed::ZERO,Fixed::EPSILON);
|
||||||
|
|
||||||
struct Ray{
|
|
||||||
origin:Planar64Vec3,
|
|
||||||
direction:Planar64Vec3,
|
|
||||||
}
|
|
||||||
impl Ray{
|
|
||||||
fn extrapolate<Num,Den,N1,T1>(&self,t:Ratio<Num,Den>)->Planar64Vec3
|
|
||||||
where
|
|
||||||
Num:Copy,
|
|
||||||
Den:Copy,
|
|
||||||
Num:core::ops::Mul<Planar64,Output=N1>,
|
|
||||||
Planar64:core::ops::Mul<Den,Output=N1>,
|
|
||||||
N1:integer::Divide<Den,Output=T1>,
|
|
||||||
T1:integer::Fix<Planar64>,
|
|
||||||
{
|
|
||||||
self.origin+self.direction.map(|elem|(t*elem).divide().fix())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information about a contact restriction
|
/// Information about a contact restriction
|
||||||
pub struct Contact{
|
pub struct Contact{
|
||||||
pub position:Planar64Vec3,
|
pub position:Planar64Vec3,
|
||||||
|
@ -161,6 +161,7 @@ pub struct Session{
|
|||||||
recording:Recording,
|
recording:Recording,
|
||||||
//players:HashMap<PlayerId,Simulation>,
|
//players:HashMap<PlayerId,Simulation>,
|
||||||
replays:HashMap<BotId,Replay>,
|
replays:HashMap<BotId,Replay>,
|
||||||
|
last_ray_hit:Option<strafesnet_common::model::ModelId>,
|
||||||
}
|
}
|
||||||
impl Session{
|
impl Session{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@ -177,6 +178,7 @@ impl Session{
|
|||||||
view_state:ViewState::Play,
|
view_state:ViewState::Play,
|
||||||
recording:Default::default(),
|
recording:Default::default(),
|
||||||
replays:HashMap::new(),
|
replays:HashMap::new(),
|
||||||
|
last_ray_hit:None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn clear_recording(&mut self){
|
fn clear_recording(&mut self){
|
||||||
@ -194,6 +196,19 @@ impl Session{
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn debug_raycast_print_model_id_if_changed(&mut self,time:SessionTime){
|
||||||
|
if let Some(frame_state)=self.get_frame_state(time){
|
||||||
|
let ray=strafesnet_common::ray::Ray{
|
||||||
|
origin:frame_state.body.extrapolated_position(self.simulation.timer.time(time)),
|
||||||
|
direction:-frame_state.camera.rotation().z_axis,
|
||||||
|
};
|
||||||
|
let model_id=self.geometry_shared.trace_ray(ray);
|
||||||
|
if model_id!=self.last_ray_hit{
|
||||||
|
println!("hit={model_id:?}");
|
||||||
|
self.last_ray_hit=model_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn user_settings(&self)->&UserSettings{
|
pub fn user_settings(&self)->&UserSettings{
|
||||||
&self.user_settings
|
&self.user_settings
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,10 @@ impl Aabb{
|
|||||||
self.min-=hs;
|
self.min-=hs;
|
||||||
self.max+=hs;
|
self.max+=hs;
|
||||||
}
|
}
|
||||||
|
pub fn contains(&self,point:Planar64Vec3)->bool{
|
||||||
|
let bvec=self.min.lt(point)&point.lt(self.max);
|
||||||
|
bvec.all()
|
||||||
|
}
|
||||||
pub fn intersects(&self,aabb:&Aabb)->bool{
|
pub fn intersects(&self,aabb:&Aabb)->bool{
|
||||||
let bvec=self.min.lt(aabb.max)&aabb.min.lt(self.max);
|
let bvec=self.min.lt(aabb.max)&aabb.min.lt(self.max);
|
||||||
bvec.all()
|
bvec.all()
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::aabb::Aabb;
|
use crate::aabb::Aabb;
|
||||||
|
use crate::ray::Ray;
|
||||||
|
use crate::integer::{Ratio,Planar64};
|
||||||
|
use crate::instruction::{InstructionCollector,TimedInstruction};
|
||||||
|
|
||||||
//da algaritum
|
//da algaritum
|
||||||
//lista boxens
|
//lista boxens
|
||||||
@ -10,6 +16,96 @@ use crate::aabb::Aabb;
|
|||||||
//sort the centerpoints on each axis (3 lists)
|
//sort the centerpoints on each axis (3 lists)
|
||||||
//bv is put into octant based on whether it is upper or lower in each list
|
//bv is put into octant based on whether it is upper or lower in each list
|
||||||
|
|
||||||
|
|
||||||
|
pub fn intersect_aabb(ray:&Ray,aabb:&Aabb)->Option<Ratio<Planar64,Planar64>>{
|
||||||
|
// n.(o+d*t)==n.p
|
||||||
|
// n.o + n.d * t == n.p
|
||||||
|
// t == (n.p - n.o)/n.d
|
||||||
|
let mut hit=None;
|
||||||
|
match ray.direction.x.cmp(&Planar64::ZERO){
|
||||||
|
Ordering::Less=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dy=rel_max.x*ray.direction.y;
|
||||||
|
let dz=rel_max.x*ray.direction.z;
|
||||||
|
// x is negative, so inequalities are flipped
|
||||||
|
if rel_min.y*ray.direction.x>dy&&dy>rel_max.y*ray.direction.x
|
||||||
|
&&rel_min.z*ray.direction.x>dz&&dz>rel_max.z*ray.direction.x{
|
||||||
|
let t=rel_max.x/ray.direction.x;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ordering::Equal=>(),
|
||||||
|
Ordering::Greater=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dy=rel_min.x*ray.direction.y;
|
||||||
|
let dz=rel_min.x*ray.direction.z;
|
||||||
|
// x is positive, so inequalities are normal
|
||||||
|
if rel_min.y*ray.direction.x<dy&&dy<rel_max.y*ray.direction.x
|
||||||
|
&&rel_min.z*ray.direction.x<dz&&dz<rel_max.z*ray.direction.x{
|
||||||
|
let t=rel_min.x/ray.direction.x;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
match ray.direction.z.cmp(&Planar64::ZERO){
|
||||||
|
Ordering::Less=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dx=rel_max.z*ray.direction.x;
|
||||||
|
let dy=rel_max.z*ray.direction.y;
|
||||||
|
// z is negative, so inequalities are flipped
|
||||||
|
if rel_min.x*ray.direction.z>dx&&dx>rel_max.x*ray.direction.z
|
||||||
|
&&rel_min.y*ray.direction.z>dy&&dy>rel_max.y*ray.direction.z{
|
||||||
|
let t=rel_max.z/ray.direction.z;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ordering::Equal=>(),
|
||||||
|
Ordering::Greater=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dx=rel_min.z*ray.direction.x;
|
||||||
|
let dy=rel_min.z*ray.direction.y;
|
||||||
|
// z is positive, so inequalities are normal
|
||||||
|
if rel_min.x*ray.direction.z<dx&&dx<rel_max.x*ray.direction.z
|
||||||
|
&&rel_min.y*ray.direction.z<dy&&dy<rel_max.y*ray.direction.z{
|
||||||
|
let t=rel_min.z/ray.direction.z;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
match ray.direction.y.cmp(&Planar64::ZERO){
|
||||||
|
Ordering::Less=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dz=rel_max.y*ray.direction.z;
|
||||||
|
let dx=rel_max.y*ray.direction.x;
|
||||||
|
// y is negative, so inequalities are flipped
|
||||||
|
if rel_min.z*ray.direction.y>dz&&dz>rel_max.z*ray.direction.y
|
||||||
|
&&rel_min.x*ray.direction.y>dx&&dx>rel_max.x*ray.direction.y{
|
||||||
|
let t=rel_max.y/ray.direction.y;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ordering::Equal=>(),
|
||||||
|
Ordering::Greater=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dz=rel_min.y*ray.direction.z;
|
||||||
|
let dx=rel_min.y*ray.direction.x;
|
||||||
|
// y is positive, so inequalities are normal
|
||||||
|
if rel_min.z*ray.direction.y<dz&&dz<rel_max.z*ray.direction.y
|
||||||
|
&&rel_min.x*ray.direction.y<dx&&dx<rel_max.x*ray.direction.y{
|
||||||
|
let t=rel_min.y/ray.direction.y;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
hit
|
||||||
|
}
|
||||||
|
|
||||||
pub enum RecursiveContent<N,L>{
|
pub enum RecursiveContent<N,L>{
|
||||||
Branch(Vec<N>),
|
Branch(Vec<N>),
|
||||||
Leaf(L),
|
Leaf(L),
|
||||||
@ -44,6 +140,92 @@ impl<L> BvhNode<L>{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn populate_nodes<'a,T,F>(
|
||||||
|
&'a self,
|
||||||
|
collector:&mut InstructionCollector<&'a L,Ratio<Planar64,Planar64>>,
|
||||||
|
nodes:&mut BTreeMap<Ratio<Planar64,Planar64>,&'a BvhNode<L>>,
|
||||||
|
ray:&Ray,
|
||||||
|
start_time:Ratio<Planar64,Planar64>,
|
||||||
|
f:&F,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
T:Ord+Copy,
|
||||||
|
Ratio<Planar64,Planar64>:From<T>,
|
||||||
|
F:Fn(&L,&Ray)->Option<T>,
|
||||||
|
{
|
||||||
|
match &self.content{
|
||||||
|
RecursiveContent::Leaf(leaf)=>if let Some(time)=f(leaf,ray){
|
||||||
|
let ins=TimedInstruction{time:time.into(),instruction:leaf};
|
||||||
|
if start_time.lt_ratio(ins.time)&&ins.time.lt_ratio(collector.time()){
|
||||||
|
collector.collect(Some(ins));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RecursiveContent::Branch(children)=>for child in children{
|
||||||
|
if child.aabb.contains(ray.origin){
|
||||||
|
child.populate_nodes(collector,nodes,ray,start_time,f);
|
||||||
|
}else{
|
||||||
|
// Am I an upcoming superstar?
|
||||||
|
if let Some(t)=intersect_aabb(ray,&child.aabb){
|
||||||
|
if start_time.lt_ratio(t)&&t.lt_ratio(collector.time()){
|
||||||
|
nodes.insert(t,child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn sample_ray<T,F>(
|
||||||
|
&self,
|
||||||
|
ray:&Ray,
|
||||||
|
start_time:T,
|
||||||
|
time_limit:T,
|
||||||
|
f:F,
|
||||||
|
)->Option<(T,&L)>
|
||||||
|
where
|
||||||
|
T:Ord+Copy,
|
||||||
|
T:From<Ratio<Planar64,Planar64>>,
|
||||||
|
Ratio<Planar64,Planar64>:From<T>,
|
||||||
|
F:Fn(&L,&Ray)->Option<T>,
|
||||||
|
{
|
||||||
|
// source of nondeterminism when Aabb boundaries are coplanar
|
||||||
|
let mut nodes=BTreeMap::new();
|
||||||
|
|
||||||
|
let start_time=start_time.into();
|
||||||
|
let time_limit=time_limit.into();
|
||||||
|
let mut collector=InstructionCollector::new(time_limit);
|
||||||
|
// break open all nodes that contain ray.origin and populate nodes with future intersection times
|
||||||
|
self.populate_nodes(&mut collector,&mut nodes,ray,start_time,&f);
|
||||||
|
|
||||||
|
// swim through nodes one at a time
|
||||||
|
while let Some((t,node))=nodes.pop_first(){
|
||||||
|
if collector.time()<t{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
match &node.content{
|
||||||
|
RecursiveContent::Leaf(leaf)=>if let Some(time)=f(leaf,ray){
|
||||||
|
let ins=TimedInstruction{time:time.into(),instruction:leaf};
|
||||||
|
// this lower bound can also be omitted
|
||||||
|
// but it causes type inference errors lol
|
||||||
|
if start_time.lt_ratio(ins.time)&&ins.time.lt_ratio(collector.time()){
|
||||||
|
collector.collect(Some(ins));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// break open the node and predict collisions with the child nodes
|
||||||
|
RecursiveContent::Branch(children)=>for child in children{
|
||||||
|
// Am I an upcoming superstar?
|
||||||
|
if let Some(t)=intersect_aabb(ray,&child.aabb){
|
||||||
|
// we don't need to check the lower bound
|
||||||
|
// because child aabbs are guaranteed to be within the parent bounds.
|
||||||
|
if t<collector.time(){
|
||||||
|
nodes.insert(t,child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collector.take().map(|TimedInstruction{time,instruction:leaf}|(time.into(),leaf))
|
||||||
|
}
|
||||||
pub fn into_inner(self)->(RecursiveContent<BvhNode<L>,L>,Aabb){
|
pub fn into_inner(self)->(RecursiveContent<BvhNode<L>,L>,Aabb){
|
||||||
(self.content,self.aabb)
|
(self.content,self.aabb)
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ pub use ratio_ops::ratio::{Ratio,Divide};
|
|||||||
//integer units
|
//integer units
|
||||||
|
|
||||||
/// specific example of a "default" time type
|
/// specific example of a "default" time type
|
||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub enum TimeInner{}
|
pub enum TimeInner{}
|
||||||
pub type AbsoluteTime=Time<TimeInner>;
|
pub type AbsoluteTime=Time<TimeInner>;
|
||||||
|
|
||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub struct Time<T>(i64,core::marker::PhantomData<T>);
|
pub struct Time<T>(i64,core::marker::PhantomData<T>);
|
||||||
impl<T> Time<T>{
|
impl<T> Time<T>{
|
||||||
pub const MIN:Self=Self::raw(i64::MIN);
|
pub const MIN:Self=Self::raw(i64::MIN);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
pub mod bvh;
|
pub mod bvh;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
|
pub mod ray;
|
||||||
pub mod run;
|
pub mod run;
|
||||||
pub mod aabb;
|
pub mod aabb;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::mouse::MouseState;
|
use crate::mouse::MouseState;
|
||||||
use crate::gameplay_modes::{ModeId,StageId};
|
use crate::gameplay_modes::{ModeId,StageId};
|
||||||
|
|
||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub enum TimeInner{}
|
pub enum TimeInner{}
|
||||||
pub type Time=crate::integer::Time<TimeInner>;
|
pub type Time=crate::integer::Time<TimeInner>;
|
||||||
|
|
||||||
|
20
lib/common/src/ray.rs
Normal file
20
lib/common/src/ray.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use ratio_ops::ratio::Ratio;
|
||||||
|
use crate::integer::{self,Planar64,Planar64Vec3};
|
||||||
|
|
||||||
|
pub struct Ray{
|
||||||
|
pub origin:Planar64Vec3,
|
||||||
|
pub direction:Planar64Vec3,
|
||||||
|
}
|
||||||
|
impl Ray{
|
||||||
|
pub fn extrapolate<Num,Den,N1,T1>(&self,t:Ratio<Num,Den>)->Planar64Vec3
|
||||||
|
where
|
||||||
|
Num:Copy,
|
||||||
|
Den:Copy,
|
||||||
|
Num:core::ops::Mul<Planar64,Output=N1>,
|
||||||
|
Planar64:core::ops::Mul<Den,Output=N1>,
|
||||||
|
N1:integer::Divide<Den,Output=T1>,
|
||||||
|
T1:integer::Fix<Planar64>,
|
||||||
|
{
|
||||||
|
self.origin+self.direction.map(|elem|(t*elem).divide().fix())
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ use crate::timer::{TimerFixed,Realtime,Paused,Unpaused};
|
|||||||
|
|
||||||
use crate::physics::{TimeInner as PhysicsTimeInner,Time as PhysicsTime};
|
use crate::physics::{TimeInner as PhysicsTimeInner,Time as PhysicsTime};
|
||||||
|
|
||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub enum TimeInner{}
|
pub enum TimeInner{}
|
||||||
pub type Time=crate::integer::Time<TimeInner>;
|
pub type Time=crate::integer::Time<TimeInner>;
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub enum TimeInner{}
|
pub enum TimeInner{}
|
||||||
pub type Time=crate::integer::Time<TimeInner>;
|
pub type Time=crate::integer::Time<TimeInner>;
|
||||||
|
@ -268,30 +268,35 @@ impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialEq<Ratio<RhsNum,RhsDen>> for Ratio<
|
|||||||
}
|
}
|
||||||
impl<Num,Den> Eq for Ratio<Num,Den> where Self:PartialEq{}
|
impl<Num,Den> Eq for Ratio<Num,Den> where Self:PartialEq{}
|
||||||
|
|
||||||
|
// Wow! These were both completely wrong!
|
||||||
|
// Idea: use a 'signed' trait instead of parity and float the sign to the numerator.
|
||||||
impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialOrd<Ratio<RhsNum,RhsDen>> for Ratio<LhsNum,LhsDen>
|
impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialOrd<Ratio<RhsNum,RhsDen>> for Ratio<LhsNum,LhsDen>
|
||||||
where
|
where
|
||||||
LhsNum:Copy,
|
LhsNum:Copy,
|
||||||
LhsDen:Copy,
|
LhsDen:Copy+Parity,
|
||||||
RhsNum:Copy,
|
RhsNum:Copy,
|
||||||
RhsDen:Copy,
|
RhsDen:Copy+Parity,
|
||||||
LhsNum:core::ops::Mul<RhsDen,Output=T>,
|
LhsNum:core::ops::Mul<RhsDen,Output=T>,
|
||||||
|
LhsDen:core::ops::Mul<RhsNum,Output=T>,
|
||||||
RhsNum:core::ops::Mul<LhsDen,Output=U>,
|
RhsNum:core::ops::Mul<LhsDen,Output=U>,
|
||||||
T:PartialOrd<U>,
|
RhsDen:core::ops::Mul<LhsNum,Output=U>,
|
||||||
|
T:PartialOrd<U>+Ord,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn partial_cmp(&self,other:&Ratio<RhsNum,RhsDen>)->Option<core::cmp::Ordering>{
|
fn partial_cmp(&self,&other:&Ratio<RhsNum,RhsDen>)->Option<core::cmp::Ordering>{
|
||||||
(self.num*other.den).partial_cmp(&(other.num*self.den))
|
self.partial_cmp_ratio(other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<Num,Den,T> Ord for Ratio<Num,Den>
|
impl<Num,Den,T> Ord for Ratio<Num,Den>
|
||||||
where
|
where
|
||||||
Num:Copy,
|
Num:Copy,
|
||||||
Den:Copy,
|
Den:Copy+Parity,
|
||||||
Num:core::ops::Mul<Den,Output=T>,
|
Num:core::ops::Mul<Den,Output=T>,
|
||||||
|
Den:core::ops::Mul<Num,Output=T>,
|
||||||
T:Ord,
|
T:Ord,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cmp(&self,other:&Self)->std::cmp::Ordering{
|
fn cmp(&self,&other:&Self)->std::cmp::Ordering{
|
||||||
(self.num*other.den).cmp(&(other.num*self.den))
|
self.cmp_ratio(other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,5 +77,8 @@ pub fn new<'a>(
|
|||||||
run_session_instruction!(ins.time,SessionInstruction::LoadReplay(bot));
|
run_session_instruction!(ins.time,SessionInstruction::LoadReplay(bot));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//whatever just do it
|
||||||
|
session.debug_raycast_print_model_id_if_changed(ins.time);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user