Compare commits

..

3 Commits

Author SHA1 Message Date
5a1fa50d16 it doesn't work in minkowski
because the return type must be the same for all branches
2026-01-30 07:23:38 -08:00
76d04a8566 again 2026-01-30 07:15:59 -08:00
e56e661805 noclip 2026-01-30 07:02:04 -08:00
9 changed files with 86 additions and 96 deletions

View File

@@ -96,7 +96,7 @@ impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>,Position=Planar64V
}
}
//test each edge collision time, ignoring roots with zero or conflicting derivative
mesh.for_each_face_edge(face_id,|directed_edge_id|{
for directed_edge_id in mesh.face_edges(face_id){
let edge_n=mesh.directed_edge_n(directed_edge_id);
let n=n.cross(edge_n);
let &[v0,v1]=mesh.edge_verts(directed_edge_id.as_undirected()).as_ref();
@@ -110,7 +110,7 @@ impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>,Position=Planar64V
break;
}
}
});
}
//if none:
},
&FEV::Edge(edge_id)=>{
@@ -151,7 +151,7 @@ impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>,Position=Planar64V
},
&FEV::Vert(vert_id)=>{
//test each edge collision time, ignoring roots with zero or conflicting derivative
mesh.for_each_vert_edge(vert_id,|directed_edge_id|{
for directed_edge_id in mesh.vert_edges(vert_id){
//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 dt in Fixed::<2,64>::zeroes2((n.dot(trajectory.position-mesh.vert(vert_id)))*2,n.dot(trajectory.velocity)*2,n.dot(trajectory.acceleration)){
@@ -162,7 +162,7 @@ impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>,Position=Planar64V
break;
}
}
});
}
//if none:
},
}

View File

@@ -26,13 +26,13 @@ pub trait MeshTopology{
type Edge:UndirectedEdge<DirectedEdge=Self::DirectedEdge>;
type DirectedEdge:DirectedEdge<UndirectedEdge=Self::Edge>;
type Vert;
fn for_each_vert_edge(&self,vert_id:Self::Vert,f:impl FnMut(Self::DirectedEdge));
fn for_each_vert_face(&self,vert_id:Self::Vert,f:impl FnMut(Self::Face));
fn vert_edges(&self,vert_id:Self::Vert)->impl Iterator<Item=Self::DirectedEdge>;
fn vert_faces(&self,vert_id:Self::Vert)->impl Iterator<Item=Self::Face>;
fn edge_faces(&self,edge_id:Self::Edge)->impl AsRef<[Self::Face;2]>;
fn edge_verts(&self,edge_id:Self::Edge)->impl AsRef<[Self::Vert;2]>;
#[expect(unused)]
fn for_each_face_vert(&self,face_id:Self::Face,f:impl FnMut(Self::Vert));
fn for_each_face_edge(&self,face_id:Self::Face,f:impl FnMut(Self::DirectedEdge));
// #[expect(unused)]
// fn face_verts(&self,face_id:Self::Face)->impl Iterator<Item=Self::Vert>;
fn face_edges(&self,face_id:Self::Face)->impl Iterator<Item=Self::DirectedEdge>;
}
// Make face_nd d value relative

View File

@@ -623,7 +623,7 @@ impl<M:MeshQuery<Position=Planar64Vec3>,C:Contains> EVFinder<'_,M,C>
{
fn next_transition_vert(&mut self,vert_id:M::Vert,point:Planar64Vec3)->Transition<M::Vert>{
let mut best_transition=Transition::Done;
self.mesh.for_each_vert_edge(vert_id,|directed_edge_id|{
for directed_edge_id in self.mesh.vert_edges(vert_id){
//test if this edge's opposite vertex closer
let edge_verts=self.mesh.edge_verts(directed_edge_id.as_undirected());
//select opposite vertex
@@ -636,14 +636,14 @@ impl<M:MeshQuery<Position=Planar64Vec3>,C:Contains> EVFinder<'_,M,C>
best_transition=Transition::Vert(test_vert_id);
self.best_distance_squared=distance_squared;
}
});
}
best_transition
}
fn final_ev(&mut self,vert_id:M::Vert,point:Planar64Vec3)->EV<M>{
let mut best_transition=EV::Vert(vert_id);
let vert_pos=self.mesh.vert(vert_id);
let diff=point-vert_pos;
self.mesh.for_each_vert_edge(vert_id,|directed_edge_id|{
for directed_edge_id in self.mesh.vert_edges(vert_id){
//test if this edge is closer
let edge_verts=self.mesh.edge_verts(directed_edge_id.as_undirected());
let test_vert_id=edge_verts.as_ref()[directed_edge_id.parity() as usize];
@@ -664,7 +664,7 @@ impl<M:MeshQuery<Position=Planar64Vec3>,C:Contains> EVFinder<'_,M,C>
self.best_distance_squared=distance_squared;
}
}
});
}
best_transition
}
fn crawl_boundaries(&mut self,mut vert_id:M::Vert,point:Planar64Vec3)->EV<M>

View File

@@ -133,7 +133,7 @@ impl MinkowskiMesh<'_>{
let mut best_time=range.end_bound().map(|&t|into_giga_time(t,trajectory.time));
let mut best_edge=None;
let face_n=self.face_nd(contact_face_id).0;
self.for_each_face_edge(contact_face_id,|directed_edge_id|{
for directed_edge_id in self.face_edges(contact_face_id){
let edge_n=self.directed_edge_n(directed_edge_id);
//f x e points in
let n=face_n.cross(edge_n);
@@ -149,7 +149,7 @@ impl MinkowskiMesh<'_>{
break;
}
}
});
}
best_edge
}
pub fn contains_point(&self,point:Planar64Vec3)->bool{
@@ -211,18 +211,18 @@ impl MeshTopology for MinkowskiMesh<'_>{
type Edge=MinkowskiEdge;
type DirectedEdge=MinkowskiDirectedEdge;
type Vert=MinkowskiVert;
fn for_each_vert_edge(&self,vert_id:Self::Vert,mut f:impl FnMut(Self::DirectedEdge)){
fn vert_edges(&self,vert_id:Self::Vert)->impl Iterator<Item=Self::DirectedEdge>{
match vert_id{
MinkowskiVert::VertVert(v0,v1)=>{
//detect shared volume when the other mesh is mirrored along a test edge dir
let v0f={
let mut faces=Vec::new();
self.mesh0.for_each_vert_face(v0,|face|faces.push(face));
self.mesh0.vert_faces(v0,|face|faces.push(face));
faces
};
let v1f={
let mut faces=Vec::new();
self.mesh1.for_each_vert_face(v1,|face|faces.push(face));
self.mesh1.vert_faces(v1,|face|faces.push(face));
faces
};
let v0f_n:Vec<_>=v0f.iter().map(|&face_id|self.mesh0.face_nd(face_id).0).collect();
@@ -230,7 +230,7 @@ impl MeshTopology for MinkowskiMesh<'_>{
// scratch vector
let mut face_normals=Vec::with_capacity(v0f.len()+v1f.len());
face_normals.clone_from(&v0f_n);
self.mesh0.for_each_vert_edge(v0,|directed_edge_id|{
self.mesh0.vert_edges(v0,|directed_edge_id|{
let n=self.mesh0.directed_edge_n(directed_edge_id);
let nn=n.dot(n);
// TODO: there's gotta be a better way to do this
@@ -247,7 +247,7 @@ impl MeshTopology for MinkowskiMesh<'_>{
}
});
face_normals.clone_from(&v1f_n);
self.mesh1.for_each_vert_edge(v1,|directed_edge_id|{
self.mesh1.vert_edges(v1,|directed_edge_id|{
let n=self.mesh1.directed_edge_n(directed_edge_id);
let nn=n.dot(n);
// drop faces beyond v1f_n
@@ -264,7 +264,7 @@ impl MeshTopology for MinkowskiMesh<'_>{
},
}
}
fn for_each_vert_face(&self,_vert_id:Self::Vert,_f:impl FnMut(Self::Face)){
fn vert_faces(&self,_vert_id:Self::Vert)->impl Iterator<Item=Self::Face>{
unimplemented!()
}
fn edge_faces(&self,edge_id:Self::Edge)->impl AsRef<[Self::Face;2]>{
@@ -273,7 +273,7 @@ impl MeshTopology for MinkowskiMesh<'_>{
//faces are listed backwards from the minkowski mesh
let v0e={
let mut edges=Vec::new();
self.mesh0.for_each_vert_edge(v0,|edge|edges.push(edge));
self.mesh0.vert_edges(v0,|edge|edges.push(edge));
edges
};
let &[e1f0,e1f1]=self.mesh1.edge_faces(e1).as_ref();
@@ -307,7 +307,7 @@ impl MeshTopology for MinkowskiMesh<'_>{
//tracking index with an external variable because .enumerate() is not available
let v1e={
let mut edges=Vec::new();
self.mesh1.for_each_vert_edge(v1,|edge|edges.push(edge));
self.mesh1.vert_edges(v1,|edge|edges.push(edge));
edges
};
let &[e0f0,e0f1]=self.mesh0.edge_faces(e0).as_ref();
@@ -346,13 +346,13 @@ impl MeshTopology for MinkowskiMesh<'_>{
),
})
}
fn for_each_face_vert(&self,_face_id:Self::Face,_f:impl FnMut(Self::Vert)){
unimplemented!()
}
fn for_each_face_edge(&self,face_id:Self::Face,mut f:impl FnMut(Self::DirectedEdge)){
// fn face_verts(&self,_face_id:Self::Face)->impl Iterator<Item=Self::Vert>{
// unimplemented!()
// }
fn face_edges(&self,face_id:Self::Face)->impl Iterator<Item=Self::DirectedEdge>{
match face_id{
MinkowskiFace::VertFace(v0,f1)=>{
self.mesh1.for_each_face_edge(f1,|edge_id1|
self.mesh1.face_edges(f1,|edge_id1|
f(MinkowskiDirectedEdge::VertEdge(v0,edge_id1.reverse()))
)
},
@@ -367,7 +367,7 @@ impl MeshTopology for MinkowskiMesh<'_>{
f(MinkowskiDirectedEdge::EdgeVert(e0.as_directed(parity),e1v1));
},
MinkowskiFace::FaceVert(f0,v1)=>{
self.mesh0.for_each_face_edge(f0,|edge_id0|
self.mesh0.face_edges(f0,|edge_id0|
f(MinkowskiDirectedEdge::EdgeVert(edge_id0,v1))
)
},

View File

@@ -438,11 +438,11 @@ impl MeshTopology for PhysicsMeshView<'_>{
type Edge=SubmeshEdgeId;
type DirectedEdge=SubmeshDirectedEdgeId;
type Vert=SubmeshVertId;
fn for_each_vert_edge(&self,vert_id:Self::Vert,f:impl FnMut(Self::DirectedEdge)){
self.topology.vert_topology[vert_id.get() as usize].edges.iter().copied().for_each(f);
fn vert_edges(&self,vert_id:Self::Vert)->impl Iterator<Item=Self::DirectedEdge>{
self.topology.vert_topology[vert_id.get() as usize].edges.iter().copied()
}
fn for_each_vert_face(&self,vert_id:Self::Vert,f:impl FnMut(Self::Face)){
self.topology.vert_topology[vert_id.get() as usize].faces.iter().copied().for_each(f);
fn vert_faces(&self,vert_id:Self::Vert)->impl Iterator<Item=Self::Face>{
self.topology.vert_topology[vert_id.get() as usize].faces.iter().copied()
}
fn edge_faces(&self,edge_id:Self::Edge)->impl AsRef<[Self::Face;2]>{
AsRefHelper(self.topology.edge_topology[edge_id.get() as usize].faces)
@@ -450,11 +450,11 @@ impl MeshTopology for PhysicsMeshView<'_>{
fn edge_verts(&self,edge_id:Self::Edge)->impl AsRef<[Self::Vert;2]>{
AsRefHelper(self.topology.edge_topology[edge_id.get() as usize].verts)
}
fn for_each_face_vert(&self,_face_id:Self::Face,_f:impl FnMut(Self::Vert)){
unimplemented!()
}
fn for_each_face_edge(&self,face_id:Self::Face,f:impl FnMut(Self::DirectedEdge)){
self.topology.face_topology[face_id.get() as usize].edges.iter().copied().for_each(f);
// fn face_verts(&self,_face_id:Self::Face)->impl Iterator<Item=Self::Vert>{
// unimplemented!()
// }
fn face_edges(&self,face_id:Self::Face)->impl Iterator<Item=Self::DirectedEdge>{
self.topology.face_topology[face_id.get() as usize].edges.iter().copied()
}
}
@@ -538,12 +538,12 @@ impl MeshTopology for TransformedMesh<'_>{
type DirectedEdge=SubmeshDirectedEdgeId;
type Vert=SubmeshVertId;
#[inline]
fn for_each_vert_edge(&self,vert_id:Self::Vert,f:impl FnMut(Self::DirectedEdge)){
self.view.for_each_vert_edge(vert_id,f)
fn vert_edges(&self,vert_id:Self::Vert)->impl Iterator<Item=Self::DirectedEdge>{
self.view.vert_edges(vert_id)
}
#[inline]
fn for_each_vert_face(&self,vert_id:Self::Vert,f:impl FnMut(Self::Face)){
self.view.for_each_vert_face(vert_id,f)
fn vert_faces(&self,vert_id:Self::Vert)->impl Iterator<Item=Self::Face>{
self.view.vert_faces(vert_id)
}
#[inline]
fn edge_faces(&self,edge_id:Self::Edge)->impl AsRef<[Self::Face;2]>{
@@ -553,12 +553,13 @@ impl MeshTopology for TransformedMesh<'_>{
fn edge_verts(&self,edge_id:Self::Edge)->impl AsRef<[Self::Vert;2]>{
self.view.edge_verts(edge_id)
}
fn for_each_face_vert(&self,face_id:Self::Face,f:impl FnMut(Self::Vert)){
self.view.for_each_face_vert(face_id,f)
}
// #[inline]
// fn face_verts(&self,face_id:Self::Face)->impl Iterator<Item=Self::Vert>{
// self.view.face_verts(face_id)
// }
#[inline]
fn for_each_face_edge(&self,face_id:Self::Face,f:impl FnMut(Self::DirectedEdge)){
self.view.for_each_face_edge(face_id,f)
fn face_edges(&self,face_id:Self::Face)->impl Iterator<Item=Self::DirectedEdge>{
self.view.face_edges(face_id)
}
}

View File

@@ -57,9 +57,6 @@ impl InputState{
fn replace_mouse(&mut self,mouse:MouseState,next_mouse:MouseState){
(self.next_mouse,self.mouse)=(next_mouse,mouse);
}
fn get_control(&self,control:Controls)->bool{
self.controls.contains(control)
}
fn set_control(&mut self,control:Controls,state:bool){
self.controls.set(control,state)
}
@@ -495,27 +492,6 @@ impl StyleHelper for StyleModifiers{
}
}
#[derive(Clone,Debug)]
struct StrafeTickState{
tick_number:u64,
}
impl StrafeTickState{
fn new(time:Time,settings:&gameplay_style::StrafeSettings)->Self{
// let time=n*seconds/ticks;
let time=time.nanos() as i128;
let ticks=settings.tick_rate.num() as i128;
let seconds=settings.tick_rate.den() as i128;
let tick_number=(time*ticks/seconds) as u64;
StrafeTickState{tick_number}
}
fn next_tick(&self,settings:&gameplay_style::StrafeSettings)->Time{
let n=self.tick_number as i128;
let ticks=settings.tick_rate.num() as i128;
let seconds=settings.tick_rate.den() as i128;
let time=n*seconds/ticks;
Time::from_nanos(time as i64)
}
}
#[derive(Clone,Debug)]
enum MoveState{
Air,
Walk(ContactMoveState),
@@ -593,7 +569,7 @@ impl MoveState{
=>None,
}
}
fn next_move_instruction(&self,strafe:Option<&gameplay_style::StrafeSettings>,strafe_tick_state:&StrafeTickState)->Option<TimedInstruction<InternalInstruction,Time>>{
fn next_move_instruction(&self,strafe:&Option<gameplay_style::StrafeSettings>,time:Time)->Option<TimedInstruction<InternalInstruction,Time>>{
//check if you have a valid walk state and create an instruction
match self{
MoveState::Walk(walk_state)|MoveState::Ladder(walk_state)=>match &walk_state.target{
@@ -607,7 +583,7 @@ impl MoveState{
}
MoveState::Air=>strafe.as_ref().map(|strafe|{
TimedInstruction{
time:strafe_tick_state.next_tick(strafe),
time:strafe.next_tick(time),
//only poll the physics if there is a before and after mouse event
instruction:InternalInstruction::StrafeTick
}
@@ -892,7 +868,7 @@ pub struct PhysicsState{
//gameplay_state
mode_state:ModeState,
move_state:MoveState,
strafe_tick_state:StrafeTickState,
no_clip:bool,
//run is non optional: when you spawn in a run is created
//the run cannot be finished unless you start it by visiting
//a start zone. If you change mode, a new run is created.
@@ -907,11 +883,11 @@ impl Default for PhysicsState{
style:StyleModifiers::default(),
touching:TouchingState::default(),
move_state:MoveState::Air,
no_clip:false,
camera:PhysicsCamera::default(),
input_state:InputState::default(),
_world:WorldState{},
mode_state:ModeState::default(),
strafe_tick_state:StrafeTickState::new(Time::ZERO,&StyleModifiers::default().strafe.unwrap()),
run:run::Run::new(),
}
}
@@ -948,9 +924,6 @@ impl PhysicsState{
pub fn get_finish_time(&self)->Option<run::Time>{
self.run.get_finish_time()
}
fn is_no_clip_enabled(&self)->bool{
self.input_state.get_control(Controls::Sprint)
}
pub fn clear(&mut self){
self.touching.clear();
}
@@ -958,7 +931,7 @@ impl PhysicsState{
*self=Self::default();
}
fn next_move_instruction(&self)->Option<TimedInstruction<InternalInstruction,Time>>{
self.move_state.next_move_instruction(self.style.strafe.as_ref(),&self.strafe_tick_state)
self.move_state.next_move_instruction(&self.style.strafe,self.time)
}
fn cull_velocity(&mut self,data:&PhysicsData,velocity:Planar64Vec3){
self.move_state.cull_velocity(velocity,&mut self.body,&mut self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state);
@@ -1225,7 +1198,7 @@ fn next_instruction_internal(state:&PhysicsState,data:&PhysicsData,time_limit:Ti
//check for collision ends
state.touching.predict_collision_end(&mut collector,&data.models,&data.hitbox_mesh,&trajectory,state.time);
if state.is_no_clip_enabled(){
if state.no_clip{
return collector.take();
}
@@ -1816,7 +1789,6 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
),
},
InternalInstruction::StrafeTick=>{
state.strafe_tick_state.tick_number+=1;
//TODO make this less huge
if let Some(strafe_settings)=&state.style.strafe{
let controls=state.input_state.controls;
@@ -1897,8 +1869,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
state.input_state.set_next_mouse(m);
},
Instruction::Mouse(MouseInstruction::ReplaceMouse{m0,m1})=>{
state.camera.move_mouse(state.input_state.mouse_delta());
state.camera.move_mouse(m0.pos-state.input_state.next_mouse.pos);
state.camera.move_mouse(m0.pos-state.input_state.mouse.pos);
state.input_state.replace_mouse(m0,m1);
},
Instruction::Misc(MiscInstruction::SetSensitivity(sensitivity))=>state.camera.sensitivity=sensitivity,
@@ -1926,6 +1897,7 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI
},
Instruction::SetControl(SetControlInstruction::SetSprint(s))=>{
state.input_state.set_control(Controls::Sprint,s);
state.no_clip=s;
},
Instruction::Mode(ModeInstruction::Reset)=>{
//totally reset physics state

View File

@@ -2,6 +2,7 @@ const VALVE_SCALE:Planar64=Planar64::raw(1<<28);// 1/16
use crate::integer::{int,vec3::int as int3,AbsoluteTime,Ratio64,Planar64,Planar64Vec3};
use crate::controls_bitflag::Controls;
use crate::physics::Time as PhysicsTime;
#[derive(Clone,Debug)]
pub struct StyleModifiers{
@@ -272,6 +273,9 @@ impl StrafeSettings{
false=>None,
}
}
pub fn next_tick(&self,time:PhysicsTime)->PhysicsTime{
PhysicsTime::from_nanos(self.tick_rate.rhs_div_int(self.tick_rate.mul_int(time.nanos())+1))
}
pub const fn activates(&self,controls:Controls)->bool{
self.enable.activates(controls)
}

View File

@@ -7,7 +7,7 @@ const BNUM_DIGIT_WIDTH:usize=64;
/// N is the number of u64s to use
/// F is the number of fractional bits (always N*32 lol)
pub struct Fixed<const N:usize,const F:usize>{
bits:BInt<{N}>,
pub(crate)bits:BInt<{N}>,
}
impl<const N:usize,const F:usize> Fixed<N,F>{
@@ -545,7 +545,7 @@ impl_shift_operator!( Fixed, Shr, shr, Self );
// wide operators. The result width is the sum of the input widths, i.e. none of the multiplication
#[allow(unused_macros)]
#[expect(unused_macros)]
macro_rules! impl_wide_operators{
($lhs:expr,$rhs:expr)=>{
impl core::ops::Mul<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{

View File

@@ -45,6 +45,8 @@ struct SetupContextPartial2<'a>{
}
impl<'a> SetupContextPartial2<'a>{
fn pick_adapter(self)->SetupContextPartial3<'a>{
let adapter;
//TODO: prefer adapter that implements optional features
//let optional_features=optional_features();
let required_features=required_features();
@@ -52,22 +54,33 @@ impl<'a> SetupContextPartial2<'a>{
//no helper function smh gotta write it myself
let adapters=pollster::block_on(self.instance.enumerate_adapters(self.backends));
let chosen_adapter=adapters.into_iter()
// reverse because we want to select adapters that appear first in ties,
// and max_by_key selects the last equal element in the iterator.
.rev()
.filter(|adapter|
adapter.is_surface_supported(&self.surface)
&&adapter.features().contains(required_features)
)
.max_by_key(|adapter|match adapter.get_info().device_type{
let mut chosen_adapter=None;
let mut chosen_adapter_score=0;
for adapter in adapters {
if !adapter.is_surface_supported(&self.surface) {
continue;
}
let score=match adapter.get_info().device_type{
wgpu::DeviceType::IntegratedGpu=>3,
wgpu::DeviceType::DiscreteGpu=>4,
wgpu::DeviceType::VirtualGpu=>2,
wgpu::DeviceType::Other|wgpu::DeviceType::Cpu=>1,
});
};
let adapter_features=adapter.features();
if chosen_adapter_score<score&&adapter_features.contains(required_features) {
chosen_adapter_score=score;
chosen_adapter=Some(adapter);
}
}
if let Some(maybe_chosen_adapter)=chosen_adapter{
adapter=maybe_chosen_adapter;
}else{
panic!("No suitable GPU adapters found on the system!");
}
let adapter=chosen_adapter.expect("No suitable GPU adapters found on the system!");
let adapter_info=adapter.get_info();
println!("Using {} ({:?})", adapter_info.name, adapter_info.backend);