This commit is contained in:
Quaternions 2024-02-04 22:37:09 -08:00
parent 8687c65e80
commit 56bf453337
5 changed files with 104 additions and 116 deletions

View File

@ -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<u32>=model.unique_pos.iter().map(|untransformed_pos|{
let map_pos_id:Vec<PositionId>=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::<f32,u32>(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<u32>=model.unique_tex.iter().map(|tex|{
let h=tex.map(|v|bytemuck::cast::<f32,u32>(v));
(if let Some(&tex_id)=tex_id_from.get(&h){
let map_tex_id:Vec<TextureCoordinateId>=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<u32>=model.unique_normal.iter().map(|untransformed_normal|{
let map_normal_id:Vec<NormalId>=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::<f32,u32>(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<u32>=model.unique_color.iter().map(|color|{
let h=color.map(|v|bytemuck::cast::<f32,u32>(v));
(if let Some(&color_id)=color_id_from.get(&h){
let map_color_id:Vec<ColorId>=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<u32>=model.unique_vertices.iter().map(|unmapped_vertex|{
let map_vertex_id:Vec<VertexId>=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);

View File

@ -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<IndexedPolygon>,
pub polys:Vec<IndexedVertexList>,
}
pub struct IndexedGraphicsModelSingleTexture{
pub unique_pos:Vec<[f32;3]>,

View File

@ -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);
}

View File

@ -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::<ContactCollision>,
intersects:std::collections::HashSet::<IntersectCollision>,
contacts:HashSet::<ContactCollision>,
intersects:HashSet::<IntersectCollision>,
}
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<gameplay_attributes::Wormhole>,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_id<stage_element.stage_id{
//TODO: check if all checkpoints are complete up to destination stage id, otherwise set to checkpoint completion stage it
game.stage_id=stage_element.stage_id;
}
match &stage_element.behaviour{
gameplay_modes::StageElementBehaviour::SpawnAt=>None,
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<game.next_ordered_checkpoint_id)
// &&mode.unordered_checkpoint_count<=game.unordered_checkpoints.len() as u32{
// //pass
None
// }else{
// //fail
// teleport_to_spawn(body,touching,style,modes.get_mode(stage_element.mode_id)?,models,game.stage_id)
// }
//checkpoint check
//TODO: need to check all stages
if stage.ordered_checkpoint_id.map_or(true,|id|id<game.next_ordered_checkpoint_id)
&&stage.unordered_checkpoint_count<=game.unordered_checkpoints.len() as u32{
//pass
}else{
//fail
return teleport_to_spawn(body,touching,style,mode,models,game.stage_id);
}
},
&gameplay_modes::StageElementBehaviour::Ordered{checkpoint_id}=>{
if checkpoint_id<game.next_ordered_checkpoint_id{
//if you hit a checkpoint you already hit, nothing happens
None
}else if game.next_ordered_checkpoint_id==checkpoint_id{
}
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+=1;
None
}else{
//If you hit an ordered checkpoint after missing a previous one
teleport_to_spawn(body,touching,style,mode,models,game.stage_id)
game.next_ordered_checkpoint_id=gameplay_modes::CheckpointId::id(game.next_ordered_checkpoint_id.get()+1);
}
},
gameplay_modes::StageElementBehaviour::Unordered=>{
}
if stage.unordered_checkpoints.contains(&model_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})=>{
&Some(gameplay_attributes::Wormhole{destination_model})=>{
let origin_model=models.model(model_id);
let destination_model=models.get_wormhole_model(destination_model)?;
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<PhysicsInstruction> for PhysicsState {
@ -1208,14 +1192,14 @@ impl instruction::InstructionConsumer<PhysicsInstruction> 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<PhysicsInstruction> 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<PhysicsInstruction> 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;

View File

@ -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=>{