Compare commits

..

1 Commits

Author SHA1 Message Date
0f39cdb89f fix bug 3, break everything else 2025-08-26 16:40:00 -07:00
5 changed files with 76 additions and 49 deletions

View File

@@ -1,8 +1,8 @@
use std::collections::{HashSet,HashMap};
use core::ops::{Bound,RangeBounds};
use strafesnet_common::integer::vec3::Vector3;
use strafesnet_common::model::{self,MeshId};
use strafesnet_common::integer::{self,vec3,Fixed,Planar32Vec3,Planar64,Planar64Vec3,Ratio};
use strafesnet_common::model::{self,MeshId,PolygonIter};
use strafesnet_common::integer::{self,vec3,Fixed,Planar64,Planar64Vec3,Ratio};
use strafesnet_common::physics::Time;
type Body=crate::body::Body<strafesnet_common::physics::TimeInner>;
@@ -74,7 +74,7 @@ struct Face{
dot:Planar64,
}
#[derive(Debug)]
struct Vert(Planar32Vec3);
struct Vert(Planar64Vec3);
pub trait MeshQuery{
type Face:Copy;
type Edge:Copy+DirectedEdge;

View File

@@ -28,6 +28,7 @@ pub enum InternalInstruction{
CollisionStart(Collision,model_physics::GigaTime),
CollisionEnd(Collision,model_physics::GigaTime),
StrafeTick,
// TODO: add GigaTime to ReachWalkTargetVelocity
ReachWalkTargetVelocity,
// Water,
}
@@ -1681,17 +1682,14 @@ fn collision_end_intersect(
}
fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction<InternalInstruction,Time>){
state.time=ins.time;
let (should_advance_body,goober_time)=match ins.instruction{
match ins.instruction{
// collisions advance the body precisely
InternalInstruction::CollisionStart(_,dt)
|InternalInstruction::CollisionEnd(_,dt)=>(true,Some(dt)),
InternalInstruction::StrafeTick
|InternalInstruction::ReachWalkTargetVelocity=>(true,None),
};
if should_advance_body{
match goober_time{
Some(dt)=>state.body.advance_time_ratio_dt(dt),
None=>state.body.advance_time(state.time),
}
|InternalInstruction::CollisionEnd(_,dt)=>state.body.advance_time_ratio_dt(dt),
// this advances imprecisely
InternalInstruction::ReachWalkTargetVelocity=>state.body.advance_time(state.time),
// strafe tick decides for itself whether to advance the body.
InternalInstruction::StrafeTick=>(),
}
match ins.instruction{
InternalInstruction::CollisionStart(collision,_)=>{
@@ -1738,6 +1736,8 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
let masked_controls=strafe_settings.mask(controls);
let control_dir=state.style.get_control_dir(masked_controls);
if control_dir!=vec3::ZERO{
// manually advance time
state.body.advance_time(state.time);
let camera_mat=state.camera.simulate_move_rotation_y(state.input_state.lerp_delta(state.time).x);
if let Some(ticked_velocity)=strafe_settings.tick_velocity(state.body.velocity,(camera_mat*control_dir).with_length(Planar64::ONE).divide().wrap_1()){
//this is wrong but will work ig

View File

@@ -552,12 +552,6 @@ impl TryFrom<[f32;3]> for Unit32Vec3{
}
*/
// placeholder until bnum supports u8
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,Ord,PartialOrd)]
pub struct Planar32(i32);
pub type Planar32Vec3=linear_ops::types::Vector3<Planar32>;
pub type Planar32Mat3=linear_ops::types::Matrix3<Planar32>;
pub type Planar64TryFromFloatError=fixed_wide::fixed::FixedFromFloatError;
pub type Planar64=fixed_wide::types::I32F32;
pub type Planar64Vec3=linear_ops::types::Vector3<Planar64>;

View File

@@ -1,6 +1,6 @@
use std::collections::HashMap;
use crate::integer::{Planar32Vec3,Planar32Mat3,Planar64Vec3};
use crate::integer::{Planar64,Planar64Vec3,Planar64Affine3};
use crate::gameplay_attributes;
pub type TextureCoordinate=glam::Vec2;
@@ -22,32 +22,61 @@ pub struct IndexedVertex{
}
#[derive(Clone,Copy,Hash,id::Id,PartialEq,Eq)]
pub struct VertexId(u32);
#[derive(Clone)]
pub struct Triangle([VertexId;3]);
impl Triangle{
pub fn new(verts:[VertexId;3])->Self{
Self(verts)
}
pub type IndexedVertexList=Vec<VertexId>;
pub trait PolygonIter{
fn polys(&self)->impl Iterator<Item=&[VertexId]>;
}
pub trait MapVertexId{
fn map_vertex_id<F:Fn(VertexId)->VertexId>(self,f:F)->Self;
}
#[derive(Clone)]
pub struct TriangleList(Vec<Triangle>);
impl TriangleList{
pub const fn new(list:Vec<Triangle>)->Self{
pub struct PolygonList(Vec<IndexedVertexList>);
impl PolygonList{
pub const fn new(list:Vec<IndexedVertexList>)->Self{
Self(list)
}
pub fn extend<T:IntoIterator<Item=Triangle>>(&mut self,iter:T){
pub fn extend<T:IntoIterator<Item=IndexedVertexList>>(&mut self,iter:T){
self.0.extend(iter);
}
}
impl PolygonIter for PolygonList{
fn polys(&self)->impl Iterator<Item=&[VertexId]>{
self.0.iter().map(|poly|poly.as_slice())
}
}
impl MapVertexId for PolygonList{
fn map_vertex_id<F:Fn(VertexId)->VertexId>(self,f:F)->Self{
Self(self.0.into_iter().map(|ivl|ivl.into_iter().map(&f).collect()).collect())
}
}
// pub struct TriangleStrip(IndexedVertexList);
// impl PolygonIter for TriangleStrip{
// fn polys(&self)->impl Iterator<Item=&[VertexId]>{
// self.0.vertices.windows(3).enumerate().map(|(i,s)|if i&0!=0{return s.iter().rev()}else{return s.iter()})
// }
// }
#[derive(Clone,Copy,Hash,id::Id,PartialEq,Eq)]
pub struct PolygonGroupId(u32);
#[derive(Clone)]
pub enum PolygonGroup{
TriangleList(TriangleList),
PolygonList(PolygonList),
//TriangleStrip(TriangleStrip),
}
impl PolygonIter for PolygonGroup{
fn polys(&self)->impl Iterator<Item=&[VertexId]>{
match self{
PolygonGroup::PolygonList(list)=>list.polys(),
//PolygonGroup::TriangleStrip(strip)=>strip.polys(),
}
}
}
impl MapVertexId for PolygonGroup{
fn map_vertex_id<F:Fn(VertexId)->VertexId>(self,f:F)->Self{
match self{
PolygonGroup::PolygonList(polys)=>Self::PolygonList(polys.map_vertex_id(f)),
}
}
}
/// Ah yes, a group of things to render at the same time
#[derive(Clone,Copy,Debug,Hash,id::Id,Eq,PartialEq)]
pub struct TextureId(u32);
@@ -80,8 +109,8 @@ pub struct IndexedPhysicsGroup{
pub struct MeshId(u32);
#[derive(Clone)]
pub struct Mesh{
pub unique_pos:Vec<Planar32Vec3>,
pub unique_normal:Vec<Planar32Vec3>,
pub unique_pos:Vec<Planar64Vec3>,//Unit32Vec3
pub unique_normal:Vec<Planar64Vec3>,//Unit32Vec3
pub unique_tex:Vec<TextureCoordinate>,
pub unique_color:Vec<Color4>,
pub unique_vertices:Vec<IndexedVertex>,
@@ -98,13 +127,13 @@ pub struct Mesh{
#[derive(Default)]
pub struct MeshBuilder{
unique_pos:Vec<Planar32Vec3>,
unique_normal:Vec<Planar32Vec3>,
unique_pos:Vec<Planar64Vec3>,//Unit32Vec3
unique_normal:Vec<Planar64Vec3>,//Unit32Vec3
unique_tex:Vec<TextureCoordinate>,
unique_color:Vec<Color4>,
unique_vertices:Vec<IndexedVertex>,
pos_id_from:HashMap<Planar32Vec3,PositionId>,
normal_id_from:HashMap<Planar32Vec3,NormalId>,
pos_id_from:HashMap<Planar64Vec3,PositionId>,//Unit32Vec3
normal_id_from:HashMap<Planar64Vec3,NormalId>,//Unit32Vec3
tex_id_from:HashMap<[u32;2],TextureCoordinateId>,
color_id_from:HashMap<[u32;4],ColorId>,
vertex_id_from:HashMap<IndexedVertex,VertexId>,
@@ -138,14 +167,19 @@ impl MeshBuilder{
physics_groups,
}
}
pub fn acquire_pos_id(&mut self,pos:Planar32Vec3)->PositionId{
pub fn acquire_pos_id(&mut self,pos:Planar64Vec3)->PositionId{
// Truncate the 16 most precise bits of the vertex positions.
// This allows the normal vectors to exactly represent the face.
// Remove this in Mesh V2
const MASK:Planar64=Planar64::raw(!((1<<16)-1));
let pos=pos.map(|c|c&MASK);
*self.pos_id_from.entry(pos).or_insert_with(||{
let pos_id=PositionId::new(self.unique_pos.len() as u32);
self.unique_pos.push(pos);
pos_id
})
}
pub fn acquire_normal_id(&mut self,normal:Planar32Vec3)->NormalId{
pub fn acquire_normal_id(&mut self,normal:Planar64Vec3)->NormalId{
*self.normal_id_from.entry(normal).or_insert_with(||{
let normal_id=NormalId::new(self.unique_normal.len() as u32);
self.unique_normal.push(normal);
@@ -183,6 +217,5 @@ pub struct Model{
pub mesh:MeshId,
pub attributes:gameplay_attributes::CollisionAttributesId,
pub color:Color4,//transparency is in here
pub matrix3:Planar32Mat3,
pub translation:Planar64Vec3,
pub transform:Planar64Affine3,
}

View File

@@ -3,7 +3,7 @@ use std::collections::HashMap;
use rbx_mesh::mesh::{Vertex2,Vertex2Truncated};
use strafesnet_common::aabb::Aabb;
use strafesnet_common::integer::vec3;
use strafesnet_common::model::{self,ColorId,IndexedVertex,NormalId,PolygonGroup,Triangle,TriangleList,PositionId,RenderConfigId,TextureCoordinateId,VertexId};
use strafesnet_common::model::{self,ColorId,IndexedVertex,PolygonGroup,PolygonList,RenderConfigId,VertexId};
use crate::loader::MeshWithSize;
@@ -67,8 +67,8 @@ fn ingest_faces2_lods3(
){
//faces have to be split into polygon groups based on lod
polygon_groups.extend(lods.windows(2).map(|lod_pair|
PolygonGroup::TriangleList(TriangleList::new(faces[lod_pair[0].0 as usize..lod_pair[1].0 as usize].iter().map(|rbx_mesh::mesh::Face2(v0,v1,v2)|
Triangle::new([vertex_id_map[&v0],vertex_id_map[&v1],vertex_id_map[&v2]])
PolygonGroup::PolygonList(PolygonList::new(faces[lod_pair[0].0 as usize..lod_pair[1].0 as usize].iter().map(|rbx_mesh::mesh::Face2(v0,v1,v2)|
vec![vertex_id_map[&v0],vertex_id_map[&v1],vertex_id_map[&v2]]
).collect()))
))
}
@@ -90,7 +90,7 @@ pub fn convert(roblox_mesh_bytes:crate::data::RobloxMeshBytes)->Result<MeshWithS
};
Ok(mb.acquire_vertex_id(vertex))
};
Ok(Triangle::new([ingest_vertex1(&trip[0])?,ingest_vertex1(&trip[1])?,ingest_vertex1(&trip[2])?))
Ok(vec![ingest_vertex1(&trip[0])?,ingest_vertex1(&trip[1])?,ingest_vertex1(&trip[2])?])
}).collect::<Result<_,_>>().map_err(Error::Planar64Vec3)?)));
},
rbx_mesh::mesh::Mesh::V2(mesh)=>{
@@ -103,8 +103,8 @@ pub fn convert(roblox_mesh_bytes:crate::data::RobloxMeshBytes)->Result<MeshWithS
rbx_mesh::mesh::SizeOfVertex2::Full=>ingest_vertices2(mesh.vertices,&mut mb),
}?;
//one big happy group for all the faces
polygon_groups.push(PolygonGroup::TriangleList(TriangleList::new(mesh.faces.into_iter().map(|face|
Triangle::new([vertex_id_map[&face.0],vertex_id_map[&face.1],vertex_id_map[&face.2]])
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().map(|face|
vec![vertex_id_map[&face.0],vertex_id_map[&face.1],vertex_id_map[&face.2]]
).collect())));
},
rbx_mesh::mesh::Mesh::V3(mesh)=>{