diff --git a/engine/graphics/src/graphics.rs b/engine/graphics/src/graphics.rs index 3d164eb2..b7e6f2c2 100644 --- a/engine/graphics/src/graphics.rs +++ b/engine/graphics/src/graphics.rs @@ -37,6 +37,7 @@ struct GraphicsModel{ } struct DebugGraphicsSubmesh{ + verts:Vec, edges:Vec, faces:Vec, } @@ -214,6 +215,7 @@ impl GraphicsState{ let submeshes=if let Ok(physics_mesh)=strafesnet_physics::model::PhysicsMesh::try_from(mesh){ physics_mesh.submesh_views().into_iter().map(|submesh_view|DebugGraphicsSubmesh{ + verts:submesh_view.verts().to_owned(), edges:submesh_view.edge_vert_ids_iter().map(|edge_verts|indices!(edge_verts)).collect(), faces:submesh_view.face_vert_ids_iter().map(|face_verts|{ // triangulate @@ -1165,15 +1167,36 @@ impl GraphicsState{ rpass.draw(0..3,0..1); // render a single debug_model in red - if let Some(model_id)=frame_state.debug_model{ - if let Some(model)=self.debug_models.get(model_id.get() as usize){ - let mesh=&self.debug_meshes[model.debug_mesh_id as usize]; - rpass.set_pipeline(&self.pipelines.debug_face); - rpass.set_bind_group(1,&model.bind_group,&[]); - rpass.set_vertex_buffer(0,mesh.vertex_buf.slice(..)); - rpass.set_index_buffer(mesh.indices.buf.slice(..),mesh.indices.format); - //TODO: loop over triangle strips - rpass.draw_indexed(0..mesh.indices.count,0,0..1); + if let Some(hit)=frame_state.hit{ + if let Some(closest_fev)=&hit.closest_fev{ + let model_id:model::ModelId=hit.convex_mesh_id.model_id.into(); + if let Some(model)=self.debug_models.get(model_id.get() as usize){ + let mesh=&self.debug_meshes[model.debug_mesh_id as usize]; + rpass.set_bind_group(1,&model.bind_group,&[]); + rpass.set_vertex_buffer(0,mesh.vertex_buf.slice(..)); + match closest_fev{ + strafesnet_physics::model::FEV::Face(face)=>{ + rpass.set_pipeline(&self.pipelines.debug_face); + let indices=&mesh.submeshes[hit.convex_mesh_id.submesh_id.get() as usize].faces[face.get() as usize]; + rpass.set_index_buffer(indices.buf.slice(..),indices.format); + //TODO: loop over triangle strips + rpass.draw_indexed(0..indices.count,0,0..1); + }, + strafesnet_physics::model::FEV::Edge(edge)=>{ + rpass.set_pipeline(&self.pipelines.debug_edge); + let indices=&mesh.submeshes[hit.convex_mesh_id.submesh_id.get() as usize].edges[edge.get() as usize]; + rpass.set_index_buffer(indices.buf.slice(..),indices.format); + rpass.draw_indexed(0..indices.count,0,0..1); + }, + strafesnet_physics::model::FEV::Vert(vert)=>{ + rpass.set_pipeline(&self.pipelines.debug_vert); + let indices=&mesh.verts; + rpass.set_index_buffer(indices.buf.slice(..),indices.format); + let vert_id=mesh.submeshes[hit.convex_mesh_id.submesh_id.get() as usize].verts[vert.get() as usize].get(); + rpass.draw_indexed(0..1,vert_id as i32,0..1); + }, + } + } } } } diff --git a/engine/physics/src/model.rs b/engine/physics/src/model.rs index f75c2297..5c2ee2b1 100644 --- a/engine/physics/src/model.rs +++ b/engine/physics/src/model.rs @@ -446,6 +446,9 @@ pub struct PhysicsMeshView<'a>{ topology:&'a PhysicsMeshTopology, } impl PhysicsMeshView<'_>{ + pub fn verts(&self)->&[MeshVertId]{ + &self.topology.verts + } pub fn edge_vert_ids_iter(&self)->impl Iterator+'_{ self.topology.edge_topology.iter().map(|edge|{ edge.verts.map(|vert_id|self.topology.verts[vert_id.get() as usize].get()) diff --git a/engine/physics/src/physics.rs b/engine/physics/src/physics.rs index ab44504a..5fb23907 100644 --- a/engine/physics/src/physics.rs +++ b/engine/physics/src/physics.rs @@ -709,8 +709,8 @@ impl From for ModelId{ //unique physics meshes indexed by this #[derive(Debug,Clone,Copy,Eq,Hash,PartialEq)] pub struct ConvexMeshId{ - model_id:Id, - submesh_id:PhysicsSubmeshId, + pub model_id:Id, + pub submesh_id:PhysicsSubmeshId, } impl ConvexMeshId{ fn map(self,model_id:NewId)->ConvexMeshId{ @@ -1038,7 +1038,7 @@ impl PhysicsData{ })?; Some(*convex_mesh_id) } - pub fn closest_fev_not_inside(&self,convex_mesh_id:ConvexMeshId,point:Planar64Vec3)->Option>>{ + pub fn closest_fev_not_inside(&self,convex_mesh_id:ConvexMeshId,point:Planar64Vec3)->Option>>{ let model_mesh=self.models.mesh(convex_mesh_id); let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,self.hitbox_mesh.transformed_mesh()); let fev=crate::minimum_difference::closest_fev_not_inside(&minkowski,point)?; diff --git a/engine/session/src/session.rs b/engine/session/src/session.rs index 5e70e4ea..a2ecc46a 100644 --- a/engine/session/src/session.rs +++ b/engine/session/src/session.rs @@ -2,7 +2,6 @@ use std::collections::HashMap; use strafesnet_common::gameplay_modes::{ModeId,StageId}; use strafesnet_common::instruction::{InstructionConsumer,InstructionEmitter,InstructionFeedback,TimedInstruction}; -use strafesnet_common::model::ModelId; // session represents the non-hardware state of the client. // Ideally it is a deterministic state which is atomically updated by instructions, same as the simulation state. use strafesnet_common::physics::{ @@ -58,11 +57,11 @@ pub enum SessionPlaybackInstruction{ IncreaseTimescale, } -pub struct FrameState{ +pub struct FrameState<'a>{ pub body:physics::Body, pub camera:physics::PhysicsCamera, pub time:PhysicsTime, - pub debug_model:Option>, + pub hit:Option<&'a Hit>, } pub struct Simulation{ @@ -79,12 +78,12 @@ impl Simulation{ physics, } } - pub fn get_frame_state(&self,time:SessionTime,debug_model:Option>)->FrameState{ + pub fn get_frame_state<'a>(&'a self,time:SessionTime,debug_model:Option<&'a Hit>)->FrameState<'a>{ FrameState{ body:self.physics.camera_body(), camera:self.physics.camera(), time:self.timer.time(time), - debug_model, + hit: debug_model, } } } @@ -152,6 +151,11 @@ enum ViewState{ Replay(BotId), } +pub struct Hit{ + pub convex_mesh_id:physics::ConvexMeshId, + pub closest_fev:Option>> +} + pub struct Session{ directories:Directories, user_settings:UserSettings, @@ -164,7 +168,7 @@ pub struct Session{ recording:Recording, //players:HashMap, replays:HashMap, - last_ray_hit:Option>, + last_ray_hit:Option, } impl Session{ pub fn new( @@ -191,9 +195,9 @@ impl Session{ self.simulation.physics.clear(); self.geometry_shared=PhysicsData::new(map); } - pub fn get_frame_state(&self,time:SessionTime)->Option{ + pub fn get_frame_state(&self,time:SessionTime)->Option>{ match &self.view_state{ - ViewState::Play=>Some(self.simulation.get_frame_state(time,self.last_ray_hit)), + ViewState::Play=>Some(self.simulation.get_frame_state(time,self.last_ray_hit.as_ref())), ViewState::Replay(bot_id)=>self.replays.get(bot_id).map(|replay| replay.simulation.get_frame_state(time,None) ), @@ -205,13 +209,15 @@ impl Session{ 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; - } - if let Some(model_id)=model_id{ - // self.geometry_shared./ + match self.geometry_shared.trace_ray(ray){ + Some(convex_mesh_id)=>{ + let closest_fev=self.geometry_shared.closest_fev_not_inside(convex_mesh_id,self.simulation.physics.body().position); + self.last_ray_hit=Some(Hit{ + convex_mesh_id, + closest_fev, + }); + }, + None=>self.last_ray_hit=None, } } }