diff --git a/src/graphics.rs b/src/graphics.rs index 3ad4135..579fe95 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use strafesnet_common::map; -use strafesnet_common::model; use strafesnet_common::integer; +use strafesnet_common::model::{self,ColorId,NormalId,PositionId,TextureCoordinateId,VertexId}; use wgpu::{util::DeviceExt,AstcBlock,AstcChannel}; use crate::model_graphics::{GraphicsVertex,GraphicsModelColor4,GraphicsModelInstance,GraphicsModelSingleTexture,IndexedGraphicsModelSingleTexture,IndexedGroupFixedTexture}; @@ -332,73 +332,73 @@ impl GraphicsState{ let model=&unique_texture_models[model_id]; let instance=&model.instances[instance_id]; //just hash word slices LOL - let map_pos_id:Vec=model.unique_pos.iter().map(|untransformed_pos|{ + let map_pos_id:Vec=model.unique_pos.iter().map(|untransformed_pos|{ let pos=instance.transform.transform_point3(glam::Vec3::from_array(untransformed_pos.clone())).to_array(); - let h=pos.map(|v|bytemuck::cast::(v)); - (if let Some(&pos_id)=pos_id_from.get(&h){ + let h=bytemuck::cast::<[f32;3],[u32;3]>(pos); + PositionId::id((if let Some(&pos_id)=pos_id_from.get(&h){ pos_id }else{ let pos_id=unique_pos.len(); - unique_pos.push(pos.clone()); + unique_pos.push(pos); pos_id_from.insert(h,pos_id); pos_id - }) as u32 + }) as u32) }).collect(); - let map_tex_id:Vec=model.unique_tex.iter().map(|tex|{ - let h=tex.map(|v|bytemuck::cast::(v)); - (if let Some(&tex_id)=tex_id_from.get(&h){ + let map_tex_id:Vec=model.unique_tex.iter().map(|&tex|{ + let h=bytemuck::cast::<[f32;2],[u32;2]>(tex); + TextureCoordinateId::id((if let Some(&tex_id)=tex_id_from.get(&h){ tex_id }else{ let tex_id=unique_tex.len(); - unique_tex.push(tex.clone()); + unique_tex.push(tex); tex_id_from.insert(h,tex_id); tex_id - }) as u32 + }) as u32) }).collect(); - let map_normal_id:Vec=model.unique_normal.iter().map(|untransformed_normal|{ + let map_normal_id:Vec=model.unique_normal.iter().map(|untransformed_normal|{ let normal=(instance.normal_transform*glam::Vec3::from_array(untransformed_normal.clone())).to_array(); - let h=normal.map(|v|bytemuck::cast::(v)); - (if let Some(&normal_id)=normal_id_from.get(&h){ + let h=bytemuck::cast::<[f32;3],[u32;3]>(normal); + NormalId::id((if let Some(&normal_id)=normal_id_from.get(&h){ normal_id }else{ let normal_id=unique_normal.len(); - unique_normal.push(normal.clone()); + unique_normal.push(normal); normal_id_from.insert(h,normal_id); normal_id - }) as u32 + }) as u32) }).collect(); - let map_color_id:Vec=model.unique_color.iter().map(|color|{ - let h=color.map(|v|bytemuck::cast::(v)); - (if let Some(&color_id)=color_id_from.get(&h){ + let map_color_id:Vec=model.unique_color.iter().map(|&color|{ + let h=bytemuck::cast::<[f32;4],[u32;4]>(color); + ColorId::id((if let Some(&color_id)=color_id_from.get(&h){ color_id }else{ let color_id=unique_color.len(); - unique_color.push(color.clone()); + unique_color.push(color); color_id_from.insert(h,color_id); color_id - }) as u32 + }) as u32) }).collect(); //map the indexed vertices onto new indices //creating the vertex map is slightly different because the vertices are directly hashable - let map_vertex_id:Vec=model.unique_vertices.iter().map(|unmapped_vertex|{ + let map_vertex_id:Vec=model.unique_vertices.iter().map(|unmapped_vertex|{ let vertex=model::IndexedVertex{ - pos:map_pos_id[unmapped_vertex.pos as usize], - tex:map_tex_id[unmapped_vertex.tex as usize], - normal:map_normal_id[unmapped_vertex.normal as usize], - color:map_color_id[unmapped_vertex.color as usize], + pos:map_pos_id[unmapped_vertex.pos.get() as usize], + tex:map_tex_id[unmapped_vertex.tex.get() as usize], + normal:map_normal_id[unmapped_vertex.normal.get() as usize], + color:map_color_id[unmapped_vertex.color.get() as usize], }; - (if let Some(&vertex_id)=vertex_id_from.get(&vertex){ + VertexId::id((if let Some(&vertex_id)=vertex_id_from.get(&vertex){ vertex_id }else{ let vertex_id=unique_vertices.len(); unique_vertices.push(vertex.clone()); vertex_id_from.insert(vertex,vertex_id); vertex_id - }) as u32 + }) as u32) }).collect(); for group in &model.groups{ for poly in &group.polys{ - polys.push(model::IndexedPolygon{vertices:poly.vertices.iter().map(|&vertex_id|map_vertex_id[vertex_id as usize]).collect()}); + polys.push(model::PolygonGroup::PolygonList(poly.vertices.iter().map(|&vertex_id|map_vertex_id[vertex_id.get() as usize]).collect())); } } } @@ -445,12 +445,12 @@ impl GraphicsState{ indices.push(i); }else{ let i=vertices.len(); - let vertex=&model.unique_vertices[vertex_index as usize]; + let vertex=&model.unique_vertices[vertex_index.get() as usize]; vertices.push(GraphicsVertex{ - pos: model.unique_pos[vertex.pos as usize], - tex: model.unique_tex[vertex.tex as usize], - normal: model.unique_normal[vertex.normal as usize], - color:model.unique_color[vertex.color as usize], + pos: model.unique_pos[vertex.pos.get() as usize], + tex: model.unique_tex[vertex.tex.get() as usize], + normal: model.unique_normal[vertex.normal.get() as usize], + color:model.unique_color[vertex.color.get() as usize], }); index_from_vertex.insert(vertex_index,i); indices.push(i); diff --git a/src/model_graphics.rs b/src/model_graphics.rs index cdc4935..9787e09 100644 --- a/src/model_graphics.rs +++ b/src/model_graphics.rs @@ -1,5 +1,5 @@ use bytemuck::{Pod, Zeroable}; -use strafesnet_common::model::{IndexedVertex,IndexedPolygon}; +use strafesnet_common::model::{IndexedVertex,IndexedVertexList}; #[derive(Clone,Copy,Pod,Zeroable)] #[repr(C)] pub struct GraphicsVertex{ @@ -9,7 +9,7 @@ pub struct GraphicsVertex{ pub color:[f32;4], } pub struct IndexedGroupFixedTexture{ - pub polys:Vec, + pub polys:Vec, } pub struct IndexedGraphicsModelSingleTexture{ pub unique_pos:Vec<[f32;3]>, diff --git a/src/model_physics.rs b/src/model_physics.rs index 081ab70..ddab83c 100644 --- a/src/model_physics.rs +++ b/src/model_physics.rs @@ -144,14 +144,14 @@ impl From<&model::IndexedModel> for PhysicsMesh{ let mut face_i=0; let mut faces=Vec::new(); let mut face_ref_guys=Vec::new(); - for group in indexed_model.groups.iter(){for poly in group.polys.iter(){ + for group in indexed_model.polygon_groups.iter(){for poly in group.polys(){ let face_id=FaceId(face_i); //one face per poly let mut normal=Planar64Vec3::ZERO; let len=poly.vertices.len(); let face_edges=poly.vertices.iter().enumerate().map(|(i,&vert_id)|{ - let vert0_id=indexed_model.unique_vertices[vert_id as usize].pos as usize; - let vert1_id=indexed_model.unique_vertices[poly.vertices[(i+1)%len] as usize].pos as usize; + let vert0_id=indexed_model.unique_vertices[vert_id as usize].pos.get() as usize; + let vert1_id=indexed_model.unique_vertices[poly.vertices[(i+1)%len] as usize].pos.get() as usize; //https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal (Newell's Method) let v0=indexed_model.unique_pos[vert0_id]; let v1=indexed_model.unique_pos[vert1_id]; @@ -180,7 +180,7 @@ impl From<&model::IndexedModel> for PhysicsMesh{ normal=normal/len as i64; let mut dot=Planar64::ZERO; for &v in poly.vertices.iter(){ - dot+=normal.dot(indexed_model.unique_pos[indexed_model.unique_vertices[v as usize].pos as usize]); + dot+=normal.dot(indexed_model.unique_pos[indexed_model.unique_vertices[v as usize].pos.get() as usize]); } faces.push(Face{normal,dot:dot/len as i64}); face_ref_guys.push(FaceRefEdges(face_edges)); @@ -740,7 +740,6 @@ fn test_is_empty_volume(){ #[test] fn build_me_a_cube(){ - let unit_cube=crate::primitives::unit_cube(); - let mesh=PhysicsMesh::from(&unit_cube); + let mesh=PhysicsMesh::unit_cube(); //println!("mesh={:?}",mesh); } \ No newline at end of file diff --git a/src/physics.rs b/src/physics.rs index f2e50ef..3ccc424 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -171,11 +171,13 @@ impl PhysicsModels{ //TODO: "statically" verify the maps don't refer to any nonexistant data, if they do delete the references. //then I can make these getter functions unchecked. fn mesh(&self,model_id:ModelId)->TransformedMesh{ + let idx=model_id.get() as usize; + let mesh_id=self.models[idx].mesh_id; TransformedMesh::new( - &self.meshes[self.models[model_id].mesh_id], - &self.models[model_id].transform, - &self.models[model_id].normal_transform, - self.models[model_id].transform_det, + &self.meshes[mesh_id.model_id.get() as usize].groups[mesh_id.group_id.get() as usize], + &self.models[idx].transform, + &self.models[idx].normal_transform, + self.models[idx].transform_det, ) } fn model(&self,model_id:ModelId)->&PhysicsModel{ @@ -192,7 +194,7 @@ impl PhysicsModels{ self.models.push(model); model_id } - fn push_attr(&mut self,attr:PhysicsCollisionAttributes)->PhysicsAttributeId{ + fn push_attr(&mut self,attr:PhysicsCollisionAttributes)->PhysicsAttributesId{ let attr_id=self.attributes.len(); self.attributes.push(attr); attr_id @@ -271,8 +273,8 @@ impl std::default::Default for ModeState{ Self{ stage_id:gameplay_modes::StageId::id(0), next_ordered_checkpoint_id:gameplay_modes::CheckpointId::id(0), - unordered_checkpoints:std::collections::HashSet::new(), - jump_counts:std::collections::HashMap::new(), + unordered_checkpoints:HashSet::new(), + jump_counts:HashMap::new(), } } } @@ -528,8 +530,8 @@ impl Collision{ } #[derive(Default)] struct TouchingState{ - contacts:std::collections::HashSet::, - intersects:std::collections::HashSet::, + contacts:HashSet::, + intersects:HashSet::, } impl TouchingState{ fn clear(&mut self){ @@ -778,9 +780,9 @@ pub struct PhysicsState{ controls:u32,//TODO this should be a struct move_state:MoveState, //does not belong here - //bvh:bvh::BvhNode, - //models:PhysicsModels, - //modes:gameplay_modes::Modes, + bvh:bvh::BvhNode, + models:PhysicsModels, + modes:gameplay_modes::Modes, } impl Default for PhysicsState{ fn default()->Self{ @@ -795,19 +797,16 @@ impl Default for PhysicsState{ controls:0, world:WorldState{}, mode_state:ModeState::default(), - //modes:Modes::default(), - //bvh:bvh::BvhNode::default(), - //models:PhysicsModels::default(), + modes:Modes::default(), + bvh:bvh::BvhNode::default(), + models:PhysicsModels::default(), } } } impl PhysicsState { pub fn clear(&mut self){ - self.models.clear(); - self.modes.clear(); self.touching.clear(); - self.bvh=bvh::BvhNode::default(); } pub fn output(&self)->PhysicsOutputState{ @@ -818,20 +817,19 @@ impl PhysicsState { } } - pub fn spawn(&mut self,spawn_point:Planar64Vec3){ - self.mode_state.stage_id=0; - self.spawn_point=spawn_point; + pub fn spawn(&mut self){ + self.mode_state.stage_id=gameplay_modes::StageId::id(0); self.process_instruction(instruction::TimedInstruction{ time:self.time, instruction: PhysicsInstruction::Input(PhysicsInputInstruction::Reset), }); } - pub fn generate_models(&mut self,indexed_models:&map::Map){ + pub fn generate_models(&mut self,map:&map::Map){ let mut starts=Vec::new(); let mut spawns=Vec::new(); - let mut attr_hash=std::collections::HashMap::new(); - for model in &indexed_models.models{ + let mut attr_hash=HashMap::new(); + for model in &map.models{ let mesh_id=self.models.meshes.len(); let mut make_mesh=false; for model_instance in &model.instances{ @@ -1084,67 +1082,53 @@ fn run_teleport_behaviour(wormhole:&Option,game:& //TODO: jump count and checkpoints are always reset on teleport. //Map makers are expected to use tools to prevent //multi-boosting on JumpLimit boosters such as spawning into a SetVelocity - let stage_element=mode.get_element(model_id)?; - { + if let Some(stage_element)=mode.get_element(model_id){ + let stage=mode.get_stage(stage_element.stage_id)?; if stage_element.force||game.stage_idNone, + gameplay_modes::StageElementBehaviour::SpawnAt=>(), gameplay_modes::StageElementBehaviour::Trigger |gameplay_modes::StageElementBehaviour::Teleport=>{ //I guess this is correct behaviour when trying to teleport to a non-existent spawn but it's still weird - teleport_to_spawn(body,touching,style,mode,models,game.stage_id) + return teleport_to_spawn(body,touching,style,mode,models,game.stage_id); }, - gameplay_modes::StageElementBehaviour::Platform=>None, + gameplay_modes::StageElementBehaviour::Platform=>(), &gameplay_modes::StageElementBehaviour::Checkpoint=>{ - // let mode=modes.get_mode(stage_element.mode_id)?; - // if mode.ordered_checkpoint_id.map_or(true,|id|id{ - if checkpoint_id{ - //count model id in accumulated unordered checkpoints - game.unordered_checkpoints.insert(model_id); - None - }, - &gameplay_modes::StageElementBehaviour::JumpLimit(jump_limit)=>{ - //let count=game.jump_counts.get(&model.id); - //TODO - None - }, } - }.or_else(|| - match wormhole{ - Some(gameplay_attributes::Wormhole{destination_model})=>{ - let origin_model=models.model(model_id); - let destination_model=models.get_wormhole_model(destination_model)?; - //ignore the transform for now - Some(teleport(body,touching,models,style,body.position-origin_model.transform.translation+destination_model.transform.translation)) + if let Some(next_checkpoint)=stage.ordered_checkpoints.get(&game.next_ordered_checkpoint_id){ + if model_id==next_checkpoint{ + //if you hit the next number in a sequence of ordered checkpoints + //increment the current checkpoint id + game.next_ordered_checkpoint_id=gameplay_modes::CheckpointId::id(game.next_ordered_checkpoint_id.get()+1); } - None=>None, } - ) + if stage.unordered_checkpoints.contains(&model_id){ + //count model id in accumulated unordered checkpoints + game.unordered_checkpoints.insert(model_id); + } + } + match wormhole{ + &Some(gameplay_attributes::Wormhole{destination_model})=>{ + let origin_model=models.model(model_id); + let destination_model=models.model(destination_model); + //ignore the transform for now + Some(teleport(body,touching,models,style,body.position-origin_model.transform.translation+destination_model.transform.translation)) + } + None=>None, + } } impl instruction::InstructionConsumer for PhysicsState { @@ -1208,14 +1192,14 @@ impl instruction::InstructionConsumer for PhysicsState { //check ground self.touching.insert(c); //I love making functions with 10 arguments to dodge the borrow checker - run_teleport_behaviour(&general.teleport_behaviour,&mut self.mode_state,&self.models,&self.modes,&self.style,&mut self.touching,&mut self.body,model_id); + run_teleport_behaviour(&general.wormhole,&mut self.mode_state,&self.models,&self.modes.get_mode(self.mode).unwrap(),&self.style,&mut self.touching,&mut self.body,model_id); //flatten v self.touching.constrain_velocity(&self.models,&style_mesh,&mut v); match &general.booster{ Some(booster)=>{ //DELETE THIS when boosters get converted to height machines match booster{ - &gameplay_attributes::Booster::Affine(transform)=>v=transform.transform_point3(v), + //&gameplay_attributes::Booster::Affine(transform)=>v=transform.transform_point3(v), &gameplay_attributes::Booster::Velocity(velocity)=>v+=velocity, &gameplay_attributes::Booster::Energy{direction: _,energy: _}=>todo!(), } @@ -1252,7 +1236,7 @@ impl instruction::InstructionConsumer for PhysicsState { (PhysicsCollisionAttributes::Intersect{intersecting: _,general},Collision::Intersect(intersect))=>{ //I think that setting the velocity to 0 was preventing surface contacts from entering an infinite loop self.touching.insert(c); - run_teleport_behaviour(&general.teleport_behaviour,&mut self.mode_state,&self.models,&self.modes,&self.style,&mut self.touching,&mut self.body,model_id); + run_teleport_behaviour(&general.wormhole,&mut self.mode_state,&self.models,&self.modes.get_mode(self.mode).unwrap(),&self.style,&mut self.touching,&mut self.body,model_id); }, _=>panic!("invalid pair"), } @@ -1339,7 +1323,12 @@ impl instruction::InstructionConsumer for PhysicsState { }, PhysicsInputInstruction::Reset => { //it matters which of these runs first, but I have not thought it through yet as it doesn't matter yet - set_position(&mut self.body,&mut self.touching,self.spawn_point); + let spawn_point={ + let mode=self.modes.get_mode(self.mode).unwrap(); + let stage=mode.get_stage(gameplay_modes::StageId::FIRST).unwrap(); + self.models.model(stage.spawn()).transform.translation + }; + set_position(&mut self.body,&mut self.touching,spawn_point); set_velocity(&mut self.body,&self.touching,&self.models,&self.style.mesh(),Planar64Vec3::ZERO); (self.move_state,self.body.acceleration)=self.touching.get_move_state(&self.body,&self.models,&self.style,&self.camera,self.controls,&self.next_mouse,self.time); refresh_walk_target=false; diff --git a/src/physics_worker.rs b/src/physics_worker.rs index b58fd2a..96ed712 100644 --- a/src/physics_worker.rs +++ b/src/physics_worker.rs @@ -120,7 +120,7 @@ pub enum Instruction{ }, Instruction::GenerateModels(indexed_model_instances)=>{ physics.generate_models(&indexed_model_instances); - physics.spawn(indexed_model_instances.spawn_point); + physics.spawn(); graphics_worker.send(crate::graphics_worker::Instruction::GenerateModels(indexed_model_instances)).unwrap(); }, Instruction::ClearModels=>{