Unquatification

This commit is contained in:
rhpidfyre 2025-01-09 02:11:29 -05:00
parent 08f419f931
commit 88dcfe40ed
88 changed files with 18282 additions and 14619 deletions

View File

@ -1,4 +1,4 @@
use strafesnet_common::{map,model,integer,gameplay_attributes}; use strafesnet_common::{gameplay_attributes, integer, map, model};
const VALVE_SCALE: f32 = 1.0 / 16.0; const VALVE_SCALE: f32 = 1.0 / 16.0;
fn valve_transform([x, y, z]: [f32; 3]) -> integer::Planar64Vec3 { fn valve_transform([x, y, z]: [f32; 3]) -> integer::Planar64Vec3 {
@ -7,7 +7,7 @@ fn valve_transform([x,y,z]:[f32;3])->integer::Planar64Vec3{
pub fn convert_bsp<AcquireRenderConfigId, AcquireMeshId>( pub fn convert_bsp<AcquireRenderConfigId, AcquireMeshId>(
bsp: &vbsp::Bsp, bsp: &vbsp::Bsp,
mut acquire_render_config_id: AcquireRenderConfigId, mut acquire_render_config_id: AcquireRenderConfigId,
mut acquire_mesh_id:AcquireMeshId mut acquire_mesh_id: AcquireMeshId,
) -> PartialMap1 ) -> PartialMap1
where where
AcquireRenderConfigId: FnMut(Option<&str>) -> model::RenderConfigId, AcquireRenderConfigId: FnMut(Option<&str>) -> model::RenderConfigId,
@ -16,11 +16,14 @@ where
//figure out real attributes later //figure out real attributes later
let mut unique_attributes = Vec::new(); let mut unique_attributes = Vec::new();
unique_attributes.push(gameplay_attributes::CollisionAttributes::Decoration); unique_attributes.push(gameplay_attributes::CollisionAttributes::Decoration);
const TEMP_TOUCH_ME_ATTRIBUTE:gameplay_attributes::CollisionAttributesId=gameplay_attributes::CollisionAttributesId::new(0); const TEMP_TOUCH_ME_ATTRIBUTE: gameplay_attributes::CollisionAttributesId =
gameplay_attributes::CollisionAttributesId::new(0);
let mut prop_mesh_count = 0; let mut prop_mesh_count = 0;
//declare all prop models to Loader //declare all prop models to Loader
let prop_models=bsp.static_props().map(|prop|{ let prop_models = bsp
.static_props()
.map(|prop| {
//get or create mesh_id //get or create mesh_id
let mesh_id = acquire_mesh_id(prop.model()); let mesh_id = acquire_mesh_id(prop.model());
//not the most failsafe code but this is just for the map tool lmao //not the most failsafe code but this is just for the map tool lmao
@ -32,22 +35,27 @@ where
mesh: mesh_id, mesh: mesh_id,
attributes: TEMP_TOUCH_ME_ATTRIBUTE, attributes: TEMP_TOUCH_ME_ATTRIBUTE,
transform: integer::Planar64Affine3::new( transform: integer::Planar64Affine3::new(
integer::mat3::try_from_f32_array_2d(( integer::mat3::try_from_f32_array_2d(
glam::Mat3A::from_diagonal(glam::Vec3::splat(placement.scale)) (glam::Mat3A::from_diagonal(glam::Vec3::splat(placement.scale))
//TODO: figure this out //TODO: figure this out
*glam::Mat3A::from_quat(glam::Quat::from_array(placement.rotation.into())) *glam::Mat3A::from_quat(glam::Quat::from_array(placement.rotation.into())))
).to_cols_array_2d()).unwrap(), .to_cols_array_2d(),
)
.unwrap(),
valve_transform(placement.origin.into()), valve_transform(placement.origin.into()),
), ),
color: glam::Vec4::ONE, color: glam::Vec4::ONE,
} }
}).collect(); })
.collect();
//TODO: make the main map one single mesh with a bunch of different physics groups and graphics groups //TODO: make the main map one single mesh with a bunch of different physics groups and graphics groups
//the generated MeshIds in here will collide with the Loader Mesh Ids //the generated MeshIds in here will collide with the Loader Mesh Ids
//but I can't think of a good workaround other than just remapping one later. //but I can't think of a good workaround other than just remapping one later.
let world_meshes:Vec<model::Mesh>=bsp.models().map(|world_model|{ let world_meshes: Vec<model::Mesh> = bsp
.models()
.map(|world_model| {
//non-deduplicated //non-deduplicated
let mut spam_pos = Vec::new(); let mut spam_pos = Vec::new();
let mut spam_tex = Vec::new(); let mut spam_tex = Vec::new();
@ -55,13 +63,20 @@ where
let mut spam_vertices = Vec::new(); let mut spam_vertices = Vec::new();
let mut graphics_groups = Vec::new(); let mut graphics_groups = Vec::new();
let mut physics_group = model::IndexedPhysicsGroup::default(); let mut physics_group = model::IndexedPhysicsGroup::default();
let polygon_groups=world_model.faces().enumerate().map(|(polygon_group_id,face)|{ let polygon_groups = world_model
.faces()
.enumerate()
.map(|(polygon_group_id, face)| {
let polygon_group_id = model::PolygonGroupId::new(polygon_group_id as u32); let polygon_group_id = model::PolygonGroupId::new(polygon_group_id as u32);
let face_texture = face.texture(); let face_texture = face.texture();
let face_texture_data = face_texture.texture_data(); let face_texture_data = face_texture.texture_data();
//this would be better as a 4x2 matrix //this would be better as a 4x2 matrix
let texture_transform_u=glam::Vec4::from_array(face_texture.texture_transforms_u)/(face_texture_data.width as f32); let texture_transform_u =
let texture_transform_v=glam::Vec4::from_array(face_texture.texture_transforms_v)/(face_texture_data.height as f32); glam::Vec4::from_array(face_texture.texture_transforms_u)
/ (face_texture_data.width as f32);
let texture_transform_v =
glam::Vec4::from_array(face_texture.texture_transforms_v)
/ (face_texture_data.height as f32);
//this automatically figures out what the texture is trying to do and creates //this automatically figures out what the texture is trying to do and creates
//a render config for it, and then returns the id to that render config //a render config for it, and then returns the id to that render config
@ -79,7 +94,8 @@ where
//calculate texture coordinates //calculate texture coordinates
let pos = glam::Vec3::from_array(vertex_xyz).extend(1.0); let pos = glam::Vec3::from_array(vertex_xyz).extend(1.0);
let tex=glam::vec2(texture_transform_u.dot(pos),texture_transform_v.dot(pos)); let tex =
glam::vec2(texture_transform_u.dot(pos), texture_transform_v.dot(pos));
let tex_idx = spam_tex.len() as u32; let tex_idx = spam_tex.len() as u32;
spam_tex.push(tex); spam_tex.push(tex);
@ -93,12 +109,17 @@ where
vertex_id vertex_id
}); });
let polygon_list = std::iter::from_fn(move || { let polygon_list = std::iter::from_fn(move || {
match (polygon_iter.next(),polygon_iter.next(),polygon_iter.next()){ match (
polygon_iter.next(),
polygon_iter.next(),
polygon_iter.next(),
) {
(Some(v1), Some(v2), Some(v3)) => Some(vec![v1, v2, v3]), (Some(v1), Some(v2), Some(v3)) => Some(vec![v1, v2, v3]),
//ignore extra vertices, not sure what to do in this case, failing the whole conversion could be appropriate //ignore extra vertices, not sure what to do in this case, failing the whole conversion could be appropriate
_ => None, _ => None,
} }
}).collect(); })
.collect();
if face.is_visible() { if face.is_visible() {
//TODO: deduplicate graphics groups by render id //TODO: deduplicate graphics groups by render id
graphics_groups.push(model::IndexedGraphicsGroup { graphics_groups.push(model::IndexedGraphicsGroup {
@ -108,7 +129,8 @@ where
} }
physics_group.groups.push(polygon_group_id); physics_group.groups.push(polygon_group_id);
model::PolygonGroup::PolygonList(model::PolygonList::new(polygon_list)) model::PolygonGroup::PolygonList(model::PolygonList::new(polygon_list))
}).collect(); })
.collect();
model::Mesh { model::Mesh {
unique_pos: spam_pos, unique_pos: spam_pos,
unique_tex: spam_tex, unique_tex: spam_tex,
@ -119,7 +141,8 @@ where
graphics_groups, graphics_groups,
physics_groups: vec![physics_group], physics_groups: vec![physics_group],
} }
}).collect(); })
.collect();
let world_models:Vec<model::Model>= let world_models:Vec<model::Model>=
//one instance of the main world mesh //one instance of the main world mesh
@ -220,33 +243,58 @@ impl PartialMap2{
//merge mesh and model lists, flatten and remap all ids //merge mesh and model lists, flatten and remap all ids
let mesh_id_offset = self.world_meshes.len(); let mesh_id_offset = self.world_meshes.len();
println!("prop_meshes.len()={}", self.prop_meshes.len()); println!("prop_meshes.len()={}", self.prop_meshes.len());
let (mut prop_meshes,prop_mesh_id_map):(Vec<model::Mesh>,std::collections::HashMap<model::MeshId,model::MeshId>) let (mut prop_meshes, prop_mesh_id_map): (
=self.prop_meshes.into_iter().enumerate().map(|(new_mesh_id,(old_mesh_id,mesh))|{ Vec<model::Mesh>,
(mesh,(old_mesh_id,model::MeshId::new((mesh_id_offset+new_mesh_id) as u32))) std::collections::HashMap<model::MeshId, model::MeshId>,
}).unzip(); ) = self
.prop_meshes
.into_iter()
.enumerate()
.map(|(new_mesh_id, (old_mesh_id, mesh))| {
(
mesh,
(
old_mesh_id,
model::MeshId::new((mesh_id_offset + new_mesh_id) as u32),
),
)
})
.unzip();
self.world_meshes.append(&mut prop_meshes); self.world_meshes.append(&mut prop_meshes);
//there is no modes or runtime behaviour with references to the model ids currently //there is no modes or runtime behaviour with references to the model ids currently
//so just relentlessly cull them if the mesh is missing //so just relentlessly cull them if the mesh is missing
self.world_models.extend(self.prop_models.into_iter().filter_map(|mut model| self.world_models
.extend(self.prop_models.into_iter().filter_map(|mut model| {
prop_mesh_id_map.get(&model.mesh).map(|&new_mesh_id| { prop_mesh_id_map.get(&model.mesh).map(|&new_mesh_id| {
model.mesh = new_mesh_id; model.mesh = new_mesh_id;
model model
}) })
)); }));
//let mut models=Vec::new(); //let mut models=Vec::new();
let (textures,texture_id_map):(Vec<Vec<u8>>,std::collections::HashMap<model::TextureId,model::TextureId>) let (textures, texture_id_map): (
=textures.into_iter() Vec<Vec<u8>>,
std::collections::HashMap<model::TextureId, model::TextureId>,
) = textures
.into_iter()
//.filter_map(f) cull unused textures //.filter_map(f) cull unused textures
.enumerate().map(|(new_texture_id,(old_texture_id,texture))|{ .enumerate()
(texture,(old_texture_id,model::TextureId::new(new_texture_id as u32))) .map(|(new_texture_id, (old_texture_id, texture))| {
}).unzip(); (
let render_configs=render_configs.into_iter().map(|(render_config_id,mut render_config)|{ texture,
(old_texture_id, model::TextureId::new(new_texture_id as u32)),
)
})
.unzip();
let render_configs = render_configs
.into_iter()
.map(|(render_config_id, mut render_config)| {
//this may generate duplicate no-texture render configs but idc //this may generate duplicate no-texture render configs but idc
render_config.texture=render_config.texture.and_then(|texture_id| render_config.texture = render_config
texture_id_map.get(&texture_id).copied() .texture
); .and_then(|texture_id| texture_id_map.get(&texture_id).copied());
render_config render_config
}).collect(); })
.collect();
map::CompleteMap { map::CompleteMap {
modes: self.modes, modes: self.modes,
attributes: self.attributes, attributes: self.attributes,
@ -289,10 +337,15 @@ where
} }
let mut graphics_groups = Vec::new(); let mut graphics_groups = Vec::new();
let mut physics_groups = Vec::new(); let mut physics_groups = Vec::new();
let polygon_groups=model.meshes().enumerate().map(|(polygon_group_id,mesh)|{ let polygon_groups = model
.meshes()
.enumerate()
.map(|(polygon_group_id, mesh)| {
let polygon_group_id = model::PolygonGroupId::new(polygon_group_id as u32); let polygon_group_id = model::PolygonGroupId::new(polygon_group_id as u32);
let render_id=if let (Some(texture_path),Some(texture_name))=(texture_paths.get(0),skin.texture(mesh.material_index())){ let render_id = if let (Some(texture_path), Some(texture_name)) =
(texture_paths.get(0), skin.texture(mesh.material_index()))
{
let mut path = std::path::PathBuf::from(texture_path.as_str()); let mut path = std::path::PathBuf::from(texture_path.as_str());
path.push(texture_name); path.push(texture_name);
acquire_render_config_id(path.as_os_str().to_str()) acquire_render_config_id(path.as_os_str().to_str())
@ -309,17 +362,24 @@ where
}); });
model::PolygonGroup::PolygonList(model::PolygonList::new( model::PolygonGroup::PolygonList(model::PolygonList::new(
//looking at the code, it would seem that the strips are pre-deindexed into triangle lists when calling this function //looking at the code, it would seem that the strips are pre-deindexed into triangle lists when calling this function
mesh.vertex_strip_indices().flat_map(|mut strip| mesh.vertex_strip_indices()
.flat_map(|mut strip| {
std::iter::from_fn(move || { std::iter::from_fn(move || {
match (strip.next(), strip.next(), strip.next()) { match (strip.next(), strip.next(), strip.next()) {
(Some(v1),Some(v2),Some(v3))=>Some([v1,v2,v3].map(|vertex_id|model::VertexId::new(vertex_id as u32)).to_vec()), (Some(v1), Some(v2), Some(v3)) => Some(
[v1, v2, v3]
.map(|vertex_id| model::VertexId::new(vertex_id as u32))
.to_vec(),
),
//ignore extra vertices, not sure what to do in this case, failing the whole conversion could be appropriate //ignore extra vertices, not sure what to do in this case, failing the whole conversion could be appropriate
_ => None, _ => None,
} }
}) })
).collect() })
.collect(),
)) ))
}).collect(); })
.collect();
Ok(model::Mesh { Ok(model::Mesh {
unique_pos: spam_pos, unique_pos: spam_pos,
unique_normal: spam_normal, unique_normal: spam_normal,

View File

@ -21,13 +21,15 @@ pub fn read<R:std::io::Read>(mut input:R)->Result<Bsp,ReadError>{
//TODO: mmap //TODO: mmap
input.read_to_end(&mut s).map_err(ReadError::Io)?; input.read_to_end(&mut s).map_err(ReadError::Io)?;
vbsp::Bsp::read(s.as_slice()).map(Bsp::new).map_err(ReadError::Bsp) vbsp::Bsp::read(s.as_slice())
.map(Bsp::new)
.map_err(ReadError::Bsp)
} }
pub fn convert<AcquireRenderConfigId, AcquireMeshId>( pub fn convert<AcquireRenderConfigId, AcquireMeshId>(
bsp: &Bsp, bsp: &Bsp,
acquire_render_config_id: AcquireRenderConfigId, acquire_render_config_id: AcquireRenderConfigId,
acquire_mesh_id:AcquireMeshId acquire_mesh_id: AcquireMeshId,
) -> bsp::PartialMap1 ) -> bsp::PartialMap1
where where
AcquireRenderConfigId: FnMut(Option<&str>) -> strafesnet_common::model::RenderConfigId, AcquireRenderConfigId: FnMut(Option<&str>) -> strafesnet_common::model::RenderConfigId,

View File

@ -8,7 +8,10 @@ pub struct Aabb{
impl Default for Aabb { impl Default for Aabb {
fn default() -> Self { fn default() -> Self {
Self{min:vec3::MAX,max:vec3::MIN} Self {
min: vec3::MAX,
max: vec3::MIN,
}
} }
} }

View File

@ -41,7 +41,8 @@ impl<T> BvhNode<T>{
pub fn the_tester<F: FnMut(&T)>(&self, aabb: &Aabb, f: &mut F) { pub fn the_tester<F: FnMut(&T)>(&self, aabb: &Aabb, f: &mut F) {
match &self.content { match &self.content {
RecursiveContent::Leaf(model) => f(model), RecursiveContent::Leaf(model) => f(model),
RecursiveContent::Branch(children)=>for child in children{ RecursiveContent::Branch(children) => {
for child in children {
//this test could be moved outside the match statement //this test could be moved outside the match statement
//but that would test the root node aabb //but that would test the root node aabb
//you're probably not going to spend a lot of time outside the map, //you're probably not going to spend a lot of time outside the map,
@ -49,18 +50,24 @@ impl<T> BvhNode<T>{
if aabb.intersects(&child.aabb) { if aabb.intersects(&child.aabb) {
child.the_tester(aabb, f); child.the_tester(aabb, f);
} }
}, }
}
} }
} }
pub fn into_visitor<F: FnMut(T)>(self, f: &mut F) { pub fn into_visitor<F: FnMut(T)>(self, f: &mut F) {
match self.content { match self.content {
RecursiveContent::Leaf(model) => f(model), RecursiveContent::Leaf(model) => f(model),
RecursiveContent::Branch(children)=>for child in children{ RecursiveContent::Branch(children) => {
for child in children {
child.into_visitor(f) child.into_visitor(f)
},
} }
} }
pub fn weigh_contents<W:Copy+std::iter::Sum<W>,F:Fn(&T)->W>(self,f:&F)->BvhWeightNode<W,T>{ }
}
pub fn weigh_contents<W: Copy + std::iter::Sum<W>, F: Fn(&T) -> W>(
self,
f: &F,
) -> BvhWeightNode<W, T> {
match self.content { match self.content {
RecursiveContent::Leaf(model) => BvhWeightNode { RecursiveContent::Leaf(model) => BvhWeightNode {
weight: f(&model), weight: f(&model),
@ -68,15 +75,16 @@ impl<T> BvhNode<T>{
aabb: self.aabb, aabb: self.aabb,
}, },
RecursiveContent::Branch(children) => { RecursiveContent::Branch(children) => {
let branch:Vec<BvhWeightNode<W,T>>=children.into_iter().map(|child| let branch: Vec<BvhWeightNode<W, T>> = children
child.weigh_contents(f) .into_iter()
).collect(); .map(|child| child.weigh_contents(f))
.collect();
BvhWeightNode { BvhWeightNode {
weight: branch.iter().map(|node| node.weight).sum(), weight: branch.iter().map(|node| node.weight).sum(),
content: RecursiveContent::Branch(branch), content: RecursiveContent::Branch(branch),
aabb: self.aabb, aabb: self.aabb,
} }
}, }
} }
} }
} }
@ -94,9 +102,11 @@ impl <W,T> BvhWeightNode<W,T>{
pub fn into_visitor<F: FnMut(T)>(self, f: &mut F) { pub fn into_visitor<F: FnMut(T)>(self, f: &mut F) {
match self.content { match self.content {
RecursiveContent::Leaf(model) => f(model), RecursiveContent::Leaf(model) => f(model),
RecursiveContent::Branch(children)=>for child in children{ RecursiveContent::Branch(children) => {
for child in children {
child.into_visitor(f) child.into_visitor(f)
}, }
}
} }
} }
} }
@ -109,13 +119,16 @@ fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
let n = boxen.len(); let n = boxen.len();
if force || n < 20 { if force || n < 20 {
let mut aabb = Aabb::default(); let mut aabb = Aabb::default();
let nodes=boxen.into_iter().map(|b|{ let nodes = boxen
.into_iter()
.map(|b| {
aabb.join(&b.1); aabb.join(&b.1);
BvhNode { BvhNode {
content: RecursiveContent::Leaf(b.0), content: RecursiveContent::Leaf(b.0),
aabb: b.1, aabb: b.1,
} }
}).collect(); })
.collect();
BvhNode { BvhNode {
content: RecursiveContent::Branch(nodes), content: RecursiveContent::Branch(nodes),
aabb, aabb,
@ -146,9 +159,24 @@ fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
let first_index_gt_median_y = sort_y.partition_point(|&(_, y)| y <= median_y); let first_index_gt_median_y = sort_y.partition_point(|&(_, y)| y <= median_y);
let first_index_gt_median_z = sort_z.partition_point(|&(_, z)| z <= median_z); let first_index_gt_median_z = sort_z.partition_point(|&(_, z)| z <= median_z);
//pick which side median value copies go into such that both sides are as balanced as possible based on distance from n/2 //pick which side median value copies go into such that both sides are as balanced as possible based on distance from n/2
let partition_point_x=if n.abs_diff(2*first_index_eq_median_x)<n.abs_diff(2*first_index_gt_median_x){first_index_eq_median_x}else{first_index_gt_median_x}; let partition_point_x =
let partition_point_y=if n.abs_diff(2*first_index_eq_median_y)<n.abs_diff(2*first_index_gt_median_y){first_index_eq_median_y}else{first_index_gt_median_y}; if n.abs_diff(2 * first_index_eq_median_x) < n.abs_diff(2 * first_index_gt_median_x) {
let partition_point_z=if n.abs_diff(2*first_index_eq_median_z)<n.abs_diff(2*first_index_gt_median_z){first_index_eq_median_z}else{first_index_gt_median_z}; first_index_eq_median_x
} else {
first_index_gt_median_x
};
let partition_point_y =
if n.abs_diff(2 * first_index_eq_median_y) < n.abs_diff(2 * first_index_gt_median_y) {
first_index_eq_median_y
} else {
first_index_gt_median_y
};
let partition_point_z =
if n.abs_diff(2 * first_index_eq_median_z) < n.abs_diff(2 * first_index_gt_median_z) {
first_index_eq_median_z
} else {
first_index_gt_median_z
};
//this ids which octant the boxen is put in //this ids which octant the boxen is put in
let mut octant = vec![0; n]; let mut octant = vec![0; n];
for &(i, _) in &sort_x[partition_point_x..] { for &(i, _) in &sort_x[partition_point_x..] {
@ -165,7 +193,8 @@ fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
let mut octant_list = Vec::with_capacity(8); let mut octant_list = Vec::with_capacity(8);
for (i, (data, aabb)) in boxen.into_iter().enumerate() { for (i, (data, aabb)) in boxen.into_iter().enumerate() {
let octant_id = octant[i]; let octant_id = octant[i];
let list_id=if let Some(list_id)=octant_list.iter().position(|&id|id==octant_id){ let list_id = if let Some(list_id) = octant_list.iter().position(|&id| id == octant_id)
{
list_id list_id
} else { } else {
let list_id = list_list.len(); let list_id = list_list.len();
@ -181,11 +210,14 @@ fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
} else { } else {
BvhNode { BvhNode {
content: RecursiveContent::Branch( content: RecursiveContent::Branch(
list_list.into_iter().map(|b|{ list_list
.into_iter()
.map(|b| {
let node = generate_bvh_node(b, false); let node = generate_bvh_node(b, false);
aabb.join(&node.aabb); aabb.join(&node.aabb);
node node
}).collect() })
.collect(),
), ),
aabb, aabb,
} }

View File

@ -1,10 +1,10 @@
use crate::model;
use crate::integer::{AbsoluteTime, Planar64, Planar64Vec3}; use crate::integer::{AbsoluteTime, Planar64, Planar64Vec3};
use crate::model;
//you have this effect while in contact //you have this effect while in contact
#[derive(Clone, Hash, Eq, PartialEq)] #[derive(Clone, Hash, Eq, PartialEq)]
pub struct ContactingLadder { pub struct ContactingLadder {
pub sticky:bool pub sticky: bool,
} }
#[derive(Clone, Hash, Eq, PartialEq)] #[derive(Clone, Hash, Eq, PartialEq)]
pub enum ContactingBehaviour { pub enum ContactingBehaviour {
@ -24,13 +24,16 @@ pub struct IntersectingWater{
//All models can be given these attributes //All models can be given these attributes
#[derive(Clone, Hash, Eq, PartialEq)] #[derive(Clone, Hash, Eq, PartialEq)]
pub struct Accelerator { pub struct Accelerator {
pub acceleration:Planar64Vec3 pub acceleration: Planar64Vec3,
} }
#[derive(Clone, Hash, Eq, PartialEq)] #[derive(Clone, Hash, Eq, PartialEq)]
pub enum Booster { pub enum Booster {
//Affine(crate::integer::Planar64Affine3),//capable of SetVelocity,DotVelocity,normal booster,bouncy part,redirect velocity, and much more //Affine(crate::integer::Planar64Affine3),//capable of SetVelocity,DotVelocity,normal booster,bouncy part,redirect velocity, and much more
Velocity(Planar64Vec3), //straight up boost velocity adds to your current velocity Velocity(Planar64Vec3), //straight up boost velocity adds to your current velocity
Energy{direction:Planar64Vec3,energy:Planar64},//increase energy in direction Energy {
direction: Planar64Vec3,
energy: Planar64,
}, //increase energy in direction
AirTime(AbsoluteTime), //increase airtime, invariant across mass and gravity changes AirTime(AbsoluteTime), //increase airtime, invariant across mass and gravity changes
Height(Planar64), //increase height, invariant across mass and gravity changes Height(Planar64), //increase height, invariant across mass and gravity changes
} }
@ -43,7 +46,7 @@ impl Booster{
//let d=direction.dot(velocity); //let d=direction.dot(velocity);
//TODO: think about negative //TODO: think about negative
//velocity+direction.with_length((d*d+energy).sqrt()-d) //velocity+direction.with_length((d*d+energy).sqrt()-d)
}, }
Booster::AirTime(_) => todo!(), Booster::AirTime(_) => todo!(),
Booster::Height(_) => todo!(), Booster::Height(_) => todo!(),
} }
@ -59,13 +62,18 @@ pub enum SetTrajectory{
//Speed-type SetTrajectory //Speed-type SetTrajectory
AirTime(AbsoluteTime), //air time (relative to gravity direction) is invariant across mass and gravity changes AirTime(AbsoluteTime), //air time (relative to gravity direction) is invariant across mass and gravity changes
Height(Planar64), //boost height (relative to gravity direction) is invariant across mass and gravity changes Height(Planar64), //boost height (relative to gravity direction) is invariant across mass and gravity changes
DotVelocity{direction:Planar64Vec3,dot:Planar64},//set your velocity in a specific direction without touching other directions DotVelocity {
direction: Planar64Vec3,
dot: Planar64,
}, //set your velocity in a specific direction without touching other directions
//Velocity-type SetTrajectory //Velocity-type SetTrajectory
TargetPointTime{//launch on a trajectory that will land at a target point in a set amount of time TargetPointTime {
//launch on a trajectory that will land at a target point in a set amount of time
target_point: Planar64Vec3, target_point: Planar64Vec3,
time: AbsoluteTime, //short time = fast and direct, long time = launch high in the air, negative time = wrong way time: AbsoluteTime, //short time = fast and direct, long time = launch high in the air, negative time = wrong way
}, },
TargetPointSpeed{//launch at a fixed speed and land at a target point TargetPointSpeed {
//launch at a fixed speed and land at a target point
target_point: Planar64Vec3, target_point: Planar64Vec3,
speed: Planar64, //if speed is too low this will fail to reach the target. The closest-passing trajectory will be chosen instead speed: Planar64, //if speed is too low this will fail to reach the target. The closest-passing trajectory will be chosen instead
trajectory_choice: TrajectoryChoice, trajectory_choice: TrajectoryChoice,
@ -77,9 +85,19 @@ impl SetTrajectory{
match self { match self {
SetTrajectory::AirTime(_) SetTrajectory::AirTime(_)
| SetTrajectory::Height(_) | SetTrajectory::Height(_)
|SetTrajectory::DotVelocity{direction:_,dot:_}=>false, | SetTrajectory::DotVelocity {
SetTrajectory::TargetPointTime{target_point:_,time:_} direction: _,
|SetTrajectory::TargetPointSpeed{target_point:_,speed:_,trajectory_choice:_} dot: _,
} => false,
SetTrajectory::TargetPointTime {
target_point: _,
time: _,
}
| SetTrajectory::TargetPointSpeed {
target_point: _,
speed: _,
trajectory_choice: _,
}
| SetTrajectory::Velocity(_) => true, | SetTrajectory::Velocity(_) => true,
} }
} }

View File

@ -1,7 +1,7 @@
use std::collections::{HashSet,HashMap};
use crate::model::ModelId;
use crate::gameplay_style; use crate::gameplay_style;
use crate::model::ModelId;
use crate::updatable::Updatable; use crate::updatable::Updatable;
use std::collections::{HashMap, HashSet};
#[derive(Clone)] #[derive(Clone)]
pub struct StageElement { pub struct StageElement {
@ -12,7 +12,12 @@ pub struct StageElement{
} }
impl StageElement { impl StageElement {
#[inline] #[inline]
pub const fn new(stage_id:StageId,force:bool,behaviour:StageElementBehaviour,jump_limit:Option<u8>)->Self{ pub const fn new(
stage_id: StageId,
force: bool,
behaviour: StageElementBehaviour,
jump_limit: Option<u8>,
) -> Self {
Self { Self {
stage_id, stage_id,
force, force,
@ -116,12 +121,23 @@ impl Stage{
self.is_complete(0, 0) self.is_complete(0, 0)
} }
#[inline] #[inline]
pub const fn is_complete(&self,ordered_checkpoints_count:u32,unordered_checkpoints_count:u32)->bool{ pub const fn is_complete(
self.ordered_checkpoints_count==ordered_checkpoints_count&&self.unordered_checkpoints_count==unordered_checkpoints_count &self,
ordered_checkpoints_count: u32,
unordered_checkpoints_count: u32,
) -> bool {
self.ordered_checkpoints_count == ordered_checkpoints_count
&& self.unordered_checkpoints_count == unordered_checkpoints_count
} }
#[inline] #[inline]
pub fn is_next_ordered_checkpoint(&self,next_ordered_checkpoint_id:CheckpointId,model_id:ModelId)->bool{ pub fn is_next_ordered_checkpoint(
self.ordered_checkpoints.get(&next_ordered_checkpoint_id).is_some_and(|&next_checkpoint|model_id==next_checkpoint) &self,
next_ordered_checkpoint_id: CheckpointId,
model_id: ModelId,
) -> bool {
self.ordered_checkpoints
.get(&next_ordered_checkpoint_id)
.is_some_and(|&next_checkpoint| model_id == next_checkpoint)
} }
#[inline] #[inline]
pub fn is_unordered_checkpoint(&self, model_id: ModelId) -> bool { pub fn is_unordered_checkpoint(&self, model_id: ModelId) -> bool {
@ -137,7 +153,8 @@ pub struct StageUpdate{
impl Updatable<StageUpdate> for Stage { impl Updatable<StageUpdate> for Stage {
fn update(&mut self, update: StageUpdate) { fn update(&mut self, update: StageUpdate) {
self.ordered_checkpoints.extend(update.ordered_checkpoints); self.ordered_checkpoints.extend(update.ordered_checkpoints);
self.unordered_checkpoints.extend(update.unordered_checkpoints); self.unordered_checkpoints
.extend(update.unordered_checkpoints);
} }
} }
@ -187,7 +204,9 @@ impl Mode{
elements: HashMap::new(), elements: HashMap::new(),
} }
} }
pub fn into_inner(self)->( pub fn into_inner(
self,
) -> (
gameplay_style::StyleModifiers, gameplay_style::StyleModifiers,
ModelId, ModelId,
HashMap<ModelId, Zone>, HashMap<ModelId, Zone>,
@ -231,27 +250,36 @@ impl Mode{
//expand and index normalized data //expand and index normalized data
self.zones.insert(self.start, Zone::Start); self.zones.insert(self.start, Zone::Start);
for (stage_id, stage) in self.stages.iter().enumerate() { for (stage_id, stage) in self.stages.iter().enumerate() {
self.elements.insert(stage.spawn,StageElement{ self.elements.insert(
stage.spawn,
StageElement {
stage_id: StageId(stage_id as u32), stage_id: StageId(stage_id as u32),
force: false, force: false,
behaviour: StageElementBehaviour::SpawnAt, behaviour: StageElementBehaviour::SpawnAt,
jump_limit: None, jump_limit: None,
}); },
);
for (_, &model) in &stage.ordered_checkpoints { for (_, &model) in &stage.ordered_checkpoints {
self.elements.insert(model,StageElement{ self.elements.insert(
model,
StageElement {
stage_id: StageId(stage_id as u32), stage_id: StageId(stage_id as u32),
force: false, force: false,
behaviour: StageElementBehaviour::Checkpoint, behaviour: StageElementBehaviour::Checkpoint,
jump_limit: None, jump_limit: None,
}); },
);
} }
for &model in &stage.unordered_checkpoints { for &model in &stage.unordered_checkpoints {
self.elements.insert(model,StageElement{ self.elements.insert(
model,
StageElement {
stage_id: StageId(stage_id as u32), stage_id: StageId(stage_id as u32),
force: false, force: false,
behaviour: StageElementBehaviour::Checkpoint, behaviour: StageElementBehaviour::Checkpoint,
jump_limit: None, jump_limit: None,
}); },
);
} }
} }
} }
@ -304,9 +332,7 @@ pub struct Modes{
} }
impl Modes { impl Modes {
pub const fn new(modes: Vec<Mode>) -> Self { pub const fn new(modes: Vec<Mode>) -> Self {
Self{ Self { modes }
modes,
}
} }
pub fn into_inner(self) -> Vec<Mode> { pub fn into_inner(self) -> Vec<Mode> {
self.modes self.modes

View File

@ -1,7 +1,7 @@
const VALVE_SCALE: Planar64 = Planar64::raw(1 << 28); // 1/16 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::controls_bitflag::Controls;
use crate::integer::{int, vec3::int as int3, AbsoluteTime, Planar64, Planar64Vec3, Ratio64};
use crate::physics::Time as PhysicsTime; use crate::physics::Time as PhysicsTime;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -75,16 +75,21 @@ impl JumpImpulse{
let v_g = gravity.dot(velocity); let v_g = gravity.dot(velocity);
//do it backwards //do it backwards
let radicand = v_g * v_g + (g * height * 2).fix_4(); let radicand = v_g * v_g + (g * height * 2).fix_4();
velocity-(*gravity*(radicand.sqrt().fix_2()+v_g)/gg).divide().fix_1() velocity
}, - (*gravity * (radicand.sqrt().fix_2() + v_g) / gg)
&JumpImpulse::Linear(jump_speed)=>velocity+(jump_dir*jump_speed/jump_dir.length()).divide().fix_1(), .divide()
.fix_1()
}
&JumpImpulse::Linear(jump_speed) => {
velocity + (jump_dir * jump_speed / jump_dir.length()).divide().fix_1()
}
&JumpImpulse::Energy(energy) => { &JumpImpulse::Energy(energy) => {
//calculate energy //calculate energy
//let e=gravity.dot(velocity); //let e=gravity.dot(velocity);
//add //add
//you get the idea //you get the idea
todo!() todo!()
}, }
} }
} }
//TODO: remove this and implement JumpCalculation properly //TODO: remove this and implement JumpCalculation properly
@ -134,7 +139,7 @@ impl JumpSettings{
//activate booster normally, jump does nothing //activate booster normally, jump does nothing
boost_vel boost_vel
} }
}, }
(true, _) => { (true, _) => {
//the source calculation (?) //the source calculation (?)
let boost_vel = match booster { let boost_vel = match booster {
@ -167,7 +172,7 @@ impl JumpSettings{
//activate booster normally, jump does nothing //activate booster normally, jump does nothing
boost_vel boost_vel
} }
}, }
//the strafe client calculation //the strafe client calculation
(false, _) => { (false, _) => {
let boost_vel = match booster { let boost_vel = match booster {
@ -175,7 +180,7 @@ impl JumpSettings{
None => rel_velocity, None => rel_velocity,
}; };
boost_vel + jump_dir.with_length(jump_speed).divide().fix_1() boost_vel + jump_dir.with_length(jump_speed).divide().fix_1()
}, }
} }
} }
} }
@ -225,7 +230,9 @@ impl ControlsActivation{
//Half-Sideways //Half-Sideways
pub const fn half_sideways() -> Self { pub const fn half_sideways() -> Self {
Self { Self {
controls_mask:Controls::MoveForward.union(Controls::MoveLeft).union(Controls::MoveRight), controls_mask: Controls::MoveForward
.union(Controls::MoveLeft)
.union(Controls::MoveRight),
controls_intersects: Controls::MoveLeft.union(Controls::MoveRight), controls_intersects: Controls::MoveLeft.union(Controls::MoveRight),
controls_contains: Controls::MoveForward, controls_contains: Controls::MoveForward,
} }
@ -233,7 +240,10 @@ impl ControlsActivation{
//Surf Half-Sideways //Surf Half-Sideways
pub const fn surf_half_sideways() -> Self { pub const fn surf_half_sideways() -> Self {
Self { Self {
controls_mask:Controls::MoveForward.union(Controls::MoveBackward).union(Controls::MoveLeft).union(Controls::MoveRight), controls_mask: Controls::MoveForward
.union(Controls::MoveBackward)
.union(Controls::MoveLeft)
.union(Controls::MoveRight),
controls_intersects: Controls::MoveForward.union(Controls::MoveBackward), controls_intersects: Controls::MoveForward.union(Controls::MoveBackward),
controls_contains: Controls::empty(), controls_contains: Controls::empty(),
} }
@ -265,16 +275,30 @@ pub struct StrafeSettings{
pub tick_rate: Ratio64, pub tick_rate: Ratio64,
} }
impl StrafeSettings { impl StrafeSettings {
pub fn tick_velocity(&self,velocity:Planar64Vec3,control_dir:Planar64Vec3)->Option<Planar64Vec3>{ pub fn tick_velocity(
&self,
velocity: Planar64Vec3,
control_dir: Planar64Vec3,
) -> Option<Planar64Vec3> {
let d = velocity.dot(control_dir); let d = velocity.dot(control_dir);
let mv = self.mv.fix_2(); let mv = self.mv.fix_2();
match d < mv { match d < mv {
true=>Some(velocity+(control_dir*self.air_accel_limit.map_or(mv-d,|limit|limit.fix_2().min(mv-d))).fix_1()), true => Some(
velocity
+ (control_dir
* self
.air_accel_limit
.map_or(mv - d, |limit| limit.fix_2().min(mv - d)))
.fix_1(),
),
false => None, false => None,
} }
} }
pub fn next_tick(&self, time: PhysicsTime) -> PhysicsTime { 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)) 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 { pub const fn activates(&self, controls: Controls) -> bool {
self.enable.activates(controls) self.enable.activates(controls)
@ -318,7 +342,11 @@ impl WalkSettings{
}; };
self.accelerate.accel.min((-gravity.y * friction).fix_1()) self.accelerate.accel.min((-gravity.y * friction).fix_1())
} }
pub fn get_walk_target_velocity(&self,control_dir:Planar64Vec3,normal:Planar64Vec3)->Planar64Vec3{ pub fn get_walk_target_velocity(
&self,
control_dir: Planar64Vec3,
normal: Planar64Vec3,
) -> Planar64Vec3 {
if control_dir == crate::integer::vec3::ZERO { if control_dir == crate::integer::vec3::ZERO {
return control_dir; return control_dir;
} }
@ -332,7 +360,9 @@ impl WalkSettings{
if cr == crate::integer::vec3::ZERO_2 { if cr == crate::integer::vec3::ZERO_2 {
crate::integer::vec3::ZERO crate::integer::vec3::ZERO
} else { } else {
(cr.cross(normal)*self.accelerate.topspeed/((nn*(nnmm-dd)).sqrt())).divide().fix_1() (cr.cross(normal) * self.accelerate.topspeed / ((nn * (nnmm - dd)).sqrt()))
.divide()
.fix_1()
} }
} else { } else {
crate::integer::vec3::ZERO crate::integer::vec3::ZERO
@ -359,7 +389,11 @@ impl LadderSettings{
//TODO: fallible ladder accel //TODO: fallible ladder accel
self.accelerate.accel self.accelerate.accel
} }
pub fn get_ladder_target_velocity(&self,mut control_dir:Planar64Vec3,normal:Planar64Vec3)->Planar64Vec3{ pub fn get_ladder_target_velocity(
&self,
mut control_dir: Planar64Vec3,
normal: Planar64Vec3,
) -> Planar64Vec3 {
if control_dir == crate::integer::vec3::ZERO { if control_dir == crate::integer::vec3::ZERO {
return control_dir; return control_dir;
} }
@ -385,7 +419,9 @@ impl LadderSettings{
if cr == crate::integer::vec3::ZERO_2 { if cr == crate::integer::vec3::ZERO_2 {
crate::integer::vec3::ZERO crate::integer::vec3::ZERO
} else { } else {
(cr.cross(normal)*self.accelerate.topspeed/((nn*(nnmm-dd)).sqrt())).divide().fix_1() (cr.cross(normal) * self.accelerate.topspeed / ((nn * (nnmm - dd)).sqrt()))
.divide()
.fix_1()
} }
} else { } else {
crate::integer::vec3::ZERO crate::integer::vec3::ZERO
@ -462,9 +498,7 @@ impl StyleModifiers{
}, },
dot: (int(1) / 2).sqrt(), dot: (int(1) / 2).sqrt(),
}), }),
swim:Some(PropulsionSettings{ swim: Some(PropulsionSettings { magnitude: int(12) }),
magnitude:int(12),
}),
hitbox: Hitbox::roblox(), hitbox: Hitbox::roblox(),
camera_offset: int3(0, 2, 0), //4.5-2.5=2 camera_offset: int3(0, 2, 0), //4.5-2.5=2
} }
@ -504,9 +538,7 @@ impl StyleModifiers{
}, },
dot: (int(1) / 2).sqrt(), dot: (int(1) / 2).sqrt(),
}), }),
swim:Some(PropulsionSettings{ swim: Some(PropulsionSettings { magnitude: int(12) }),
magnitude:int(12),
}),
hitbox: Hitbox::roblox(), hitbox: Hitbox::roblox(),
camera_offset: int3(0, 2, 0), //4.5-2.5=2 camera_offset: int3(0, 2, 0), //4.5-2.5=2
} }

View File

@ -9,12 +9,18 @@ pub struct TimedInstruction<I,T>{
pub trait InstructionEmitter { pub trait InstructionEmitter {
type Instruction; type Instruction;
type TimeInner; type TimeInner;
fn next_instruction(&self,time_limit:Time<Self::TimeInner>)->Option<TimedInstruction<Self::Instruction,Self::TimeInner>>; fn next_instruction(
&self,
time_limit: Time<Self::TimeInner>,
) -> Option<TimedInstruction<Self::Instruction, Self::TimeInner>>;
} }
pub trait InstructionConsumer { pub trait InstructionConsumer {
type Instruction; type Instruction;
type TimeInner; type TimeInner;
fn process_instruction(&mut self, instruction:TimedInstruction<Self::Instruction,Self::TimeInner>); fn process_instruction(
&mut self,
instruction: TimedInstruction<Self::Instruction, Self::TimeInner>,
);
} }
//PROPER PRIVATE FIELDS!!! //PROPER PRIVATE FIELDS!!!
@ -23,12 +29,13 @@ pub struct InstructionCollector<I,T>{
instruction: Option<I>, instruction: Option<I>,
} }
impl<I, T> InstructionCollector<I, T> impl<I, T> InstructionCollector<I, T>
where Time<T>:Copy+PartialOrd, where
Time<T>: Copy + PartialOrd,
{ {
pub const fn new(time: Time<T>) -> Self { pub const fn new(time: Time<T>) -> Self {
Self { Self {
time, time,
instruction:None instruction: None,
} }
} }
#[inline] #[inline]
@ -42,7 +49,7 @@ impl<I,T> InstructionCollector<I,T>
self.time = unwrap_instruction.time; self.time = unwrap_instruction.time;
self.instruction = Some(unwrap_instruction.instruction); self.instruction = Some(unwrap_instruction.instruction);
} }
}, }
None => (), None => (),
} }
} }
@ -51,7 +58,7 @@ impl<I,T> InstructionCollector<I,T>
match self.instruction { match self.instruction {
Some(instruction) => Some(TimedInstruction { Some(instruction) => Some(TimedInstruction {
time: self.time, time: self.time,
instruction instruction,
}), }),
None => None, None => None,
} }

View File

@ -1,5 +1,5 @@
pub use fixed_wide::fixed::{Fixed,Fix}; pub use fixed_wide::fixed::{Fix, Fixed};
pub use ratio_ops::ratio::{Ratio,Divide}; pub use ratio_ops::ratio::{Divide, Ratio};
//integer units //integer units
@ -70,13 +70,23 @@ impl<T,Num,Den,N1,T1> From<Ratio<Num,Den>> for Time<T>
{ {
#[inline] #[inline]
fn from(value: Ratio<Num, Den>) -> Self { fn from(value: Ratio<Num, Den>) -> Self {
Self::raw((value*Planar64::raw(1_000_000_000)).divide().fix().to_raw()) Self::raw(
(value * Planar64::raw(1_000_000_000))
.divide()
.fix()
.to_raw(),
)
} }
} }
impl<T> std::fmt::Display for Time<T> { impl<T> std::fmt::Display for Time<T> {
#[inline] #[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"{}s+{:09}ns",self.0/Self::ONE_SECOND.0,self.0%Self::ONE_SECOND.0) write!(
f,
"{}s+{:09}ns",
self.0 / Self::ONE_SECOND.0,
self.0 % Self::ONE_SECOND.0
)
} }
} }
impl<T> std::default::Default for Time<T> { impl<T> std::default::Default for Time<T> {
@ -122,7 +132,10 @@ impl<T> std::ops::Mul for Time<T>{
type Output = Ratio<fixed_wide::fixed::Fixed<2, 64>, fixed_wide::fixed::Fixed<2, 64>>; type Output = Ratio<fixed_wide::fixed::Fixed<2, 64>, fixed_wide::fixed::Fixed<2, 64>>;
#[inline] #[inline]
fn mul(self, rhs: Self) -> Self::Output { fn mul(self, rhs: Self) -> Self::Output {
Ratio::new(Fixed::raw(self.0)*Fixed::raw(rhs.0),Fixed::raw_digit(1_000_000_000i64.pow(2))) Ratio::new(
Fixed::raw(self.0) * Fixed::raw(rhs.0),
Fixed::raw_digit(1_000_000_000i64.pow(2)),
)
} }
} }
impl<T> std::ops::Div<i64> for Time<T> { impl<T> std::ops::Div<i64> for Time<T> {
@ -162,13 +175,25 @@ mod test_time{
#[test] #[test]
fn time_squared() { fn time_squared() {
let a = Time::from_secs(2); let a = Time::from_secs(2);
assert_eq!(a*a,Ratio::new(Fixed::<2,64>::raw_digit(1_000_000_000i64.pow(2))*4,Fixed::<2,64>::raw_digit(1_000_000_000i64.pow(2)))); assert_eq!(
a * a,
Ratio::new(
Fixed::<2, 64>::raw_digit(1_000_000_000i64.pow(2)) * 4,
Fixed::<2, 64>::raw_digit(1_000_000_000i64.pow(2))
)
);
} }
#[test] #[test]
fn time_times_planar64() { fn time_times_planar64() {
let a = Time::from_secs(2); let a = Time::from_secs(2);
let b = Planar64::from(2); let b = Planar64::from(2);
assert_eq!(b*a,Ratio::new(Fixed::<2,64>::raw_digit(1_000_000_000*(1<<32))<<2,Fixed::<1,32>::raw_digit(1_000_000_000))); assert_eq!(
b * a,
Ratio::new(
Fixed::<2, 64>::raw_digit(1_000_000_000 * (1 << 32)) << 2,
Fixed::<1, 32>::raw_digit(1_000_000_000)
)
);
} }
} }
@ -176,7 +201,7 @@ mod test_time{
const fn gcd(mut a: u64, mut b: u64) -> u64 { const fn gcd(mut a: u64, mut b: u64) -> u64 {
while b != 0 { while b != 0 {
(a, b) = (b, a.rem_euclid(b)); (a, b) = (b, a.rem_euclid(b));
}; }
a a
} }
#[derive(Clone, Copy, Debug, Hash)] #[derive(Clone, Copy, Debug, Hash)]
@ -193,7 +218,10 @@ impl Ratio64{
None None
} else { } else {
let d = gcd(num.unsigned_abs(), den); let d = gcd(num.unsigned_abs(), den);
Some(Self{num:num/(d as i64),den:den/d}) Some(Self {
num: num / (d as i64),
den: den / d,
})
} }
} }
#[inline] #[inline]
@ -305,8 +333,9 @@ impl TryFrom<f32> for Ratio64{
std::num::FpCategory::Nan => Err(Self::Error::Nan), std::num::FpCategory::Nan => Err(Self::Error::Nan),
std::num::FpCategory::Infinite => Err(Self::Error::Infinite), std::num::FpCategory::Infinite => Err(Self::Error::Infinite),
std::num::FpCategory::Zero => Ok(Self::ZERO), std::num::FpCategory::Zero => Ok(Self::ZERO),
std::num::FpCategory::Subnormal std::num::FpCategory::Subnormal | std::num::FpCategory::Normal => {
|std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f32(value)), ratio64_from_mes(integer_decode_f32(value))
}
} }
} }
} }
@ -318,8 +347,9 @@ impl TryFrom<f64> for Ratio64{
std::num::FpCategory::Nan => Err(Self::Error::Nan), std::num::FpCategory::Nan => Err(Self::Error::Nan),
std::num::FpCategory::Infinite => Err(Self::Error::Infinite), std::num::FpCategory::Infinite => Err(Self::Error::Infinite),
std::num::FpCategory::Zero => Ok(Self::ZERO), std::num::FpCategory::Zero => Ok(Self::ZERO),
std::num::FpCategory::Subnormal std::num::FpCategory::Subnormal | std::num::FpCategory::Normal => {
|std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f64(value)), ratio64_from_mes(integer_decode_f64(value))
}
} }
} }
} }
@ -361,17 +391,17 @@ pub struct Ratio64Vec2{
pub y: Ratio64, pub y: Ratio64,
} }
impl Ratio64Vec2 { impl Ratio64Vec2 {
pub const ONE:Self=Self{x:Ratio64::ONE,y:Ratio64::ONE}; pub const ONE: Self = Self {
x: Ratio64::ONE,
y: Ratio64::ONE,
};
#[inline] #[inline]
pub const fn new(x: Ratio64, y: Ratio64) -> Self { pub const fn new(x: Ratio64, y: Ratio64) -> Self {
Self { x, y } Self { x, y }
} }
#[inline] #[inline]
pub const fn mul_int(&self, rhs: glam::I64Vec2) -> glam::I64Vec2 { pub const fn mul_int(&self, rhs: glam::I64Vec2) -> glam::I64Vec2 {
glam::i64vec2( glam::i64vec2(self.x.mul_int(rhs.x), self.y.mul_int(rhs.y))
self.x.mul_int(rhs.x),
self.y.mul_int(rhs.y),
)
} }
} }
impl std::ops::Mul<i64> for Ratio64Vec2 { impl std::ops::Mul<i64> for Ratio64Vec2 {
@ -397,7 +427,9 @@ impl Angle32{
pub const fn wrap_from_i64(theta: i64) -> Self { pub const fn wrap_from_i64(theta: i64) -> Self {
//take lower bits //take lower bits
//note: this was checked on compiler explorer and compiles to 1 instruction! //note: this was checked on compiler explorer and compiles to 1 instruction!
Self(i32::from_ne_bytes(((theta&((1<<32)-1)) as u32).to_ne_bytes())) Self(i32::from_ne_bytes(
((theta & ((1 << 32) - 1)) as u32).to_ne_bytes(),
))
} }
#[inline] #[inline]
pub fn clamp_from_i64(theta: i64) -> Self { pub fn clamp_from_i64(theta: i64) -> Self {
@ -414,18 +446,15 @@ impl Angle32{
#[inline] #[inline]
pub fn clamp(&self, theta_min: Self, theta_max: Self) -> Self { pub fn clamp(&self, theta_min: Self, theta_max: Self) -> Self {
//((max-min as u32)/2 as i32)+min //((max-min as u32)/2 as i32)+min
let midpoint=(( let midpoint = (((theta_max.0 as u32).wrapping_sub(theta_min.0 as u32) / 2) as i32) //(u32::MAX/2) as i32 ALWAYS works
(theta_max.0 as u32)
.wrapping_sub(theta_min.0 as u32)
/2
) as i32)//(u32::MAX/2) as i32 ALWAYS works
.wrapping_add(theta_min.0); .wrapping_add(theta_min.0);
//(theta-mid).clamp(max-mid,min-mid)+mid //(theta-mid).clamp(max-mid,min-mid)+mid
Self( Self(
self.0.wrapping_sub(midpoint) self.0
.wrapping_sub(midpoint)
.max(theta_min.0.wrapping_sub(midpoint)) .max(theta_min.0.wrapping_sub(midpoint))
.min(theta_max.0.wrapping_sub(midpoint)) .min(theta_max.0.wrapping_sub(midpoint))
.wrapping_add(midpoint) .wrapping_add(midpoint),
) )
} }
#[inline] #[inline]
@ -451,7 +480,10 @@ impl Angle32{
(Planar64::raw(x),Planar64::raw(y)) (Planar64::raw(x),Planar64::raw(y))
*/ */
let (s, c) = (self.0 as f64 * Self::ANGLE32_TO_FLOAT64_RADIANS).sin_cos(); let (s, c) = (self.0 as f64 * Self::ANGLE32_TO_FLOAT64_RADIANS).sin_cos();
(Planar64::raw((c*((1u64<<32) as f64)) as i64),Planar64::raw((s*((1u64<<32) as f64)) as i64)) (
Planar64::raw((c * ((1u64 << 32) as f64)) as i64),
Planar64::raw((s * ((1u64 << 32) as f64)) as i64),
)
} }
} }
impl Into<f32> for Angle32 { impl Into<f32> for Angle32 {
@ -508,8 +540,14 @@ fn angle_sin_cos(){
println!("cordic s={} c={}", (s / h).divide(), (c / h).divide()); println!("cordic s={} c={}", (s / h).divide(), (c / h).divide());
let (fs, fc) = f.sin_cos(); let (fs, fc) = f.sin_cos();
println!("float s={} c={}", fs, fc); println!("float s={} c={}", fs, fc);
assert!(close_enough((c/h).divide().fix_1(),Planar64::raw((fc*((1u64<<32) as f64)) as i64))); assert!(close_enough(
assert!(close_enough((s/h).divide().fix_1(),Planar64::raw((fs*((1u64<<32) as f64)) as i64))); (c / h).divide().fix_1(),
Planar64::raw((fc * ((1u64 << 32) as f64)) as i64)
));
assert!(close_enough(
(s / h).divide().fix_1(),
Planar64::raw((fs * ((1u64 << 32) as f64)) as i64)
));
} }
test_angle(1.0); test_angle(1.0);
test_angle(std::f64::consts::PI / 4.0); test_angle(std::f64::consts::PI / 4.0);
@ -550,18 +588,27 @@ pub mod vec3{
pub const MIN: Planar64Vec3 = Planar64Vec3::new([Planar64::MIN; 3]); pub const MIN: Planar64Vec3 = Planar64Vec3::new([Planar64::MIN; 3]);
pub const MAX: Planar64Vec3 = Planar64Vec3::new([Planar64::MAX; 3]); pub const MAX: Planar64Vec3 = Planar64Vec3::new([Planar64::MAX; 3]);
pub const ZERO: Planar64Vec3 = Planar64Vec3::new([Planar64::ZERO; 3]); pub const ZERO: Planar64Vec3 = Planar64Vec3::new([Planar64::ZERO; 3]);
pub const ZERO_2:linear_ops::types::Vector3<Fixed::<2,64>>=linear_ops::types::Vector3::new([Fixed::<2,64>::ZERO;3]); pub const ZERO_2: linear_ops::types::Vector3<Fixed<2, 64>> =
linear_ops::types::Vector3::new([Fixed::<2, 64>::ZERO; 3]);
pub const X: Planar64Vec3 = Planar64Vec3::new([Planar64::ONE, Planar64::ZERO, Planar64::ZERO]); pub const X: Planar64Vec3 = Planar64Vec3::new([Planar64::ONE, Planar64::ZERO, Planar64::ZERO]);
pub const Y: Planar64Vec3 = Planar64Vec3::new([Planar64::ZERO, Planar64::ONE, Planar64::ZERO]); pub const Y: Planar64Vec3 = Planar64Vec3::new([Planar64::ZERO, Planar64::ONE, Planar64::ZERO]);
pub const Z: Planar64Vec3 = Planar64Vec3::new([Planar64::ZERO, Planar64::ZERO, Planar64::ONE]); pub const Z: Planar64Vec3 = Planar64Vec3::new([Planar64::ZERO, Planar64::ZERO, Planar64::ONE]);
pub const ONE: Planar64Vec3 = Planar64Vec3::new([Planar64::ONE, Planar64::ONE, Planar64::ONE]); pub const ONE: Planar64Vec3 = Planar64Vec3::new([Planar64::ONE, Planar64::ONE, Planar64::ONE]);
pub const NEG_X:Planar64Vec3=Planar64Vec3::new([Planar64::NEG_ONE,Planar64::ZERO,Planar64::ZERO]); pub const NEG_X: Planar64Vec3 =
pub const NEG_Y:Planar64Vec3=Planar64Vec3::new([Planar64::ZERO,Planar64::NEG_ONE,Planar64::ZERO]); Planar64Vec3::new([Planar64::NEG_ONE, Planar64::ZERO, Planar64::ZERO]);
pub const NEG_Z:Planar64Vec3=Planar64Vec3::new([Planar64::ZERO,Planar64::ZERO,Planar64::NEG_ONE]); pub const NEG_Y: Planar64Vec3 =
pub const NEG_ONE:Planar64Vec3=Planar64Vec3::new([Planar64::NEG_ONE,Planar64::NEG_ONE,Planar64::NEG_ONE]); Planar64Vec3::new([Planar64::ZERO, Planar64::NEG_ONE, Planar64::ZERO]);
pub const NEG_Z: Planar64Vec3 =
Planar64Vec3::new([Planar64::ZERO, Planar64::ZERO, Planar64::NEG_ONE]);
pub const NEG_ONE: Planar64Vec3 =
Planar64Vec3::new([Planar64::NEG_ONE, Planar64::NEG_ONE, Planar64::NEG_ONE]);
#[inline] #[inline]
pub const fn int(x: i32, y: i32, z: i32) -> Planar64Vec3 { pub const fn int(x: i32, y: i32, z: i32) -> Planar64Vec3 {
Planar64Vec3::new([Planar64::raw((x as i64)<<32),Planar64::raw((y as i64)<<32),Planar64::raw((z as i64)<<32)]) Planar64Vec3::new([
Planar64::raw((x as i64) << 32),
Planar64::raw((y as i64) << 32),
Planar64::raw((z as i64) << 32),
])
} }
#[inline] #[inline]
pub fn raw_array(array: [i64; 3]) -> Planar64Vec3 { pub fn raw_array(array: [i64; 3]) -> Planar64Vec3 {
@ -572,7 +619,9 @@ pub mod vec3{
Planar64Vec3::new([Planar64::raw(x), Planar64::raw(y), Planar64::raw(z)]) Planar64Vec3::new([Planar64::raw(x), Planar64::raw(y), Planar64::raw(z)])
} }
#[inline] #[inline]
pub fn try_from_f32_array([x,y,z]:[f32;3])->Result<Planar64Vec3,Planar64TryFromFloatError>{ pub fn try_from_f32_array(
[x, y, z]: [f32; 3],
) -> Result<Planar64Vec3, Planar64TryFromFloatError> {
Ok(Planar64Vec3::new([ Ok(Planar64Vec3::new([
try_from_f32(x)?, try_from_f32(x)?,
try_from_f32(y)?, try_from_f32(y)?,
@ -632,7 +681,9 @@ pub mod mat3{
]) ])
} }
#[inline] #[inline]
pub fn try_from_f32_array_2d([x_axis,y_axis,z_axis]:[[f32;3];3])->Result<Planar64Mat3,Planar64TryFromFloatError>{ pub fn try_from_f32_array_2d(
[x_axis, y_axis, z_axis]: [[f32; 3]; 3],
) -> Result<Planar64Mat3, Planar64TryFromFloatError> {
Ok(Planar64Mat3::new([ Ok(Planar64Mat3::new([
vec3::try_from_f32_array(x_axis)?.to_array(), vec3::try_from_f32_array(x_axis)?.to_array(),
vec3::try_from_f32_array(y_axis)?.to_array(), vec3::try_from_f32_array(y_axis)?.to_array(),
@ -649,7 +700,10 @@ pub struct Planar64Affine3{
impl Planar64Affine3 { impl Planar64Affine3 {
#[inline] #[inline]
pub const fn new(matrix3: Planar64Mat3, translation: Planar64Vec3) -> Self { pub const fn new(matrix3: Planar64Mat3, translation: Planar64Vec3) -> Self {
Self{matrix3,translation} Self {
matrix3,
translation,
}
} }
#[inline] #[inline]
pub fn transform_point3(&self, point: Planar64Vec3) -> vec3::Vector3<Fixed<2, 64>> { pub fn transform_point3(&self, point: Planar64Vec3) -> vec3::Vector3<Fixed<2, 64>> {
@ -659,13 +713,28 @@ impl Planar64Affine3{
impl Into<glam::Mat4> for Planar64Affine3 { impl Into<glam::Mat4> for Planar64Affine3 {
#[inline] #[inline]
fn into(self) -> glam::Mat4 { fn into(self) -> glam::Mat4 {
let matrix3=self.matrix3.to_array().map(|row|row.map(Into::<f32>::into)); let matrix3 = self
.matrix3
.to_array()
.map(|row| row.map(Into::<f32>::into));
let translation = self.translation.to_array().map(Into::<f32>::into); let translation = self.translation.to_array().map(Into::<f32>::into);
glam::Mat4::from_cols_array(&[ glam::Mat4::from_cols_array(&[
matrix3[0][0],matrix3[0][1],matrix3[0][2],0.0, matrix3[0][0],
matrix3[1][0],matrix3[1][1],matrix3[1][2],0.0, matrix3[0][1],
matrix3[2][0],matrix3[2][1],matrix3[2][2],0.0, matrix3[0][2],
translation[0],translation[1],translation[2],1.0 0.0,
matrix3[1][0],
matrix3[1][1],
matrix3[1][2],
0.0,
matrix3[2][0],
matrix3[2][1],
matrix3[2][2],
0.0,
translation[0],
translation[1],
translation[2],
1.0,
]) ])
} }
} }

View File

@ -1,16 +1,16 @@
pub mod bvh;
pub mod map;
pub mod run;
pub mod aabb; pub mod aabb;
pub mod model; pub mod bvh;
pub mod mouse; pub mod controls_bitflag;
pub mod timer;
pub mod integer;
pub mod physics;
pub mod session;
pub mod updatable;
pub mod instruction;
pub mod gameplay_attributes; pub mod gameplay_attributes;
pub mod gameplay_modes; pub mod gameplay_modes;
pub mod gameplay_style; pub mod gameplay_style;
pub mod controls_bitflag; pub mod instruction;
pub mod integer;
pub mod map;
pub mod model;
pub mod mouse;
pub mod physics;
pub mod run;
pub mod session;
pub mod timer;
pub mod updatable;

View File

@ -1,6 +1,6 @@
use crate::model;
use crate::gameplay_modes;
use crate::gameplay_attributes; use crate::gameplay_attributes;
use crate::gameplay_modes;
use crate::model;
//this is a temporary struct to try to get the code running again //this is a temporary struct to try to get the code running again
//TODO: use snf::map::Region to update the data in physics and graphics instead of this //TODO: use snf::map::Region to update the data in physics and graphics instead of this
pub struct CompleteMap { pub struct CompleteMap {

View File

@ -1,5 +1,5 @@
use crate::integer::{Planar64Vec3,Planar64Affine3};
use crate::gameplay_attributes; use crate::gameplay_attributes;
use crate::integer::{Planar64Affine3, Planar64Vec3};
pub type TextureCoordinate = glam::Vec2; pub type TextureCoordinate = glam::Vec2;
pub type Color4 = glam::Vec4; pub type Color4 = glam::Vec4;
@ -44,7 +44,12 @@ impl PolygonIter for PolygonList{
} }
impl MapVertexId for PolygonList { impl MapVertexId for PolygonList {
fn map_vertex_id<F: Fn(VertexId) -> VertexId>(self, f: F) -> Self { 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()) Self(
self.0
.into_iter()
.map(|ivl| ivl.into_iter().map(&f).collect())
.collect(),
)
} }
} }
// pub struct TriangleStrip(IndexedVertexList); // pub struct TriangleStrip(IndexedVertexList);

View File

@ -14,7 +14,8 @@ impl<T> Default for MouseState<T>{
} }
} }
impl<T> MouseState<T> impl<T> MouseState<T>
where Time<T>:Copy, where
Time<T>: Copy,
{ {
pub fn lerp(&self, target: &MouseState<T>, time: Time<T>) -> glam::IVec2 { pub fn lerp(&self, target: &MouseState<T>, time: Time<T>) -> glam::IVec2 {
let m0 = self.pos.as_i64vec2(); let m0 = self.pos.as_i64vec2();

View File

@ -4,7 +4,10 @@ pub type Time=crate::integer::Time<TimeInner>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Instruction { pub enum Instruction {
ReplaceMouse(crate::mouse::MouseState<TimeInner>,crate::mouse::MouseState<TimeInner>), ReplaceMouse(
crate::mouse::MouseState<TimeInner>,
crate::mouse::MouseState<TimeInner>,
),
SetNextMouse(crate::mouse::MouseState<TimeInner>), SetNextMouse(crate::mouse::MouseState<TimeInner>),
SetMoveRight(bool), SetMoveRight(bool),
SetMoveUp(bool), SetMoveUp(bool),
@ -21,7 +24,10 @@ pub enum Instruction{
Restart, Restart,
/// Spawn: Teleport to a specific mode's spawn /// Spawn: Teleport to a specific mode's spawn
/// Sets current mode & spawn /// Sets current mode & spawn
Spawn(crate::gameplay_modes::ModeId,crate::gameplay_modes::StageId), Spawn(
crate::gameplay_modes::ModeId,
crate::gameplay_modes::StageId,
),
Idle, Idle,
//Idle: there were no input events, but the simulation is safe to advance to this timestep //Idle: there were no input events, but the simulation is safe to advance to this timestep
//for interpolation / networking / playback reasons, most playback heads will always want //for interpolation / networking / playback reasons, most playback heads will always want

View File

@ -1,6 +1,6 @@
use crate::timer::{TimerFixed,Realtime,Paused,Unpaused}; use crate::timer::{Paused, Realtime, TimerFixed, Unpaused};
use crate::physics::{TimeInner as PhysicsTimeInner,Time as PhysicsTime}; use crate::physics::{Time as PhysicsTime, TimeInner as PhysicsTimeInner};
#[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Debug)] #[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Debug)]
pub enum TimeInner {} pub enum TimeInner {}
@ -55,8 +55,12 @@ impl std::error::Error for Error{}
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
enum RunState { enum RunState {
Created, Created,
Started{timer:TimerFixed<Realtime<PhysicsTimeInner,TimeInner>,Unpaused>}, Started {
Finished{timer:TimerFixed<Realtime<PhysicsTimeInner,TimeInner>,Paused>}, timer: TimerFixed<Realtime<PhysicsTimeInner, TimeInner>, Unpaused>,
},
Finished {
timer: TimerFixed<Realtime<PhysicsTimeInner, TimeInner>, Paused>,
},
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -86,7 +90,7 @@ impl Run{
timer: TimerFixed::new(time, Time::ZERO), timer: TimerFixed::new(time, Time::ZERO),
}; };
Ok(()) Ok(())
}, }
RunState::Started { .. } => Err(Error::AlreadyStarted), RunState::Started { .. } => Err(Error::AlreadyStarted),
RunState::Finished { .. } => Err(Error::AlreadyFinished), RunState::Finished { .. } => Err(Error::AlreadyFinished),
} }
@ -100,7 +104,7 @@ impl Run{
timer: timer.into_paused(time), timer: timer.into_paused(time),
}; };
Ok(()) Ok(())
}, }
RunState::Finished { .. } => Err(Error::AlreadyFinished), RunState::Finished { .. } => Err(Error::AlreadyFinished),
} }
} }

View File

@ -1,4 +1,4 @@
use crate::integer::{Time,Ratio64}; use crate::integer::{Ratio64, Time};
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct Paused; pub struct Paused;
@ -50,7 +50,8 @@ pub struct Scaled<In,Out>{
_out: core::marker::PhantomData<Out>, _out: core::marker::PhantomData<Out>,
} }
impl<In, Out> Scaled<In, Out> impl<In, Out> Scaled<In, Out>
where Time<In>:Copy, where
Time<In>: Copy,
{ {
pub const fn new(scale: Ratio64, offset: InnerTime) -> Self { pub const fn new(scale: Ratio64, offset: InnerTime) -> Self {
Self { Self {
@ -105,7 +106,8 @@ impl<In,Out> TimerState for Realtime<In,Out>{
} }
} }
impl<In, Out> TimerState for Scaled<In, Out> impl<In, Out> TimerState for Scaled<In, Out>
where Time<In>:Copy, where
Time<In>: Copy,
{ {
type In = In; type In = In;
type Out = Out; type Out = Out;
@ -134,7 +136,8 @@ pub struct TimerFixed<T:TimerState,P:PauseState>{
//scaled timer methods are generic across PauseState //scaled timer methods are generic across PauseState
impl<P: PauseState, In, Out> TimerFixed<Scaled<In, Out>, P> impl<P: PauseState, In, Out> TimerFixed<Scaled<In, Out>, P>
where Time<In>:Copy, where
Time<In>: Copy,
{ {
pub fn scaled(time: Time<In>, new_time: Time<Out>, scale: Ratio64) -> Self { pub fn scaled(time: Time<In>, new_time: Time<Out>, scale: Ratio64) -> Self {
let mut timer = Self { let mut timer = Self {
@ -154,7 +157,8 @@ impl<P:PauseState,In,Out> TimerFixed<Scaled<In,Out>,P>
//pause and unpause is generic across TimerState //pause and unpause is generic across TimerState
impl<T: TimerState> TimerFixed<T, Paused> impl<T: TimerState> TimerFixed<T, Paused>
where Time<T::In>:Copy, where
Time<T::In>: Copy,
{ {
pub fn into_unpaused(self, time: Time<T::In>) -> TimerFixed<T, Unpaused> { pub fn into_unpaused(self, time: Time<T::In>) -> TimerFixed<T, Unpaused> {
let new_time = self.time(time); let new_time = self.time(time);
@ -167,7 +171,8 @@ impl<T:TimerState> TimerFixed<T,Paused>
} }
} }
impl<T: TimerState> TimerFixed<T, Unpaused> impl<T: TimerState> TimerFixed<T, Unpaused>
where Time<T::In>:Copy, where
Time<T::In>: Copy,
{ {
pub fn into_paused(self, time: Time<T::In>) -> TimerFixed<T, Paused> { pub fn into_paused(self, time: Time<T::In>) -> TimerFixed<T, Paused> {
let new_time = self.time(time); let new_time = self.time(time);
@ -295,7 +300,8 @@ impl<T:TimerState> Timer<T>
} }
//scaled timer methods are generic across PauseState //scaled timer methods are generic across PauseState
impl<In, Out> Timer<Scaled<In, Out>> impl<In, Out> Timer<Scaled<In, Out>>
where Time<In>:Copy, where
Time<In>: Copy,
{ {
pub const fn get_scale(&self) -> Ratio64 { pub const fn get_scale(&self) -> Ratio64 {
match self { match self {
@ -327,7 +333,10 @@ mod test{
#[test] #[test]
fn test_timerfixed_scaled() { fn test_timerfixed_scaled() {
//create a paused timer that reads 0s //create a paused timer that reads 0s
let timer=TimerFixed::<Scaled<Parent,Calculated>,Paused>::from_state(Scaled::new(0.5f32.try_into().unwrap(),sec!(0))); let timer = TimerFixed::<Scaled<Parent, Calculated>, Paused>::from_state(Scaled::new(
0.5f32.try_into().unwrap(),
sec!(0),
));
//the paused timer at 1 second should read 0s //the paused timer at 1 second should read 0s
assert_eq!(timer.time(sec!(1)), sec!(0)); assert_eq!(timer.time(sec!(1)), sec!(0));

View File

@ -18,7 +18,7 @@ struct Outer{
enum Update<I, U> { enum Update<I, U> {
Insert(I), Insert(I),
Update(U), Update(U),
Remove Remove,
} }
struct InnerUpdate { struct InnerUpdate {

View File

@ -1,4 +1,4 @@
use bnum::{BInt,cast::As}; use bnum::{cast::As, BInt};
#[derive(Clone, Copy, Debug, Default, Hash)] #[derive(Clone, Copy, Debug, Default, Hash)]
/// A Fixed point number for which multiply operations widen the bits in the output. (when the wide-mul feature is enabled) /// A Fixed point number for which multiply operations widen the bits in the output. (when the wide-mul feature is enabled)
@ -23,10 +23,8 @@ impl<const N:usize,const F:usize> Fixed<N,F>{
} }
impl<const N: usize, const F: usize> Fixed<N, F> { impl<const N: usize, const F: usize> Fixed<N, F> {
#[inline] #[inline]
pub const fn from_bits(bits:BInt::<N>)->Self{ pub const fn from_bits(bits: BInt<N>) -> Self {
Self{ Self { bits }
bits,
}
} }
#[inline] #[inline]
pub const fn to_bits(self) -> BInt<N> { pub const fn to_bits(self) -> BInt<N> {
@ -82,10 +80,7 @@ macro_rules! impl_from {
)* )*
}; };
} }
impl_from!( impl_from!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
u8,u16,u32,u64,u128,usize,
i8,i16,i32,i64,i128,isize
);
impl<const N: usize, const F: usize> PartialEq for Fixed<N, F> { impl<const N: usize, const F: usize> PartialEq for Fixed<N, F> {
#[inline] #[inline]
@ -96,7 +91,7 @@ impl<const N:usize,const F:usize> PartialEq for Fixed<N,F>{
impl<const N: usize, const F: usize, T> PartialEq<T> for Fixed<N, F> impl<const N: usize, const F: usize, T> PartialEq<T> for Fixed<N, F>
where where
T: Copy, T: Copy,
BInt::<N>:From<T>, BInt<N>: From<T>,
{ {
#[inline] #[inline]
fn eq(&self, &other: &T) -> bool { fn eq(&self, &other: &T) -> bool {
@ -114,7 +109,7 @@ impl<const N:usize,const F:usize> PartialOrd for Fixed<N,F>{
impl<const N: usize, const F: usize, T> PartialOrd<T> for Fixed<N, F> impl<const N: usize, const F: usize, T> PartialOrd<T> for Fixed<N, F>
where where
T: Copy, T: Copy,
BInt::<N>:From<T>, BInt<N>: From<T>,
{ {
#[inline] #[inline]
fn partial_cmp(&self, &other: &T) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, &other: &T) -> Option<std::cmp::Ordering> {
@ -161,7 +156,11 @@ macro_rules! impl_into_float {
const DIGIT_SHIFT: u32 = 6; //Log2[64] const DIGIT_SHIFT: u32 = 6; //Log2[64]
// SBBB BBBB // SBBB BBBB
// 1001 1110 0000 0000 // 1001 1110 0000 0000
let sign=if self.bits.is_negative(){(1 as $unsigned)<<(<$unsigned>::BITS-1)}else{0}; let sign = if self.bits.is_negative() {
(1 as $unsigned) << (<$unsigned>::BITS - 1)
} else {
0
};
let unsigned = self.bits.unsigned_abs(); let unsigned = self.bits.unsigned_abs();
let most_significant_bit = unsigned.bits(); let most_significant_bit = unsigned.bits();
let exp = if unsigned.is_zero() { let exp = if unsigned.is_zero() {
@ -192,7 +191,7 @@ macro_rules! impl_into_float {
<$output>::from_bits(bits) <$output>::from_bits(bits)
} }
} }
} };
} }
impl_into_float!(f32, u32, 8, 24); impl_into_float!(f32, u32, 8, 24);
impl_into_float!(f64, u64, 11, 53); impl_into_float!(f64, u64, 11, 53);
@ -251,9 +250,7 @@ macro_rules! impl_from_float {
std::num::FpCategory::Nan => Err(FixedFromFloatError::Nan), std::num::FpCategory::Nan => Err(FixedFromFloatError::Nan),
std::num::FpCategory::Infinite => Err(FixedFromFloatError::Infinite), std::num::FpCategory::Infinite => Err(FixedFromFloatError::Infinite),
std::num::FpCategory::Zero => Ok(Self::ZERO), std::num::FpCategory::Zero => Ok(Self::ZERO),
std::num::FpCategory::Subnormal std::num::FpCategory::Subnormal | std::num::FpCategory::Normal => {
|std::num::FpCategory::Normal
=>{
let (m, e, s) = $decode(value); let (m, e, s) = $decode(value);
let mut digits = [0u64; N]; let mut digits = [0u64; N];
let most_significant_bit = e as i32 + $mantissa_bits as i32 + F as i32; let most_significant_bit = e as i32 + $mantissa_bits as i32 + F as i32;
@ -261,15 +258,19 @@ macro_rules! impl_from_float {
return Err(FixedFromFloatError::Underflow); return Err(FixedFromFloatError::Underflow);
} }
let digit_index = most_significant_bit >> DIGIT_SHIFT; let digit_index = most_significant_bit >> DIGIT_SHIFT;
let digit=digits.get_mut(digit_index as usize).ok_or(FixedFromFloatError::Overflow)?; let digit = digits
.get_mut(digit_index as usize)
.ok_or(FixedFromFloatError::Overflow)?;
let take_bits = most_significant_bit - (digit_index << DIGIT_SHIFT); let take_bits = most_significant_bit - (digit_index << DIGIT_SHIFT);
let rest_of_mantissa = -($mantissa_bits as i32 - (take_bits as i32)); let rest_of_mantissa = -($mantissa_bits as i32 - (take_bits as i32));
*digit = signed_shift(m, rest_of_mantissa); *digit = signed_shift(m, rest_of_mantissa);
if rest_of_mantissa < 0 && digit_index != 0 { if rest_of_mantissa < 0 && digit_index != 0 {
//we don't care if some float bits are partially truncated //we don't care if some float bits are partially truncated
if let Some(digit) = digits.get_mut((digit_index - 1) as usize) { if let Some(digit) = digits.get_mut((digit_index - 1) as usize) {
let take_bits=most_significant_bit-((digit_index-1)<<DIGIT_SHIFT); let take_bits =
let rest_of_mantissa=-($mantissa_bits as i32-(take_bits as i32)); most_significant_bit - ((digit_index - 1) << DIGIT_SHIFT);
let rest_of_mantissa =
-($mantissa_bits as i32 - (take_bits as i32));
*digit = signed_shift(m, rest_of_mantissa); *digit = signed_shift(m, rest_of_mantissa);
} }
} }
@ -279,11 +280,11 @@ macro_rules! impl_from_float {
} else { } else {
Self::from_bits(bits) Self::from_bits(bits)
}) })
},
} }
} }
} }
} }
};
} }
impl_from_float!(integer_decode_f32, f32, 24); impl_from_float!(integer_decode_f32, f32, 24);
impl_from_float!(integer_decode_f64, f64, 53); impl_from_float!(integer_decode_f64, f64, 53);
@ -313,7 +314,7 @@ macro_rules! impl_additive_operator {
} }
impl<const N: usize, const F: usize, U> core::ops::$trait<U> for $struct<N, F> impl<const N: usize, const F: usize, U> core::ops::$trait<U> for $struct<N, F>
where where
BInt::<N>:From<U>, BInt<N>: From<U>,
{ {
type Output = $output; type Output = $output;
#[inline] #[inline]
@ -333,7 +334,7 @@ macro_rules! impl_additive_assign_operator {
} }
impl<const N: usize, const F: usize, U> core::ops::$trait<U> for $struct<N, F> impl<const N: usize, const F: usize, U> core::ops::$trait<U> for $struct<N, F>
where where
BInt::<N>:From<U>, BInt<N>: From<U>,
{ {
#[inline] #[inline]
fn $method(&mut self, other: U) { fn $method(&mut self, other: U) {
@ -406,7 +407,10 @@ macro_rules! impl_multiply_operator_not_const_generic {
} }
} }
#[cfg(not(feature = "wide-mul"))] #[cfg(not(feature = "wide-mul"))]
impl_multiplicative_operator_not_const_generic!(($struct, $trait, $method, $output ), $width); impl_multiplicative_operator_not_const_generic!(
($struct, $trait, $method, $output),
$width
);
#[cfg(feature = "deferred-division")] #[cfg(feature = "deferred-division")]
impl ratio_ops::ratio::Divide<i64> for Fixed<$width, { $width * 32 }> { impl ratio_ops::ratio::Divide<i64> for Fixed<$width, { $width * 32 }> {
type Output = Self; type Output = Self;
@ -415,7 +419,7 @@ macro_rules! impl_multiply_operator_not_const_generic {
Self::from_bits(self.bits.div_euclid(BInt::from(other))) Self::from_bits(self.bits.div_euclid(BInt::from(other)))
} }
} }
} };
} }
macro_rules! impl_divide_operator_not_const_generic { macro_rules! impl_divide_operator_not_const_generic {
( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => { ( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => {
@ -431,7 +435,10 @@ macro_rules! impl_divide_operator_not_const_generic {
} }
} }
#[cfg(all(not(feature = "wide-mul"), not(feature = "deferred-division")))] #[cfg(all(not(feature = "wide-mul"), not(feature = "deferred-division")))]
impl_multiplicative_operator_not_const_generic!(($struct, $trait, $method, $output ), $width); impl_multiplicative_operator_not_const_generic!(
($struct, $trait, $method, $output),
$width
);
#[cfg(all(not(feature = "wide-mul"), feature = "deferred-division"))] #[cfg(all(not(feature = "wide-mul"), feature = "deferred-division"))]
impl<const F: usize> ratio_ops::ratio::Divide for $struct<$width, F> { impl<const F: usize> ratio_ops::ratio::Divide for $struct<$width, F> {
type Output = $output; type Output = $output;
@ -449,7 +456,7 @@ macro_rules! impl_multiplicative_operator {
( $struct: ident, $trait: ident, $method: ident, $inner_method: ident, $output: ty ) => { ( $struct: ident, $trait: ident, $method: ident, $inner_method: ident, $output: ty ) => {
impl<const N: usize, const F: usize, U> core::ops::$trait<U> for $struct<N, F> impl<const N: usize, const F: usize, U> core::ops::$trait<U> for $struct<N, F>
where where
BInt::<N>:From<U>+core::ops::$trait, BInt<N>: From<U> + core::ops::$trait,
{ {
type Output = $output; type Output = $output;
#[inline] #[inline]
@ -463,7 +470,7 @@ macro_rules! impl_multiplicative_assign_operator {
( $struct: ident, $trait: ident, $method: ident, $not_assign_method: ident ) => { ( $struct: ident, $trait: ident, $method: ident, $not_assign_method: ident ) => {
impl<const N: usize, const F: usize, U> core::ops::$trait<U> for $struct<N, F> impl<const N: usize, const F: usize, U> core::ops::$trait<U> for $struct<N, F>
where where
BInt::<N>:From<U>+core::ops::$trait, BInt<N>: From<U> + core::ops::$trait,
{ {
#[inline] #[inline]
fn $method(&mut self, other: U) { fn $method(&mut self, other: U) {
@ -488,19 +495,33 @@ macro_rules! macro_repeated{
macro_rules! macro_16 { macro_rules! macro_16 {
( $macro: ident, $any:tt ) => { ( $macro: ident, $any:tt ) => {
macro_repeated!($macro, $any, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); macro_repeated!($macro, $any, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
} };
} }
macro_16!( impl_multiplicative_assign_operator_not_const_generic, (Fixed, MulAssign, mul_assign, mul) ); macro_16!(
macro_16!( impl_multiply_operator_not_const_generic, (Fixed, Mul, mul, Self) ); impl_multiplicative_assign_operator_not_const_generic,
macro_16!( impl_multiplicative_assign_operator_not_const_generic, (Fixed, DivAssign, div_assign, div) ); (Fixed, MulAssign, mul_assign, mul)
macro_16!( impl_divide_operator_not_const_generic, (Fixed, Div, div, Self) ); );
macro_16!(
impl_multiply_operator_not_const_generic,
(Fixed, Mul, mul, Self)
);
macro_16!(
impl_multiplicative_assign_operator_not_const_generic,
(Fixed, DivAssign, div_assign, div)
);
macro_16!(
impl_divide_operator_not_const_generic,
(Fixed, Div, div, Self)
);
impl_multiplicative_assign_operator!(Fixed, MulAssign, mul_assign, mul); impl_multiplicative_assign_operator!(Fixed, MulAssign, mul_assign, mul);
impl_multiplicative_operator!(Fixed, Mul, mul, mul, Self); impl_multiplicative_operator!(Fixed, Mul, mul, mul, Self);
impl_multiplicative_assign_operator!(Fixed, DivAssign, div_assign, div_euclid); impl_multiplicative_assign_operator!(Fixed, DivAssign, div_assign, div_euclid);
impl_multiplicative_operator!(Fixed, Div, div, div_euclid, Self); impl_multiplicative_operator!(Fixed, Div, div, div_euclid, Self);
#[cfg(feature = "deferred-division")] #[cfg(feature = "deferred-division")]
impl<const LHS_N:usize,const LHS_F:usize,const RHS_N:usize,const RHS_F:usize> core::ops::Div<Fixed<RHS_N,RHS_F>> for Fixed<LHS_N,LHS_F>{ impl<const LHS_N: usize, const LHS_F: usize, const RHS_N: usize, const RHS_F: usize>
core::ops::Div<Fixed<RHS_N, RHS_F>> for Fixed<LHS_N, LHS_F>
{
type Output = ratio_ops::ratio::Ratio<Fixed<LHS_N, LHS_F>, Fixed<RHS_N, RHS_F>>; type Output = ratio_ops::ratio::Ratio<Fixed<LHS_N, LHS_F>, Fixed<RHS_N, RHS_F>>;
#[inline] #[inline]
fn div(self, other: Fixed<RHS_N, RHS_F>) -> Self::Output { fn div(self, other: Fixed<RHS_N, RHS_F>) -> Self::Output {
@ -573,7 +594,7 @@ macro_rules! impl_wide_operators{
} }
} }
} }
} };
} }
// WIDE MUL: multiply into a wider type // WIDE MUL: multiply into a wider type
@ -648,26 +669,133 @@ macro_rules! impl_wide_same_size_not_const_generic{
//const generics sidestepped wahoo //const generics sidestepped wahoo
macro_repeated!( macro_repeated!(
impl_wide_not_const_generic,(), impl_wide_not_const_generic,
(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1), (),
(1,2), (3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2), (2, 1),
(1,3),(2,3), (4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3), (3, 1),
(1,4),(2,4),(3,4), (5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4), (4, 1),
(1,5),(2,5),(3,5),(4,5), (6,5),(7,5),(8,5),(9,5),(10,5),(11,5), (5, 1),
(1,6),(2,6),(3,6),(4,6),(5,6), (7,6),(8,6),(9,6),(10,6), (6, 1),
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7), (8,7),(9,7), (7, 1),
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8), (9,8), (8, 1),
(1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9), (9, 1),
(1,10),(2,10),(3,10),(4,10),(5,10),(6,10), (10, 1),
(1,11),(2,11),(3,11),(4,11),(5,11), (11, 1),
(1,12),(2,12),(3,12),(4,12), (12, 1),
(1,13),(2,13),(3,13), (13, 1),
(1,14),(2,14), (14, 1),
(15, 1),
(1, 2),
(3, 2),
(4, 2),
(5, 2),
(6, 2),
(7, 2),
(8, 2),
(9, 2),
(10, 2),
(11, 2),
(12, 2),
(13, 2),
(14, 2),
(1, 3),
(2, 3),
(4, 3),
(5, 3),
(6, 3),
(7, 3),
(8, 3),
(9, 3),
(10, 3),
(11, 3),
(12, 3),
(13, 3),
(1, 4),
(2, 4),
(3, 4),
(5, 4),
(6, 4),
(7, 4),
(8, 4),
(9, 4),
(10, 4),
(11, 4),
(12, 4),
(1, 5),
(2, 5),
(3, 5),
(4, 5),
(6, 5),
(7, 5),
(8, 5),
(9, 5),
(10, 5),
(11, 5),
(1, 6),
(2, 6),
(3, 6),
(4, 6),
(5, 6),
(7, 6),
(8, 6),
(9, 6),
(10, 6),
(1, 7),
(2, 7),
(3, 7),
(4, 7),
(5, 7),
(6, 7),
(8, 7),
(9, 7),
(1, 8),
(2, 8),
(3, 8),
(4, 8),
(5, 8),
(6, 8),
(7, 8),
(9, 8),
(1, 9),
(2, 9),
(3, 9),
(4, 9),
(5, 9),
(6, 9),
(7, 9),
(1, 10),
(2, 10),
(3, 10),
(4, 10),
(5, 10),
(6, 10),
(1, 11),
(2, 11),
(3, 11),
(4, 11),
(5, 11),
(1, 12),
(2, 12),
(3, 12),
(4, 12),
(1, 13),
(2, 13),
(3, 13),
(1, 14),
(2, 14),
(1, 15) (1, 15)
); );
macro_repeated!( macro_repeated!(
impl_wide_same_size_not_const_generic,(), impl_wide_same_size_not_const_generic,
1,2,3,4,5,6,7,8 (),
1,
2,
3,
4,
5,
6,
7,
8
); );
pub trait Fix<Out> { pub trait Fix<Out> {
@ -725,8 +853,7 @@ macro_rules! impl_fix_lhs_eq_rhs_not_const_generic{
(), (),
($lhs:expr,$rhs:expr) ($lhs:expr,$rhs:expr)
) => { ) => {
impl Fixed<$lhs,{$lhs*32}> impl Fixed<$lhs, { $lhs * 32 }> {
{
paste::item! { paste::item! {
#[inline] #[inline]
pub fn [<fix_ $rhs>](self)->Fixed<$rhs,{$rhs*32}>{ pub fn [<fix_ $rhs>](self)->Fixed<$rhs,{$rhs*32}>{
@ -741,50 +868,279 @@ macro_rules! impl_fix_lhs_eq_rhs_not_const_generic{
} }
} }
} }
} };
} }
// I LOVE NOT BEING ABLE TO USE CONST GENERICS // I LOVE NOT BEING ABLE TO USE CONST GENERICS
macro_repeated!( macro_repeated!(
impl_fix_rhs_lt_lhs_not_const_generic,(), impl_fix_rhs_lt_lhs_not_const_generic,
(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1),(16,1),(17,1), (),
(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2), (2, 1),
(4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3),(14,3),(15,3),(16,3), (3, 1),
(5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4),(13,4),(14,4),(15,4),(16,4), (4, 1),
(6,5),(7,5),(8,5),(9,5),(10,5),(11,5),(12,5),(13,5),(14,5),(15,5),(16,5), (5, 1),
(7,6),(8,6),(9,6),(10,6),(11,6),(12,6),(13,6),(14,6),(15,6),(16,6), (6, 1),
(8,7),(9,7),(10,7),(11,7),(12,7),(13,7),(14,7),(15,7),(16,7), (7, 1),
(9,8),(10,8),(11,8),(12,8),(13,8),(14,8),(15,8),(16,8), (8, 1),
(10,9),(11,9),(12,9),(13,9),(14,9),(15,9),(16,9), (9, 1),
(11,10),(12,10),(13,10),(14,10),(15,10),(16,10), (10, 1),
(12,11),(13,11),(14,11),(15,11),(16,11), (11, 1),
(13,12),(14,12),(15,12),(16,12), (12, 1),
(14,13),(15,13),(16,13), (13, 1),
(15,14),(16,14), (14, 1),
(15, 1),
(16, 1),
(17, 1),
(3, 2),
(4, 2),
(5, 2),
(6, 2),
(7, 2),
(8, 2),
(9, 2),
(10, 2),
(11, 2),
(12, 2),
(13, 2),
(14, 2),
(15, 2),
(16, 2),
(4, 3),
(5, 3),
(6, 3),
(7, 3),
(8, 3),
(9, 3),
(10, 3),
(11, 3),
(12, 3),
(13, 3),
(14, 3),
(15, 3),
(16, 3),
(5, 4),
(6, 4),
(7, 4),
(8, 4),
(9, 4),
(10, 4),
(11, 4),
(12, 4),
(13, 4),
(14, 4),
(15, 4),
(16, 4),
(6, 5),
(7, 5),
(8, 5),
(9, 5),
(10, 5),
(11, 5),
(12, 5),
(13, 5),
(14, 5),
(15, 5),
(16, 5),
(7, 6),
(8, 6),
(9, 6),
(10, 6),
(11, 6),
(12, 6),
(13, 6),
(14, 6),
(15, 6),
(16, 6),
(8, 7),
(9, 7),
(10, 7),
(11, 7),
(12, 7),
(13, 7),
(14, 7),
(15, 7),
(16, 7),
(9, 8),
(10, 8),
(11, 8),
(12, 8),
(13, 8),
(14, 8),
(15, 8),
(16, 8),
(10, 9),
(11, 9),
(12, 9),
(13, 9),
(14, 9),
(15, 9),
(16, 9),
(11, 10),
(12, 10),
(13, 10),
(14, 10),
(15, 10),
(16, 10),
(12, 11),
(13, 11),
(14, 11),
(15, 11),
(16, 11),
(13, 12),
(14, 12),
(15, 12),
(16, 12),
(14, 13),
(15, 13),
(16, 13),
(15, 14),
(16, 14),
(16, 15) (16, 15)
); );
macro_repeated!( macro_repeated!(
impl_fix_lhs_lt_rhs_not_const_generic,(), impl_fix_lhs_lt_rhs_not_const_generic,
(),
(1, 2), (1, 2),
(1,3),(2,3), (1, 3),
(1,4),(2,4),(3,4), (2, 3),
(1,5),(2,5),(3,5),(4,5), (1, 4),
(1,6),(2,6),(3,6),(4,6),(5,6), (2, 4),
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7), (3, 4),
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8), (1, 5),
(1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9),(8,9), (2, 5),
(1,10),(2,10),(3,10),(4,10),(5,10),(6,10),(7,10),(8,10),(9,10), (3, 5),
(1,11),(2,11),(3,11),(4,11),(5,11),(6,11),(7,11),(8,11),(9,11),(10,11), (4, 5),
(1,12),(2,12),(3,12),(4,12),(5,12),(6,12),(7,12),(8,12),(9,12),(10,12),(11,12), (1, 6),
(1,13),(2,13),(3,13),(4,13),(5,13),(6,13),(7,13),(8,13),(9,13),(10,13),(11,13),(12,13), (2, 6),
(1,14),(2,14),(3,14),(4,14),(5,14),(6,14),(7,14),(8,14),(9,14),(10,14),(11,14),(12,14),(13,14), (3, 6),
(1,15),(2,15),(3,15),(4,15),(5,15),(6,15),(7,15),(8,15),(9,15),(10,15),(11,15),(12,15),(13,15),(14,15), (4, 6),
(1,16),(2,16),(3,16),(4,16),(5,16),(6,16),(7,16),(8,16),(9,16),(10,16),(11,16),(12,16),(13,16),(14,16),(15,16) (5, 6),
(1, 7),
(2, 7),
(3, 7),
(4, 7),
(5, 7),
(6, 7),
(1, 8),
(2, 8),
(3, 8),
(4, 8),
(5, 8),
(6, 8),
(7, 8),
(1, 9),
(2, 9),
(3, 9),
(4, 9),
(5, 9),
(6, 9),
(7, 9),
(8, 9),
(1, 10),
(2, 10),
(3, 10),
(4, 10),
(5, 10),
(6, 10),
(7, 10),
(8, 10),
(9, 10),
(1, 11),
(2, 11),
(3, 11),
(4, 11),
(5, 11),
(6, 11),
(7, 11),
(8, 11),
(9, 11),
(10, 11),
(1, 12),
(2, 12),
(3, 12),
(4, 12),
(5, 12),
(6, 12),
(7, 12),
(8, 12),
(9, 12),
(10, 12),
(11, 12),
(1, 13),
(2, 13),
(3, 13),
(4, 13),
(5, 13),
(6, 13),
(7, 13),
(8, 13),
(9, 13),
(10, 13),
(11, 13),
(12, 13),
(1, 14),
(2, 14),
(3, 14),
(4, 14),
(5, 14),
(6, 14),
(7, 14),
(8, 14),
(9, 14),
(10, 14),
(11, 14),
(12, 14),
(13, 14),
(1, 15),
(2, 15),
(3, 15),
(4, 15),
(5, 15),
(6, 15),
(7, 15),
(8, 15),
(9, 15),
(10, 15),
(11, 15),
(12, 15),
(13, 15),
(14, 15),
(1, 16),
(2, 16),
(3, 16),
(4, 16),
(5, 16),
(6, 16),
(7, 16),
(8, 16),
(9, 16),
(10, 16),
(11, 16),
(12, 16),
(13, 16),
(14, 16),
(15, 16)
); );
macro_repeated!( macro_repeated!(
impl_fix_lhs_eq_rhs_not_const_generic,(), impl_fix_lhs_eq_rhs_not_const_generic,
(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12),(13,13),(14,14),(15,15),(16,16) (),
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 10),
(11, 11),
(12, 12),
(13, 13),
(14, 14),
(15, 15),
(16, 16)
); );
macro_rules! impl_not_const_generic { macro_rules! impl_not_const_generic {
@ -836,7 +1192,7 @@ macro_rules! impl_not_const_generic{
} }
} }
} }
} };
} }
impl_not_const_generic!(1, 2); impl_not_const_generic!(1, 2);
impl_not_const_generic!(2, 4); impl_not_const_generic!(2, 4);

View File

@ -1,5 +1,5 @@
use crate::types::I32F32;
use crate::types::I256F256; use crate::types::I256F256;
use crate::types::I32F32;
#[test] #[test]
fn you_can_add_numbers() { fn you_can_add_numbers() {
@ -49,7 +49,9 @@ fn from_f32(){
let b: Result<I256F256, _> = 0.try_into(); let b: Result<I256F256, _> = 0.try_into();
assert_eq!(b, Ok(a)); assert_eq!(b, Ok(a));
let a = I256F256::from(0b101011110101001010101010000000000000000000000000000i64) << 16; let a = I256F256::from(0b101011110101001010101010000000000000000000000000000i64) << 16;
let b:Result<I256F256,_>=(0b101011110101001010101010000000000000000000000000000u64 as f32*2.0f32.powi(16)).try_into(); let b: Result<I256F256, _> = (0b101011110101001010101010000000000000000000000000000u64 as f32
* 2.0f32.powi(16))
.try_into();
assert_eq!(b, Ok(a)); assert_eq!(b, Ok(a));
//I32F32::MAX into f32 is truncated into this value //I32F32::MAX into f32 is truncated into this value
let a = I32F32::raw(0b111111111111111111111111000000000000000000000000000000000000000i64); let a = I32F32::raw(0b111111111111111111111111000000000000000000000000000000000000000i64);
@ -67,7 +69,9 @@ fn from_f32(){
assert_eq!(b, Err(crate::fixed::FixedFromFloatError::Underflow)); assert_eq!(b, Err(crate::fixed::FixedFromFloatError::Underflow));
//test many cases //test many cases
for i in 0..64 { for i in 0..64 {
let a=crate::fixed::Fixed::<2,64>::raw_digit(0b111111111111111111111111000000000000000000000000000000000000000i64)<<i; let a = crate::fixed::Fixed::<2, 64>::raw_digit(
0b111111111111111111111111000000000000000000000000000000000000000i64,
) << i;
let f: f32 = a.into(); let f: f32 = a.into();
let b: Result<crate::fixed::Fixed<2, 64>, _> = f.try_into(); let b: Result<crate::fixed::Fixed<2, 64>, _> = f.try_into();
assert_eq!(b, Ok(a)); assert_eq!(b, Ok(a));
@ -86,7 +90,9 @@ fn from_f64(){
let b: Result<I256F256, _> = 0.try_into(); let b: Result<I256F256, _> = 0.try_into();
assert_eq!(b, Ok(a)); assert_eq!(b, Ok(a));
let a = I256F256::from(0b101011110101001010101010000000000000000000000000000i64) << 16; let a = I256F256::from(0b101011110101001010101010000000000000000000000000000i64) << 16;
let b:Result<I256F256,_>=(0b101011110101001010101010000000000000000000000000000u64 as f64*2.0f64.powi(16)).try_into(); let b: Result<I256F256, _> = (0b101011110101001010101010000000000000000000000000000u64 as f64
* 2.0f64.powi(16))
.try_into();
assert_eq!(b, Ok(a)); assert_eq!(b, Ok(a));
} }
@ -198,9 +204,15 @@ fn test_zeroes_normal(){
// (x-1)*(x+1) // (x-1)*(x+1)
// x^2-1 // x^2-1
let zeroes = I32F32::zeroes2(I32F32::NEG_ONE, I32F32::ZERO, I32F32::ONE); let zeroes = I32F32::zeroes2(I32F32::NEG_ONE, I32F32::ZERO, I32F32::ONE);
assert_eq!(zeroes,arrayvec::ArrayVec::from_iter([I32F32::NEG_ONE,I32F32::ONE])); assert_eq!(
zeroes,
arrayvec::ArrayVec::from_iter([I32F32::NEG_ONE, I32F32::ONE])
);
let zeroes = I32F32::zeroes2(I32F32::NEG_ONE * 3, I32F32::ONE * 2, I32F32::ONE); let zeroes = I32F32::zeroes2(I32F32::NEG_ONE * 3, I32F32::ONE * 2, I32F32::ONE);
assert_eq!(zeroes,arrayvec::ArrayVec::from_iter([I32F32::NEG_ONE*3,I32F32::ONE])); assert_eq!(
zeroes,
arrayvec::ArrayVec::from_iter([I32F32::NEG_ONE * 3, I32F32::ONE])
);
} }
#[test] #[test]
#[cfg(all(feature = "zeroes", feature = "deferred-division"))] #[cfg(all(feature = "zeroes", feature = "deferred-division"))]

View File

@ -6,10 +6,16 @@ macro_rules! impl_zeroes{
($n:expr) => { ($n:expr) => {
impl Fixed<$n, { $n * 32 }> { impl Fixed<$n, { $n * 32 }> {
#[inline] #[inline]
pub fn zeroes2(a0:Self,a1:Self,a2:Self)->ArrayVec<<Self as core::ops::Div>::Output,2>{ pub fn zeroes2(
a0: Self,
a1: Self,
a2: Self,
) -> ArrayVec<<Self as core::ops::Div>::Output, 2> {
let a2pos = match a2.cmp(&Self::ZERO) { let a2pos = match a2.cmp(&Self::ZERO) {
Ordering::Greater => true, Ordering::Greater => true,
Ordering::Equal=>return ArrayVec::from_iter(Self::zeroes1(a0,a1).into_iter()), Ordering::Equal => {
return ArrayVec::from_iter(Self::zeroes1(a0, a1).into_iter())
}
Ordering::Less => false, Ordering::Less => false,
}; };
let radicand = a1 * a1 - a2 * a0 * 4; let radicand = a1 * a1 - a2 * a0 * 4;
@ -20,13 +26,25 @@ macro_rules! impl_zeroes{
} }
//sort roots ascending and avoid taking the difference of large numbers //sort roots ascending and avoid taking the difference of large numbers
let zeroes = match (a2pos, Self::ZERO < a1) { let zeroes = match (a2pos, Self::ZERO < a1) {
(true, true )=>[(-a1-planar_radicand)/(a2*2),(a0*2)/(-a1-planar_radicand)], (true, true) => [
(true, false)=>[(a0*2)/(-a1+planar_radicand),(-a1+planar_radicand)/(a2*2)], (-a1 - planar_radicand) / (a2 * 2),
(false,true )=>[(a0*2)/(-a1-planar_radicand),(-a1-planar_radicand)/(a2*2)], (a0 * 2) / (-a1 - planar_radicand),
(false,false)=>[(-a1+planar_radicand)/(a2*2),(a0*2)/(-a1+planar_radicand)], ],
(true, false) => [
(a0 * 2) / (-a1 + planar_radicand),
(-a1 + planar_radicand) / (a2 * 2),
],
(false, true) => [
(a0 * 2) / (-a1 - planar_radicand),
(-a1 - planar_radicand) / (a2 * 2),
],
(false, false) => [
(-a1 + planar_radicand) / (a2 * 2),
(a0 * 2) / (-a1 + planar_radicand),
],
}; };
ArrayVec::from_iter(zeroes) ArrayVec::from_iter(zeroes)
}, }
Ordering::Equal => ArrayVec::from_iter([(a1) / (a2 * -2)]), Ordering::Equal => ArrayVec::from_iter([(a1) / (a2 * -2)]),
Ordering::Less => ArrayVec::new_const(), Ordering::Less => ArrayVec::new_const(),
} }

View File

@ -1,7 +1,7 @@
mod macros; mod macros;
pub mod matrix;
pub mod types; pub mod types;
pub mod vector; pub mod vector;
pub mod matrix;
#[cfg(feature = "named-fields")] #[cfg(feature = "named-fields")]
mod named; mod named;

View File

@ -7,15 +7,24 @@ macro_rules! impl_fixed_wide_vector_not_const_generic {
) => { ) => {
impl<const N: usize> Vector<N, fixed_wide::fixed::Fixed<$n, { $n * 32 }>> { impl<const N: usize> Vector<N, fixed_wide::fixed::Fixed<$n, { $n * 32 }>> {
#[inline] #[inline]
pub fn length(self)-><fixed_wide::fixed::Fixed::<$n,{$n*32}> as core::ops::Mul>::Output{ pub fn length(
self,
) -> <fixed_wide::fixed::Fixed<$n, { $n * 32 }> as core::ops::Mul>::Output {
self.length_squared().sqrt_unchecked() self.length_squared().sqrt_unchecked()
} }
#[inline] #[inline]
pub fn with_length<U,V>(self,length:U)-><Vector<N,V> as core::ops::Div<<fixed_wide::fixed::Fixed::<$n,{$n*32}> as core::ops::Mul>::Output>>::Output pub fn with_length<U, V>(
self,
length: U,
) -> <Vector<N, V> as core::ops::Div<
<fixed_wide::fixed::Fixed<$n, { $n * 32 }> as core::ops::Mul>::Output,
>>::Output
where where
fixed_wide::fixed::Fixed<$n, { $n * 32 }>: core::ops::Mul<U, Output = V>, fixed_wide::fixed::Fixed<$n, { $n * 32 }>: core::ops::Mul<U, Output = V>,
U: Copy, U: Copy,
V:core::ops::Div<<fixed_wide::fixed::Fixed::<$n,{$n*32}> as core::ops::Mul>::Output>, V: core::ops::Div<
<fixed_wide::fixed::Fixed<$n, { $n * 32 }> as core::ops::Mul>::Output,
>,
{ {
self * length / self.length() self * length / self.length()
} }
@ -28,7 +37,7 @@ macro_rules! impl_fixed_wide_vector_not_const_generic {
macro_rules! macro_4 { macro_rules! macro_4 {
( $macro: ident, $any:tt ) => { ( $macro: ident, $any:tt ) => {
$crate::macro_repeated!($macro, $any, 1, 2, 3, 4); $crate::macro_repeated!($macro, $any, 1, 2, 3, 4);
} };
} }
#[doc(hidden)] #[doc(hidden)]
@ -38,23 +47,264 @@ macro_rules! impl_fixed_wide_vector {
$crate::macro_4!(impl_fixed_wide_vector_not_const_generic, ()); $crate::macro_4!(impl_fixed_wide_vector_not_const_generic, ());
// I LOVE NOT BEING ABLE TO USE CONST GENERICS // I LOVE NOT BEING ABLE TO USE CONST GENERICS
$crate::macro_repeated!( $crate::macro_repeated!(
impl_fix_not_const_generic,(), impl_fix_not_const_generic,
(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1),(16,1), (),
(1,2),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2), (1, 1),
(1,3),(2,3),(3,3),(4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3),(14,3),(15,3),(16,3), (2, 1),
(1,4),(2,4),(3,4),(4,4),(5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4),(13,4),(14,4),(15,4),(16,4), (3, 1),
(1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5),(8,5),(9,5),(10,5),(11,5),(12,5),(13,5),(14,5),(15,5),(16,5), (4, 1),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6),(8,6),(9,6),(10,6),(11,6),(12,6),(13,6),(14,6),(15,6),(16,6), (5, 1),
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7),(7,7),(8,7),(9,7),(10,7),(11,7),(12,7),(13,7),(14,7),(15,7),(16,7), (6, 1),
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),(8,8),(9,8),(10,8),(11,8),(12,8),(13,8),(14,8),(15,8),(16,8), (7, 1),
(1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9),(8,9),(9,9),(10,9),(11,9),(12,9),(13,9),(14,9),(15,9),(16,9), (8, 1),
(1,10),(2,10),(3,10),(4,10),(5,10),(6,10),(7,10),(8,10),(9,10),(10,10),(11,10),(12,10),(13,10),(14,10),(15,10),(16,10), (9, 1),
(1,11),(2,11),(3,11),(4,11),(5,11),(6,11),(7,11),(8,11),(9,11),(10,11),(11,11),(12,11),(13,11),(14,11),(15,11),(16,11), (10, 1),
(1,12),(2,12),(3,12),(4,12),(5,12),(6,12),(7,12),(8,12),(9,12),(10,12),(11,12),(12,12),(13,12),(14,12),(15,12),(16,12), (11, 1),
(1,13),(2,13),(3,13),(4,13),(5,13),(6,13),(7,13),(8,13),(9,13),(10,13),(11,13),(12,13),(13,13),(14,13),(15,13),(16,13), (12, 1),
(1,14),(2,14),(3,14),(4,14),(5,14),(6,14),(7,14),(8,14),(9,14),(10,14),(11,14),(12,14),(13,14),(14,14),(15,14),(16,14), (13, 1),
(1,15),(2,15),(3,15),(4,15),(5,15),(6,15),(7,15),(8,15),(9,15),(10,15),(11,15),(12,15),(13,15),(14,15),(15,15),(16,15), (14, 1),
(1,16),(2,16),(3,16),(4,16),(5,16),(6,16),(7,16),(8,16),(9,16),(10,16),(11,16),(12,16),(13,16),(14,16),(15,16),(16,16) (15, 1),
(16, 1),
(1, 2),
(2, 2),
(3, 2),
(4, 2),
(5, 2),
(6, 2),
(7, 2),
(8, 2),
(9, 2),
(10, 2),
(11, 2),
(12, 2),
(13, 2),
(14, 2),
(15, 2),
(16, 2),
(1, 3),
(2, 3),
(3, 3),
(4, 3),
(5, 3),
(6, 3),
(7, 3),
(8, 3),
(9, 3),
(10, 3),
(11, 3),
(12, 3),
(13, 3),
(14, 3),
(15, 3),
(16, 3),
(1, 4),
(2, 4),
(3, 4),
(4, 4),
(5, 4),
(6, 4),
(7, 4),
(8, 4),
(9, 4),
(10, 4),
(11, 4),
(12, 4),
(13, 4),
(14, 4),
(15, 4),
(16, 4),
(1, 5),
(2, 5),
(3, 5),
(4, 5),
(5, 5),
(6, 5),
(7, 5),
(8, 5),
(9, 5),
(10, 5),
(11, 5),
(12, 5),
(13, 5),
(14, 5),
(15, 5),
(16, 5),
(1, 6),
(2, 6),
(3, 6),
(4, 6),
(5, 6),
(6, 6),
(7, 6),
(8, 6),
(9, 6),
(10, 6),
(11, 6),
(12, 6),
(13, 6),
(14, 6),
(15, 6),
(16, 6),
(1, 7),
(2, 7),
(3, 7),
(4, 7),
(5, 7),
(6, 7),
(7, 7),
(8, 7),
(9, 7),
(10, 7),
(11, 7),
(12, 7),
(13, 7),
(14, 7),
(15, 7),
(16, 7),
(1, 8),
(2, 8),
(3, 8),
(4, 8),
(5, 8),
(6, 8),
(7, 8),
(8, 8),
(9, 8),
(10, 8),
(11, 8),
(12, 8),
(13, 8),
(14, 8),
(15, 8),
(16, 8),
(1, 9),
(2, 9),
(3, 9),
(4, 9),
(5, 9),
(6, 9),
(7, 9),
(8, 9),
(9, 9),
(10, 9),
(11, 9),
(12, 9),
(13, 9),
(14, 9),
(15, 9),
(16, 9),
(1, 10),
(2, 10),
(3, 10),
(4, 10),
(5, 10),
(6, 10),
(7, 10),
(8, 10),
(9, 10),
(10, 10),
(11, 10),
(12, 10),
(13, 10),
(14, 10),
(15, 10),
(16, 10),
(1, 11),
(2, 11),
(3, 11),
(4, 11),
(5, 11),
(6, 11),
(7, 11),
(8, 11),
(9, 11),
(10, 11),
(11, 11),
(12, 11),
(13, 11),
(14, 11),
(15, 11),
(16, 11),
(1, 12),
(2, 12),
(3, 12),
(4, 12),
(5, 12),
(6, 12),
(7, 12),
(8, 12),
(9, 12),
(10, 12),
(11, 12),
(12, 12),
(13, 12),
(14, 12),
(15, 12),
(16, 12),
(1, 13),
(2, 13),
(3, 13),
(4, 13),
(5, 13),
(6, 13),
(7, 13),
(8, 13),
(9, 13),
(10, 13),
(11, 13),
(12, 13),
(13, 13),
(14, 13),
(15, 13),
(16, 13),
(1, 14),
(2, 14),
(3, 14),
(4, 14),
(5, 14),
(6, 14),
(7, 14),
(8, 14),
(9, 14),
(10, 14),
(11, 14),
(12, 14),
(13, 14),
(14, 14),
(15, 14),
(16, 14),
(1, 15),
(2, 15),
(3, 15),
(4, 15),
(5, 15),
(6, 15),
(7, 15),
(8, 15),
(9, 15),
(10, 15),
(11, 15),
(12, 15),
(13, 15),
(14, 15),
(15, 15),
(16, 15),
(1, 16),
(2, 16),
(3, 16),
(4, 16),
(5, 16),
(6, 16),
(7, 16),
(8, 16),
(9, 16),
(10, 16),
(11, 16),
(12, 16),
(13, 16),
(14, 16),
(15, 16),
(16, 16)
); );
}; };
} }
@ -66,8 +316,7 @@ macro_rules! impl_fix_not_const_generic{
(), (),
($lhs:expr,$rhs:expr) ($lhs:expr,$rhs:expr)
) => { ) => {
impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<$lhs,{$lhs*32}>> impl<const N: usize> Vector<N, fixed_wide::fixed::Fixed<$lhs, { $lhs * 32 }>> {
{
paste::item! { paste::item! {
#[inline] #[inline]
pub fn [<fix_ $rhs>](self)->Vector<N,fixed_wide::fixed::Fixed<$rhs,{$rhs*32}>>{ pub fn [<fix_ $rhs>](self)->Vector<N,fixed_wide::fixed::Fixed<$rhs,{$rhs*32}>>{
@ -75,5 +324,5 @@ macro_rules! impl_fix_not_const_generic{
} }
} }
} }
} };
} }

View File

@ -12,32 +12,25 @@ macro_rules! impl_matrix {
self.array self.array
} }
#[inline] #[inline]
pub fn from_cols(cols:[Vector<Y,T>;X])->Self pub fn from_cols(cols: [Vector<Y, T>; X]) -> Self {
{ Matrix::new(cols.map(|col| col.array))
Matrix::new(
cols.map(|col|col.array),
)
} }
#[inline] #[inline]
pub fn map<F, U>(self, f: F) -> Matrix<X, Y, U> pub fn map<F, U>(self, f: F) -> Matrix<X, Y, U>
where where
F:Fn(T)->U F: Fn(T) -> U,
{ {
Matrix::new( Matrix::new(self.array.map(|inner| inner.map(&f)))
self.array.map(|inner|inner.map(&f)),
)
} }
#[inline] #[inline]
pub fn transpose(self) -> Matrix<Y, X, T> { pub fn transpose(self) -> Matrix<Y, X, T> {
//how did I think of this //how did I think of this
let mut array_of_iterators = self.array.map(|axis| axis.into_iter()); let mut array_of_iterators = self.array.map(|axis| axis.into_iter());
Matrix::new( Matrix::new(core::array::from_fn(|_| {
core::array::from_fn(|_| array_of_iterators
array_of_iterators.each_mut().map(|iter| .each_mut()
iter.next().unwrap() .map(|iter| iter.next().unwrap())
) }))
)
)
} }
#[inline] #[inline]
// old (list of rows) MatY<VecX>.MatX<VecZ> = MatY<VecZ> // old (list of rows) MatY<VecX>.MatX<VecZ> = MatY<VecZ>
@ -50,16 +43,15 @@ macro_rules! impl_matrix {
{ {
let mut array_of_iterators = self.array.map(|axis| axis.into_iter().cycle()); let mut array_of_iterators = self.array.map(|axis| axis.into_iter().cycle());
Matrix { Matrix {
array:rhs.array.map(|rhs_axis| array: rhs.array.map(|rhs_axis| {
core::array::from_fn(|_| core::array::from_fn(|_| {
array_of_iterators array_of_iterators
.iter_mut() .iter_mut()
.zip(rhs_axis.iter()) .zip(rhs_axis.iter())
.map(|(lhs_iter,&rhs_value)| .map(|(lhs_iter, &rhs_value)| lhs_iter.next().unwrap() * rhs_value)
lhs_iter.next().unwrap()*rhs_value .sum()
).sum() })
) }),
)
} }
} }
#[inline] #[inline]
@ -71,21 +63,18 @@ macro_rules! impl_matrix {
U: Copy, U: Copy,
{ {
let mut array_of_iterators = self.array.map(|axis| axis.into_iter()); let mut array_of_iterators = self.array.map(|axis| axis.into_iter());
Vector::new( Vector::new(core::array::from_fn(|_| {
core::array::from_fn(|_|
array_of_iterators array_of_iterators
.iter_mut() .iter_mut()
.zip(rhs.array.iter()) .zip(rhs.array.iter())
.map(|(lhs_iter,&rhs_value)| .map(|(lhs_iter, &rhs_value)| lhs_iter.next().unwrap() * rhs_value)
lhs_iter.next().unwrap()*rhs_value .sum()
).sum() }))
)
)
} }
} }
impl<const X: usize, const Y: usize, T> Matrix<X, Y, T> impl<const X: usize, const Y: usize, T> Matrix<X, Y, T>
where where
T:Copy T: Copy,
{ {
#[inline(always)] #[inline(always)]
pub const fn from_value(value: T) -> Self { pub const fn from_value(value: T) -> Self {
@ -96,13 +85,15 @@ macro_rules! impl_matrix {
impl<const X: usize, const Y: usize, T: Default> Default for Matrix<X, Y, T> { impl<const X: usize, const Y: usize, T: Default> Default for Matrix<X, Y, T> {
#[inline] #[inline]
fn default() -> Self { fn default() -> Self {
Self::new( Self::new(core::array::from_fn(|_| {
core::array::from_fn(|_|core::array::from_fn(|_|Default::default())) core::array::from_fn(|_| Default::default())
) }))
} }
} }
impl<const X:usize,const Y:usize,T:core::fmt::Display> core::fmt::Display for Matrix<X,Y,T>{ impl<const X: usize, const Y: usize, T: core::fmt::Display> core::fmt::Display
for Matrix<X, Y, T>
{
#[inline] #[inline]
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
for col in &self.array[0..X] { for col in &self.array[0..X] {
@ -117,7 +108,8 @@ macro_rules! impl_matrix {
} }
} }
impl<const X:usize,const Y:usize,const Z:usize,T,U,V> core::ops::Mul<Matrix<Z,X,U>> for Matrix<X,Y,T> impl<const X: usize, const Y: usize, const Z: usize, T, U, V>
core::ops::Mul<Matrix<Z, X, U>> for Matrix<X, Y, T>
where where
T: core::ops::Mul<U, Output = V> + Copy, T: core::ops::Mul<U, Output = V> + Copy,
V: core::iter::Sum, V: core::iter::Sum,
@ -129,7 +121,8 @@ macro_rules! impl_matrix {
self.dot(rhs) self.dot(rhs)
} }
} }
impl<const X:usize,const Y:usize,T,U,V> core::ops::Mul<Vector<X,U>> for Matrix<X,Y,T> impl<const X: usize, const Y: usize, T, U, V> core::ops::Mul<Vector<X, U>>
for Matrix<X, Y, T>
where where
T: core::ops::Mul<U, Output = V>, T: core::ops::Mul<U, Output = V>,
V: core::iter::Sum, V: core::iter::Sum,
@ -143,14 +136,21 @@ macro_rules! impl_matrix {
} }
#[cfg(feature = "deferred-division")] #[cfg(feature = "deferred-division")]
$crate::impl_matrix_deferred_division!(); $crate::impl_matrix_deferred_division!();
} };
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_matrix_deferred_division { macro_rules! impl_matrix_deferred_division {
() => { () => {
impl<const X:usize,const Y:usize,T:ratio_ops::ratio::Divide<U,Output=V>,U:Copy,V> ratio_ops::ratio::Divide<U> for Matrix<X,Y,T>{ impl<
const X: usize,
const Y: usize,
T: ratio_ops::ratio::Divide<U, Output = V>,
U: Copy,
V,
> ratio_ops::ratio::Divide<U> for Matrix<X, Y, T>
{
type Output = Matrix<X, Y, V>; type Output = Matrix<X, Y, V>;
#[inline] #[inline]
fn divide(self, rhs: U) -> Self::Output { fn divide(self, rhs: U) -> Self::Output {
@ -164,7 +164,7 @@ macro_rules! impl_matrix_deferred_division {
ratio_ops::ratio::Ratio::new(self, rhs) ratio_ops::ratio::Ratio::new(self, rhs)
} }
} }
} };
} }
#[doc(hidden)] #[doc(hidden)]
@ -175,22 +175,20 @@ macro_rules! impl_matrix_extend {
#[inline] #[inline]
pub fn extend_column(self, value: Vector<$y, T>) -> Matrix<{ $x + 1 }, $y, T> { pub fn extend_column(self, value: Vector<$y, T>) -> Matrix<{ $x + 1 }, $y, T> {
let mut iter = self.array.into_iter().chain(core::iter::once(value.array)); let mut iter = self.array.into_iter().chain(core::iter::once(value.array));
Matrix::new( Matrix::new(core::array::from_fn(|_| iter.next().unwrap()))
core::array::from_fn(|_|iter.next().unwrap()),
)
} }
#[inline] #[inline]
pub fn extend_row(self, value: Vector<$x, T>) -> Matrix<$x, { $y + 1 }, T> { pub fn extend_row(self, value: Vector<$x, T>) -> Matrix<$x, { $y + 1 }, T> {
let mut iter_rows = value.array.into_iter(); let mut iter_rows = value.array.into_iter();
Matrix::new( Matrix::new(self.array.map(|axis| {
self.array.map(|axis|{ let mut elements_iter = axis
let mut elements_iter=axis.into_iter().chain(core::iter::once(iter_rows.next().unwrap())); .into_iter()
.chain(core::iter::once(iter_rows.next().unwrap()));
core::array::from_fn(|_| elements_iter.next().unwrap()) core::array::from_fn(|_| elements_iter.next().unwrap())
}) }))
)
}
} }
} }
};
} }
#[doc(hidden)] #[doc(hidden)]
@ -213,7 +211,7 @@ macro_rules! impl_matrix_named_fields_shape {
unsafe { core::mem::transmute(&mut self.array) } unsafe { core::mem::transmute(&mut self.array) }
} }
} }
} };
} }
#[doc(hidden)] #[doc(hidden)]
@ -262,11 +260,23 @@ macro_rules! impl_matrix_3x3 {
{ {
pub fn adjugate(self) -> Matrix<3, 3, <T2 as core::ops::Sub>::Output> { pub fn adjugate(self) -> Matrix<3, 3, <T2 as core::ops::Sub>::Output> {
Matrix::new([ Matrix::new([
[self.y_axis.y*self.z_axis.z-self.y_axis.z*self.z_axis.y,self.x_axis.z*self.z_axis.y-self.x_axis.y*self.z_axis.z,self.x_axis.y*self.y_axis.z-self.x_axis.z*self.y_axis.y], [
[self.y_axis.z*self.z_axis.x-self.y_axis.x*self.z_axis.z,self.x_axis.x*self.z_axis.z-self.x_axis.z*self.z_axis.x,self.x_axis.z*self.y_axis.x-self.x_axis.x*self.y_axis.z], self.y_axis.y * self.z_axis.z - self.y_axis.z * self.z_axis.y,
[self.y_axis.x*self.z_axis.y-self.y_axis.y*self.z_axis.x,self.x_axis.y*self.z_axis.x-self.x_axis.x*self.z_axis.y,self.x_axis.x*self.y_axis.y-self.x_axis.y*self.y_axis.x], self.x_axis.z * self.z_axis.y - self.x_axis.y * self.z_axis.z,
self.x_axis.y * self.y_axis.z - self.x_axis.z * self.y_axis.y,
],
[
self.y_axis.z * self.z_axis.x - self.y_axis.x * self.z_axis.z,
self.x_axis.x * self.z_axis.z - self.x_axis.z * self.z_axis.x,
self.x_axis.z * self.y_axis.x - self.x_axis.x * self.y_axis.z,
],
[
self.y_axis.x * self.z_axis.y - self.y_axis.y * self.z_axis.x,
self.x_axis.y * self.z_axis.x - self.x_axis.x * self.z_axis.y,
self.x_axis.x * self.y_axis.y - self.x_axis.y * self.y_axis.x,
],
]) ])
} }
} }
} };
} }

View File

@ -1,6 +1,6 @@
pub mod common; pub mod common;
pub mod vector;
pub mod matrix; pub mod matrix;
pub mod vector;
#[cfg(feature = "fixed-wide")] #[cfg(feature = "fixed-wide")]
pub mod fixed_wide; pub mod fixed_wide;

View File

@ -14,11 +14,9 @@ macro_rules! impl_vector {
#[inline] #[inline]
pub fn map<F, U>(self, f: F) -> Vector<N, U> pub fn map<F, U>(self, f: F) -> Vector<N, U>
where where
F:Fn(T)->U F: Fn(T) -> U,
{ {
Vector::new( Vector::new(self.array.map(f))
self.array.map(f)
)
} }
#[inline] #[inline]
pub fn map_zip<F, U, V>(self, other: Vector<N, U>, f: F) -> Vector<N, V> pub fn map_zip<F, U, V>(self, other: Vector<N, U>, f: F) -> Vector<N, V>
@ -26,9 +24,7 @@ macro_rules! impl_vector {
F: Fn((T, U)) -> V, F: Fn((T, U)) -> V,
{ {
let mut iter = self.array.into_iter().zip(other.array); let mut iter = self.array.into_iter().zip(other.array);
Vector::new( Vector::new(core::array::from_fn(|_| f(iter.next().unwrap())))
core::array::from_fn(|_|f(iter.next().unwrap())),
)
} }
} }
impl<const N: usize, T: Copy> Vector<N, T> { impl<const N: usize, T: Copy> Vector<N, T> {
@ -41,9 +37,7 @@ macro_rules! impl_vector {
impl<const N: usize, T: Default> Default for Vector<N, T> { impl<const N: usize, T: Default> Default for Vector<N, T> {
#[inline] #[inline]
fn default() -> Self { fn default() -> Self {
Self::new( Self::new(core::array::from_fn(|_| Default::default()))
core::array::from_fn(|_|Default::default())
)
} }
} }
@ -104,21 +98,22 @@ macro_rules! impl_vector {
type Output = Vector<N, V>; type Output = Vector<N, V>;
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
Vector::new( Vector::new(self.array.map(|t| -t))
self.array.map(|t|-t)
)
} }
} }
impl<const N:usize,T> Vector<N,T> impl<const N: usize, T> Vector<N, T> {
{
#[inline] #[inline]
pub fn dot<U, V>(self, rhs: Vector<N, U>) -> V pub fn dot<U, V>(self, rhs: Vector<N, U>) -> V
where where
T: core::ops::Mul<U, Output = V>, T: core::ops::Mul<U, Output = V>,
V: core::iter::Sum, V: core::iter::Sum,
{ {
self.array.into_iter().zip(rhs.array).map(|(a,b)|a*b).sum() self.array
.into_iter()
.zip(rhs.array)
.map(|(a, b)| a * b)
.sum()
} }
} }
@ -168,13 +163,15 @@ macro_rules! impl_vector {
// dedicated methods for this type // dedicated methods for this type
#[cfg(feature = "fixed-wide")] #[cfg(feature = "fixed-wide")]
$crate::impl_fixed_wide_vector!(); $crate::impl_fixed_wide_vector!();
} };
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector_deferred_division { macro_rules! impl_vector_deferred_division {
() => { () => {
impl<const N:usize,T:ratio_ops::ratio::Divide<U,Output=V>,U:Copy,V> ratio_ops::ratio::Divide<U> for Vector<N,T>{ impl<const N: usize, T: ratio_ops::ratio::Divide<U, Output = V>, U: Copy, V>
ratio_ops::ratio::Divide<U> for Vector<N, T>
{
type Output = Vector<N, V>; type Output = Vector<N, V>;
#[inline] #[inline]
fn divide(self, rhs: U) -> Self::Output { fn divide(self, rhs: U) -> Self::Output {
@ -188,113 +185,130 @@ macro_rules! impl_vector_deferred_division {
ratio_ops::ratio::Ratio::new(self, rhs) ratio_ops::ratio::Ratio::new(self, rhs)
} }
} }
} };
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector_operator_scalar { macro_rules! impl_vector_operator_scalar {
($trait: ident, $method: ident ) => { ($trait: ident, $method: ident ) => {
impl<const N:usize,T:core::ops::$trait<U,Output=V>,U:Copy,V> core::ops::$trait<U> for Vector<N,T>{ impl<const N: usize, T: core::ops::$trait<U, Output = V>, U: Copy, V> core::ops::$trait<U>
for Vector<N, T>
{
type Output = Vector<N, V>; type Output = Vector<N, V>;
#[inline] #[inline]
fn $method(self, rhs: U) -> Self::Output { fn $method(self, rhs: U) -> Self::Output {
self.map(|t| t.$method(rhs)) self.map(|t| t.$method(rhs))
} }
} }
} };
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector_operator { macro_rules! impl_vector_operator {
($trait: ident, $method: ident ) => { ($trait: ident, $method: ident ) => {
impl<const N:usize,T:core::ops::$trait<U,Output=V>,U,V> core::ops::$trait<Vector<N,U>> for Vector<N,T>{ impl<const N: usize, T: core::ops::$trait<U, Output = V>, U, V>
core::ops::$trait<Vector<N, U>> for Vector<N, T>
{
type Output = Vector<N, V>; type Output = Vector<N, V>;
#[inline] #[inline]
fn $method(self, rhs: Vector<N, U>) -> Self::Output { fn $method(self, rhs: Vector<N, U>) -> Self::Output {
self.map_zip(rhs, |(a, b)| a.$method(b)) self.map_zip(rhs, |(a, b)| a.$method(b))
} }
} }
impl<const N:usize,T:core::ops::$trait<i64,Output=T>> core::ops::$trait<i64> for Vector<N,T>{ impl<const N: usize, T: core::ops::$trait<i64, Output = T>> core::ops::$trait<i64>
for Vector<N, T>
{
type Output = Self; type Output = Self;
#[inline] #[inline]
fn $method(self, rhs: i64) -> Self::Output { fn $method(self, rhs: i64) -> Self::Output {
self.map(|t| t.$method(rhs)) self.map(|t| t.$method(rhs))
} }
} }
} };
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector_assign_operator_scalar { macro_rules! impl_vector_assign_operator_scalar {
($trait: ident, $method: ident ) => { ($trait: ident, $method: ident ) => {
impl<const N:usize,T:core::ops::$trait<U>,U:Copy> core::ops::$trait<U> for Vector<N,T>{ impl<const N: usize, T: core::ops::$trait<U>, U: Copy> core::ops::$trait<U>
for Vector<N, T>
{
#[inline] #[inline]
fn $method(&mut self, rhs: U) { fn $method(&mut self, rhs: U) {
self.array.iter_mut() self.array.iter_mut().for_each(|t| t.$method(rhs))
.for_each(|t|t.$method(rhs))
}
} }
} }
};
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector_assign_operator { macro_rules! impl_vector_assign_operator {
($trait: ident, $method: ident ) => { ($trait: ident, $method: ident ) => {
impl<const N:usize,T:core::ops::$trait<U>,U> core::ops::$trait<Vector<N,U>> for Vector<N,T>{ impl<const N: usize, T: core::ops::$trait<U>, U> core::ops::$trait<Vector<N, U>>
for Vector<N, T>
{
#[inline] #[inline]
fn $method(&mut self, rhs: Vector<N, U>) { fn $method(&mut self, rhs: Vector<N, U>) {
self.array.iter_mut().zip(rhs.array) self.array
.iter_mut()
.zip(rhs.array)
.for_each(|(a, b)| a.$method(b)) .for_each(|(a, b)| a.$method(b))
} }
} }
impl<const N: usize, T: core::ops::$trait<i64>> core::ops::$trait<i64> for Vector<N, T> { impl<const N: usize, T: core::ops::$trait<i64>> core::ops::$trait<i64> for Vector<N, T> {
#[inline] #[inline]
fn $method(&mut self, rhs: i64) { fn $method(&mut self, rhs: i64) {
self.array.iter_mut() self.array.iter_mut().for_each(|t| t.$method(rhs))
.for_each(|t|t.$method(rhs))
}
} }
} }
};
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector_shift_operator { macro_rules! impl_vector_shift_operator {
($trait: ident, $method: ident ) => { ($trait: ident, $method: ident ) => {
impl<const N:usize,T:core::ops::$trait<U,Output=V>,U,V> core::ops::$trait<Vector<N,U>> for Vector<N,T>{ impl<const N: usize, T: core::ops::$trait<U, Output = V>, U, V>
core::ops::$trait<Vector<N, U>> for Vector<N, T>
{
type Output = Vector<N, V>; type Output = Vector<N, V>;
#[inline] #[inline]
fn $method(self, rhs: Vector<N, U>) -> Self::Output { fn $method(self, rhs: Vector<N, U>) -> Self::Output {
self.map_zip(rhs, |(a, b)| a.$method(b)) self.map_zip(rhs, |(a, b)| a.$method(b))
} }
} }
impl<const N:usize,T:core::ops::$trait<u32,Output=V>,V> core::ops::$trait<u32> for Vector<N,T>{ impl<const N: usize, T: core::ops::$trait<u32, Output = V>, V> core::ops::$trait<u32>
for Vector<N, T>
{
type Output = Vector<N, V>; type Output = Vector<N, V>;
#[inline] #[inline]
fn $method(self, rhs: u32) -> Self::Output { fn $method(self, rhs: u32) -> Self::Output {
self.map(|t| t.$method(rhs)) self.map(|t| t.$method(rhs))
} }
} }
} };
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector_shift_assign_operator { macro_rules! impl_vector_shift_assign_operator {
($trait: ident, $method: ident ) => { ($trait: ident, $method: ident ) => {
impl<const N:usize,T:core::ops::$trait<U>,U> core::ops::$trait<Vector<N,U>> for Vector<N,T>{ impl<const N: usize, T: core::ops::$trait<U>, U> core::ops::$trait<Vector<N, U>>
for Vector<N, T>
{
#[inline] #[inline]
fn $method(&mut self, rhs: Vector<N, U>) { fn $method(&mut self, rhs: Vector<N, U>) {
self.array.iter_mut().zip(rhs.array) self.array
.iter_mut()
.zip(rhs.array)
.for_each(|(a, b)| a.$method(b)) .for_each(|(a, b)| a.$method(b))
} }
} }
impl<const N: usize, T: core::ops::$trait<u32>> core::ops::$trait<u32> for Vector<N, T> { impl<const N: usize, T: core::ops::$trait<u32>> core::ops::$trait<u32> for Vector<N, T> {
#[inline] #[inline]
fn $method(&mut self, rhs: u32) { fn $method(&mut self, rhs: u32) {
self.array.iter_mut() self.array.iter_mut().for_each(|t| t.$method(rhs))
.for_each(|t|t.$method(rhs))
}
} }
} }
};
} }
#[doc(hidden)] #[doc(hidden)]
@ -305,12 +319,10 @@ macro_rules! impl_vector_extend {
#[inline] #[inline]
pub fn extend(self, value: T) -> Vector<{ $size + 1 }, T> { pub fn extend(self, value: T) -> Vector<{ $size + 1 }, T> {
let mut iter = self.array.into_iter().chain(core::iter::once(value)); let mut iter = self.array.into_iter().chain(core::iter::once(value));
Vector::new( Vector::new(core::array::from_fn(|_| iter.next().unwrap()))
core::array::from_fn(|_|iter.next().unwrap()),
)
}
} }
} }
};
} }
#[doc(hidden)] #[doc(hidden)]
@ -330,15 +342,14 @@ macro_rules! impl_vector_named_fields {
unsafe { core::mem::transmute(&mut self.array) } unsafe { core::mem::transmute(&mut self.array) }
} }
} }
} };
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector_3 { macro_rules! impl_vector_3 {
() => { () => {
impl<T> Vector<3,T> impl<T> Vector<3, T> {
{
#[inline] #[inline]
pub fn cross<U, V>(self, rhs: Vector<3, U>) -> Vector<3, <V as core::ops::Sub>::Output> pub fn cross<U, V>(self, rhs: Vector<3, U>) -> Vector<3, <V as core::ops::Sub>::Output>
where where
@ -353,5 +364,5 @@ macro_rules! impl_vector_3 {
]) ])
} }
} }
} };
} }

View File

@ -1,5 +1,5 @@
use crate::vector::Vector;
use crate::matrix::Matrix; use crate::matrix::Matrix;
use crate::vector::Vector;
#[repr(C)] #[repr(C)]
pub struct Vector2<T> { pub struct Vector2<T> {
@ -45,15 +45,7 @@ pub struct Matrix4<T> {
crate::impl_matrix_named_fields!( crate::impl_matrix_named_fields!(
//outer struct //outer struct
( ((Matrix2, 2), (Matrix3, 3), (Matrix4, 4)),
(Matrix2, 2),
(Matrix3, 3),
(Matrix4, 4)
),
//inner struct //inner struct
( ((2), (3), (4))
(2),
(3),
(4)
)
); );

View File

@ -12,7 +12,10 @@ fn wide_vec3(){
let v2 = v1 * v1.y; let v2 = v1 * v1.y;
let v3 = v2 * v2.z; let v3 = v2 * v2.z;
assert_eq!(v3.array,Vector3::from_value(Planar64Wide3::from(3i128.pow(8))).array); assert_eq!(
v3.array,
Vector3::from_value(Planar64Wide3::from(3i128.pow(8))).array
);
} }
#[test] #[test]
@ -38,16 +41,33 @@ fn wide_vec3_length_squared(){
#[test] #[test]
fn wide_matrix_dot() { fn wide_matrix_dot() {
let lhs = Matrix3x4::new([ let lhs = Matrix3x4::new([
[Planar64::from(1),Planar64::from(2),Planar64::from(3),Planar64::from(4)], [
[Planar64::from(5),Planar64::from(6),Planar64::from(7),Planar64::from(8)], Planar64::from(1),
[Planar64::from(9),Planar64::from(10),Planar64::from(11),Planar64::from(12)], Planar64::from(2),
]).transpose(); Planar64::from(3),
Planar64::from(4),
],
[
Planar64::from(5),
Planar64::from(6),
Planar64::from(7),
Planar64::from(8),
],
[
Planar64::from(9),
Planar64::from(10),
Planar64::from(11),
Planar64::from(12),
],
])
.transpose();
let rhs = Matrix4x2::new([ let rhs = Matrix4x2::new([
[Planar64::from(1), Planar64::from(2)], [Planar64::from(1), Planar64::from(2)],
[Planar64::from(3), Planar64::from(4)], [Planar64::from(3), Planar64::from(4)],
[Planar64::from(5), Planar64::from(6)], [Planar64::from(5), Planar64::from(6)],
[Planar64::from(7), Planar64::from(8)], [Planar64::from(7), Planar64::from(8)],
]).transpose(); ])
.transpose();
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2> // Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
let m_dot = lhs * rhs; let m_dot = lhs * rhs;
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}} //In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
@ -58,7 +78,9 @@ fn wide_matrix_dot(){
[Planar64Wide1::from(50), Planar64Wide1::from(60)], [Planar64Wide1::from(50), Planar64Wide1::from(60)],
[Planar64Wide1::from(114), Planar64Wide1::from(140)], [Planar64Wide1::from(114), Planar64Wide1::from(140)],
[Planar64Wide1::from(178), Planar64Wide1::from(220)], [Planar64Wide1::from(178), Planar64Wide1::from(220)],
]).transpose().array ])
.transpose()
.array
); );
} }
@ -88,9 +110,22 @@ fn wide_matrix_adjugate(){
assert_eq!( assert_eq!(
m.adjugate().array, m.adjugate().array,
Matrix3::new([ Matrix3::new([
[Planar64Wide1::from(-11),Planar64Wide1::from(6),Planar64Wide1::from(-1)], [
[Planar64Wide1::from(6),Planar64Wide1::from(-9),Planar64Wide1::from(5)], Planar64Wide1::from(-11),
[Planar64Wide1::from(2),Planar64Wide1::from(4),Planar64Wide1::from(-3)], Planar64Wide1::from(6),
]).array Planar64Wide1::from(-1)
],
[
Planar64Wide1::from(6),
Planar64Wide1::from(-9),
Planar64Wide1::from(5)
],
[
Planar64Wide1::from(2),
Planar64Wide1::from(4),
Planar64Wide1::from(-3)
],
])
.array
); );
} }

View File

@ -1,4 +1,4 @@
use crate::types::{Vector3,Matrix3}; use crate::types::{Matrix3, Vector3};
#[test] #[test]
fn test_vector() { fn test_vector() {
@ -14,7 +14,6 @@ fn test_vector(){
assert_eq!(v.y, 10); assert_eq!(v.y, 10);
} }
#[test] #[test]
fn test_matrix() { fn test_matrix() {
let mut v = Matrix3::from_value(2); let mut v = Matrix3::from_value(2);

View File

@ -1,4 +1,4 @@
use crate::types::{Vector2,Vector3,Matrix3x4,Matrix4x2,Matrix3x2,Matrix2x3}; use crate::types::{Matrix2x3, Matrix3x2, Matrix3x4, Matrix4x2, Vector2, Vector3};
#[test] #[test]
fn test_bool() { fn test_bool() {
@ -21,10 +21,7 @@ fn test_arithmetic(){
#[test] #[test]
fn matrix_transform_vector() { fn matrix_transform_vector() {
let m=Matrix2x3::new([ let m = Matrix2x3::new([[1, 2, 3], [4, 5, 6]]).transpose();
[1,2,3],
[4,5,6],
]).transpose();
let v = Vector3::new([1, 2, 3]); let v = Vector3::new([1, 2, 3]);
let transformed = m * v; let transformed = m * v;
assert_eq!(transformed.array, Vector2::new([14, 32]).array); assert_eq!(transformed.array, Vector2::new([14, 32]).array);
@ -33,27 +30,22 @@ fn matrix_transform_vector(){
#[test] #[test]
fn matrix_dot() { fn matrix_dot() {
// All this code was written row major and I converted the lib to colum major // All this code was written row major and I converted the lib to colum major
let rhs=Matrix4x2::new([ let rhs = Matrix4x2::new([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], [7.0, 8.0]]).transpose(); // | | |
[ 1.0, 2.0], let lhs = Matrix3x4::new([
[ 3.0, 4.0], // | | |
[ 5.0, 6.0],
[ 7.0, 8.0],
]).transpose(); // | | |
let lhs=Matrix3x4::new([ // | | |
[1.0, 2.0, 3.0, 4.0], // [ 50.0, 60.0], [1.0, 2.0, 3.0, 4.0], // [ 50.0, 60.0],
[5.0, 6.0, 7.0, 8.0], // [114.0,140.0], [5.0, 6.0, 7.0, 8.0], // [114.0,140.0],
[9.0, 10.0, 11.0, 12.0], // [178.0,220.0], [9.0, 10.0, 11.0, 12.0], // [178.0,220.0],
]).transpose(); ])
.transpose();
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2> // Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
let m_dot = lhs * rhs; let m_dot = lhs * rhs;
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}} //In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
//Out[1]= {{50, 60}, {114, 140}, {178, 220}} //Out[1]= {{50, 60}, {114, 140}, {178, 220}}
assert_eq!( assert_eq!(
m_dot.array, m_dot.array,
Matrix3x2::new([ Matrix3x2::new([[50.0, 60.0], [114.0, 140.0], [178.0, 220.0],])
[50.0,60.0], .transpose()
[114.0,140.0], .array
[178.0,220.0],
]).transpose().array
); );
} }

View File

@ -1,5 +1,5 @@
use crate::vector::Vector;
use crate::matrix::Matrix; use crate::matrix::Matrix;
use crate::vector::Vector;
pub type Vector2<T> = Vector<2, T>; pub type Vector2<T> = Vector<2, T>;
pub type Vector3<T> = Vector<3, T>; pub type Vector3<T> = Vector<3, T>;

View File

@ -30,7 +30,10 @@ impl<Num,Den> Ratio<Num,Den>
impl<LhsNum, LhsDen> Ratio<LhsNum, LhsDen> { impl<LhsNum, LhsDen> Ratio<LhsNum, LhsDen> {
#[inline] #[inline]
pub fn mul_ratio<RhsNum,RhsDen>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsNum as core::ops::Mul<RhsNum>>::Output,<LhsDen as core::ops::Mul<RhsDen>>::Output> pub fn mul_ratio<RhsNum, RhsDen>(
self,
rhs: Ratio<RhsNum, RhsDen>,
) -> Ratio<<LhsNum as core::ops::Mul<RhsNum>>::Output, <LhsDen as core::ops::Mul<RhsDen>>::Output>
where where
LhsNum: core::ops::Mul<RhsNum>, LhsNum: core::ops::Mul<RhsNum>,
LhsDen: core::ops::Mul<RhsDen>, LhsDen: core::ops::Mul<RhsDen>,
@ -38,7 +41,10 @@ impl<LhsNum,LhsDen> Ratio<LhsNum,LhsDen>{
Ratio::new(self.num * rhs.num, self.den * rhs.den) Ratio::new(self.num * rhs.num, self.den * rhs.den)
} }
#[inline] #[inline]
pub fn div_ratio<RhsNum,RhsDen>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsNum as core::ops::Mul<RhsDen>>::Output,<LhsDen as core::ops::Mul<RhsNum>>::Output> pub fn div_ratio<RhsNum, RhsDen>(
self,
rhs: Ratio<RhsNum, RhsDen>,
) -> Ratio<<LhsNum as core::ops::Mul<RhsDen>>::Output, <LhsDen as core::ops::Mul<RhsNum>>::Output>
where where
LhsNum: core::ops::Mul<RhsDen>, LhsNum: core::ops::Mul<RhsDen>,
LhsDen: core::ops::Mul<RhsNum>, LhsDen: core::ops::Mul<RhsNum>,
@ -50,7 +56,13 @@ macro_rules! impl_ratio_method {
($trait:ident, $method:ident, $ratio_method:ident) => { ($trait:ident, $method:ident, $ratio_method:ident) => {
impl<LhsNum, LhsDen> Ratio<LhsNum, LhsDen> { impl<LhsNum, LhsDen> Ratio<LhsNum, LhsDen> {
#[inline] #[inline]
pub fn $ratio_method<RhsNum,RhsDen,LhsCrossMul,RhsCrossMul>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsCrossMul as core::ops::$trait<RhsCrossMul>>::Output,<LhsDen as core::ops::Mul<RhsDen>>::Output> pub fn $ratio_method<RhsNum, RhsDen, LhsCrossMul, RhsCrossMul>(
self,
rhs: Ratio<RhsNum, RhsDen>,
) -> Ratio<
<LhsCrossMul as core::ops::$trait<RhsCrossMul>>::Output,
<LhsDen as core::ops::Mul<RhsDen>>::Output,
>
where where
LhsNum: core::ops::Mul<RhsDen, Output = LhsCrossMul>, LhsNum: core::ops::Mul<RhsDen, Output = LhsCrossMul>,
LhsDen: core::ops::Mul<RhsNum, Output = RhsCrossMul>, LhsDen: core::ops::Mul<RhsNum, Output = RhsCrossMul>,
@ -59,7 +71,10 @@ macro_rules! impl_ratio_method {
RhsDen: Copy, RhsDen: Copy,
LhsCrossMul: core::ops::$trait<RhsCrossMul>, LhsCrossMul: core::ops::$trait<RhsCrossMul>,
{ {
Ratio::new((self.num*rhs.den).$method(self.den*rhs.num),self.den*rhs.den) Ratio::new(
(self.num * rhs.den).$method(self.den * rhs.num),
self.den * rhs.den,
)
} }
} }
}; };
@ -115,7 +130,10 @@ macro_rules! impl_ratio_ord_method{
($method:ident, $ratio_method:ident, $output:ty) => { ($method:ident, $ratio_method:ident, $output:ty) => {
impl<LhsNum, LhsDen: Parity> Ratio<LhsNum, LhsDen> { impl<LhsNum, LhsDen: Parity> Ratio<LhsNum, LhsDen> {
#[inline] #[inline]
pub fn $ratio_method<RhsNum,RhsDen:Parity,T>(self,rhs:Ratio<RhsNum,RhsDen>)->$output pub fn $ratio_method<RhsNum, RhsDen: Parity, T>(
self,
rhs: Ratio<RhsNum, RhsDen>,
) -> $output
where where
LhsNum: core::ops::Mul<RhsDen, Output = T>, LhsNum: core::ops::Mul<RhsDen, Output = T>,
LhsDen: core::ops::Mul<RhsNum, Output = T>, LhsDen: core::ops::Mul<RhsNum, Output = T>,
@ -127,7 +145,7 @@ macro_rules! impl_ratio_ord_method{
} }
} }
} }
} };
} }
//PartialEq //PartialEq
impl_ratio_ord_method!(eq, eq_ratio, bool); impl_ratio_ord_method!(eq, eq_ratio, bool);
@ -251,7 +269,8 @@ impl_ratio_assign_operator!(RemAssign,rem_assign);
// Only implement PartialEq<Self> // Only implement PartialEq<Self>
// Rust's operators aren't actually that good // Rust's operators aren't actually that good
impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialEq<Ratio<RhsNum,RhsDen>> for Ratio<LhsNum,LhsDen> impl<LhsNum, LhsDen, RhsNum, RhsDen, T, U> PartialEq<Ratio<RhsNum, RhsDen>>
for Ratio<LhsNum, LhsDen>
where where
LhsNum: Copy, LhsNum: Copy,
LhsDen: Copy, LhsDen: Copy,
@ -268,7 +287,8 @@ impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialEq<Ratio<RhsNum,RhsDen>> for Ratio<
} }
impl<Num, Den> Eq for Ratio<Num, Den> where Self: PartialEq {} impl<Num, Den> Eq for Ratio<Num, Den> where Self: PartialEq {}
impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialOrd<Ratio<RhsNum,RhsDen>> for Ratio<LhsNum,LhsDen> impl<LhsNum, LhsDen, RhsNum, RhsDen, T, U> PartialOrd<Ratio<RhsNum, RhsDen>>
for Ratio<LhsNum, LhsDen>
where where
LhsNum: Copy, LhsNum: Copy,
LhsDen: Copy, LhsDen: Copy,

View File

@ -1,9 +1,9 @@
use std::io::Read;
use rbx_dom_weak::WeakDom; use rbx_dom_weak::WeakDom;
use std::io::Read;
mod rbx;
mod mesh; mod mesh;
mod primitives; mod primitives;
mod rbx;
pub mod data { pub mod data {
pub struct RobloxMeshBytes(Vec<u8>); pub struct RobloxMeshBytes(Vec<u8>);
@ -54,7 +54,9 @@ impl Place{
let runner = roblox_emulator::runner::Runner::new().unwrap(); let runner = roblox_emulator::runner::Runner::new().unwrap();
let context = roblox_emulator::context::Context::from_mut(dom); let context = roblox_emulator::context::Context::from_mut(dom);
let scripts = context.scripts(); let scripts = context.scripts();
let runnable=runner.runnable_context_with_services(context,services).unwrap(); let runnable = runner
.runnable_context_with_services(context, services)
.unwrap();
for script in scripts { for script in scripts {
if let Err(e) = runnable.run_script(script) { if let Err(e) = runnable.run_script(script) {
println!("runner error: {e}"); println!("runner error: {e}");
@ -86,8 +88,12 @@ pub fn read<R:Read>(input:R)->Result<Model,ReadError>{
let mut buf = std::io::BufReader::new(input); let mut buf = std::io::BufReader::new(input);
let peek = std::io::BufRead::fill_buf(&mut buf).map_err(ReadError::Io)?; let peek = std::io::BufRead::fill_buf(&mut buf).map_err(ReadError::Io)?;
match &peek[0..8] { match &peek[0..8] {
b"<roblox!"=>rbx_binary::from_reader(buf).map(Model::new).map_err(ReadError::RbxBinary), b"<roblox!" => rbx_binary::from_reader(buf)
b"<roblox "=>rbx_xml::from_reader_default(buf).map(Model::new).map_err(ReadError::RbxXml), .map(Model::new)
.map_err(ReadError::RbxBinary),
b"<roblox " => rbx_xml::from_reader_default(buf)
.map(Model::new)
.map_err(ReadError::RbxXml),
_ => Err(ReadError::UnknownFileFormat), _ => Err(ReadError::UnknownFileFormat),
} }
} }
@ -97,7 +103,7 @@ pub fn read<R:Read>(input:R)->Result<Model,ReadError>{
pub fn convert<AcquireRenderConfigId, AcquireMeshId>( pub fn convert<AcquireRenderConfigId, AcquireMeshId>(
dom: impl AsRef<WeakDom>, dom: impl AsRef<WeakDom>,
acquire_render_config_id: AcquireRenderConfigId, acquire_render_config_id: AcquireRenderConfigId,
acquire_mesh_id:AcquireMeshId acquire_mesh_id: AcquireMeshId,
) -> rbx::PartialMap1 ) -> rbx::PartialMap1
where where
AcquireRenderConfigId: FnMut(Option<&str>) -> strafesnet_common::model::RenderConfigId, AcquireRenderConfigId: FnMut(Option<&str>) -> strafesnet_common::model::RenderConfigId,

View File

@ -1,12 +1,18 @@
use std::collections::HashMap; use std::collections::HashMap;
use rbx_mesh::mesh::{Vertex2, Vertex2Truncated}; use rbx_mesh::mesh::{Vertex2, Vertex2Truncated};
use strafesnet_common::{integer::vec3,model::{self, ColorId, IndexedVertex, NormalId, PolygonGroup, PolygonList, PositionId, TextureCoordinateId, VertexId}}; use strafesnet_common::{
integer::vec3,
model::{
self, ColorId, IndexedVertex, NormalId, PolygonGroup, PolygonList, PositionId,
TextureCoordinateId, VertexId,
},
};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
Planar64Vec3(strafesnet_common::integer::Planar64TryFromFloatError), Planar64Vec3(strafesnet_common::integer::Planar64TryFromFloatError),
RbxMesh(rbx_mesh::mesh::Error) RbxMesh(rbx_mesh::mesh::Error),
} }
impl std::fmt::Display for Error { impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -15,13 +21,7 @@ impl std::fmt::Display for Error{
} }
impl std::error::Error for Error {} impl std::error::Error for Error {}
fn ingest_vertices2< fn ingest_vertices2<AcquirePosId, AcquireTexId, AcquireNormalId, AcquireColorId, AcquireVertexId>(
AcquirePosId,
AcquireTexId,
AcquireNormalId,
AcquireColorId,
AcquireVertexId,
>(
vertices: Vec<Vertex2>, vertices: Vec<Vertex2>,
acquire_pos_id: &mut AcquirePosId, acquire_pos_id: &mut AcquirePosId,
acquire_tex_id: &mut AcquireTexId, acquire_tex_id: &mut AcquireTexId,
@ -38,22 +38,23 @@ where
{ {
//this monster is collecting a map of old_vertices_index -> unique_vertices_index //this monster is collecting a map of old_vertices_index -> unique_vertices_index
//while also doing the inserting unique entries into lists simultaneously //while also doing the inserting unique entries into lists simultaneously
Ok(vertices.into_iter().enumerate().map(|(vertex_id,vertex)|Ok(( Ok(vertices
.into_iter()
.enumerate()
.map(|(vertex_id, vertex)| {
Ok((
rbx_mesh::mesh::VertexId2(vertex_id as u32), rbx_mesh::mesh::VertexId2(vertex_id as u32),
acquire_vertex_id(IndexedVertex { acquire_vertex_id(IndexedVertex {
pos: acquire_pos_id(vertex.pos)?, pos: acquire_pos_id(vertex.pos)?,
tex: acquire_tex_id(vertex.tex), tex: acquire_tex_id(vertex.tex),
normal: acquire_normal_id(vertex.norm)?, normal: acquire_normal_id(vertex.norm)?,
color:acquire_color_id(vertex.color.map(|f|f as f32/255.0f32)) color: acquire_color_id(vertex.color.map(|f| f as f32 / 255.0f32)),
}), }),
))).collect::<Result<_,_>>()?) ))
})
.collect::<Result<_, _>>()?)
} }
fn ingest_vertices_truncated2< fn ingest_vertices_truncated2<AcquirePosId, AcquireTexId, AcquireNormalId, AcquireVertexId>(
AcquirePosId,
AcquireTexId,
AcquireNormalId,
AcquireVertexId,
>(
vertices: Vec<Vertex2Truncated>, vertices: Vec<Vertex2Truncated>,
acquire_pos_id: &mut AcquirePosId, acquire_pos_id: &mut AcquirePosId,
acquire_tex_id: &mut AcquireTexId, acquire_tex_id: &mut AcquireTexId,
@ -69,29 +70,44 @@ where
{ {
//this monster is collecting a map of old_vertices_index -> unique_vertices_index //this monster is collecting a map of old_vertices_index -> unique_vertices_index
//while also doing the inserting unique entries into lists simultaneously //while also doing the inserting unique entries into lists simultaneously
Ok(vertices.into_iter().enumerate().map(|(vertex_id,vertex)|Ok(( Ok(vertices
.into_iter()
.enumerate()
.map(|(vertex_id, vertex)| {
Ok((
rbx_mesh::mesh::VertexId2(vertex_id as u32), rbx_mesh::mesh::VertexId2(vertex_id as u32),
acquire_vertex_id(IndexedVertex { acquire_vertex_id(IndexedVertex {
pos: acquire_pos_id(vertex.pos)?, pos: acquire_pos_id(vertex.pos)?,
tex: acquire_tex_id(vertex.tex), tex: acquire_tex_id(vertex.tex),
normal: acquire_normal_id(vertex.norm)?, normal: acquire_normal_id(vertex.norm)?,
color:static_color_id color: static_color_id,
}), }),
))).collect::<Result<_,_>>()?) ))
})
.collect::<Result<_, _>>()?)
} }
fn ingest_faces2_lods3( fn ingest_faces2_lods3(
polygon_groups: &mut Vec<PolygonGroup>, polygon_groups: &mut Vec<PolygonGroup>,
vertex_id_map: &HashMap<rbx_mesh::mesh::VertexId2, VertexId>, vertex_id_map: &HashMap<rbx_mesh::mesh::VertexId2, VertexId>,
faces: &Vec<rbx_mesh::mesh::Face2>, faces: &Vec<rbx_mesh::mesh::Face2>,
lods:&Vec<rbx_mesh::mesh::Lod3> lods: &Vec<rbx_mesh::mesh::Lod3>,
) { ) {
//faces have to be split into polygon groups based on lod //faces have to be split into polygon groups based on lod
polygon_groups.extend(lods.windows(2).map(|lod_pair| polygon_groups.extend(lods.windows(2).map(|lod_pair| {
PolygonGroup::PolygonList(PolygonList::new(faces[lod_pair[0].0 as usize..lod_pair[1].0 as usize].iter().map(|face| PolygonGroup::PolygonList(PolygonList::new(
vec![vertex_id_map[&face.0],vertex_id_map[&face.1],vertex_id_map[&face.2]] faces[lod_pair[0].0 as usize..lod_pair[1].0 as usize]
).collect())) .iter()
.map(|face| {
vec![
vertex_id_map[&face.0],
vertex_id_map[&face.1],
vertex_id_map[&face.2],
]
})
.collect(),
)) ))
}))
} }
pub fn convert(roblox_mesh_bytes: crate::data::RobloxMeshBytes) -> Result<model::Mesh, Error> { pub fn convert(roblox_mesh_bytes: crate::data::RobloxMeshBytes) -> Result<model::Mesh, Error> {
@ -149,52 +165,110 @@ pub fn convert(roblox_mesh_bytes:crate::data::RobloxMeshBytes)->Result<model::Me
match rbx_mesh::read_versioned(roblox_mesh_bytes.cursor()).map_err(Error::RbxMesh)? { match rbx_mesh::read_versioned(roblox_mesh_bytes.cursor()).map_err(Error::RbxMesh)? {
rbx_mesh::mesh::VersionedMesh::Version1(mesh) => { rbx_mesh::mesh::VersionedMesh::Version1(mesh) => {
let color_id = acquire_color_id([1.0f32; 4]); let color_id = acquire_color_id([1.0f32; 4]);
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(mesh.vertices.chunks_exact(3).map(|trip|{ polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(
let mut ingest_vertex1=|vertex:&rbx_mesh::mesh::Vertex1|Ok(acquire_vertex_id(IndexedVertex{ mesh.vertices
.chunks_exact(3)
.map(|trip| {
let mut ingest_vertex1 = |vertex: &rbx_mesh::mesh::Vertex1| {
Ok(acquire_vertex_id(IndexedVertex {
pos: acquire_pos_id(vertex.pos)?, pos: acquire_pos_id(vertex.pos)?,
tex: acquire_tex_id([vertex.tex[0], vertex.tex[1]]), tex: acquire_tex_id([vertex.tex[0], vertex.tex[1]]),
normal: acquire_normal_id(vertex.norm)?, normal: acquire_normal_id(vertex.norm)?,
color: color_id, color: color_id,
})); }))
Ok(vec![ingest_vertex1(&trip[0])?,ingest_vertex1(&trip[1])?,ingest_vertex1(&trip[2])?]) };
}).collect::<Result<_,_>>()?))); Ok(vec![
}, ingest_vertex1(&trip[0])?,
ingest_vertex1(&trip[1])?,
ingest_vertex1(&trip[2])?,
])
})
.collect::<Result<_, _>>()?,
)));
}
rbx_mesh::mesh::VersionedMesh::Version2(mesh) => { rbx_mesh::mesh::VersionedMesh::Version2(mesh) => {
let vertex_id_map = match mesh.header.sizeof_vertex { let vertex_id_map = match mesh.header.sizeof_vertex {
rbx_mesh::mesh::SizeOfVertex2::Truncated => { rbx_mesh::mesh::SizeOfVertex2::Truncated => {
//pick white and make all the vertices white //pick white and make all the vertices white
let color_id = acquire_color_id([1.0f32; 4]); let color_id = acquire_color_id([1.0f32; 4]);
ingest_vertices_truncated2(mesh.vertices_truncated,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,color_id,&mut acquire_vertex_id) ingest_vertices_truncated2(
}, mesh.vertices_truncated,
rbx_mesh::mesh::SizeOfVertex2::Full=>ingest_vertices2(mesh.vertices,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,&mut acquire_color_id,&mut acquire_vertex_id), &mut acquire_pos_id,
&mut acquire_tex_id,
&mut acquire_normal_id,
color_id,
&mut acquire_vertex_id,
)
}
rbx_mesh::mesh::SizeOfVertex2::Full => ingest_vertices2(
mesh.vertices,
&mut acquire_pos_id,
&mut acquire_tex_id,
&mut acquire_normal_id,
&mut acquire_color_id,
&mut acquire_vertex_id,
),
}?; }?;
//one big happy group for all the faces //one big happy group for all the faces
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(mesh.faces.into_iter().map(|face| polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(
vec![vertex_id_map[&face.0],vertex_id_map[&face.1],vertex_id_map[&face.2]] mesh.faces
).collect()))); .into_iter()
}, .map(|face| {
vec![
vertex_id_map[&face.0],
vertex_id_map[&face.1],
vertex_id_map[&face.2],
]
})
.collect(),
)));
}
rbx_mesh::mesh::VersionedMesh::Version3(mesh) => { rbx_mesh::mesh::VersionedMesh::Version3(mesh) => {
let vertex_id_map = match mesh.header.sizeof_vertex { let vertex_id_map = match mesh.header.sizeof_vertex {
rbx_mesh::mesh::SizeOfVertex2::Truncated => { rbx_mesh::mesh::SizeOfVertex2::Truncated => {
let color_id = acquire_color_id([1.0f32; 4]); let color_id = acquire_color_id([1.0f32; 4]);
ingest_vertices_truncated2(mesh.vertices_truncated,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,color_id,&mut acquire_vertex_id) ingest_vertices_truncated2(
}, mesh.vertices_truncated,
rbx_mesh::mesh::SizeOfVertex2::Full=>ingest_vertices2(mesh.vertices,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,&mut acquire_color_id,&mut acquire_vertex_id), &mut acquire_pos_id,
&mut acquire_tex_id,
&mut acquire_normal_id,
color_id,
&mut acquire_vertex_id,
)
}
rbx_mesh::mesh::SizeOfVertex2::Full => ingest_vertices2(
mesh.vertices,
&mut acquire_pos_id,
&mut acquire_tex_id,
&mut acquire_normal_id,
&mut acquire_color_id,
&mut acquire_vertex_id,
),
}?; }?;
ingest_faces2_lods3(&mut polygon_groups, &vertex_id_map, &mesh.faces, &mesh.lods); ingest_faces2_lods3(&mut polygon_groups, &vertex_id_map, &mesh.faces, &mesh.lods);
}, }
rbx_mesh::mesh::VersionedMesh::Version4(mesh) => { rbx_mesh::mesh::VersionedMesh::Version4(mesh) => {
let vertex_id_map = ingest_vertices2( let vertex_id_map = ingest_vertices2(
mesh.vertices,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,&mut acquire_color_id,&mut acquire_vertex_id mesh.vertices,
&mut acquire_pos_id,
&mut acquire_tex_id,
&mut acquire_normal_id,
&mut acquire_color_id,
&mut acquire_vertex_id,
)?; )?;
ingest_faces2_lods3(&mut polygon_groups, &vertex_id_map, &mesh.faces, &mesh.lods); ingest_faces2_lods3(&mut polygon_groups, &vertex_id_map, &mesh.faces, &mesh.lods);
}, }
rbx_mesh::mesh::VersionedMesh::Version5(mesh) => { rbx_mesh::mesh::VersionedMesh::Version5(mesh) => {
let vertex_id_map = ingest_vertices2( let vertex_id_map = ingest_vertices2(
mesh.vertices,&mut acquire_pos_id,&mut acquire_tex_id,&mut acquire_normal_id,&mut acquire_color_id,&mut acquire_vertex_id mesh.vertices,
&mut acquire_pos_id,
&mut acquire_tex_id,
&mut acquire_normal_id,
&mut acquire_color_id,
&mut acquire_vertex_id,
)?; )?;
ingest_faces2_lods3(&mut polygon_groups, &vertex_id_map, &mesh.faces, &mesh.lods); ingest_faces2_lods3(&mut polygon_groups, &vertex_id_map, &mesh.faces, &mesh.lods);
}, }
} }
Ok(model::Mesh { Ok(model::Mesh {
unique_pos, unique_pos,

View File

@ -1,5 +1,9 @@
use strafesnet_common::model::{Color4,TextureCoordinate,Mesh,IndexedGraphicsGroup,IndexedPhysicsGroup,IndexedVertex,PolygonGroupId,PolygonGroup,PolygonList,IndexedVertexList,PositionId,TextureCoordinateId,NormalId,ColorId,VertexId,RenderConfigId};
use strafesnet_common::integer::{vec3, Planar64Vec3}; use strafesnet_common::integer::{vec3, Planar64Vec3};
use strafesnet_common::model::{
Color4, ColorId, IndexedGraphicsGroup, IndexedPhysicsGroup, IndexedVertex, IndexedVertexList,
Mesh, NormalId, PolygonGroup, PolygonGroupId, PolygonList, PositionId, RenderConfigId,
TextureCoordinate, TextureCoordinateId, VertexId,
};
#[derive(Debug)] #[derive(Debug)]
pub enum Primitives { pub enum Primitives {
@ -51,40 +55,15 @@ const CUBE_DEFAULT_POLYS:[[[u32;3];4];6]=[
[1, 3, 0], [1, 3, 0],
], ],
// top (0, 1, 0) // top (0, 1, 0)
[ [[5, 3, 1], [4, 2, 1], [3, 1, 1], [2, 0, 1]],
[5,3,1],
[4,2,1],
[3,1,1],
[2,0,1],
],
// back (0, 0, 1) // back (0, 0, 1)
[ [[0, 3, 2], [1, 2, 2], [2, 1, 2], [3, 0, 2]],
[0,3,2],
[1,2,2],
[2,1,2],
[3,0,2],
],
// left (-1, 0, 0) // left (-1, 0, 0)
[ [[0, 2, 3], [3, 1, 3], [4, 0, 3], [7, 3, 3]],
[0,2,3],
[3,1,3],
[4,0,3],
[7,3,3],
],
// bottom (0,-1, 0) // bottom (0,-1, 0)
[ [[1, 1, 4], [0, 0, 4], [7, 3, 4], [6, 2, 4]],
[1,1,4],
[0,0,4],
[7,3,4],
[6,2,4],
],
// front (0, 0,-1) // front (0, 0,-1)
[ [[4, 1, 5], [5, 0, 5], [6, 3, 5], [7, 2, 5]],
[4,1,5],
[5,0,5],
[6,3,5],
[7,2,5],
],
]; ];
#[derive(Hash, PartialEq, Eq)] #[derive(Hash, PartialEq, Eq)]
@ -135,8 +114,16 @@ impl CubeFaceDescription{
pub fn insert(&mut self, index: CubeFace, value: FaceDescription) { pub fn insert(&mut self, index: CubeFace, value: FaceDescription) {
self.0[index as usize] = Some(value); self.0[index as usize] = Some(value);
} }
pub fn pairs(self)->std::iter::FilterMap<std::iter::Enumerate<std::array::IntoIter<Option<FaceDescription>,6>>,impl FnMut((usize,Option<FaceDescription>))->Option<(usize,FaceDescription)>>{ pub fn pairs(
self.0.into_iter().enumerate().filter_map(|v|v.1.map(|u|(v.0,u))) self,
) -> std::iter::FilterMap<
std::iter::Enumerate<std::array::IntoIter<Option<FaceDescription>, 6>>,
impl FnMut((usize, Option<FaceDescription>)) -> Option<(usize, FaceDescription)>,
> {
self.0
.into_iter()
.enumerate()
.filter_map(|v| v.1.map(|u| (v.0, u)))
} }
} }
pub fn unit_cube(render: RenderConfigId) -> Mesh { pub fn unit_cube(render: RenderConfigId) -> Mesh {
@ -145,7 +132,10 @@ pub fn unit_cube(render:RenderConfigId)->Mesh{
t.insert(CubeFace::Top, FaceDescription::new_with_render_id(render)); t.insert(CubeFace::Top, FaceDescription::new_with_render_id(render));
t.insert(CubeFace::Back, FaceDescription::new_with_render_id(render)); t.insert(CubeFace::Back, FaceDescription::new_with_render_id(render));
t.insert(CubeFace::Left, FaceDescription::new_with_render_id(render)); t.insert(CubeFace::Left, FaceDescription::new_with_render_id(render));
t.insert(CubeFace::Bottom,FaceDescription::new_with_render_id(render)); t.insert(
CubeFace::Bottom,
FaceDescription::new_with_render_id(render),
);
t.insert(CubeFace::Front, FaceDescription::new_with_render_id(render)); t.insert(CubeFace::Front, FaceDescription::new_with_render_id(render));
generate_partial_unit_cube(t) generate_partial_unit_cube(t)
} }
@ -159,17 +149,34 @@ impl WedgeFaceDescription{
pub fn insert(&mut self, index: WedgeFace, value: FaceDescription) { pub fn insert(&mut self, index: WedgeFace, value: FaceDescription) {
self.0[index as usize] = Some(value); self.0[index as usize] = Some(value);
} }
pub fn pairs(self)->std::iter::FilterMap<std::iter::Enumerate<std::array::IntoIter<Option<FaceDescription>,5>>,impl FnMut((usize,Option<FaceDescription>))->Option<(usize,FaceDescription)>>{ pub fn pairs(
self.0.into_iter().enumerate().filter_map(|v|v.1.map(|u|(v.0,u))) self,
) -> std::iter::FilterMap<
std::iter::Enumerate<std::array::IntoIter<Option<FaceDescription>, 5>>,
impl FnMut((usize, Option<FaceDescription>)) -> Option<(usize, FaceDescription)>,
> {
self.0
.into_iter()
.enumerate()
.filter_map(|v| v.1.map(|u| (v.0, u)))
} }
} }
pub fn unit_wedge(render: RenderConfigId) -> Mesh { pub fn unit_wedge(render: RenderConfigId) -> Mesh {
let mut t = WedgeFaceDescription::default(); let mut t = WedgeFaceDescription::default();
t.insert(WedgeFace::Right,FaceDescription::new_with_render_id(render)); t.insert(
t.insert(WedgeFace::TopFront,FaceDescription::new_with_render_id(render)); WedgeFace::Right,
FaceDescription::new_with_render_id(render),
);
t.insert(
WedgeFace::TopFront,
FaceDescription::new_with_render_id(render),
);
t.insert(WedgeFace::Back, FaceDescription::new_with_render_id(render)); t.insert(WedgeFace::Back, FaceDescription::new_with_render_id(render));
t.insert(WedgeFace::Left, FaceDescription::new_with_render_id(render)); t.insert(WedgeFace::Left, FaceDescription::new_with_render_id(render));
t.insert(WedgeFace::Bottom,FaceDescription::new_with_render_id(render)); t.insert(
WedgeFace::Bottom,
FaceDescription::new_with_render_id(render),
);
generate_partial_unit_wedge(t) generate_partial_unit_wedge(t)
} }
#[derive(Default)] #[derive(Default)]
@ -178,17 +185,40 @@ impl CornerWedgeFaceDescription{
pub fn insert(&mut self, index: CornerWedgeFace, value: FaceDescription) { pub fn insert(&mut self, index: CornerWedgeFace, value: FaceDescription) {
self.0[index as usize] = Some(value); self.0[index as usize] = Some(value);
} }
pub fn pairs(self)->std::iter::FilterMap<std::iter::Enumerate<std::array::IntoIter<Option<FaceDescription>,5>>,impl FnMut((usize,Option<FaceDescription>))->Option<(usize,FaceDescription)>>{ pub fn pairs(
self.0.into_iter().enumerate().filter_map(|v|v.1.map(|u|(v.0,u))) self,
) -> std::iter::FilterMap<
std::iter::Enumerate<std::array::IntoIter<Option<FaceDescription>, 5>>,
impl FnMut((usize, Option<FaceDescription>)) -> Option<(usize, FaceDescription)>,
> {
self.0
.into_iter()
.enumerate()
.filter_map(|v| v.1.map(|u| (v.0, u)))
} }
} }
pub fn unit_cornerwedge(render: RenderConfigId) -> Mesh { pub fn unit_cornerwedge(render: RenderConfigId) -> Mesh {
let mut t = CornerWedgeFaceDescription::default(); let mut t = CornerWedgeFaceDescription::default();
t.insert(CornerWedgeFace::Right,FaceDescription::new_with_render_id(render)); t.insert(
t.insert(CornerWedgeFace::TopBack,FaceDescription::new_with_render_id(render)); CornerWedgeFace::Right,
t.insert(CornerWedgeFace::TopLeft,FaceDescription::new_with_render_id(render)); FaceDescription::new_with_render_id(render),
t.insert(CornerWedgeFace::Bottom,FaceDescription::new_with_render_id(render)); );
t.insert(CornerWedgeFace::Front,FaceDescription::new_with_render_id(render)); t.insert(
CornerWedgeFace::TopBack,
FaceDescription::new_with_render_id(render),
);
t.insert(
CornerWedgeFace::TopLeft,
FaceDescription::new_with_render_id(render),
);
t.insert(
CornerWedgeFace::Bottom,
FaceDescription::new_with_render_id(render),
);
t.insert(
CornerWedgeFace::Front,
FaceDescription::new_with_render_id(render),
);
generate_partial_unit_cornerwedge(t) generate_partial_unit_cornerwedge(t)
} }
@ -220,18 +250,25 @@ pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->Mesh{
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices. //note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
for (face_id, face_description) in face_descriptions.pairs() { for (face_id, face_description) in face_descriptions.pairs() {
//assume that scanning short lists is faster than hashing. //assume that scanning short lists is faster than hashing.
let transform_index=if let Some(transform_index)=transforms.iter().position(|&transform|transform==face_description.transform){ let transform_index = if let Some(transform_index) = transforms
.iter()
.position(|&transform| transform == face_description.transform)
{
transform_index transform_index
} else { } else {
//create new transform_index //create new transform_index
let transform_index = transforms.len(); let transform_index = transforms.len();
transforms.push(face_description.transform); transforms.push(face_description.transform);
generated_tex.extend(CUBE_DEFAULT_TEXTURE_COORDS.map(|tex| generated_tex.extend(
face_description.transform.transform_point2(tex) CUBE_DEFAULT_TEXTURE_COORDS
)); .map(|tex| face_description.transform.transform_point2(tex)),
);
transform_index transform_index
} as u32; } as u32;
let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){ let color_index = if let Some(color_index) = generated_color
.iter()
.position(|&color| color == face_description.color)
{
color_index color_index
} else { } else {
//create new color_index //create new color_index
@ -245,9 +282,11 @@ pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->Mesh{
//push vertices as they are needed //push vertices as they are needed
let group_id = PolygonGroupId::new(polygon_groups.len() as u32); let group_id = PolygonGroupId::new(polygon_groups.len() as u32);
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(vec![ polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(vec![
CUBE_DEFAULT_POLYS[face_id].map(|tup|{ CUBE_DEFAULT_POLYS[face_id]
.map(|tup| {
let pos = CUBE_DEFAULT_VERTICES[tup[0] as usize]; let pos = CUBE_DEFAULT_VERTICES[tup[0] as usize];
let pos_index=if let Some(pos_index)=generated_pos.iter().position(|&p|p==pos){ let pos_index =
if let Some(pos_index) = generated_pos.iter().position(|&p| p == pos) {
pos_index pos_index
} else { } else {
//create new pos_index //create new pos_index
@ -265,7 +304,8 @@ pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->Mesh{
let vert_index = generated_vertices.len(); let vert_index = generated_vertices.len();
generated_vertices.push(vertex); generated_vertices.push(vertex);
VertexId::new(vert_index as u32) VertexId::new(vert_index as u32)
}).to_vec(), })
.to_vec(),
]))); ])));
graphics_groups.push(IndexedGraphicsGroup { graphics_groups.push(IndexedGraphicsGroup {
render: face_description.render, render: face_description.render,
@ -294,32 +334,13 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->Mesh
[1, 3, 0], [1, 3, 0],
], ],
// FrontTop (0, 1, -1) // FrontTop (0, 1, -1)
vec![ vec![[3, 1, 1], [2, 0, 1], [6, 3, 1], [7, 2, 1]],
[3,1,1],
[2,0,1],
[6,3,1],
[7,2,1],
],
// back (0, 0, 1) // back (0, 0, 1)
vec![ vec![[0, 3, 2], [1, 2, 2], [2, 1, 2], [3, 0, 2]],
[0,3,2],
[1,2,2],
[2,1,2],
[3,0,2],
],
// left (-1, 0, 0) // left (-1, 0, 0)
vec![ vec![[0, 2, 3], [3, 1, 3], [7, 3, 3]],
[0,2,3],
[3,1,3],
[7,3,3],
],
// bottom (0,-1, 0) // bottom (0,-1, 0)
vec![ vec![[1, 1, 4], [0, 0, 4], [7, 3, 4], [6, 2, 4]],
[1,1,4],
[0,0,4],
[7,3,4],
[6,2,4],
],
]; ];
let mut generated_pos = Vec::new(); let mut generated_pos = Vec::new();
let mut generated_tex = Vec::new(); let mut generated_tex = Vec::new();
@ -333,18 +354,25 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->Mesh
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices. //note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
for (face_id, face_description) in face_descriptions.pairs() { for (face_id, face_description) in face_descriptions.pairs() {
//assume that scanning short lists is faster than hashing. //assume that scanning short lists is faster than hashing.
let transform_index=if let Some(transform_index)=transforms.iter().position(|&transform|transform==face_description.transform){ let transform_index = if let Some(transform_index) = transforms
.iter()
.position(|&transform| transform == face_description.transform)
{
transform_index transform_index
} else { } else {
//create new transform_index //create new transform_index
let transform_index = transforms.len(); let transform_index = transforms.len();
transforms.push(face_description.transform); transforms.push(face_description.transform);
generated_tex.extend(CUBE_DEFAULT_TEXTURE_COORDS.map(|tex| generated_tex.extend(
face_description.transform.transform_point2(tex) CUBE_DEFAULT_TEXTURE_COORDS
)); .map(|tex| face_description.transform.transform_point2(tex)),
);
transform_index transform_index
} as u32; } as u32;
let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){ let color_index = if let Some(color_index) = generated_color
.iter()
.position(|&color| color == face_description.color)
{
color_index color_index
} else { } else {
//create new color_index //create new color_index
@ -358,9 +386,12 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->Mesh
//push vertices as they are needed //push vertices as they are needed
let group_id = PolygonGroupId::new(polygon_groups.len() as u32); let group_id = PolygonGroupId::new(polygon_groups.len() as u32);
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(vec![ polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(vec![
wedge_default_polys[face_id].iter().map(|tup|{ wedge_default_polys[face_id]
.iter()
.map(|tup| {
let pos = CUBE_DEFAULT_VERTICES[tup[0] as usize]; let pos = CUBE_DEFAULT_VERTICES[tup[0] as usize];
let pos_index=if let Some(pos_index)=generated_pos.iter().position(|&p|p==pos){ let pos_index =
if let Some(pos_index) = generated_pos.iter().position(|&p| p == pos) {
pos_index pos_index
} else { } else {
//create new pos_index //create new pos_index
@ -378,7 +409,8 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->Mesh
let vert_index = generated_vertices.len(); let vert_index = generated_vertices.len();
generated_vertices.push(vertex); generated_vertices.push(vertex);
VertexId::new(vert_index as u32) VertexId::new(vert_index as u32)
}).collect() })
.collect(),
]))); ])));
graphics_groups.push(IndexedGraphicsGroup { graphics_groups.push(IndexedGraphicsGroup {
render: face_description.render, render: face_description.render,
@ -407,30 +439,13 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
[1, 3, 0], [1, 3, 0],
], ],
// BackTop (0, 1, 1) // BackTop (0, 1, 1)
vec![ vec![[5, 3, 1], [0, 1, 1], [1, 0, 1]],
[5,3,1],
[0,1,1],
[1,0,1],
],
// LeftTop (-1, 1, 0) // LeftTop (-1, 1, 0)
vec![ vec![[5, 3, 2], [7, 2, 2], [0, 1, 2]],
[5,3,2],
[7,2,2],
[0,1,2],
],
// bottom (0,-1, 0) // bottom (0,-1, 0)
vec![ vec![[1, 1, 3], [0, 0, 3], [7, 3, 3], [6, 2, 3]],
[1,1,3],
[0,0,3],
[7,3,3],
[6,2,3],
],
// front (0, 0,-1) // front (0, 0,-1)
vec![ vec![[5, 0, 4], [6, 3, 4], [7, 2, 4]],
[5,0,4],
[6,3,4],
[7,2,4],
],
]; ];
let mut generated_pos = Vec::new(); let mut generated_pos = Vec::new();
let mut generated_tex = Vec::new(); let mut generated_tex = Vec::new();
@ -444,18 +459,25 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices. //note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
for (face_id, face_description) in face_descriptions.pairs() { for (face_id, face_description) in face_descriptions.pairs() {
//assume that scanning short lists is faster than hashing. //assume that scanning short lists is faster than hashing.
let transform_index=if let Some(transform_index)=transforms.iter().position(|&transform|transform==face_description.transform){ let transform_index = if let Some(transform_index) = transforms
.iter()
.position(|&transform| transform == face_description.transform)
{
transform_index transform_index
} else { } else {
//create new transform_index //create new transform_index
let transform_index = transforms.len(); let transform_index = transforms.len();
transforms.push(face_description.transform); transforms.push(face_description.transform);
generated_tex.extend(CUBE_DEFAULT_TEXTURE_COORDS.map(|tex| generated_tex.extend(
face_description.transform.transform_point2(tex) CUBE_DEFAULT_TEXTURE_COORDS
)); .map(|tex| face_description.transform.transform_point2(tex)),
);
transform_index transform_index
} as u32; } as u32;
let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){ let color_index = if let Some(color_index) = generated_color
.iter()
.position(|&color| color == face_description.color)
{
color_index color_index
} else { } else {
//create new color_index //create new color_index
@ -469,9 +491,12 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
//push vertices as they are needed //push vertices as they are needed
let group_id = PolygonGroupId::new(polygon_groups.len() as u32); let group_id = PolygonGroupId::new(polygon_groups.len() as u32);
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(vec![ polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(vec![
cornerwedge_default_polys[face_id].iter().map(|tup|{ cornerwedge_default_polys[face_id]
.iter()
.map(|tup| {
let pos = CUBE_DEFAULT_VERTICES[tup[0] as usize]; let pos = CUBE_DEFAULT_VERTICES[tup[0] as usize];
let pos_index=if let Some(pos_index)=generated_pos.iter().position(|&p|p==pos){ let pos_index =
if let Some(pos_index) = generated_pos.iter().position(|&p| p == pos) {
pos_index pos_index
} else { } else {
//create new pos_index //create new pos_index
@ -489,7 +514,8 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
let vert_index = generated_vertices.len(); let vert_index = generated_vertices.len();
generated_vertices.push(vertex); generated_vertices.push(vertex);
VertexId::new(vert_index as u32) VertexId::new(vert_index as u32)
}).collect(), })
.collect(),
]))); ])));
graphics_groups.push(IndexedGraphicsGroup { graphics_groups.push(IndexedGraphicsGroup {
render: face_description.render, render: face_description.render,

File diff suppressed because it is too large Load Diff

View File

@ -2,12 +2,15 @@ use rbx_dom_weak::{types::Ref,InstanceBuilder,WeakDom};
pub fn class_is_a(class: &str, superclass: &str) -> bool { pub fn class_is_a(class: &str, superclass: &str) -> bool {
class == superclass class == superclass
||rbx_reflection_database::get().classes.get(class) || rbx_reflection_database::get()
.is_some_and(|descriptor| .classes
descriptor.superclass.as_ref().is_some_and(|class_super| .get(class)
class_is_a(class_super,superclass) .is_some_and(|descriptor| {
) descriptor
) .superclass
.as_ref()
.is_some_and(|class_super| class_is_a(class_super, superclass))
})
} }
#[repr(transparent)] #[repr(transparent)]
@ -19,16 +22,21 @@ impl Context{
pub const fn new(dom: WeakDom) -> Self { pub const fn new(dom: WeakDom) -> Self {
Self { dom } Self { dom }
} }
pub fn script_singleton(source:String)->(Context,crate::runner::instance::Instance,Services){ pub fn script_singleton(
source: String,
) -> (Context, crate::runner::instance::Instance, Services) {
let script = InstanceBuilder::new("Script") let script = InstanceBuilder::new("Script")
.with_property("Source", rbx_types::Variant::String(source)); .with_property("Source", rbx_types::Variant::String(source));
let script_ref = script.referent(); let script_ref = script.referent();
let mut context = Self::new(WeakDom::new( let mut context = Self::new(WeakDom::new(
InstanceBuilder::new("DataModel") InstanceBuilder::new("DataModel").with_child(script),
.with_child(script)
)); ));
let services = context.convert_into_place(); let services = context.convert_into_place();
(context,crate::runner::instance::Instance::new(script_ref),services) (
context,
crate::runner::instance::Instance::new(script_ref),
services,
)
} }
pub fn from_ref(dom: &WeakDom) -> &Context { pub fn from_ref(dom: &WeakDom) -> &Context {
unsafe { &*(dom as *const WeakDom as *const Context) } unsafe { &*(dom as *const WeakDom as *const Context) }
@ -38,19 +46,24 @@ impl Context{
} }
/// Creates an iterator over all items of a particular class. /// Creates an iterator over all items of a particular class.
pub fn superclass_iter<'a>(&'a self, superclass: &'a str) -> impl Iterator<Item = Ref> + 'a { pub fn superclass_iter<'a>(&'a self, superclass: &'a str) -> impl Iterator<Item = Ref> + 'a {
self.dom.descendants().filter(|&instance| self.dom
class_is_a(instance.class.as_ref(),superclass) .descendants()
).map(|instance|instance.referent()) .filter(|&instance| class_is_a(instance.class.as_ref(), superclass))
.map(|instance| instance.referent())
} }
pub fn scripts(&self) -> Vec<crate::runner::instance::Instance> { pub fn scripts(&self) -> Vec<crate::runner::instance::Instance> {
self.superclass_iter("LuaSourceContainer").map(crate::runner::instance::Instance::new).collect() self.superclass_iter("LuaSourceContainer")
.map(crate::runner::instance::Instance::new)
.collect()
} }
pub fn find_services(&self) -> Option<Services> { pub fn find_services(&self) -> Option<Services> {
Some(Services { Some(Services {
workspace:*self.dom.root().children().iter().find(|&&r| workspace: *self.dom.root().children().iter().find(|&&r| {
self.dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace") self.dom
)?, .get_by_ref(r)
.is_some_and(|instance| instance.class == "Workspace")
})?,
game: self.dom.root_ref(), game: self.dom.root_ref(),
}) })
} }
@ -61,17 +74,20 @@ impl Context{
//insert services //insert services
let game = self.dom.root_ref(); let game = self.dom.root_ref();
let terrain_bldr = InstanceBuilder::new("Terrain"); let terrain_bldr = InstanceBuilder::new("Terrain");
let workspace=self.dom.insert(game, let workspace = self.dom.insert(
game,
InstanceBuilder::new("Workspace") InstanceBuilder::new("Workspace")
//Set Workspace.Terrain property equal to Terrain //Set Workspace.Terrain property equal to Terrain
.with_property("Terrain", terrain_bldr.referent()) .with_property("Terrain", terrain_bldr.referent())
.with_child(terrain_bldr) .with_child(terrain_bldr),
); );
{ {
//Lowercase and upper case workspace property! //Lowercase and upper case workspace property!
let game = self.dom.root_mut(); let game = self.dom.root_mut();
game.properties.insert("workspace".to_owned(),rbx_types::Variant::Ref(workspace)); game.properties
game.properties.insert("Workspace".to_owned(),rbx_types::Variant::Ref(workspace)); .insert("workspace".to_owned(), rbx_types::Variant::Ref(workspace));
game.properties
.insert("Workspace".to_owned(), rbx_types::Variant::Ref(workspace));
} }
self.dom.insert(game, InstanceBuilder::new("Lighting")); self.dom.insert(game, InstanceBuilder::new("Lighting"));
@ -80,10 +96,7 @@ impl Context{
self.dom.transfer_within(instance, workspace); self.dom.transfer_within(instance, workspace);
} }
Services{ Services { game, workspace }
game,
workspace,
}
} }
} }

View File

@ -1,5 +1,5 @@
pub mod runner;
pub mod context; pub mod context;
pub mod runner;
#[cfg(feature = "run-service")] #[cfg(feature = "run-service")]
pub(crate) mod scheduler; pub(crate) mod scheduler;

View File

@ -5,25 +5,38 @@ pub struct CFrame(pub(crate)glam::Affine3A);
impl CFrame { impl CFrame {
pub fn new( pub fn new(
x:f32,y:f32,z:f32, x: f32,
xx:f32,yx:f32,zx:f32, y: f32,
xy:f32,yy:f32,zy:f32, z: f32,
xz:f32,yz:f32,zz:f32, xx: f32,
yx: f32,
zx: f32,
xy: f32,
yy: f32,
zy: f32,
xz: f32,
yz: f32,
zz: f32,
) -> Self { ) -> Self {
Self(glam::Affine3A::from_mat3_translation( Self(glam::Affine3A::from_mat3_translation(
glam::mat3( glam::mat3(
glam::vec3(xx, yx, zx), glam::vec3(xx, yx, zx),
glam::vec3(xy, yy, zy), glam::vec3(xy, yy, zy),
glam::vec3(xz,yz,zz) glam::vec3(xz, yz, zz),
), ),
glam::vec3(x,y,z) glam::vec3(x, y, z),
)) ))
} }
pub fn point(x: f32, y: f32, z: f32) -> Self { pub fn point(x: f32, y: f32, z: f32) -> Self {
Self(glam::Affine3A::from_translation(glam::vec3(x, y, z))) Self(glam::Affine3A::from_translation(glam::vec3(x, y, z)))
} }
pub fn angles(x: f32, y: f32, z: f32) -> Self { pub fn angles(x: f32, y: f32, z: f32) -> Self {
Self(glam::Affine3A::from_mat3(glam::Mat3::from_euler(glam::EulerRot::YXZ,y,x,z))) Self(glam::Affine3A::from_mat3(glam::Mat3::from_euler(
glam::EulerRot::YXZ,
y,
x,
z,
)))
} }
} }
@ -42,7 +55,7 @@ impl Into<rbx_types::CFrame> for CFrame{
vec3_to_glam(self.0.matrix3.x_axis), vec3_to_glam(self.0.matrix3.x_axis),
vec3_to_glam(self.0.matrix3.y_axis), vec3_to_glam(self.0.matrix3.y_axis),
vec3_to_glam(self.0.matrix3.z_axis), vec3_to_glam(self.0.matrix3.z_axis),
) ),
) )
} }
} }
@ -54,7 +67,7 @@ impl From<rbx_types::CFrame> for CFrame{
vec3_from_glam(value.orientation.y), vec3_from_glam(value.orientation.y),
vec3_from_glam(value.orientation.z), vec3_from_glam(value.orientation.z),
), ),
translation:vec3_from_glam(value.position) translation: vec3_from_glam(value.position),
}) })
} }
} }
@ -63,61 +76,102 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let cframe_table = lua.create_table()?; let cframe_table = lua.create_table()?;
//CFrame.new //CFrame.new
cframe_table.raw_set("new", cframe_table.raw_set(
lua.create_function(|_,tuple:( "new",
mlua::Value,mlua::Value,Option<f32>, lua.create_function(
Option<f32>,Option<f32>,Option<f32>, |_,
Option<f32>,Option<f32>,Option<f32>, tuple: (
Option<f32>,Option<f32>,Option<f32>, mlua::Value,
mlua::Value,
Option<f32>,
Option<f32>,
Option<f32>,
Option<f32>,
Option<f32>,
Option<f32>,
Option<f32>,
Option<f32>,
Option<f32>,
Option<f32>,
)| match tuple { )| match tuple {
//CFrame.new(pos) //CFrame.new(pos)
( (
mlua::Value::UserData(pos),mlua::Value::Nil,None, mlua::Value::UserData(pos),
None,None,None, mlua::Value::Nil,
None,None,None, None,
None,None,None, None,
None,
None,
None,
None,
None,
None,
None,
None,
) => { ) => {
let pos: Vector3 = pos.take()?; let pos: Vector3 = pos.take()?;
Ok(CFrame::point(pos.0.x, pos.0.y, pos.0.z)) Ok(CFrame::point(pos.0.x, pos.0.y, pos.0.z))
}, }
//TODO: CFrame.new(pos,look) //TODO: CFrame.new(pos,look)
( (
mlua::Value::UserData(pos),mlua::Value::UserData(look),None, mlua::Value::UserData(pos),
None,None,None, mlua::Value::UserData(look),
None,None,None, None,
None,None,None, None,
None,
None,
None,
None,
None,
None,
None,
None,
) => { ) => {
let _pos: Vector3 = pos.take()?; let _pos: Vector3 = pos.take()?;
let _look: Vector3 = look.take()?; let _look: Vector3 = look.take()?;
Err(mlua::Error::runtime("Not yet implemented")) Err(mlua::Error::runtime("Not yet implemented"))
}, }
//CFrame.new(x,y,z) //CFrame.new(x,y,z)
( (
mlua::Value::Number(x),mlua::Value::Number(y),Some(z), mlua::Value::Number(x),
None,None,None, mlua::Value::Number(y),
None,None,None, Some(z),
None,None,None, None,
None,
None,
None,
None,
None,
None,
None,
None,
) => Ok(CFrame::point(x as f32, y as f32, z)), ) => Ok(CFrame::point(x as f32, y as f32, z)),
//CFrame.new(x,y,z,xx,yx,zx,xy,yy,zy,xz,yz,zz) //CFrame.new(x,y,z,xx,yx,zx,xy,yy,zy,xz,yz,zz)
( (
mlua::Value::Number(x),mlua::Value::Number(y),Some(z), mlua::Value::Number(x),
Some(xx),Some(yx),Some(zx), mlua::Value::Number(y),
Some(xy),Some(yy),Some(zy), Some(z),
Some(xz),Some(yz),Some(zz), Some(xx),
)=>Ok(CFrame::new(x as f32,y as f32,z, Some(yx),
xx,yx,zx, Some(zx),
xy,yy,zy, Some(xy),
xz,yz,zz, Some(yy),
Some(zy),
Some(xz),
Some(yz),
Some(zz),
) => Ok(CFrame::new(
x as f32, y as f32, z, xx, yx, zx, xy, yy, zy, xz, yz, zz,
)), )),
_=>Err(mlua::Error::runtime("Invalid arguments")) _ => Err(mlua::Error::runtime("Invalid arguments")),
})? },
)?,
)?; )?;
//CFrame.Angles //CFrame.Angles
cframe_table.raw_set("Angles", cframe_table.raw_set(
lua.create_function(|_,(x,y,z):(f32,f32,f32)| "Angles",
Ok(CFrame::angles(x,y,z)) lua.create_function(|_, (x, y, z): (f32, f32, f32)| Ok(CFrame::angles(x, y, z)))?,
)?
)?; )?;
globals.set("CFrame", cframe_table)?; globals.set("CFrame", cframe_table)?;
@ -132,28 +186,8 @@ impl mlua::UserData for CFrame{
} }
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_method("components",|_,this,()|Ok(( methods.add_method("components", |_, this, ()| {
this.0.translation.x, Ok((
this.0.translation.y,
this.0.translation.z,
this.0.matrix3.x_axis.x,
this.0.matrix3.y_axis.x,
this.0.matrix3.z_axis.x,
this.0.matrix3.x_axis.y,
this.0.matrix3.y_axis.y,
this.0.matrix3.z_axis.y,
this.0.matrix3.x_axis.z,
this.0.matrix3.y_axis.z,
this.0.matrix3.z_axis.z,
)));
methods.add_method("VectorToWorldSpace",|_,this,v:Vector3|
Ok(Vector3(this.0.transform_vector3a(v.0)))
);
//methods.add_meta_method(mlua::MetaMethod::Mul,|_,this,val:&Vector3|Ok(Vector3(this.0.matrix3*val.0+this.0.translation)));
methods.add_meta_function(mlua::MetaMethod::Mul,|_,(this,val):(Self,Self)|Ok(Self(this.0*val.0)));
methods.add_meta_function(mlua::MetaMethod::ToString,|_,this:Self|
Ok(format!("CFrame.new({},{},{},{},{},{},{},{},{},{},{},{})",
this.0.translation.x, this.0.translation.x,
this.0.translation.y, this.0.translation.y,
this.0.translation.z, this.0.translation.z,
@ -167,7 +201,32 @@ impl mlua::UserData for CFrame{
this.0.matrix3.y_axis.z, this.0.matrix3.y_axis.z,
this.0.matrix3.z_axis.z, this.0.matrix3.z_axis.z,
)) ))
); });
methods.add_method("VectorToWorldSpace", |_, this, v: Vector3| {
Ok(Vector3(this.0.transform_vector3a(v.0)))
});
//methods.add_meta_method(mlua::MetaMethod::Mul,|_,this,val:&Vector3|Ok(Vector3(this.0.matrix3*val.0+this.0.translation)));
methods.add_meta_function(mlua::MetaMethod::Mul, |_, (this, val): (Self, Self)| {
Ok(Self(this.0 * val.0))
});
methods.add_meta_function(mlua::MetaMethod::ToString, |_, this: Self| {
Ok(format!(
"CFrame.new({},{},{},{},{},{},{},{},{},{},{},{})",
this.0.translation.x,
this.0.translation.y,
this.0.translation.z,
this.0.matrix3.x_axis.x,
this.0.matrix3.y_axis.x,
this.0.matrix3.z_axis.x,
this.0.matrix3.x_axis.y,
this.0.matrix3.y_axis.y,
this.0.matrix3.z_axis.y,
this.0.matrix3.x_axis.z,
this.0.matrix3.y_axis.z,
this.0.matrix3.z_axis.z,
))
});
} }
} }

View File

@ -18,15 +18,19 @@ impl Into<rbx_types::Color3> for Color3{
pub fn set_globals(lua: &mlua::Lua, globals: &mlua::Table) -> Result<(), mlua::Error> { pub fn set_globals(lua: &mlua::Lua, globals: &mlua::Table) -> Result<(), mlua::Error> {
let color3_table = lua.create_table()?; let color3_table = lua.create_table()?;
color3_table.raw_set("new", color3_table.raw_set(
lua.create_function(|_,(r,g,b):(f32,f32,f32)| "new",
Ok(Color3::new(r,g,b)) lua.create_function(|_, (r, g, b): (f32, f32, f32)| Ok(Color3::new(r, g, b)))?,
)?
)?; )?;
color3_table.raw_set("fromRGB", color3_table.raw_set(
lua.create_function(|_,(r,g,b):(u8,u8,u8)| "fromRGB",
Ok(Color3::new(r as f32/255.0,g as f32/255.0,b as f32/255.0)) lua.create_function(|_, (r, g, b): (u8, u8, u8)| {
)? Ok(Color3::new(
r as f32 / 255.0,
g as f32 / 255.0,
b as f32 / 255.0,
))
})?,
)?; )?;
globals.set("Color3", color3_table)?; globals.set("Color3", color3_table)?;
@ -56,13 +60,13 @@ impl mlua::UserData for Color3{
}); });
} }
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_method("Lerp",|_,this,(other,t):(Self,f32)| methods.add_method("Lerp", |_, this, (other, t): (Self, f32)| {
Ok(Color3::new( Ok(Color3::new(
lerp(this.r, other.r, t), lerp(this.r, other.r, t),
lerp(this.g, other.g, t), lerp(this.g, other.g, t),
lerp(this.b, other.b, t), lerp(this.b, other.b, t),
)) ))
) })
} }
} }
type_from_lua_userdata!(Color3); type_from_lua_userdata!(Color3);

View File

@ -8,7 +8,7 @@ impl ColorSequence{
impl Into<rbx_types::ColorSequence> for ColorSequence { impl Into<rbx_types::ColorSequence> for ColorSequence {
fn into(self) -> rbx_types::ColorSequence { fn into(self) -> rbx_types::ColorSequence {
rbx_types::ColorSequence { rbx_types::ColorSequence {
keypoints:Vec::new() keypoints: Vec::new(),
} }
} }
} }
@ -16,10 +16,9 @@ impl Into<rbx_types::ColorSequence> for ColorSequence{
pub fn set_globals(lua: &mlua::Lua, globals: &mlua::Table) -> Result<(), mlua::Error> { pub fn set_globals(lua: &mlua::Lua, globals: &mlua::Table) -> Result<(), mlua::Error> {
let number_sequence_table = lua.create_table()?; let number_sequence_table = lua.create_table()?;
number_sequence_table.raw_set("new", number_sequence_table.raw_set(
lua.create_function(|_,_:mlua::MultiValue| "new",
Ok(ColorSequence::new()) lua.create_function(|_, _: mlua::MultiValue| Ok(ColorSequence::new()))?,
)?
)?; )?;
globals.set("ColorSequence", number_sequence_table)?; globals.set("ColorSequence", number_sequence_table)?;

View File

@ -26,38 +26,42 @@ pub fn set_globals(_lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>
} }
impl mlua::UserData for EnumItem<'_> { impl mlua::UserData for EnumItem<'_> {
fn add_fields<F:mlua::UserDataFields<Self>>(_fields:&mut F){ fn add_fields<F: mlua::UserDataFields<Self>>(_fields: &mut F) {}
}
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,val):(EnumItem<'_>,mlua::String)|{ methods.add_meta_function(
match this.ed.items.get(&*val.to_str()?){ mlua::MetaMethod::Index,
|lua, (this, val): (EnumItem<'_>, mlua::String)| match this
.ed
.items
.get(&*val.to_str()?)
{
Some(&id) => Enum(id).into_lua(lua), Some(&id) => Enum(id).into_lua(lua),
None => mlua::Value::Nil.into_lua(lua), None => mlua::Value::Nil.into_lua(lua),
} },
}); );
} }
} }
type_from_lua_userdata_lua_lifetime!(EnumItem); type_from_lua_userdata_lua_lifetime!(EnumItem);
impl mlua::UserData for EnumItems { impl mlua::UserData for EnumItems {
fn add_fields<F:mlua::UserDataFields<Self>>(_fields:&mut F){ fn add_fields<F: mlua::UserDataFields<Self>>(_fields: &mut F) {}
}
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_function(mlua::MetaMethod::Index,|lua,(_,val):(Self,mlua::String)|{ methods.add_meta_function(
mlua::MetaMethod::Index,
|lua, (_, val): (Self, mlua::String)| {
let db = rbx_reflection_database::get(); let db = rbx_reflection_database::get();
match db.enums.get(&*val.to_str()?) { match db.enums.get(&*val.to_str()?) {
Some(ed) => EnumItem::new(ed).into_lua(lua), Some(ed) => EnumItem::new(ed).into_lua(lua),
None => mlua::Value::Nil.into_lua(lua), None => mlua::Value::Nil.into_lua(lua),
} }
}); },
);
} }
} }
type_from_lua_userdata!(EnumItems); type_from_lua_userdata!(EnumItems);
impl mlua::UserData for Enum { impl mlua::UserData for Enum {
fn add_fields<F:mlua::UserDataFields<Self>>(_fields:&mut F){ fn add_fields<F: mlua::UserDataFields<Self>>(_fields: &mut F) {}
} fn add_methods<M: mlua::UserDataMethods<Self>>(_methods: &mut M) {}
fn add_methods<M:mlua::UserDataMethods<Self>>(_methods:&mut M){
}
} }
type_from_lua_userdata!(Enum); type_from_lua_userdata!(Enum);

View File

@ -1,8 +1,8 @@
use std::collections::{hash_map::Entry, HashMap}; use std::collections::{hash_map::Entry, HashMap};
use mlua::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti}; use mlua::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
use rbx_types::Ref;
use rbx_dom_weak::{InstanceBuilder, WeakDom}; use rbx_dom_weak::{InstanceBuilder, WeakDom};
use rbx_types::Ref;
use crate::runner::vector3::Vector3; use crate::runner::vector3::Vector3;
@ -14,15 +14,22 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let instance_table = lua.create_table()?; let instance_table = lua.create_table()?;
//Instance.new //Instance.new
instance_table.raw_set("new", instance_table.raw_set(
lua.create_function(|lua,(class_name,parent):(mlua::String,Option<Instance>)|{ "new",
lua.create_function(
|lua, (class_name, parent): (mlua::String, Option<Instance>)| {
let class_name_str = &*class_name.to_str()?; let class_name_str = &*class_name.to_str()?;
let parent=parent.ok_or_else(||mlua::Error::runtime("Nil Parent not yet supported"))?; let parent =
parent.ok_or_else(|| mlua::Error::runtime("Nil Parent not yet supported"))?;
dom_mut(lua, |dom| { dom_mut(lua, |dom| {
//TODO: Nil instances //TODO: Nil instances
Ok(Instance::new(dom.insert(parent.referent,InstanceBuilder::new(class_name_str)))) Ok(Instance::new(dom.insert(
parent.referent,
InstanceBuilder::new(class_name_str),
)))
}) })
})? },
)?,
)?; )?;
globals.set("Instance", instance_table)?; globals.set("Instance", instance_table)?;
@ -31,8 +38,13 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
} }
// LMAO look at this function! // LMAO look at this function!
pub fn dom_mut<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result<T>)->mlua::Result<T>{ pub fn dom_mut<T>(
let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or_else(||mlua::Error::runtime("DataModel missing"))?; lua: &mlua::Lua,
mut f: impl FnMut(&mut WeakDom) -> mlua::Result<T>,
) -> mlua::Result<T> {
let mut dom = lua
.app_data_mut::<&'static mut WeakDom>()
.ok_or_else(|| mlua::Error::runtime("DataModel missing"))?;
f(&mut *dom) f(&mut *dom)
} }
@ -66,18 +78,44 @@ pub fn get_name_source(lua:&mlua::Lua,script:Instance)->Result<(String,String),m
}) })
} }
pub fn find_first_child<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,name:&str)->Option<&'a rbx_dom_weak::Instance>{ pub fn find_first_child<'a>(
instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.name==name) dom: &'a rbx_dom_weak::WeakDom,
instance: &rbx_dom_weak::Instance,
name: &str,
) -> Option<&'a rbx_dom_weak::Instance> {
instance
.children()
.iter()
.filter_map(|&r| dom.get_by_ref(r))
.find(|inst| inst.name == name)
} }
pub fn find_first_descendant<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,name:&str)->Option<&'a rbx_dom_weak::Instance>{ pub fn find_first_descendant<'a>(
dom.descendants_of(instance.referent()).find(|&inst|inst.name==name) dom: &'a rbx_dom_weak::WeakDom,
instance: &rbx_dom_weak::Instance,
name: &str,
) -> Option<&'a rbx_dom_weak::Instance> {
dom.descendants_of(instance.referent())
.find(|&inst| inst.name == name)
} }
pub fn find_first_child_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,class:&str)->Option<&'a rbx_dom_weak::Instance>{ pub fn find_first_child_of_class<'a>(
instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.class==class) dom: &'a rbx_dom_weak::WeakDom,
instance: &rbx_dom_weak::Instance,
class: &str,
) -> Option<&'a rbx_dom_weak::Instance> {
instance
.children()
.iter()
.filter_map(|&r| dom.get_by_ref(r))
.find(|inst| inst.class == class)
} }
pub fn find_first_descendant_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,class:&str)->Option<&'a rbx_dom_weak::Instance>{ pub fn find_first_descendant_of_class<'a>(
dom.descendants_of(instance.referent()).find(|&inst|inst.class==class) dom: &'a rbx_dom_weak::WeakDom,
instance: &rbx_dom_weak::Instance,
class: &str,
) -> Option<&'a rbx_dom_weak::Instance> {
dom.descendants_of(instance.referent())
.find(|&inst| inst.class == class)
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -89,10 +127,15 @@ impl Instance{
Self { referent } Self { referent }
} }
pub fn get<'a>(&self, dom: &'a WeakDom) -> mlua::Result<&'a rbx_dom_weak::Instance> { pub fn get<'a>(&self, dom: &'a WeakDom) -> mlua::Result<&'a rbx_dom_weak::Instance> {
dom.get_by_ref(self.referent).ok_or_else(||mlua::Error::runtime("Instance missing")) dom.get_by_ref(self.referent)
.ok_or_else(|| mlua::Error::runtime("Instance missing"))
} }
pub fn get_mut<'a>(&self,dom:&'a mut WeakDom)->mlua::Result<&'a mut rbx_dom_weak::Instance>{ pub fn get_mut<'a>(
dom.get_by_ref_mut(self.referent).ok_or_else(||mlua::Error::runtime("Instance missing")) &self,
dom: &'a mut WeakDom,
) -> mlua::Result<&'a mut rbx_dom_weak::Instance> {
dom.get_by_ref_mut(self.referent)
.ok_or_else(|| mlua::Error::runtime("Instance missing"))
} }
} }
type_from_lua_userdata!(Instance); type_from_lua_userdata!(Instance);
@ -153,7 +196,7 @@ impl mlua::UserData for Instance{
}); });
} }
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_method("GetChildren",|lua,this,_:()| methods.add_method("GetChildren", |lua, this, _: ()| {
dom_mut(lua, |dom| { dom_mut(lua, |dom| {
let instance = this.get(dom)?; let instance = this.get(dom)?;
let children: Vec<_> = instance let children: Vec<_> = instance
@ -164,61 +207,61 @@ impl mlua::UserData for Instance{
.collect(); .collect();
Ok(children) Ok(children)
}) })
); });
fn ffc(lua:&mlua::Lua,this:&Instance,(name,search_descendants):(mlua::String,Option<bool>))->mlua::Result<Option<Instance>>{ fn ffc(
lua: &mlua::Lua,
this: &Instance,
(name, search_descendants): (mlua::String, Option<bool>),
) -> mlua::Result<Option<Instance>> {
let name_str = &*name.to_str()?; let name_str = &*name.to_str()?;
dom_mut(lua, |dom| { dom_mut(lua, |dom| {
let instance = this.get(dom)?; let instance = this.get(dom)?;
Ok( Ok(match search_descendants.unwrap_or(false) {
match search_descendants.unwrap_or(false){
true => find_first_descendant(dom, instance, name_str), true => find_first_descendant(dom, instance, name_str),
false => find_first_child(dom, instance, name_str), false => find_first_child(dom, instance, name_str),
} }
.map(|instance| .map(|instance| Instance::new(instance.referent())))
Instance::new(instance.referent())
)
)
}) })
} }
methods.add_method("FindFirstChild", ffc); methods.add_method("FindFirstChild", ffc);
methods.add_method("WaitForChild", ffc); methods.add_method("WaitForChild", ffc);
methods.add_method("FindFirstChildOfClass",|lua,this,(class,search_descendants):(mlua::String,Option<bool>)|{ methods.add_method(
"FindFirstChildOfClass",
|lua, this, (class, search_descendants): (mlua::String, Option<bool>)| {
let class_str = &*class.to_str()?; let class_str = &*class.to_str()?;
dom_mut(lua, |dom| { dom_mut(lua, |dom| {
Ok( Ok(match search_descendants.unwrap_or(false) {
match search_descendants.unwrap_or(false){
true => find_first_descendant_of_class(dom, this.get(dom)?, class_str), true => find_first_descendant_of_class(dom, this.get(dom)?, class_str),
false => find_first_child_of_class(dom, this.get(dom)?, class_str), false => find_first_child_of_class(dom, this.get(dom)?, class_str),
} }
.map(|instance| .map(|instance| Instance::new(instance.referent())))
Instance::new(instance.referent())
)
)
}) })
}); },
methods.add_method("GetDescendants",|lua,this,_:()| );
methods.add_method("GetDescendants", |lua, this, _: ()| {
dom_mut(lua, |dom| { dom_mut(lua, |dom| {
let children: Vec<_> = dom let children: Vec<_> = dom
.descendants_of(this.referent) .descendants_of(this.referent)
.map(|instance| .map(|instance| Instance::new(instance.referent()))
Instance::new(instance.referent())
)
.collect(); .collect();
Ok(children) Ok(children)
}) })
); });
methods.add_method("IsA",|lua,this,classname:mlua::String| methods.add_method("IsA", |lua, this, classname: mlua::String| {
dom_mut(lua, |dom| { dom_mut(lua, |dom| {
let instance = this.get(dom)?; let instance = this.get(dom)?;
Ok(crate::context::class_is_a(instance.class.as_str(),&*classname.to_str()?)) Ok(crate::context::class_is_a(
instance.class.as_str(),
&*classname.to_str()?,
))
}) })
); });
methods.add_method("Destroy",|lua,this,()| methods.add_method("Destroy", |lua, this, ()| {
dom_mut(lua, |dom| { dom_mut(lua, |dom| {
dom.destroy(this.referent); dom.destroy(this.referent);
Ok(()) Ok(())
}) })
); });
methods.add_meta_function(mlua::MetaMethod::ToString, |lua, this: Instance| { methods.add_meta_function(mlua::MetaMethod::ToString, |lua, this: Instance| {
dom_mut(lua, |dom| { dom_mut(lua, |dom| {
let instance = this.get(dom)?; let instance = this.get(dom)?;
@ -289,68 +332,139 @@ impl mlua::UserData for Instance{
.into_lua(lua) .into_lua(lua)
}) })
}); });
methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(Instance,mlua::String,mlua::Value)|{ methods.add_meta_function(
mlua::MetaMethod::NewIndex,
|lua, (this, index, value): (Instance, mlua::String, mlua::Value)| {
dom_mut(lua, |dom| { dom_mut(lua, |dom| {
let instance = this.get_mut(dom)?; let instance = this.get_mut(dom)?;
//println!("__newindex t={} i={index:?} v={value:?}",instance.name); //println!("__newindex t={} i={index:?} v={value:?}",instance.name);
let index_str = &*index.to_str()?; let index_str = &*index.to_str()?;
let db = rbx_reflection_database::get(); let db = rbx_reflection_database::get();
let class=db.classes.get(instance.class.as_str()).ok_or_else(||mlua::Error::runtime("Class missing"))?; let class = db
.classes
.get(instance.class.as_str())
.ok_or_else(|| mlua::Error::runtime("Class missing"))?;
let mut iter = SuperClassIter { let mut iter = SuperClassIter {
database: db, database: db,
descriptor: Some(class), descriptor: Some(class),
}; };
let property=iter.find_map(|cls|cls.properties.get(index_str)).ok_or_else(||mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; let property = iter
.find_map(|cls| cls.properties.get(index_str))
.ok_or_else(|| {
mlua::Error::runtime(format!(
"Property '{index_str}' missing on class '{}'",
class.name
))
})?;
match &property.data_type { match &property.data_type {
rbx_reflection::DataType::Value(rbx_types::VariantType::Vector3) => { rbx_reflection::DataType::Value(rbx_types::VariantType::Vector3) => {
let typed_value:Vector3=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected Userdata"))?.borrow()?; let typed_value: Vector3 = *value
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Vector3(typed_value.into())); .as_userdata()
}, .ok_or_else(|| mlua::Error::runtime("Expected Userdata"))?
.borrow()?;
instance.properties.insert(
index_str.to_owned(),
rbx_types::Variant::Vector3(typed_value.into()),
);
}
rbx_reflection::DataType::Value(rbx_types::VariantType::Float32) => { rbx_reflection::DataType::Value(rbx_types::VariantType::Float32) => {
let typed_value:f32=coerce_float32(&value).ok_or_else(||mlua::Error::runtime("Expected f32"))?; let typed_value: f32 = coerce_float32(&value)
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); .ok_or_else(|| mlua::Error::runtime("Expected f32"))?;
}, instance.properties.insert(
index_str.to_owned(),
rbx_types::Variant::Float32(typed_value),
);
}
rbx_reflection::DataType::Enum(enum_name) => { rbx_reflection::DataType::Enum(enum_name) => {
let typed_value = match &value { let typed_value = match &value {
&mlua::Value::Integer(int)=>Ok(rbx_types::Enum::from_u32(int as u32)), &mlua::Value::Integer(int) => {
&mlua::Value::Number(num)=>Ok(rbx_types::Enum::from_u32(num as u32)), Ok(rbx_types::Enum::from_u32(int as u32))
}
&mlua::Value::Number(num) => {
Ok(rbx_types::Enum::from_u32(num as u32))
}
mlua::Value::String(s) => { mlua::Value::String(s) => {
let e=db.enums.get(enum_name).ok_or_else(||mlua::Error::runtime("Database DataType Enum name does not exist"))?; let e = db.enums.get(enum_name).ok_or_else(|| {
Ok(rbx_types::Enum::from_u32(*e.items.get(&*s.to_str()?).ok_or_else(||mlua::Error::runtime("Invalid enum item"))?)) mlua::Error::runtime(
}, "Database DataType Enum name does not exist",
)
})?;
Ok(rbx_types::Enum::from_u32(
*e.items.get(&*s.to_str()?).ok_or_else(|| {
mlua::Error::runtime("Invalid enum item")
})?,
))
}
mlua::Value::UserData(any_user_data) => { mlua::Value::UserData(any_user_data) => {
let e: crate::runner::r#enum::Enum = *any_user_data.borrow()?; let e: crate::runner::r#enum::Enum = *any_user_data.borrow()?;
Ok(e.into()) Ok(e.into())
}, }
_ => Err(mlua::Error::runtime("Expected Enum")), _ => Err(mlua::Error::runtime("Expected Enum")),
}?; }?;
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value)); instance.properties.insert(
}, index_str.to_owned(),
rbx_types::Variant::Enum(typed_value),
);
}
rbx_reflection::DataType::Value(rbx_types::VariantType::Color3) => { rbx_reflection::DataType::Value(rbx_types::VariantType::Color3) => {
let typed_value:crate::runner::color3::Color3=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected Color3"))?.borrow()?; let typed_value: crate::runner::color3::Color3 = *value
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); .as_userdata()
}, .ok_or_else(|| mlua::Error::runtime("Expected Color3"))?
.borrow()?;
instance.properties.insert(
index_str.to_owned(),
rbx_types::Variant::Color3(typed_value.into()),
);
}
rbx_reflection::DataType::Value(rbx_types::VariantType::Bool) => { rbx_reflection::DataType::Value(rbx_types::VariantType::Bool) => {
let typed_value=value.as_boolean().ok_or_else(||mlua::Error::runtime("Expected boolean"))?; let typed_value = value
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Bool(typed_value)); .as_boolean()
}, .ok_or_else(|| mlua::Error::runtime("Expected boolean"))?;
instance.properties.insert(
index_str.to_owned(),
rbx_types::Variant::Bool(typed_value),
);
}
rbx_reflection::DataType::Value(rbx_types::VariantType::String) => { rbx_reflection::DataType::Value(rbx_types::VariantType::String) => {
let typed_value=value.as_str().ok_or_else(||mlua::Error::runtime("Expected boolean"))?; let typed_value = value
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::String(typed_value.to_owned())); .as_str()
}, .ok_or_else(|| mlua::Error::runtime("Expected boolean"))?;
instance.properties.insert(
index_str.to_owned(),
rbx_types::Variant::String(typed_value.to_owned()),
);
}
rbx_reflection::DataType::Value(rbx_types::VariantType::NumberSequence) => { rbx_reflection::DataType::Value(rbx_types::VariantType::NumberSequence) => {
let typed_value:crate::runner::number_sequence::NumberSequence=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected NumberSequence"))?.borrow()?; let typed_value: crate::runner::number_sequence::NumberSequence =
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::NumberSequence(typed_value.into())); *value
}, .as_userdata()
.ok_or_else(|| mlua::Error::runtime("Expected NumberSequence"))?
.borrow()?;
instance.properties.insert(
index_str.to_owned(),
rbx_types::Variant::NumberSequence(typed_value.into()),
);
}
rbx_reflection::DataType::Value(rbx_types::VariantType::ColorSequence) => { rbx_reflection::DataType::Value(rbx_types::VariantType::ColorSequence) => {
let typed_value:crate::runner::color_sequence::ColorSequence=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected ColorSequence"))?.borrow()?; let typed_value: crate::runner::color_sequence::ColorSequence = *value
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::ColorSequence(typed_value.into())); .as_userdata()
}, .ok_or_else(|| mlua::Error::runtime("Expected ColorSequence"))?
other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), .borrow()?;
instance.properties.insert(
index_str.to_owned(),
rbx_types::Variant::ColorSequence(typed_value.into()),
);
}
other => {
return Err(mlua::Error::runtime(format!(
"Unimplemented property type: {other:?}"
)))
}
} }
Ok(()) Ok(())
}) })
}); },
);
} }
} }
@ -367,10 +481,12 @@ type ClassFunctionPointer=fn(&mlua::Lua,mlua::MultiValue)->mlua::Result<mlua::Mu
// TODO: use macros to define these with better organization // TODO: use macros to define these with better organization
/// A double hash map of function pointers. /// A double hash map of function pointers.
/// The class tree is walked by the Instance.__index metamethod to find available class methods. /// The class tree is walked by the Instance.__index metamethod to find available class methods.
type CFD=phf::Map<&'static str,// Class name type CFD = phf::Map<
phf::Map<&'static str,// Method name &'static str, // Class name
ClassFunctionPointer phf::Map<
> &'static str, // Method name
ClassFunctionPointer,
>,
>; >;
static CLASS_FUNCTION_DATABASE: CFD = phf::phf_map! { static CLASS_FUNCTION_DATABASE: CFD = phf::phf_map! {
"DataModel"=>phf::phf_map!{ "DataModel"=>phf::phf_map!{
@ -401,25 +517,28 @@ static CLASS_FUNCTION_DATABASE:CFD=phf::phf_map!{
/// Functions are created the first time they are accessed and stored in this data structure. /// Functions are created the first time they are accessed and stored in this data structure.
#[derive(Default)] #[derive(Default)]
struct ClassMethodsStore { struct ClassMethodsStore {
classes:HashMap<&'static str,//ClassName classes: HashMap<
HashMap<&'static str,//Method name &'static str, //ClassName
mlua::Function HashMap<
> &'static str, //Method name
> mlua::Function,
>,
>,
} }
impl ClassMethodsStore { impl ClassMethodsStore {
/// return self.classes[class] or create the ClassMethods and then return it /// return self.classes[class] or create the ClassMethods and then return it
fn get_or_create_class_methods(&mut self, class: &str) -> Option<ClassMethods> { fn get_or_create_class_methods(&mut self, class: &str) -> Option<ClassMethods> {
// Use get_entry to get the &'static str keys of the database // Use get_entry to get the &'static str keys of the database
// and use it as a key for the classes hashmap // and use it as a key for the classes hashmap
CLASS_FUNCTION_DATABASE.get_entry(class) CLASS_FUNCTION_DATABASE
.map(|(&static_class_str,method_pointers)| .get_entry(class)
ClassMethods{ .map(|(&static_class_str, method_pointers)| ClassMethods {
method_pointers, method_pointers,
methods:self.classes.entry(static_class_str) methods: self
.classes
.entry(static_class_str)
.or_insert_with(|| HashMap::new()), .or_insert_with(|| HashMap::new()),
} })
)
} }
} }
struct ClassMethods<'a> { struct ClassMethods<'a> {
@ -428,44 +547,49 @@ struct ClassMethods<'a>{
} }
impl ClassMethods<'_> { impl ClassMethods<'_> {
/// return self.methods[index] or create the function in the hashmap and then return it /// return self.methods[index] or create the function in the hashmap and then return it
fn get_or_create_function(&mut self,lua:&mlua::Lua,index:&str)->mlua::Result<Option<mlua::Function>>{ fn get_or_create_function(
&mut self,
lua: &mlua::Lua,
index: &str,
) -> mlua::Result<Option<mlua::Function>> {
Ok(match self.method_pointers.get_entry(index) { Ok(match self.method_pointers.get_entry(index) {
Some((&static_index_str,&function_pointer))=>Some( Some((&static_index_str, &function_pointer)) => {
match self.methods.entry(static_index_str){ Some(match self.methods.entry(static_index_str) {
Entry::Occupied(entry) => entry.get().clone(), Entry::Occupied(entry) => entry.get().clone(),
Entry::Vacant(entry)=>entry.insert( Entry::Vacant(entry) => {
lua.create_function(function_pointer)? entry.insert(lua.create_function(function_pointer)?).clone()
).clone(), }
})
} }
),
None => None, None => None,
}) })
} }
} }
fn class_methods_store_mut<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut ClassMethodsStore)->mlua::Result<T>)->mlua::Result<T>{ fn class_methods_store_mut<T>(
let mut cf=lua.app_data_mut::<ClassMethodsStore>().ok_or_else(||mlua::Error::runtime("ClassMethodsStore missing"))?; lua: &mlua::Lua,
mut f: impl FnMut(&mut ClassMethodsStore) -> mlua::Result<T>,
) -> mlua::Result<T> {
let mut cf = lua
.app_data_mut::<ClassMethodsStore>()
.ok_or_else(|| mlua::Error::runtime("ClassMethodsStore missing"))?;
f(&mut *cf) f(&mut *cf)
} }
/// A virtual property pointer definition shorthand. /// A virtual property pointer definition shorthand.
type VirtualPropertyFunctionPointer = fn(&rbx_types::Variant) -> Option<rbx_types::Variant>; type VirtualPropertyFunctionPointer = fn(&rbx_types::Variant) -> Option<rbx_types::Variant>;
const fn vpp( const fn vpp(property: &'static str, pointer: VirtualPropertyFunctionPointer) -> VirtualProperty {
property:&'static str, VirtualProperty { property, pointer }
pointer:VirtualPropertyFunctionPointer,
)->VirtualProperty{
VirtualProperty{
property,
pointer,
}
} }
struct VirtualProperty { struct VirtualProperty {
property: &'static str, // Source property name property: &'static str, // Source property name
pointer: VirtualPropertyFunctionPointer, pointer: VirtualPropertyFunctionPointer,
} }
type VPD=phf::Map<&'static str,// Class name type VPD = phf::Map<
phf::Map<&'static str,// Virtual property name &'static str, // Class name
VirtualProperty phf::Map<
> &'static str, // Virtual property name
VirtualProperty,
>,
>; >;
static VIRTUAL_PROPERTY_DATABASE: VPD = phf::phf_map! { static VIRTUAL_PROPERTY_DATABASE: VPD = phf::phf_map! {
"BasePart"=>phf::phf_map!{ "BasePart"=>phf::phf_map!{
@ -482,7 +606,7 @@ static VIRTUAL_PROPERTY_DATABASE:VPD=phf::phf_map!{
fn find_virtual_property( fn find_virtual_property(
properties: &HashMap<String, rbx_types::Variant>, properties: &HashMap<String, rbx_types::Variant>,
class: &rbx_reflection::ClassDescriptor, class: &rbx_reflection::ClassDescriptor,
index:&str index: &str,
) -> Option<rbx_types::Variant> { ) -> Option<rbx_types::Variant> {
//Find virtual property //Find virtual property
let class_virtual_properties = VIRTUAL_PROPERTY_DATABASE.get(&class.name)?; let class_virtual_properties = VIRTUAL_PROPERTY_DATABASE.get(&class.name)?;
@ -499,10 +623,12 @@ fn find_virtual_property(
// This whole thing is a bad idea and a garbage collection nightmare. // This whole thing is a bad idea and a garbage collection nightmare.
// TODO: recreate rbx_dom_weak with my own instance type that owns this data. // TODO: recreate rbx_dom_weak with my own instance type that owns this data.
type CreateUserData = fn(&mlua::Lua) -> mlua::Result<mlua::AnyUserData>; type CreateUserData = fn(&mlua::Lua) -> mlua::Result<mlua::AnyUserData>;
type LUD=phf::Map<&'static str,// Class name type LUD = phf::Map<
phf::Map<&'static str,// Value name &'static str, // Class name
CreateUserData phf::Map<
> &'static str, // Value name
CreateUserData,
>,
>; >;
static LAZY_USER_DATA: LUD = phf::phf_map! { static LAZY_USER_DATA: LUD = phf::phf_map! {
"RunService"=>phf::phf_map!{ "RunService"=>phf::phf_map!{
@ -513,45 +639,52 @@ static LAZY_USER_DATA:LUD=phf::phf_map!{
}; };
#[derive(Default)] #[derive(Default)]
pub struct InstanceValueStore { pub struct InstanceValueStore {
values:HashMap<Ref, values: HashMap<Ref, HashMap<&'static str, mlua::AnyUserData>>,
HashMap<&'static str,
mlua::AnyUserData
>
>,
} }
pub struct InstanceValues<'a> { pub struct InstanceValues<'a> {
named_values: &'static phf::Map<&'static str, CreateUserData>, named_values: &'static phf::Map<&'static str, CreateUserData>,
values: &'a mut HashMap<&'static str, mlua::AnyUserData>, values: &'a mut HashMap<&'static str, mlua::AnyUserData>,
} }
impl InstanceValueStore { impl InstanceValueStore {
pub fn get_or_create_instance_values(&mut self,instance:&rbx_dom_weak::Instance)->Option<InstanceValues>{ pub fn get_or_create_instance_values(
LAZY_USER_DATA.get(instance.class.as_str()) &mut self,
.map(|named_values| instance: &rbx_dom_weak::Instance,
InstanceValues{ ) -> Option<InstanceValues> {
LAZY_USER_DATA
.get(instance.class.as_str())
.map(|named_values| InstanceValues {
named_values, named_values,
values:self.values.entry(instance.referent()) values: self
.values
.entry(instance.referent())
.or_insert_with(|| HashMap::new()), .or_insert_with(|| HashMap::new()),
} })
)
} }
} }
impl InstanceValues<'_> { impl InstanceValues<'_> {
pub fn get_or_create_value(&mut self,lua:&mlua::Lua,index:&str)->mlua::Result<Option<mlua::AnyUserData>>{ pub fn get_or_create_value(
&mut self,
lua: &mlua::Lua,
index: &str,
) -> mlua::Result<Option<mlua::AnyUserData>> {
Ok(match self.named_values.get_entry(index) { Ok(match self.named_values.get_entry(index) {
Some((&static_index_str,&function_pointer))=>Some( Some((&static_index_str, &function_pointer)) => {
match self.values.entry(static_index_str){ Some(match self.values.entry(static_index_str) {
Entry::Occupied(entry) => entry.get().clone(), Entry::Occupied(entry) => entry.get().clone(),
Entry::Vacant(entry)=>entry.insert( Entry::Vacant(entry) => entry.insert(function_pointer(lua)?).clone(),
function_pointer(lua)? })
).clone(),
} }
),
None => None, None => None,
}) })
} }
} }
pub fn instance_value_store_mut<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut InstanceValueStore)->mlua::Result<T>)->mlua::Result<T>{ pub fn instance_value_store_mut<T>(
let mut cf=lua.app_data_mut::<InstanceValueStore>().ok_or_else(||mlua::Error::runtime("InstanceValueStore missing"))?; lua: &mlua::Lua,
mut f: impl FnMut(&mut InstanceValueStore) -> mlua::Result<T>,
) -> mlua::Result<T> {
let mut cf = lua
.app_data_mut::<InstanceValueStore>()
.ok_or_else(|| mlua::Error::runtime("InstanceValueStore missing"))?;
f(&mut *cf) f(&mut *cf)
} }

View File

@ -4,7 +4,11 @@ macro_rules! type_from_lua_userdata{
fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> Result<Self, mlua::Error> { fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> Result<Self, mlua::Error> {
match value { match value {
mlua::Value::UserData(ud) => Ok(*ud.borrow::<Self>()?), mlua::Value::UserData(ud) => Ok(*ud.borrow::<Self>()?),
other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($asd),other))), other => Err(mlua::Error::runtime(format!(
"Expected {} got {:?}",
stringify!($asd),
other
))),
} }
} }
} }
@ -16,7 +20,11 @@ macro_rules! type_from_lua_userdata_lua_lifetime{
fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> Result<Self, mlua::Error> { fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> Result<Self, mlua::Error> {
match value { match value {
mlua::Value::UserData(ud) => Ok(*ud.borrow::<Self>()?), mlua::Value::UserData(ud) => Ok(*ud.borrow::<Self>()?),
other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($asd),other))), other => Err(mlua::Error::runtime(format!(
"Expected {} got {:?}",
stringify!($asd),
other
))),
} }
} }
} }

View File

@ -2,13 +2,13 @@
mod macros; mod macros;
mod runner; mod runner;
mod r#enum;
mod color3;
mod cframe; mod cframe;
mod vector3; mod color3;
pub mod instance;
mod script_signal;
mod color_sequence; mod color_sequence;
mod r#enum;
pub mod instance;
mod number_sequence; mod number_sequence;
mod script_signal;
mod vector3;
pub use runner::{Runner,Runnable,Error}; pub use runner::{Error, Runnable, Runner};

View File

@ -8,7 +8,7 @@ impl NumberSequence{
impl Into<rbx_types::NumberSequence> for NumberSequence { impl Into<rbx_types::NumberSequence> for NumberSequence {
fn into(self) -> rbx_types::NumberSequence { fn into(self) -> rbx_types::NumberSequence {
rbx_types::NumberSequence { rbx_types::NumberSequence {
keypoints:Vec::new() keypoints: Vec::new(),
} }
} }
} }
@ -16,10 +16,9 @@ impl Into<rbx_types::NumberSequence> for NumberSequence{
pub fn set_globals(lua: &mlua::Lua, globals: &mlua::Table) -> Result<(), mlua::Error> { pub fn set_globals(lua: &mlua::Lua, globals: &mlua::Table) -> Result<(), mlua::Error> {
let number_sequence_table = lua.create_table()?; let number_sequence_table = lua.create_table()?;
number_sequence_table.raw_set("new", number_sequence_table.raw_set(
lua.create_function(|_,_:mlua::MultiValue| "new",
Ok(NumberSequence::new()) lua.create_function(|_, _: mlua::MultiValue| Ok(NumberSequence::new()))?,
)?
)?; )?;
globals.set("NumberSequence", number_sequence_table)?; globals.set("NumberSequence", number_sequence_table)?;

View File

@ -7,10 +7,7 @@ pub struct Runner{
} }
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
Lua{ Lua { source: String, error: mlua::Error },
source:String,
error:mlua::Error
},
RustLua(mlua::Error), RustLua(mlua::Error),
NoServices, NoServices,
} }
@ -57,19 +54,34 @@ impl Runner{
let services = context.find_services().ok_or(Error::NoServices)?; let services = context.find_services().ok_or(Error::NoServices)?;
self.runnable_context_with_services(context, &services) self.runnable_context_with_services(context, &services)
} }
pub fn runnable_context_with_services<'a>(self,context:&'a mut Context,services:&crate::context::Services)->Result<Runnable<'a>,Error>{ pub fn runnable_context_with_services<'a>(
self,
context: &'a mut Context,
services: &crate::context::Services,
) -> Result<Runnable<'a>, Error> {
{ {
let globals = self.lua.globals(); let globals = self.lua.globals();
globals.set("game",super::instance::Instance::new(services.game)).map_err(Error::RustLua)?; globals
globals.set("workspace",super::instance::Instance::new(services.workspace)).map_err(Error::RustLua)?; .set("game", super::instance::Instance::new(services.game))
.map_err(Error::RustLua)?;
globals
.set(
"workspace",
super::instance::Instance::new(services.workspace),
)
.map_err(Error::RustLua)?;
} }
//this makes set_app_data shut up about the lifetime //this makes set_app_data shut up about the lifetime
self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); self.lua
.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe {
core::mem::transmute(&mut context.dom)
});
#[cfg(feature = "run-service")] #[cfg(feature = "run-service")]
self.lua.set_app_data::<crate::scheduler::Scheduler>(crate::scheduler::Scheduler::default()); self.lua
.set_app_data::<crate::scheduler::Scheduler>(crate::scheduler::Scheduler::default());
Ok(Runnable { Ok(Runnable {
lua: self.lua, lua: self.lua,
_lifetime:&std::marker::PhantomData _lifetime: &std::marker::PhantomData,
}) })
} }
} }
@ -77,42 +89,53 @@ impl Runner{
//Runnable is the same thing but has context set, which it holds the lifetime for. //Runnable is the same thing but has context set, which it holds the lifetime for.
pub struct Runnable<'a> { pub struct Runnable<'a> {
lua: mlua::Lua, lua: mlua::Lua,
_lifetime:&'a std::marker::PhantomData<()> _lifetime: &'a std::marker::PhantomData<()>,
} }
impl Runnable<'_> { impl Runnable<'_> {
pub fn drop_context(self) -> Runner { pub fn drop_context(self) -> Runner {
self.lua.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>(); self.lua
.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>();
#[cfg(feature = "run-service")] #[cfg(feature = "run-service")]
self.lua.remove_app_data::<crate::scheduler::Scheduler>(); self.lua.remove_app_data::<crate::scheduler::Scheduler>();
Runner{ Runner { lua: self.lua }
lua:self.lua,
}
} }
pub fn run_script(&self, script: super::instance::Instance) -> Result<(), Error> { pub fn run_script(&self, script: super::instance::Instance) -> Result<(), Error> {
let (name,source)=super::instance::instance::get_name_source(&self.lua,script).map_err(Error::RustLua)?; let (name, source) = super::instance::instance::get_name_source(&self.lua, script)
self.lua.globals().raw_set("script",script).map_err(Error::RustLua)?; .map_err(Error::RustLua)?;
let f=self.lua.load(source.as_str()) self.lua
.set_name(name).into_function().map_err(Error::RustLua)?; .globals()
.raw_set("script", script)
.map_err(Error::RustLua)?;
let f = self
.lua
.load(source.as_str())
.set_name(name)
.into_function()
.map_err(Error::RustLua)?;
// TODO: set_environment without losing the ability to print from Lua // TODO: set_environment without losing the ability to print from Lua
let thread = self.lua.create_thread(f).map_err(Error::RustLua)?; let thread = self.lua.create_thread(f).map_err(Error::RustLua)?;
thread.resume::<mlua::MultiValue>(()).map_err(|error|Error::Lua{source,error})?; thread
.resume::<mlua::MultiValue>(())
.map_err(|error| Error::Lua { source, error })?;
// wait() is called from inside Lua and goes to a rust function that schedules the thread and then yields // wait() is called from inside Lua and goes to a rust function that schedules the thread and then yields
// No need to schedule the thread here // No need to schedule the thread here
Ok(()) Ok(())
} }
#[cfg(feature = "run-service")] #[cfg(feature = "run-service")]
pub fn has_scheduled_threads(&self) -> Result<bool, mlua::Error> { pub fn has_scheduled_threads(&self) -> Result<bool, mlua::Error> {
scheduler_mut(&self.lua,|scheduler| scheduler_mut(&self.lua, |scheduler| Ok(scheduler.has_scheduled_threads()))
Ok(scheduler.has_scheduled_threads())
)
} }
#[cfg(feature = "run-service")] #[cfg(feature = "run-service")]
pub fn game_tick(&self) -> Result<(), mlua::Error> { pub fn game_tick(&self) -> Result<(), mlua::Error> {
if let Some(threads) = scheduler_mut(&self.lua, |scheduler| Ok(scheduler.tick_threads()))? { if let Some(threads) = scheduler_mut(&self.lua, |scheduler| Ok(scheduler.tick_threads()))? {
for thread in threads { for thread in threads {
//TODO: return dt and total run time //TODO: return dt and total run time
let result=thread.resume::<mlua::MultiValue>((1.0/30.0,0.0)) let result = thread
.map_err(|error|Error::Lua{source:"source unavailable".to_owned(),error}); .resume::<mlua::MultiValue>((1.0 / 30.0, 0.0))
.map_err(|error| Error::Lua {
source: "source unavailable".to_owned(),
error,
});
match result { match result {
Ok(_) => (), Ok(_) => (),
Err(e) => println!("game_tick Error: {e}"), Err(e) => println!("game_tick Error: {e}"),
@ -124,11 +147,16 @@ impl Runnable<'_>{
#[cfg(feature = "run-service")] #[cfg(feature = "run-service")]
pub fn run_service_step(&self) -> Result<(), mlua::Error> { pub fn run_service_step(&self) -> Result<(), mlua::Error> {
let render_stepped = super::instance::instance::dom_mut(&self.lua, |dom| { let render_stepped = super::instance::instance::dom_mut(&self.lua, |dom| {
let run_service=super::instance::instance::find_first_child_of_class(dom,dom.root(),"RunService").ok_or_else(||mlua::Error::runtime("RunService missing"))?; let run_service =
super::instance::instance::find_first_child_of_class(dom, dom.root(), "RunService")
.ok_or_else(|| mlua::Error::runtime("RunService missing"))?;
super::instance::instance::instance_value_store_mut(&self.lua, |instance_value_store| { super::instance::instance::instance_value_store_mut(&self.lua, |instance_value_store| {
//unwrap because I trust my find_first_child_of_class function to //unwrap because I trust my find_first_child_of_class function to
let mut instance_values=instance_value_store.get_or_create_instance_values(run_service).ok_or_else(||mlua::Error::runtime("RunService InstanceValues missing"))?; let mut instance_values = instance_value_store
let render_stepped=instance_values.get_or_create_value(&self.lua,"RenderStepped")?; .get_or_create_instance_values(run_service)
.ok_or_else(|| mlua::Error::runtime("RunService InstanceValues missing"))?;
let render_stepped =
instance_values.get_or_create_value(&self.lua, "RenderStepped")?;
//let stepped=instance_values.get_or_create_value(&self.lua,"Stepped")?; //let stepped=instance_values.get_or_create_value(&self.lua,"Stepped")?;
//let heartbeat=instance_values.get_or_create_value(&self.lua,"Heartbeat")?; //let heartbeat=instance_values.get_or_create_value(&self.lua,"Heartbeat")?;
Ok(render_stepped) Ok(render_stepped)

View File

@ -73,14 +73,22 @@ impl ScriptSignal{
} }
} }
pub fn connect(&self, function: mlua::Function) -> ScriptConnection { pub fn connect(&self, function: mlua::Function) -> ScriptConnection {
self.connections.functions.borrow_mut().functions.push(function.clone()); self.connections
.functions
.borrow_mut()
.functions
.push(function.clone());
ScriptConnection { ScriptConnection {
connection: self.connections.clone(), connection: self.connections.clone(),
function, function,
} }
} }
pub fn once(&self, function: mlua::Function) -> ScriptConnection { pub fn once(&self, function: mlua::Function) -> ScriptConnection {
self.once.functions.borrow_mut().functions.push(function.clone()); self.once
.functions
.borrow_mut()
.functions
.push(function.clone());
ScriptConnection { ScriptConnection {
connection: self.once.clone(), connection: self.once.clone(),
function, function,
@ -92,18 +100,21 @@ impl ScriptSignal{
} }
impl ScriptConnection { impl ScriptConnection {
pub fn position(&self) -> Option<usize> { pub fn position(&self) -> Option<usize> {
self.connection.functions.borrow().functions.iter().position(|function|function==&self.function) self.connection
.functions
.borrow()
.functions
.iter()
.position(|function| function == &self.function)
} }
} }
impl mlua::UserData for ScriptSignal { impl mlua::UserData for ScriptSignal {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_method("Connect",|_lua,this,f:mlua::Function| methods.add_method("Connect", |_lua, this, f: mlua::Function| {
Ok(this.connect(f)) Ok(this.connect(f))
); });
methods.add_method("Once",|_lua,this,f:mlua::Function| methods.add_method("Once", |_lua, this, f: mlua::Function| Ok(this.once(f)));
Ok(this.once(f))
);
// Fire is not allowed to be called from Lua // Fire is not allowed to be called from Lua
// methods.add_method("Fire",|_lua,this,args:mlua::MultiValue| // methods.add_method("Fire",|_lua,this,args:mlua::MultiValue|
// Ok(this.fire(args)) // Ok(this.fire(args))
@ -114,21 +125,27 @@ impl mlua::FromLua for ScriptSignal{
fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> Result<Self, mlua::Error> { fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> Result<Self, mlua::Error> {
match value { match value {
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()), mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!(ScriptSignal),other))), other => Err(mlua::Error::runtime(format!(
"Expected {} got {:?}",
stringify!(ScriptSignal),
other
))),
} }
} }
} }
impl mlua::UserData for ScriptConnection { impl mlua::UserData for ScriptConnection {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) { fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("Connected",|_,this|{ fields.add_field_method_get("Connected", |_, this| Ok(this.position().is_some()));
Ok(this.position().is_some())
});
} }
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_method("Disconnect", |_, this, _: ()| { methods.add_method("Disconnect", |_, this, _: ()| {
if let Some(index) = this.position() { if let Some(index) = this.position() {
this.connection.functions.borrow_mut().functions.remove(index); this.connection
.functions
.borrow_mut()
.functions
.remove(index);
} }
Ok(()) Ok(())
}); });
@ -140,8 +157,7 @@ fn wait_thread(lua:&mlua::Lua,this:ScriptSignal)->Result<(),mlua::Error>{
} }
// This is used to avoid calling coroutine.yield from the rust side. // This is used to avoid calling coroutine.yield from the rust side.
const LUA_WAIT:&str= const LUA_WAIT: &str = "local coroutine_yield=coroutine.yield
"local coroutine_yield=coroutine.yield
local wait_thread=wait_thread local wait_thread=wait_thread
return function(signal) return function(signal)
wait_thread(signal) wait_thread(signal)
@ -158,7 +174,8 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
wait_env.raw_set("wait_thread", wait_thread)?; wait_env.raw_set("wait_thread", wait_thread)?;
//construct wait function from Lua code //construct wait function from Lua code
let wait=lua.load(LUA_WAIT) let wait = lua
.load(LUA_WAIT)
.set_name("wait") .set_name("wait")
.set_environment(wait_env) .set_environment(wait_env)
.call::<mlua::Function>(())?; .call::<mlua::Function>(())?;

View File

@ -11,10 +11,9 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let vector3_table = lua.create_table()?; let vector3_table = lua.create_table()?;
//Vector3.new //Vector3.new
vector3_table.raw_set("new", vector3_table.raw_set(
lua.create_function(|_,(x,y,z):(f32,f32,f32)| "new",
Ok(Vector3::new(x,y,z)) lua.create_function(|_, (x, y, z): (f32, f32, f32)| Ok(Vector3::new(x, y, z)))?,
)?
)?; )?;
globals.set("Vector3", vector3_table)?; globals.set("Vector3", vector3_table)?;
@ -57,25 +56,29 @@ impl mlua::UserData for Vector3{
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
//methods.add_method("area",|_,this,()| Ok(this.length * this.width)); //methods.add_method("area",|_,this,()| Ok(this.length * this.width));
methods.add_meta_function(mlua::MetaMethod::Add,|_,(this,val):(Self,Self)|Ok(Self(this.0+val.0))); methods.add_meta_function(mlua::MetaMethod::Add, |_, (this, val): (Self, Self)| {
methods.add_meta_function(mlua::MetaMethod::Div,|_,(this,val):(Self,mlua::Value)|{ Ok(Self(this.0 + val.0))
match val{ });
methods.add_meta_function(
mlua::MetaMethod::Div,
|_, (this, val): (Self, mlua::Value)| match val {
mlua::Value::Integer(n) => Ok(Self(this.0 / (n as f32))), mlua::Value::Integer(n) => Ok(Self(this.0 / (n as f32))),
mlua::Value::Number(n) => Ok(Self(this.0 / (n as f32))), mlua::Value::Number(n) => Ok(Self(this.0 / (n as f32))),
mlua::Value::UserData(ud) => { mlua::Value::UserData(ud) => {
let rhs: Vector3 = ud.take()?; let rhs: Vector3 = ud.take()?;
Ok(Self(this.0 / rhs.0)) Ok(Self(this.0 / rhs.0))
},
other=>Err(mlua::Error::runtime(format!("Attempt to divide Vector3 by {other:?}"))),
} }
}); other => Err(mlua::Error::runtime(format!(
methods.add_meta_function(mlua::MetaMethod::ToString,|_,this:Self| "Attempt to divide Vector3 by {other:?}"
Ok(format!("Vector3.new({},{},{})", ))),
this.0.x, },
this.0.y,
this.0.z,
))
); );
methods.add_meta_function(mlua::MetaMethod::ToString, |_, this: Self| {
Ok(format!(
"Vector3.new({},{},{})",
this.0.x, this.0.y, this.0.z,
))
});
} }
} }

View File

@ -36,7 +36,8 @@ impl Scheduler{
!self.schedule.is_empty() !self.schedule.is_empty()
} }
pub fn schedule_thread(&mut self, delay: u64, thread: mlua::Thread) { pub fn schedule_thread(&mut self, delay: u64, thread: mlua::Thread) {
self.schedule.entry(self.tick+delay.max(1)) self.schedule
.entry(self.tick + delay.max(1))
.or_insert(Vec::new()) .or_insert(Vec::new())
.push(thread); .push(thread);
} }
@ -46,8 +47,13 @@ impl Scheduler{
} }
} }
pub fn scheduler_mut<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut crate::scheduler::Scheduler)->mlua::Result<T>)->mlua::Result<T>{ pub fn scheduler_mut<T>(
let mut scheduler=lua.app_data_mut::<crate::scheduler::Scheduler>().ok_or_else(||mlua::Error::runtime("Scheduler missing"))?; lua: &mlua::Lua,
mut f: impl FnMut(&mut crate::scheduler::Scheduler) -> mlua::Result<T>,
) -> mlua::Result<T> {
let mut scheduler = lua
.app_data_mut::<crate::scheduler::Scheduler>()
.ok_or_else(|| mlua::Error::runtime("Scheduler missing"))?;
f(&mut *scheduler) f(&mut *scheduler)
} }
@ -60,13 +66,15 @@ fn schedule_thread(lua:&mlua::Lua,dt:mlua::Value)->Result<(),mlua::Error>{
std::num::FpCategory::Nan => Err(mlua::Error::runtime("NaN"))?, std::num::FpCategory::Nan => Err(mlua::Error::runtime("NaN"))?,
// cases where the number is too large to schedule // cases where the number is too large to schedule
std::num::FpCategory::Infinite => return Ok(()), std::num::FpCategory::Infinite => return Ok(()),
std::num::FpCategory::Normal=>if (u64::MAX as f64)<delay{ std::num::FpCategory::Normal => {
if (u64::MAX as f64) < delay {
return Ok(()); return Ok(());
}, }
}
_ => (), _ => (),
} }
delay as u64 delay as u64
}, }
mlua::Value::Nil => 0, mlua::Value::Nil => 0,
_ => Err(mlua::Error::runtime("Expected float"))?, _ => Err(mlua::Error::runtime("Expected float"))?,
}; };
@ -77,8 +85,7 @@ fn schedule_thread(lua:&mlua::Lua,dt:mlua::Value)->Result<(),mlua::Error>{
} }
// This is used to avoid calling coroutine.yield from the rust side. // This is used to avoid calling coroutine.yield from the rust side.
const LUA_WAIT:&str= const LUA_WAIT: &str = "local coroutine_yield=coroutine.yield
"local coroutine_yield=coroutine.yield
local schedule_thread=schedule_thread local schedule_thread=schedule_thread
return function(dt) return function(dt)
schedule_thread(dt) schedule_thread(dt)
@ -95,7 +102,8 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
wait_env.raw_set("schedule_thread", schedule_thread)?; wait_env.raw_set("schedule_thread", schedule_thread)?;
//construct wait function from Lua code //construct wait function from Lua code
let wait=lua.load(LUA_WAIT) let wait = lua
.load(LUA_WAIT)
.set_name("wait") .set_name("wait")
.set_environment(wait_env) .set_environment(wait_env)
.call::<mlua::Function>(())?; .call::<mlua::Function>(())?;

View File

@ -0,0 +1 @@

View File

@ -1,4 +1,4 @@
use binrw::{BinReaderExt, binrw}; use binrw::{binrw, BinReaderExt};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -90,7 +90,10 @@ impl<R:BinReaderExt> StreamableBot<R>{
Err(Error::InvalidHeader) Err(Error::InvalidHeader)
} }
pub fn load_segment(&mut self, segment_id: SegmentId) -> Result<Segment, Error> { pub fn load_segment(&mut self, segment_id: SegmentId) -> Result<Segment, Error> {
let block_id=*self.segment_id_to_block_id.get(segment_id.get() as usize).ok_or(Error::InvalidSegmentId(segment_id))?; let block_id = *self
.segment_id_to_block_id
.get(segment_id.get() as usize)
.ok_or(Error::InvalidSegmentId(segment_id))?;
let mut block = self.file.block_reader(block_id).map_err(Error::File)?; let mut block = self.file.block_reader(block_id).map_err(Error::File)?;
let segment = block.read_le().map_err(Error::InvalidSegment)?; let segment = block.read_le().map_err(Error::InvalidSegment)?;
Ok(segment) Ok(segment)

View File

@ -1,6 +1,6 @@
//file format "sniff" //file format "sniff"
use binrw::{binrw,BinReaderExt,io::TakeSeekExt}; use binrw::{binrw, io::TakeSeekExt, BinReaderExt};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -95,13 +95,18 @@ impl<R:BinReaderExt> File<R>{
pub(crate) fn data_mut(&mut self) -> &mut R { pub(crate) fn data_mut(&mut self) -> &mut R {
&mut self.data &mut self.data
} }
pub(crate) fn block_reader(&mut self,block_id:BlockId)->Result<binrw::io::TakeSeek<&mut R>,Error>{ pub(crate) fn block_reader(
&mut self,
block_id: BlockId,
) -> Result<binrw::io::TakeSeek<&mut R>, Error> {
if self.header.block_location.len() as u32 <= block_id.get() { if self.header.block_location.len() as u32 <= block_id.get() {
return Err(Error::InvalidBlockId(block_id)) return Err(Error::InvalidBlockId(block_id));
} }
let block_start = self.header.block_location[block_id.get() as usize]; let block_start = self.header.block_location[block_id.get() as usize];
let block_end = self.header.block_location[block_id.get() as usize + 1]; let block_end = self.header.block_location[block_id.get() as usize + 1];
self.data.seek(std::io::SeekFrom::Start(block_start)).map_err(Error::Seek)?; self.data
.seek(std::io::SeekFrom::Start(block_start))
.map_err(Error::Seek)?;
Ok(self.data_mut().take_seek(block_end - block_start)) Ok(self.data_mut().take_seek(block_end - block_start))
} }
pub(crate) fn fourcc(&self) -> FourCC { pub(crate) fn fourcc(&self) -> FourCC {

View File

@ -2,10 +2,10 @@ use binrw::BinReaderExt;
mod newtypes; mod newtypes;
mod file;
pub mod map;
pub mod bot; pub mod bot;
pub mod demo; pub mod demo;
mod file;
pub mod map;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -40,21 +40,21 @@ pub fn read_map<R:BinReaderExt>(input:R)->Result<map::StreamableMap<R>,Error>{
let file = file::File::new(input).map_err(Error::Header)?; let file = file::File::new(input).map_err(Error::Header)?;
match file.fourcc() { match file.fourcc() {
file::FourCC::Map => Ok(map::StreamableMap::new(file).map_err(Error::Map)?), file::FourCC::Map => Ok(map::StreamableMap::new(file).map_err(Error::Map)?),
_=>Err(Error::UnexpectedFourCC) _ => Err(Error::UnexpectedFourCC),
} }
} }
pub fn read_bot<R: BinReaderExt>(input: R) -> Result<bot::StreamableBot<R>, Error> { pub fn read_bot<R: BinReaderExt>(input: R) -> Result<bot::StreamableBot<R>, Error> {
let file = file::File::new(input).map_err(Error::Header)?; let file = file::File::new(input).map_err(Error::Header)?;
match file.fourcc() { match file.fourcc() {
file::FourCC::Bot => Ok(bot::StreamableBot::new(file).map_err(Error::Bot)?), file::FourCC::Bot => Ok(bot::StreamableBot::new(file).map_err(Error::Bot)?),
_=>Err(Error::UnexpectedFourCC) _ => Err(Error::UnexpectedFourCC),
} }
} }
pub fn read_demo<R: BinReaderExt>(input: R) -> Result<demo::StreamableDemo<R>, Error> { pub fn read_demo<R: BinReaderExt>(input: R) -> Result<demo::StreamableDemo<R>, Error> {
let file = file::File::new(input).map_err(Error::Header)?; let file = file::File::new(input).map_err(Error::Header)?;
match file.fourcc() { match file.fourcc() {
file::FourCC::Demo => Ok(demo::StreamableDemo::new(file).map_err(Error::Demo)?), file::FourCC::Demo => Ok(demo::StreamableDemo::new(file).map_err(Error::Demo)?),
_=>Err(Error::UnexpectedFourCC) _ => Err(Error::UnexpectedFourCC),
} }
} }
@ -63,6 +63,5 @@ mod tests {
//use super::*; //use super::*;
#[test] #[test]
fn test() { fn test() {}
}
} }

View File

@ -1,13 +1,13 @@
use std::io::Read;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Read;
use crate::newtypes;
use crate::file::BlockId; use crate::file::BlockId;
use crate::newtypes;
use binrw::{binrw, BinReaderExt, BinWriterExt}; use binrw::{binrw, BinReaderExt, BinWriterExt};
use strafesnet_common::model;
use strafesnet_common::aabb::Aabb; use strafesnet_common::aabb::Aabb;
use strafesnet_common::bvh::BvhNode; use strafesnet_common::bvh::BvhNode;
use strafesnet_common::gameplay_modes; use strafesnet_common::gameplay_modes;
use strafesnet_common::model;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -174,23 +174,34 @@ struct Region{
} }
//code deduplication reused in into_complete_map //code deduplication reused in into_complete_map
fn read_region<R:BinReaderExt>(file:&mut crate::file::File<R>,block_id:BlockId)->Result<Vec<(model::ModelId,model::Model)>,Error>{ fn read_region<R: BinReaderExt>(
file: &mut crate::file::File<R>,
block_id: BlockId,
) -> Result<Vec<(model::ModelId, model::Model)>, Error> {
//load region from disk //load region from disk
//parse the models and determine what resources need to be loaded //parse the models and determine what resources need to be loaded
//load resources into self.resources //load resources into self.resources
//return Region //return Region
let mut block = file.block_reader(block_id).map_err(Error::File)?; let mut block = file.block_reader(block_id).map_err(Error::File)?;
let region: Region = block.read_le().map_err(Error::InvalidData)?; let region: Region = block.read_le().map_err(Error::InvalidData)?;
Ok(region.models.into_iter().map(|(model_id,model)| Ok(region
(model::ModelId::new(model_id),model.into()) .models
).collect()) .into_iter()
.map(|(model_id, model)| (model::ModelId::new(model_id), model.into()))
.collect())
} }
fn read_mesh<R:BinReaderExt>(file:&mut crate::file::File<R>,block_id:BlockId)->Result<model::Mesh,Error>{ fn read_mesh<R: BinReaderExt>(
file: &mut crate::file::File<R>,
block_id: BlockId,
) -> Result<model::Mesh, Error> {
let mut block = file.block_reader(block_id).map_err(Error::File)?; let mut block = file.block_reader(block_id).map_err(Error::File)?;
let mesh: newtypes::model::Mesh = block.read_le().map_err(Error::InvalidData)?; let mesh: newtypes::model::Mesh = block.read_le().map_err(Error::InvalidData)?;
Ok(mesh.into()) Ok(mesh.into())
} }
fn read_texture<R:BinReaderExt>(file:&mut crate::file::File<R>,block_id:BlockId)->Result<Vec<u8>,Error>{ fn read_texture<R: BinReaderExt>(
file: &mut crate::file::File<R>,
block_id: BlockId,
) -> Result<Vec<u8>, Error> {
let mut block = file.block_reader(block_id).map_err(Error::File)?; let mut block = file.block_reader(block_id).map_err(Error::File)?;
let mut texture = Vec::new(); let mut texture = Vec::new();
block.read_to_end(&mut texture).map_err(Error::IO)?; block.read_to_end(&mut texture).map_err(Error::IO)?;
@ -215,12 +226,19 @@ impl<R:BinReaderExt> StreamableMap<R>{
pub(crate) fn new(mut file: crate::file::File<R>) -> Result<Self, Error> { pub(crate) fn new(mut file: crate::file::File<R>) -> Result<Self, Error> {
//assume the file seek is in the right place to start reading a map header //assume the file seek is in the right place to start reading a map header
let header: MapHeader = file.data_mut().read_le().map_err(Error::InvalidHeader)?; let header: MapHeader = file.data_mut().read_le().map_err(Error::InvalidHeader)?;
let modes=header.modes.into_iter().map(TryInto::try_into).collect::<Result<_,_>>().map_err(Error::InvalidMode)?; let modes = header
.modes
.into_iter()
.map(TryInto::try_into)
.collect::<Result<_, _>>()
.map_err(Error::InvalidMode)?;
let attributes = header.attributes.into_iter().map(Into::into).collect(); let attributes = header.attributes.into_iter().map(Into::into).collect();
let render_configs = header.render_configs.into_iter().map(Into::into).collect(); let render_configs = header.render_configs.into_iter().map(Into::into).collect();
let bvh=header.spacial_blocks.into_iter().map(|spacial_block| let bvh = header
(spacial_block.id,spacial_block.extents.into()) .spacial_blocks
).collect(); .into_iter()
.map(|spacial_block| (spacial_block.id, spacial_block.extents.into()))
.collect();
//generate mesh ids and texture ids from resource list order //generate mesh ids and texture ids from resource list order
let mut resource_blocks = ResourceMap::default(); let mut resource_blocks = ResourceMap::default();
for resource_block_header in header.resource_blocks { for resource_block_header in header.resource_blocks {
@ -229,15 +247,15 @@ impl<R:BinReaderExt> StreamableMap<R>{
resource_blocks.meshes.insert( resource_blocks.meshes.insert(
//generate the id from the current length //generate the id from the current length
model::MeshId::new(resource_blocks.meshes.len() as u32), model::MeshId::new(resource_blocks.meshes.len() as u32),
resource_block_header.id resource_block_header.id,
); );
}, }
ResourceType::Texture => { ResourceType::Texture => {
resource_blocks.textures.insert( resource_blocks.textures.insert(
model::TextureId::new(resource_blocks.textures.len() as u32), model::TextureId::new(resource_blocks.textures.len() as u32),
resource_block_header.id resource_block_header.id,
); );
}, }
} }
} }
Ok(Self { Ok(Self {
@ -252,23 +270,36 @@ impl<R:BinReaderExt> StreamableMap<R>{
} }
pub fn get_intersecting_region_block_ids(&self, aabb: &Aabb) -> Vec<BlockId> { pub fn get_intersecting_region_block_ids(&self, aabb: &Aabb) -> Vec<BlockId> {
let mut block_ids = Vec::new(); let mut block_ids = Vec::new();
self.bvh.the_tester(aabb,&mut |&block_id|block_ids.push(block_id)); self.bvh
.the_tester(aabb, &mut |&block_id| block_ids.push(block_id));
block_ids block_ids
} }
pub fn load_region(&mut self,block_id:BlockId)->Result<Vec<(model::ModelId,model::Model)>,Error>{ pub fn load_region(
&mut self,
block_id: BlockId,
) -> Result<Vec<(model::ModelId, model::Model)>, Error> {
read_region(&mut self.file, block_id) read_region(&mut self.file, block_id)
} }
pub fn load_mesh(&mut self, mesh_id: model::MeshId) -> Result<model::Mesh, Error> { pub fn load_mesh(&mut self, mesh_id: model::MeshId) -> Result<model::Mesh, Error> {
let block_id=*self.resource_blocks.meshes.get(&mesh_id).ok_or(Error::InvalidMeshId(mesh_id))?; let block_id = *self
.resource_blocks
.meshes
.get(&mesh_id)
.ok_or(Error::InvalidMeshId(mesh_id))?;
read_mesh(&mut self.file, block_id) read_mesh(&mut self.file, block_id)
} }
pub fn load_texture(&mut self, texture_id: model::TextureId) -> Result<Vec<u8>, Error> { pub fn load_texture(&mut self, texture_id: model::TextureId) -> Result<Vec<u8>, Error> {
let block_id=*self.resource_blocks.textures.get(&texture_id).ok_or(Error::InvalidTextureId(texture_id))?; let block_id = *self
.resource_blocks
.textures
.get(&texture_id)
.ok_or(Error::InvalidTextureId(texture_id))?;
read_texture(&mut self.file, block_id) read_texture(&mut self.file, block_id)
} }
pub fn into_complete_map(mut self) -> Result<strafesnet_common::map::CompleteMap, Error> { pub fn into_complete_map(mut self) -> Result<strafesnet_common::map::CompleteMap, Error> {
let mut block_ids = Vec::new(); let mut block_ids = Vec::new();
self.bvh.into_visitor(&mut |block_id|block_ids.push(block_id)); self.bvh
.into_visitor(&mut |block_id| block_ids.push(block_id));
//count on reading the file in sequential order being fastest //count on reading the file in sequential order being fastest
block_ids.sort_unstable(); block_ids.sort_unstable();
//load all regions //load all regions
@ -279,7 +310,11 @@ impl<R:BinReaderExt> StreamableMap<R>{
let mut models = Vec::with_capacity(model_pairs.len()); let mut models = Vec::with_capacity(model_pairs.len());
for model_id in 0..model_pairs.len() as u32 { for model_id in 0..model_pairs.len() as u32 {
let model_id = model::ModelId::new(model_id); let model_id = model::ModelId::new(model_id);
models.push(model_pairs.remove(&model_id).ok_or(Error::InvalidModelId(model_id))?); models.push(
model_pairs
.remove(&model_id)
.ok_or(Error::InvalidModelId(model_id))?,
);
} }
//load all meshes //load all meshes
let mut meshes = Vec::with_capacity(self.resource_blocks.meshes.len()); let mut meshes = Vec::with_capacity(self.resource_blocks.meshes.len());
@ -287,7 +322,7 @@ impl<R:BinReaderExt> StreamableMap<R>{
let mesh_id = model::MeshId::new(mesh_id); let mesh_id = model::MeshId::new(mesh_id);
let block_id = self.resource_blocks.meshes[&mesh_id]; let block_id = self.resource_blocks.meshes[&mesh_id];
meshes.push(read_mesh(&mut self.file, block_id)?); meshes.push(read_mesh(&mut self.file, block_id)?);
}; }
//load all textures //load all textures
let mut textures = Vec::with_capacity(self.resource_blocks.textures.len()); let mut textures = Vec::with_capacity(self.resource_blocks.textures.len());
for texture_id in 0..self.resource_blocks.textures.len() as u32 { for texture_id in 0..self.resource_blocks.textures.len() as u32 {
@ -311,7 +346,10 @@ fn collect_spacial_blocks(
block_location: &mut Vec<u64>, block_location: &mut Vec<u64>,
block_headers: &mut Vec<SpacialBlockHeader>, block_headers: &mut Vec<SpacialBlockHeader>,
sequential_block_data: &mut std::io::Cursor<&mut Vec<u8>>, sequential_block_data: &mut std::io::Cursor<&mut Vec<u8>>,
bvh_node:strafesnet_common::bvh::BvhWeightNode<usize,(model::ModelId,newtypes::model::Model)> bvh_node: strafesnet_common::bvh::BvhWeightNode<
usize,
(model::ModelId, newtypes::model::Model),
>,
) -> Result<(), Error> { ) -> Result<(), Error> {
//inspect the node weights top-down. //inspect the node weights top-down.
//When a node weighs less than the limit, //When a node weighs less than the limit,
@ -325,10 +363,7 @@ fn collect_spacial_blocks(
models.push((model_id.get(), model)); models.push((model_id.get(), model));
}); });
let id = BlockId::new(block_headers.len() as u32 + 1); let id = BlockId::new(block_headers.len() as u32 + 1);
block_headers.push(SpacialBlockHeader{ block_headers.push(SpacialBlockHeader { id, extents });
id,
extents,
});
let region = Region { let region = Region {
model_count, model_count,
models, models,
@ -339,9 +374,14 @@ fn collect_spacial_blocks(
match bvh_node.into_content() { match bvh_node.into_content() {
strafesnet_common::bvh::RecursiveContent::Branch(bvh_node_list) => { strafesnet_common::bvh::RecursiveContent::Branch(bvh_node_list) => {
for bvh_node in bvh_node_list { for bvh_node in bvh_node_list {
collect_spacial_blocks(block_location,block_headers,sequential_block_data,bvh_node)?; collect_spacial_blocks(
block_location,
block_headers,
sequential_block_data,
bvh_node,
)?;
}
} }
},
strafesnet_common::bvh::RecursiveContent::Leaf(_) => panic!(), //bvh branches are 20 leaves minimum strafesnet_common::bvh::RecursiveContent::Leaf(_) => panic!(), //bvh branches are 20 leaves minimum
} }
} }
@ -350,18 +390,30 @@ fn collect_spacial_blocks(
/// TODO: Optionally provide a bot that describes the path through the map /// TODO: Optionally provide a bot that describes the path through the map
/// otherwise sort by distance to start zone /// otherwise sort by distance to start zone
pub fn write_map<W:BinWriterExt>(mut writer:W,map:strafesnet_common::map::CompleteMap)->Result<(),Error>{ pub fn write_map<W: BinWriterExt>(
mut writer: W,
map: strafesnet_common::map::CompleteMap,
) -> Result<(), Error> {
//serialize models and make a bvh that knows the file size of the branch //serialize models and make a bvh that knows the file size of the branch
let boxen=map.models.into_iter().enumerate().map(|(model_id,model)|{ let boxen = map
.models
.into_iter()
.enumerate()
.map(|(model_id, model)| {
//grow your own aabb //grow your own aabb
let mesh=map.meshes.get(model.mesh.get() as usize).ok_or(Error::InvalidMeshId(model.mesh))?; let mesh = map
.meshes
.get(model.mesh.get() as usize)
.ok_or(Error::InvalidMeshId(model.mesh))?;
let mut aabb = strafesnet_common::aabb::Aabb::default(); let mut aabb = strafesnet_common::aabb::Aabb::default();
for &pos in &mesh.unique_pos { for &pos in &mesh.unique_pos {
aabb.grow(model.transform.transform_point3(pos).fix_1()); aabb.grow(model.transform.transform_point3(pos).fix_1());
} }
Ok(((model::ModelId::new(model_id as u32), model.into()), aabb)) Ok(((model::ModelId::new(model_id as u32), model.into()), aabb))
}).collect::<Result<Vec<_>,_>>()?; })
let bvh=strafesnet_common::bvh::generate_bvh(boxen).weigh_contents(&|_|std::mem::size_of::<newtypes::model::Model>()); .collect::<Result<Vec<_>, _>>()?;
let bvh = strafesnet_common::bvh::generate_bvh(boxen)
.weigh_contents(&|_| std::mem::size_of::<newtypes::model::Model>());
//build blocks //build blocks
//block location is initialized with two values //block location is initialized with two values
//the first value represents the location of the first byte after the file header //the first value represents the location of the first byte after the file header
@ -372,7 +424,12 @@ pub fn write_map<W:BinWriterExt>(mut writer:W,map:strafesnet_common::map::Comple
let mut spacial_blocks = Vec::new(); //for map header let mut spacial_blocks = Vec::new(); //for map header
let mut sequential_block_data = Vec::new(); let mut sequential_block_data = Vec::new();
let mut cursor_to_data = std::io::Cursor::new(&mut sequential_block_data); let mut cursor_to_data = std::io::Cursor::new(&mut sequential_block_data);
collect_spacial_blocks(&mut block_location,&mut spacial_blocks,&mut cursor_to_data,bvh)?; collect_spacial_blocks(
&mut block_location,
&mut spacial_blocks,
&mut cursor_to_data,
bvh,
)?;
let mut block_count = spacial_blocks.len() as u32 + 1; //continue block id let mut block_count = spacial_blocks.len() as u32 + 1; //continue block id
let mut resource_blocks = Vec::new(); //for map header let mut resource_blocks = Vec::new(); //for map header
//meshes //meshes
@ -383,7 +440,8 @@ pub fn write_map<W:BinWriterExt>(mut writer:W,map:strafesnet_common::map::Comple
}); });
block_count += 1; block_count += 1;
let serializable_mesh: newtypes::model::Mesh = mesh.into(); let serializable_mesh: newtypes::model::Mesh = mesh.into();
binrw::BinWrite::write_le(&serializable_mesh,&mut cursor_to_data).map_err(Error::InvalidData)?; binrw::BinWrite::write_le(&serializable_mesh, &mut cursor_to_data)
.map_err(Error::InvalidData)?;
block_location.push(cursor_to_data.position()); block_location.push(cursor_to_data.position());
} }
//textures //textures
@ -421,9 +479,14 @@ pub fn write_map<W:BinWriterExt>(mut writer:W,map:strafesnet_common::map::Comple
}; };
//probe header length //probe header length
let mut file_header_data = Vec::new(); let mut file_header_data = Vec::new();
binrw::BinWrite::write_le(&file_header,&mut std::io::Cursor::new(&mut file_header_data)).map_err(Error::InvalidData)?; binrw::BinWrite::write_le(
&file_header,
&mut std::io::Cursor::new(&mut file_header_data),
)
.map_err(Error::InvalidData)?;
let mut map_header_data = Vec::new(); let mut map_header_data = Vec::new();
binrw::BinWrite::write_le(&map_header,&mut std::io::Cursor::new(&mut map_header_data)).map_err(Error::InvalidData)?; binrw::BinWrite::write_le(&map_header, &mut std::io::Cursor::new(&mut map_header_data))
.map_err(Error::InvalidData)?;
//update file header according to probe data //update file header according to probe data
let mut offset = file_header_data.len() as u64; let mut offset = file_header_data.len() as u64;

View File

@ -1,7 +1,7 @@
mod common;
pub mod aabb; pub mod aabb;
pub mod model; mod common;
pub mod integer; pub mod gameplay_attributes;
pub mod gameplay_modes; pub mod gameplay_modes;
pub mod gameplay_style; pub mod gameplay_style;
pub mod gameplay_attributes; pub mod integer;
pub mod model;

View File

@ -1,5 +1,5 @@
use super::common::flag; use super::common::flag;
use super::integer::{Time,Planar64,Planar64Vec3}; use super::integer::{Planar64, Planar64Vec3, Time};
#[binrw::binrw] #[binrw::binrw]
#[brw(little)] #[brw(little)]
@ -40,36 +40,44 @@ pub enum ContactingBehaviour{
impl Into<strafesnet_common::gameplay_attributes::ContactingBehaviour> for ContactingBehaviour { impl Into<strafesnet_common::gameplay_attributes::ContactingBehaviour> for ContactingBehaviour {
fn into(self) -> strafesnet_common::gameplay_attributes::ContactingBehaviour { fn into(self) -> strafesnet_common::gameplay_attributes::ContactingBehaviour {
match self { match self {
ContactingBehaviour::Surf=> ContactingBehaviour::Surf => {
strafesnet_common::gameplay_attributes::ContactingBehaviour::Surf, strafesnet_common::gameplay_attributes::ContactingBehaviour::Surf
ContactingBehaviour::Ladder(contacting_ladder)=> }
ContactingBehaviour::Ladder(contacting_ladder) => {
strafesnet_common::gameplay_attributes::ContactingBehaviour::Ladder( strafesnet_common::gameplay_attributes::ContactingBehaviour::Ladder(
contacting_ladder.into(), contacting_ladder.into(),
), )
ContactingBehaviour::NoJump=> }
strafesnet_common::gameplay_attributes::ContactingBehaviour::NoJump, ContactingBehaviour::NoJump => {
ContactingBehaviour::Cling=> strafesnet_common::gameplay_attributes::ContactingBehaviour::NoJump
strafesnet_common::gameplay_attributes::ContactingBehaviour::Cling, }
ContactingBehaviour::Elastic(elasticity)=> ContactingBehaviour::Cling => {
strafesnet_common::gameplay_attributes::ContactingBehaviour::Elastic(elasticity), strafesnet_common::gameplay_attributes::ContactingBehaviour::Cling
}
ContactingBehaviour::Elastic(elasticity) => {
strafesnet_common::gameplay_attributes::ContactingBehaviour::Elastic(elasticity)
}
} }
} }
} }
impl From<strafesnet_common::gameplay_attributes::ContactingBehaviour> for ContactingBehaviour { impl From<strafesnet_common::gameplay_attributes::ContactingBehaviour> for ContactingBehaviour {
fn from(value: strafesnet_common::gameplay_attributes::ContactingBehaviour) -> Self { fn from(value: strafesnet_common::gameplay_attributes::ContactingBehaviour) -> Self {
match value { match value {
strafesnet_common::gameplay_attributes::ContactingBehaviour::Surf=> strafesnet_common::gameplay_attributes::ContactingBehaviour::Surf => {
ContactingBehaviour::Surf, ContactingBehaviour::Surf
strafesnet_common::gameplay_attributes::ContactingBehaviour::Ladder(contacting_ladder)=> }
ContactingBehaviour::Ladder( strafesnet_common::gameplay_attributes::ContactingBehaviour::Ladder(
contacting_ladder.into() contacting_ladder,
), ) => ContactingBehaviour::Ladder(contacting_ladder.into()),
strafesnet_common::gameplay_attributes::ContactingBehaviour::NoJump=> strafesnet_common::gameplay_attributes::ContactingBehaviour::NoJump => {
ContactingBehaviour::NoJump, ContactingBehaviour::NoJump
strafesnet_common::gameplay_attributes::ContactingBehaviour::Cling=> }
ContactingBehaviour::Cling, strafesnet_common::gameplay_attributes::ContactingBehaviour::Cling => {
strafesnet_common::gameplay_attributes::ContactingBehaviour::Elastic(elasticity)=> ContactingBehaviour::Cling
ContactingBehaviour::Elastic(elasticity), }
strafesnet_common::gameplay_attributes::ContactingBehaviour::Elastic(elasticity) => {
ContactingBehaviour::Elastic(elasticity)
}
} }
} }
} }
@ -103,12 +111,12 @@ impl From<strafesnet_common::gameplay_attributes::IntersectingWater> for Interse
#[binrw::binrw] #[binrw::binrw]
#[brw(little)] #[brw(little)]
pub struct Accelerator { pub struct Accelerator {
pub acceleration:Planar64Vec3 pub acceleration: Planar64Vec3,
} }
impl Into<strafesnet_common::gameplay_attributes::Accelerator> for Accelerator { impl Into<strafesnet_common::gameplay_attributes::Accelerator> for Accelerator {
fn into(self) -> strafesnet_common::gameplay_attributes::Accelerator { fn into(self) -> strafesnet_common::gameplay_attributes::Accelerator {
strafesnet_common::gameplay_attributes::Accelerator { strafesnet_common::gameplay_attributes::Accelerator {
acceleration:strafesnet_common::integer::vec3::raw_array(self.acceleration) acceleration: strafesnet_common::integer::vec3::raw_array(self.acceleration),
} }
} }
} }
@ -126,32 +134,34 @@ pub enum Booster{
#[brw(magic = 0u8)] #[brw(magic = 0u8)]
Velocity(Planar64Vec3), Velocity(Planar64Vec3),
#[brw(magic = 1u8)] #[brw(magic = 1u8)]
Energy{direction:Planar64Vec3,energy:Planar64}, Energy {
direction: Planar64Vec3,
energy: Planar64,
},
#[brw(magic = 2u8)] #[brw(magic = 2u8)]
AirTime(Time), AirTime(Time),
#[brw(magic = 3u8)] #[brw(magic = 3u8)]
Height(Planar64), Height(Planar64),
} }
impl Into<strafesnet_common::gameplay_attributes::Booster> for Booster { impl Into<strafesnet_common::gameplay_attributes::Booster> for Booster {
fn into(self) -> strafesnet_common::gameplay_attributes::Booster { fn into(self) -> strafesnet_common::gameplay_attributes::Booster {
match self { match self {
Booster::Velocity(velocity)=> Booster::Velocity(velocity) => {
strafesnet_common::gameplay_attributes::Booster::Velocity( strafesnet_common::gameplay_attributes::Booster::Velocity(
strafesnet_common::integer::vec3::raw_array(velocity) strafesnet_common::integer::vec3::raw_array(velocity),
), )
Booster::Energy{direction,energy}=> }
Booster::Energy { direction, energy } => {
strafesnet_common::gameplay_attributes::Booster::Energy { strafesnet_common::gameplay_attributes::Booster::Energy {
direction: strafesnet_common::integer::vec3::raw_array(direction), direction: strafesnet_common::integer::vec3::raw_array(direction),
energy:strafesnet_common::integer::Planar64::raw(energy) energy: strafesnet_common::integer::Planar64::raw(energy),
}, }
Booster::AirTime(time)=> }
strafesnet_common::gameplay_attributes::Booster::AirTime( Booster::AirTime(time) => strafesnet_common::gameplay_attributes::Booster::AirTime(
strafesnet_common::integer::Time::raw(time) strafesnet_common::integer::Time::raw(time),
), ),
Booster::Height(height)=> Booster::Height(height) => strafesnet_common::gameplay_attributes::Booster::Height(
strafesnet_common::gameplay_attributes::Booster::Height( strafesnet_common::integer::Planar64::raw(height),
strafesnet_common::integer::Planar64::raw(height)
), ),
} }
} }
@ -159,17 +169,21 @@ impl Into<strafesnet_common::gameplay_attributes::Booster> for Booster{
impl From<strafesnet_common::gameplay_attributes::Booster> for Booster { impl From<strafesnet_common::gameplay_attributes::Booster> for Booster {
fn from(value: strafesnet_common::gameplay_attributes::Booster) -> Self { fn from(value: strafesnet_common::gameplay_attributes::Booster) -> Self {
match value { match value {
strafesnet_common::gameplay_attributes::Booster::Velocity(velocity)=> strafesnet_common::gameplay_attributes::Booster::Velocity(velocity) => {
Booster::Velocity(velocity.map(|t|t.to_raw()).to_array()), Booster::Velocity(velocity.map(|t| t.to_raw()).to_array())
strafesnet_common::gameplay_attributes::Booster::Energy{direction,energy}=> }
strafesnet_common::gameplay_attributes::Booster::Energy { direction, energy } => {
Booster::Energy { Booster::Energy {
direction: direction.map(|t| t.to_raw()).to_array(), direction: direction.map(|t| t.to_raw()).to_array(),
energy: energy.to_raw(), energy: energy.to_raw(),
}, }
strafesnet_common::gameplay_attributes::Booster::AirTime(time)=> }
Booster::AirTime(time.get()), strafesnet_common::gameplay_attributes::Booster::AirTime(time) => {
strafesnet_common::gameplay_attributes::Booster::Height(height)=> Booster::AirTime(time.get())
Booster::Height(height.to_raw()), }
strafesnet_common::gameplay_attributes::Booster::Height(height) => {
Booster::Height(height.to_raw())
}
} }
} }
} }
@ -183,20 +197,24 @@ pub enum TrajectoryChoice{
impl Into<strafesnet_common::gameplay_attributes::TrajectoryChoice> for TrajectoryChoice { impl Into<strafesnet_common::gameplay_attributes::TrajectoryChoice> for TrajectoryChoice {
fn into(self) -> strafesnet_common::gameplay_attributes::TrajectoryChoice { fn into(self) -> strafesnet_common::gameplay_attributes::TrajectoryChoice {
match self { match self {
TrajectoryChoice::HighArcLongDuration=> TrajectoryChoice::HighArcLongDuration => {
strafesnet_common::gameplay_attributes::TrajectoryChoice::HighArcLongDuration, strafesnet_common::gameplay_attributes::TrajectoryChoice::HighArcLongDuration
TrajectoryChoice::LowArcShortDuration=> }
strafesnet_common::gameplay_attributes::TrajectoryChoice::LowArcShortDuration, TrajectoryChoice::LowArcShortDuration => {
strafesnet_common::gameplay_attributes::TrajectoryChoice::LowArcShortDuration
}
} }
} }
} }
impl From<strafesnet_common::gameplay_attributes::TrajectoryChoice> for TrajectoryChoice { impl From<strafesnet_common::gameplay_attributes::TrajectoryChoice> for TrajectoryChoice {
fn from(value: strafesnet_common::gameplay_attributes::TrajectoryChoice) -> Self { fn from(value: strafesnet_common::gameplay_attributes::TrajectoryChoice) -> Self {
match value { match value {
strafesnet_common::gameplay_attributes::TrajectoryChoice::HighArcLongDuration=> strafesnet_common::gameplay_attributes::TrajectoryChoice::HighArcLongDuration => {
TrajectoryChoice::HighArcLongDuration, TrajectoryChoice::HighArcLongDuration
strafesnet_common::gameplay_attributes::TrajectoryChoice::LowArcShortDuration=> }
TrajectoryChoice::LowArcShortDuration, strafesnet_common::gameplay_attributes::TrajectoryChoice::LowArcShortDuration => {
TrajectoryChoice::LowArcShortDuration
}
} }
} }
} }
@ -209,7 +227,10 @@ pub enum SetTrajectory{
#[brw(magic = 1u8)] #[brw(magic = 1u8)]
Height(Planar64), Height(Planar64),
#[brw(magic = 2u8)] #[brw(magic = 2u8)]
DotVelocity{direction:Planar64Vec3,dot:Planar64}, DotVelocity {
direction: Planar64Vec3,
dot: Planar64,
},
#[brw(magic = 3u8)] #[brw(magic = 3u8)]
TargetPointTime { TargetPointTime {
target_point: Planar64Vec3, target_point: Planar64Vec3,
@ -227,68 +248,80 @@ pub enum SetTrajectory{
impl Into<strafesnet_common::gameplay_attributes::SetTrajectory> for SetTrajectory { impl Into<strafesnet_common::gameplay_attributes::SetTrajectory> for SetTrajectory {
fn into(self) -> strafesnet_common::gameplay_attributes::SetTrajectory { fn into(self) -> strafesnet_common::gameplay_attributes::SetTrajectory {
match self { match self {
SetTrajectory::AirTime(time)=> SetTrajectory::AirTime(time) => {
strafesnet_common::gameplay_attributes::SetTrajectory::AirTime( strafesnet_common::gameplay_attributes::SetTrajectory::AirTime(
strafesnet_common::integer::Time::raw(time) strafesnet_common::integer::Time::raw(time),
), )
SetTrajectory::Height(height)=> }
SetTrajectory::Height(height) => {
strafesnet_common::gameplay_attributes::SetTrajectory::Height( strafesnet_common::gameplay_attributes::SetTrajectory::Height(
strafesnet_common::integer::Planar64::raw(height) strafesnet_common::integer::Planar64::raw(height),
), )
SetTrajectory::DotVelocity{direction,dot}=> }
SetTrajectory::DotVelocity { direction, dot } => {
strafesnet_common::gameplay_attributes::SetTrajectory::DotVelocity { strafesnet_common::gameplay_attributes::SetTrajectory::DotVelocity {
direction: strafesnet_common::integer::vec3::raw_array(direction), direction: strafesnet_common::integer::vec3::raw_array(direction),
dot: strafesnet_common::integer::Planar64::raw(dot), dot: strafesnet_common::integer::Planar64::raw(dot),
}, }
SetTrajectory::TargetPointTime{target_point,time}=> }
SetTrajectory::TargetPointTime { target_point, time } => {
strafesnet_common::gameplay_attributes::SetTrajectory::TargetPointTime { strafesnet_common::gameplay_attributes::SetTrajectory::TargetPointTime {
target_point: strafesnet_common::integer::vec3::raw_array(target_point), target_point: strafesnet_common::integer::vec3::raw_array(target_point),
time: strafesnet_common::integer::Time::raw(time), time: strafesnet_common::integer::Time::raw(time),
}, }
SetTrajectory::TargetPointSpeed{target_point,speed,trajectory_choice}=> }
strafesnet_common::gameplay_attributes::SetTrajectory::TargetPointSpeed{ SetTrajectory::TargetPointSpeed {
target_point,
speed,
trajectory_choice,
} => strafesnet_common::gameplay_attributes::SetTrajectory::TargetPointSpeed {
target_point: strafesnet_common::integer::vec3::raw_array(target_point), target_point: strafesnet_common::integer::vec3::raw_array(target_point),
speed: strafesnet_common::integer::Planar64::raw(speed), speed: strafesnet_common::integer::Planar64::raw(speed),
trajectory_choice: trajectory_choice.into(), trajectory_choice: trajectory_choice.into(),
}, },
SetTrajectory::Velocity(velocity)=> SetTrajectory::Velocity(velocity) => {
strafesnet_common::gameplay_attributes::SetTrajectory::Velocity( strafesnet_common::gameplay_attributes::SetTrajectory::Velocity(
strafesnet_common::integer::vec3::raw_array(velocity) strafesnet_common::integer::vec3::raw_array(velocity),
), )
}
} }
} }
} }
impl From<strafesnet_common::gameplay_attributes::SetTrajectory> for SetTrajectory { impl From<strafesnet_common::gameplay_attributes::SetTrajectory> for SetTrajectory {
fn from(value: strafesnet_common::gameplay_attributes::SetTrajectory) -> Self { fn from(value: strafesnet_common::gameplay_attributes::SetTrajectory) -> Self {
match value { match value {
strafesnet_common::gameplay_attributes::SetTrajectory::AirTime(time)=> strafesnet_common::gameplay_attributes::SetTrajectory::AirTime(time) => {
SetTrajectory::AirTime( SetTrajectory::AirTime(time.get())
time.get() }
), strafesnet_common::gameplay_attributes::SetTrajectory::Height(height) => {
strafesnet_common::gameplay_attributes::SetTrajectory::Height(height)=> SetTrajectory::Height(height.to_raw())
SetTrajectory::Height( }
height.to_raw() strafesnet_common::gameplay_attributes::SetTrajectory::DotVelocity {
), direction,
strafesnet_common::gameplay_attributes::SetTrajectory::DotVelocity{direction,dot}=> dot,
SetTrajectory::DotVelocity{ } => SetTrajectory::DotVelocity {
direction: direction.map(|t| t.to_raw()).to_array(), direction: direction.map(|t| t.to_raw()).to_array(),
dot: dot.to_raw(), dot: dot.to_raw(),
}, },
strafesnet_common::gameplay_attributes::SetTrajectory::TargetPointTime{target_point,time}=> strafesnet_common::gameplay_attributes::SetTrajectory::TargetPointTime {
SetTrajectory::TargetPointTime{ target_point,
time,
} => SetTrajectory::TargetPointTime {
target_point: target_point.map(|t| t.to_raw()).to_array(), target_point: target_point.map(|t| t.to_raw()).to_array(),
time: time.get(), time: time.get(),
}, },
strafesnet_common::gameplay_attributes::SetTrajectory::TargetPointSpeed{target_point,speed,trajectory_choice}=> strafesnet_common::gameplay_attributes::SetTrajectory::TargetPointSpeed {
SetTrajectory::TargetPointSpeed{ target_point,
speed,
trajectory_choice,
} => SetTrajectory::TargetPointSpeed {
target_point: target_point.map(|t| t.to_raw()).to_array(), target_point: target_point.map(|t| t.to_raw()).to_array(),
speed: speed.to_raw(), speed: speed.to_raw(),
trajectory_choice: trajectory_choice.into(), trajectory_choice: trajectory_choice.into(),
}, },
strafesnet_common::gameplay_attributes::SetTrajectory::Velocity(velocity)=> strafesnet_common::gameplay_attributes::SetTrajectory::Velocity(velocity) => {
SetTrajectory::Velocity( SetTrajectory::Velocity(velocity.map(|t| t.to_raw()).to_array())
velocity.map(|t|t.to_raw()).to_array() }
),
} }
} }
} }
@ -344,8 +377,7 @@ impl Into<strafesnet_common::gameplay_attributes::GeneralAttributes> for General
} }
impl From<strafesnet_common::gameplay_attributes::GeneralAttributes> for GeneralAttributes { impl From<strafesnet_common::gameplay_attributes::GeneralAttributes> for GeneralAttributes {
fn from(value: strafesnet_common::gameplay_attributes::GeneralAttributes) -> Self { fn from(value: strafesnet_common::gameplay_attributes::GeneralAttributes) -> Self {
let header= let header = flag(value.booster.is_some(), GeneralAttributes::BOOSTER)
flag(value.booster.is_some(),GeneralAttributes::BOOSTER)
| flag(value.trajectory.is_some(), GeneralAttributes::TRAJECTORY) | flag(value.trajectory.is_some(), GeneralAttributes::TRAJECTORY)
| flag(value.wormhole.is_some(), GeneralAttributes::WORMHOLE) | flag(value.wormhole.is_some(), GeneralAttributes::WORMHOLE)
| flag(value.accelerator.is_some(), GeneralAttributes::ACCELERATOR); | flag(value.accelerator.is_some(), GeneralAttributes::ACCELERATOR);
@ -379,7 +411,10 @@ impl Into<strafesnet_common::gameplay_attributes::ContactingAttributes> for Cont
impl From<strafesnet_common::gameplay_attributes::ContactingAttributes> for ContactingAttributes { impl From<strafesnet_common::gameplay_attributes::ContactingAttributes> for ContactingAttributes {
fn from(value: strafesnet_common::gameplay_attributes::ContactingAttributes) -> Self { fn from(value: strafesnet_common::gameplay_attributes::ContactingAttributes) -> Self {
Self { Self {
header:flag(value.contact_behaviour.is_some(),ContactingAttributes::CONTACTING_BEHAVIOUR), header: flag(
value.contact_behaviour.is_some(),
ContactingAttributes::CONTACTING_BEHAVIOUR,
),
contact_behaviour: value.contact_behaviour.map(Into::into), contact_behaviour: value.contact_behaviour.map(Into::into),
} }
} }
@ -395,17 +430,24 @@ pub struct IntersectingAttributes{
impl IntersectingAttributes { impl IntersectingAttributes {
const INTERSECTING_WATER: u8 = 1 << 0; const INTERSECTING_WATER: u8 = 1 << 0;
} }
impl Into<strafesnet_common::gameplay_attributes::IntersectingAttributes> for IntersectingAttributes{ impl Into<strafesnet_common::gameplay_attributes::IntersectingAttributes>
for IntersectingAttributes
{
fn into(self) -> strafesnet_common::gameplay_attributes::IntersectingAttributes { fn into(self) -> strafesnet_common::gameplay_attributes::IntersectingAttributes {
strafesnet_common::gameplay_attributes::IntersectingAttributes { strafesnet_common::gameplay_attributes::IntersectingAttributes {
water: self.water.map(Into::into), water: self.water.map(Into::into),
} }
} }
} }
impl From<strafesnet_common::gameplay_attributes::IntersectingAttributes> for IntersectingAttributes{ impl From<strafesnet_common::gameplay_attributes::IntersectingAttributes>
for IntersectingAttributes
{
fn from(value: strafesnet_common::gameplay_attributes::IntersectingAttributes) -> Self { fn from(value: strafesnet_common::gameplay_attributes::IntersectingAttributes) -> Self {
Self { Self {
header:flag(value.water.is_some(),IntersectingAttributes::INTERSECTING_WATER), header: flag(
value.water.is_some(),
IntersectingAttributes::INTERSECTING_WATER,
),
water: value.water.map(Into::into), water: value.water.map(Into::into),
} }
} }
@ -470,24 +512,30 @@ pub enum CollisionAttributes{
impl Into<strafesnet_common::gameplay_attributes::CollisionAttributes> for CollisionAttributes { impl Into<strafesnet_common::gameplay_attributes::CollisionAttributes> for CollisionAttributes {
fn into(self) -> strafesnet_common::gameplay_attributes::CollisionAttributes { fn into(self) -> strafesnet_common::gameplay_attributes::CollisionAttributes {
match self { match self {
CollisionAttributes::Decoration=> CollisionAttributes::Decoration => {
strafesnet_common::gameplay_attributes::CollisionAttributes::Decoration, strafesnet_common::gameplay_attributes::CollisionAttributes::Decoration
CollisionAttributes::Contact(attr)=> }
strafesnet_common::gameplay_attributes::CollisionAttributes::Contact(attr.into()), CollisionAttributes::Contact(attr) => {
CollisionAttributes::Intersect(attr)=> strafesnet_common::gameplay_attributes::CollisionAttributes::Contact(attr.into())
strafesnet_common::gameplay_attributes::CollisionAttributes::Intersect(attr.into()), }
CollisionAttributes::Intersect(attr) => {
strafesnet_common::gameplay_attributes::CollisionAttributes::Intersect(attr.into())
}
} }
} }
} }
impl From<strafesnet_common::gameplay_attributes::CollisionAttributes> for CollisionAttributes { impl From<strafesnet_common::gameplay_attributes::CollisionAttributes> for CollisionAttributes {
fn from(value: strafesnet_common::gameplay_attributes::CollisionAttributes) -> Self { fn from(value: strafesnet_common::gameplay_attributes::CollisionAttributes) -> Self {
match value { match value {
strafesnet_common::gameplay_attributes::CollisionAttributes::Decoration=> strafesnet_common::gameplay_attributes::CollisionAttributes::Decoration => {
CollisionAttributes::Decoration, CollisionAttributes::Decoration
strafesnet_common::gameplay_attributes::CollisionAttributes::Contact(attr)=> }
CollisionAttributes::Contact(attr.into()), strafesnet_common::gameplay_attributes::CollisionAttributes::Contact(attr) => {
strafesnet_common::gameplay_attributes::CollisionAttributes::Intersect(attr)=> CollisionAttributes::Contact(attr.into())
CollisionAttributes::Intersect(attr.into()), }
strafesnet_common::gameplay_attributes::CollisionAttributes::Intersect(attr) => {
CollisionAttributes::Intersect(attr.into())
}
} }
} }
} }

View File

@ -46,7 +46,8 @@ impl TryInto<strafesnet_common::gameplay_modes::StageElement> for StageElement{
Ok(strafesnet_common::gameplay_modes::StageElement::new( Ok(strafesnet_common::gameplay_modes::StageElement::new(
strafesnet_common::gameplay_modes::StageId::new(self.stage_id), strafesnet_common::gameplay_modes::StageId::new(self.stage_id),
self.force(), self.force(),
self.behaviour().ok_or(StageElementError::InvalidBehaviour)?, self.behaviour()
.ok_or(StageElementError::InvalidBehaviour)?,
self.jump_limit, self.jump_limit,
)) ))
} }
@ -61,8 +62,7 @@ impl From<strafesnet_common::gameplay_modes::StageElement> for StageElement{
strafesnet_common::gameplay_modes::StageElementBehaviour::Check => 4, strafesnet_common::gameplay_modes::StageElementBehaviour::Check => 4,
strafesnet_common::gameplay_modes::StageElementBehaviour::Checkpoint => 5, strafesnet_common::gameplay_modes::StageElementBehaviour::Checkpoint => 5,
}; };
let header= let header = behaviour
behaviour
| flag(value.jump_limit().is_some(), StageElement::JUMP_LIMIT) | flag(value.jump_limit().is_some(), StageElement::JUMP_LIMIT)
| flag(value.force(), StageElement::FORCE); | flag(value.force(), StageElement::FORCE);
Self { Self {
@ -92,11 +92,17 @@ impl Into<strafesnet_common::gameplay_modes::Stage> for Stage{
strafesnet_common::model::ModelId::new(self.spawn), strafesnet_common::model::ModelId::new(self.spawn),
self.ordered_checkpoints_count, self.ordered_checkpoints_count,
self.unordered_checkpoints_count, self.unordered_checkpoints_count,
self.ordered_checkpoints.into_iter().map(|(checkpoint_id,model_id)|( self.ordered_checkpoints
.into_iter()
.map(|(checkpoint_id, model_id)| {
(
strafesnet_common::gameplay_modes::CheckpointId::new(checkpoint_id), strafesnet_common::gameplay_modes::CheckpointId::new(checkpoint_id),
strafesnet_common::model::ModelId::new(model_id), strafesnet_common::model::ModelId::new(model_id),
)).collect(), )
self.unordered_checkpoints.into_iter() })
.collect(),
self.unordered_checkpoints
.into_iter()
.map(strafesnet_common::model::ModelId::new) .map(strafesnet_common::model::ModelId::new)
.collect(), .collect(),
) )
@ -112,10 +118,12 @@ impl From<strafesnet_common::gameplay_modes::Stage> for Stage{
spawn, spawn,
ordered_checkpoints_count, ordered_checkpoints_count,
unordered_checkpoints_count, unordered_checkpoints_count,
ordered_checkpoints:ordered_checkpoints.into_iter() ordered_checkpoints: ordered_checkpoints
.into_iter()
.map(|(checkpoint_id, model_id)| (checkpoint_id.get(), model_id.get())) .map(|(checkpoint_id, model_id)| (checkpoint_id.get(), model_id.get()))
.collect(), .collect(),
unordered_checkpoints:unordered_checkpoints.into_iter() unordered_checkpoints: unordered_checkpoints
.into_iter()
.map(|model_id| model_id.get()) .map(|model_id| model_id.get())
.collect(), .collect(),
} }
@ -185,13 +193,26 @@ impl TryInto<strafesnet_common::gameplay_modes::Mode> for Mode{
Ok(strafesnet_common::gameplay_modes::Mode::new( Ok(strafesnet_common::gameplay_modes::Mode::new(
self.style.try_into().map_err(ModeError::StyleModifier)?, self.style.try_into().map_err(ModeError::StyleModifier)?,
strafesnet_common::model::ModelId::new(self.start), strafesnet_common::model::ModelId::new(self.start),
self.zones.into_iter().map(|(model_id,zone)| self.zones
(strafesnet_common::model::ModelId::new(model_id),zone.into()) .into_iter()
).collect(), .map(|(model_id, zone)| {
(
strafesnet_common::model::ModelId::new(model_id),
zone.into(),
)
})
.collect(),
self.stages.into_iter().map(Into::into).collect(), self.stages.into_iter().map(Into::into).collect(),
self.elements.into_iter().map(|(model_id,stage_element)| self.elements
Ok((strafesnet_common::model::ModelId::new(model_id),stage_element.try_into()?)) .into_iter()
).collect::<Result<_,_>>().map_err(ModeError::StageElement)?, .map(|(model_id, stage_element)| {
Ok((
strafesnet_common::model::ModelId::new(model_id),
stage_element.try_into()?,
))
})
.collect::<Result<_, _>>()
.map_err(ModeError::StageElement)?,
)) ))
} }
} }
@ -206,13 +227,13 @@ impl From<strafesnet_common::gameplay_modes::Mode> for Mode{
}, },
style: style.into(), style: style.into(),
start: start.get(), start: start.get(),
zones:zones.into_iter() zones: zones
.into_iter()
.map(|(model_id, zone)| (model_id.get(), zone.into())) .map(|(model_id, zone)| (model_id.get(), zone.into()))
.collect(), .collect(),
stages:stages.into_iter() stages: stages.into_iter().map(Into::into).collect(),
.map(Into::into) elements: elements
.collect(), .into_iter()
elements:elements.into_iter()
.map(|(model_id, stage_element)| (model_id.get(), stage_element.into())) .map(|(model_id, stage_element)| (model_id.get(), stage_element.into()))
.collect(), .collect(),
} }

View File

@ -1,5 +1,5 @@
use super::common::flag; use super::common::flag;
use super::integer::{Time,Ratio64,Planar64,Planar64Vec3}; use super::integer::{Planar64, Planar64Vec3, Ratio64, Time};
pub type Controls = u32; pub type Controls = u32;
#[derive(Debug)] #[derive(Debug)]
@ -60,11 +60,25 @@ impl TryInto<strafesnet_common::gameplay_style::StyleModifiers> for StyleModifie
type Error = StyleModifierError; type Error = StyleModifierError;
fn try_into(self) -> Result<strafesnet_common::gameplay_style::StyleModifiers, Self::Error> { fn try_into(self) -> Result<strafesnet_common::gameplay_style::StyleModifiers, Self::Error> {
Ok(strafesnet_common::gameplay_style::StyleModifiers { Ok(strafesnet_common::gameplay_style::StyleModifiers {
controls_mask:strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_mask).ok_or(StyleModifierError::Controls(ControlsError::UnknownBits))?, controls_mask: strafesnet_common::controls_bitflag::Controls::from_bits(
controls_mask_state:strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_mask_state).ok_or(StyleModifierError::Controls(ControlsError::UnknownBits))?, self.controls_mask,
strafe:self.strafe.map(TryInto::try_into).transpose().map_err(StyleModifierError::StrafeSettings)?, )
.ok_or(StyleModifierError::Controls(ControlsError::UnknownBits))?,
controls_mask_state: strafesnet_common::controls_bitflag::Controls::from_bits(
self.controls_mask_state,
)
.ok_or(StyleModifierError::Controls(ControlsError::UnknownBits))?,
strafe: self
.strafe
.map(TryInto::try_into)
.transpose()
.map_err(StyleModifierError::StrafeSettings)?,
rocket: self.rocket.map(Into::into), rocket: self.rocket.map(Into::into),
jump:self.jump.map(TryInto::try_into).transpose().map_err(StyleModifierError::JumpSettings)?, jump: self
.jump
.map(TryInto::try_into)
.transpose()
.map_err(StyleModifierError::JumpSettings)?,
walk: self.walk.map(Into::into), walk: self.walk.map(Into::into),
ladder: self.ladder.map(Into::into), ladder: self.ladder.map(Into::into),
swim: self.swim.map(Into::into), swim: self.swim.map(Into::into),
@ -77,8 +91,7 @@ impl TryInto<strafesnet_common::gameplay_style::StyleModifiers> for StyleModifie
} }
impl From<strafesnet_common::gameplay_style::StyleModifiers> for StyleModifiers { impl From<strafesnet_common::gameplay_style::StyleModifiers> for StyleModifiers {
fn from(value: strafesnet_common::gameplay_style::StyleModifiers) -> Self { fn from(value: strafesnet_common::gameplay_style::StyleModifiers) -> Self {
let header= let header = flag(value.strafe.is_some(), StyleModifiers::STRAFE)
flag(value.strafe.is_some(),StyleModifiers::STRAFE)
| flag(value.rocket.is_some(), StyleModifiers::ROCKET) | flag(value.rocket.is_some(), StyleModifiers::ROCKET)
| flag(value.jump.is_some(), StyleModifiers::JUMP) | flag(value.jump.is_some(), StyleModifiers::JUMP)
| flag(value.walk.is_some(), StyleModifiers::WALK) | flag(value.walk.is_some(), StyleModifiers::WALK)
@ -113,8 +126,12 @@ impl Into<strafesnet_common::gameplay_style::JumpCalculation> for JumpCalculatio
fn into(self) -> strafesnet_common::gameplay_style::JumpCalculation { fn into(self) -> strafesnet_common::gameplay_style::JumpCalculation {
match self { match self {
JumpCalculation::Max => strafesnet_common::gameplay_style::JumpCalculation::Max, JumpCalculation::Max => strafesnet_common::gameplay_style::JumpCalculation::Max,
JumpCalculation::BoostThenJump=>strafesnet_common::gameplay_style::JumpCalculation::BoostThenJump, JumpCalculation::BoostThenJump => {
JumpCalculation::JumpThenBoost=>strafesnet_common::gameplay_style::JumpCalculation::JumpThenBoost, strafesnet_common::gameplay_style::JumpCalculation::BoostThenJump
}
JumpCalculation::JumpThenBoost => {
strafesnet_common::gameplay_style::JumpCalculation::JumpThenBoost
}
} }
} }
} }
@ -122,8 +139,12 @@ impl From<strafesnet_common::gameplay_style::JumpCalculation> for JumpCalculatio
fn from(value: strafesnet_common::gameplay_style::JumpCalculation) -> Self { fn from(value: strafesnet_common::gameplay_style::JumpCalculation) -> Self {
match value { match value {
strafesnet_common::gameplay_style::JumpCalculation::Max => JumpCalculation::Max, strafesnet_common::gameplay_style::JumpCalculation::Max => JumpCalculation::Max,
strafesnet_common::gameplay_style::JumpCalculation::BoostThenJump=>JumpCalculation::BoostThenJump, strafesnet_common::gameplay_style::JumpCalculation::BoostThenJump => {
strafesnet_common::gameplay_style::JumpCalculation::JumpThenBoost=>JumpCalculation::JumpThenBoost, JumpCalculation::BoostThenJump
}
strafesnet_common::gameplay_style::JumpCalculation::JumpThenBoost => {
JumpCalculation::JumpThenBoost
}
} }
} }
} }
@ -137,20 +158,36 @@ pub enum JumpImpulse{
impl Into<strafesnet_common::gameplay_style::JumpImpulse> for JumpImpulse { impl Into<strafesnet_common::gameplay_style::JumpImpulse> for JumpImpulse {
fn into(self) -> strafesnet_common::gameplay_style::JumpImpulse { fn into(self) -> strafesnet_common::gameplay_style::JumpImpulse {
match self { match self {
JumpImpulse::Time(time)=>strafesnet_common::gameplay_style::JumpImpulse::Time(strafesnet_common::integer::Time::raw(time)), JumpImpulse::Time(time) => strafesnet_common::gameplay_style::JumpImpulse::Time(
JumpImpulse::Height(height)=>strafesnet_common::gameplay_style::JumpImpulse::Height(strafesnet_common::integer::Planar64::raw(height)), strafesnet_common::integer::Time::raw(time),
JumpImpulse::Linear(deltav)=>strafesnet_common::gameplay_style::JumpImpulse::Linear(strafesnet_common::integer::Planar64::raw(deltav)), ),
JumpImpulse::Energy(energy)=>strafesnet_common::gameplay_style::JumpImpulse::Energy(strafesnet_common::integer::Planar64::raw(energy)), JumpImpulse::Height(height) => strafesnet_common::gameplay_style::JumpImpulse::Height(
strafesnet_common::integer::Planar64::raw(height),
),
JumpImpulse::Linear(deltav) => strafesnet_common::gameplay_style::JumpImpulse::Linear(
strafesnet_common::integer::Planar64::raw(deltav),
),
JumpImpulse::Energy(energy) => strafesnet_common::gameplay_style::JumpImpulse::Energy(
strafesnet_common::integer::Planar64::raw(energy),
),
} }
} }
} }
impl From<strafesnet_common::gameplay_style::JumpImpulse> for JumpImpulse { impl From<strafesnet_common::gameplay_style::JumpImpulse> for JumpImpulse {
fn from(value: strafesnet_common::gameplay_style::JumpImpulse) -> Self { fn from(value: strafesnet_common::gameplay_style::JumpImpulse) -> Self {
match value { match value {
strafesnet_common::gameplay_style::JumpImpulse::Time(time)=>JumpImpulse::Time(time.get()), strafesnet_common::gameplay_style::JumpImpulse::Time(time) => {
strafesnet_common::gameplay_style::JumpImpulse::Height(height)=>JumpImpulse::Height(height.to_raw()), JumpImpulse::Time(time.get())
strafesnet_common::gameplay_style::JumpImpulse::Linear(deltav)=>JumpImpulse::Linear(deltav.to_raw()), }
strafesnet_common::gameplay_style::JumpImpulse::Energy(energy)=>JumpImpulse::Energy(energy.to_raw()), strafesnet_common::gameplay_style::JumpImpulse::Height(height) => {
JumpImpulse::Height(height.to_raw())
}
strafesnet_common::gameplay_style::JumpImpulse::Linear(deltav) => {
JumpImpulse::Linear(deltav.to_raw())
}
strafesnet_common::gameplay_style::JumpImpulse::Energy(energy) => {
JumpImpulse::Energy(energy.to_raw())
}
} }
} }
} }
@ -164,11 +201,22 @@ pub struct ControlsActivation{
} }
impl TryInto<strafesnet_common::gameplay_style::ControlsActivation> for ControlsActivation { impl TryInto<strafesnet_common::gameplay_style::ControlsActivation> for ControlsActivation {
type Error = ControlsError; type Error = ControlsError;
fn try_into(self)->Result<strafesnet_common::gameplay_style::ControlsActivation,Self::Error>{ fn try_into(
self,
) -> Result<strafesnet_common::gameplay_style::ControlsActivation, Self::Error> {
Ok(strafesnet_common::gameplay_style::ControlsActivation { Ok(strafesnet_common::gameplay_style::ControlsActivation {
controls_mask:strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_mask).ok_or(ControlsError::UnknownBits)?, controls_mask: strafesnet_common::controls_bitflag::Controls::from_bits(
controls_intersects:strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_intersects).ok_or(ControlsError::UnknownBits)?, self.controls_mask,
controls_contains:strafesnet_common::controls_bitflag::Controls::from_bits(self.controls_contains).ok_or(ControlsError::UnknownBits)?, )
.ok_or(ControlsError::UnknownBits)?,
controls_intersects: strafesnet_common::controls_bitflag::Controls::from_bits(
self.controls_intersects,
)
.ok_or(ControlsError::UnknownBits)?,
controls_contains: strafesnet_common::controls_bitflag::Controls::from_bits(
self.controls_contains,
)
.ok_or(ControlsError::UnknownBits)?,
}) })
} }
} }
@ -210,16 +258,27 @@ impl TryInto<strafesnet_common::gameplay_style::StrafeSettings> for StrafeSettin
type Error = StrafeSettingsError; type Error = StrafeSettingsError;
fn try_into(self) -> Result<strafesnet_common::gameplay_style::StrafeSettings, Self::Error> { fn try_into(self) -> Result<strafesnet_common::gameplay_style::StrafeSettings, Self::Error> {
Ok(strafesnet_common::gameplay_style::StrafeSettings { Ok(strafesnet_common::gameplay_style::StrafeSettings {
enable:self.enable.try_into().map_err(StrafeSettingsError::Controls)?, enable: self
.enable
.try_into()
.map_err(StrafeSettingsError::Controls)?,
mv: strafesnet_common::integer::Planar64::raw(self.mv), mv: strafesnet_common::integer::Planar64::raw(self.mv),
air_accel_limit:self.air_accel_limit.map(strafesnet_common::integer::Planar64::raw), air_accel_limit: self
tick_rate:self.tick_rate.try_into().map_err(StrafeSettingsError::Ratio)?, .air_accel_limit
.map(strafesnet_common::integer::Planar64::raw),
tick_rate: self
.tick_rate
.try_into()
.map_err(StrafeSettingsError::Ratio)?,
}) })
} }
} }
impl From<strafesnet_common::gameplay_style::StrafeSettings> for StrafeSettings { impl From<strafesnet_common::gameplay_style::StrafeSettings> for StrafeSettings {
fn from(value: strafesnet_common::gameplay_style::StrafeSettings) -> Self { fn from(value: strafesnet_common::gameplay_style::StrafeSettings) -> Self {
let header=flag(value.air_accel_limit.is_some(),StrafeSettings::AIR_ACCEL_LIMIT); let header = flag(
value.air_accel_limit.is_some(),
StrafeSettings::AIR_ACCEL_LIMIT,
);
Self { Self {
header, header,
enable: value.enable.into(), enable: value.enable.into(),
@ -238,7 +297,7 @@ pub struct PropulsionSettings{
impl Into<strafesnet_common::gameplay_style::PropulsionSettings> for PropulsionSettings { impl Into<strafesnet_common::gameplay_style::PropulsionSettings> for PropulsionSettings {
fn into(self) -> strafesnet_common::gameplay_style::PropulsionSettings { fn into(self) -> strafesnet_common::gameplay_style::PropulsionSettings {
strafesnet_common::gameplay_style::PropulsionSettings { strafesnet_common::gameplay_style::PropulsionSettings {
magnitude:strafesnet_common::integer::Planar64::raw(self.magnitude) magnitude: strafesnet_common::integer::Planar64::raw(self.magnitude),
} }
} }
} }
@ -262,10 +321,18 @@ impl JumpSettings{
const LIMIT_MINIMUM: u8 = 0b10000; const LIMIT_MINIMUM: u8 = 0b10000;
const fn impulse(&self) -> Option<strafesnet_common::gameplay_style::JumpImpulse> { const fn impulse(&self) -> Option<strafesnet_common::gameplay_style::JumpImpulse> {
match self.header & Self::IMPULSE { match self.header & Self::IMPULSE {
0=>Some(strafesnet_common::gameplay_style::JumpImpulse::Time(strafesnet_common::integer::Time::raw(self.impulse))), 0 => Some(strafesnet_common::gameplay_style::JumpImpulse::Time(
1=>Some(strafesnet_common::gameplay_style::JumpImpulse::Height(strafesnet_common::integer::Planar64::raw(self.impulse))), strafesnet_common::integer::Time::raw(self.impulse),
2=>Some(strafesnet_common::gameplay_style::JumpImpulse::Linear(strafesnet_common::integer::Planar64::raw(self.impulse))), )),
3=>Some(strafesnet_common::gameplay_style::JumpImpulse::Energy(strafesnet_common::integer::Planar64::raw(self.impulse))), 1 => Some(strafesnet_common::gameplay_style::JumpImpulse::Height(
strafesnet_common::integer::Planar64::raw(self.impulse),
)),
2 => Some(strafesnet_common::gameplay_style::JumpImpulse::Linear(
strafesnet_common::integer::Planar64::raw(self.impulse),
)),
3 => Some(strafesnet_common::gameplay_style::JumpImpulse::Energy(
strafesnet_common::integer::Planar64::raw(self.impulse),
)),
_ => None, _ => None,
} }
} }
@ -290,8 +357,12 @@ impl TryInto<strafesnet_common::gameplay_style::JumpSettings> for JumpSettings{
type Error = JumpSettingsError; type Error = JumpSettingsError;
fn try_into(self) -> Result<strafesnet_common::gameplay_style::JumpSettings, Self::Error> { fn try_into(self) -> Result<strafesnet_common::gameplay_style::JumpSettings, Self::Error> {
Ok(strafesnet_common::gameplay_style::JumpSettings { Ok(strafesnet_common::gameplay_style::JumpSettings {
impulse:self.impulse().ok_or(JumpSettingsError::InvalidImpulseDiscriminant)?, impulse: self
calculation:self.calculation().ok_or(JumpSettingsError::InvalidCalculationDiscriminant)?, .impulse()
.ok_or(JumpSettingsError::InvalidImpulseDiscriminant)?,
calculation: self
.calculation()
.ok_or(JumpSettingsError::InvalidCalculationDiscriminant)?,
limit_minimum: self.limit_minimum(), limit_minimum: self.limit_minimum(),
}) })
} }
@ -300,9 +371,15 @@ impl From<strafesnet_common::gameplay_style::JumpSettings> for JumpSettings{
fn from(value: strafesnet_common::gameplay_style::JumpSettings) -> Self { fn from(value: strafesnet_common::gameplay_style::JumpSettings) -> Self {
let (impulse, impulse_header) = match value.impulse { let (impulse, impulse_header) = match value.impulse {
strafesnet_common::gameplay_style::JumpImpulse::Time(impulse) => (impulse.get(), 0), strafesnet_common::gameplay_style::JumpImpulse::Time(impulse) => (impulse.get(), 0),
strafesnet_common::gameplay_style::JumpImpulse::Height(impulse)=>(impulse.to_raw(),1), strafesnet_common::gameplay_style::JumpImpulse::Height(impulse) => {
strafesnet_common::gameplay_style::JumpImpulse::Linear(impulse)=>(impulse.to_raw(),2), (impulse.to_raw(), 1)
strafesnet_common::gameplay_style::JumpImpulse::Energy(impulse)=>(impulse.to_raw(),3), }
strafesnet_common::gameplay_style::JumpImpulse::Linear(impulse) => {
(impulse.to_raw(), 2)
}
strafesnet_common::gameplay_style::JumpImpulse::Energy(impulse) => {
(impulse.to_raw(), 3)
}
}; };
let calculation_header = match value.calculation { let calculation_header = match value.calculation {
strafesnet_common::gameplay_style::JumpCalculation::Max => 0, strafesnet_common::gameplay_style::JumpCalculation::Max => 0,
@ -310,13 +387,8 @@ impl From<strafesnet_common::gameplay_style::JumpSettings> for JumpSettings{
strafesnet_common::gameplay_style::JumpCalculation::BoostThenJump => 2, strafesnet_common::gameplay_style::JumpCalculation::BoostThenJump => 2,
}; };
let header = let header =
impulse_header impulse_header | (calculation_header << 2) | ((value.limit_minimum as u8) << 4);
|(calculation_header<<2) Self { header, impulse }
|((value.limit_minimum as u8)<<4);
Self{
header,
impulse,
}
} }
} }

View File

@ -1,7 +1,7 @@
use super::common::flag; use super::common::flag;
use strafesnet_common::model::PolygonIter; use strafesnet_common::model::PolygonIter;
use super::integer::{Planar64Vec3,Planar64Affine3}; use super::integer::{Planar64Affine3, Planar64Vec3};
pub type TextureCoordinate = [f32; 2]; pub type TextureCoordinate = [f32; 2];
pub type Color4 = [f32; 4]; pub type Color4 = [f32; 4];
@ -43,13 +43,16 @@ impl From<strafesnet_common::model::PolygonGroup> for PolygonGroup{
fn from(value: strafesnet_common::model::PolygonGroup) -> Self { fn from(value: strafesnet_common::model::PolygonGroup) -> Self {
match value { match value {
strafesnet_common::model::PolygonGroup::PolygonList(polygon_list) => { strafesnet_common::model::PolygonGroup::PolygonList(polygon_list) => {
let polys:Vec<Polygon>=polygon_list.polys().map(|poly|{ let polys: Vec<Polygon> = polygon_list
.polys()
.map(|poly| {
let vertices: Vec<u32> = poly.iter().map(|vert| vert.get()).collect(); let vertices: Vec<u32> = poly.iter().map(|vert| vert.get()).collect();
Polygon { Polygon {
count: vertices.len() as u32, count: vertices.len() as u32,
vertices, vertices,
} }
}).collect(); })
.collect();
Self { Self {
count: polys.len() as u32, count: polys.len() as u32,
polys, polys,
@ -97,7 +100,11 @@ impl From<strafesnet_common::model::IndexedGraphicsGroup> for IndexedGraphicsGro
Self { Self {
count: value.groups.len() as u32, count: value.groups.len() as u32,
render: value.render.get(), render: value.render.get(),
groups:value.groups.into_iter().map(|group_id|group_id.get()).collect(), groups: value
.groups
.into_iter()
.map(|group_id| group_id.get())
.collect(),
} }
} }
} }
@ -112,7 +119,11 @@ impl From<strafesnet_common::model::IndexedPhysicsGroup> for IndexedPhysicsGroup
fn from(value: strafesnet_common::model::IndexedPhysicsGroup) -> Self { fn from(value: strafesnet_common::model::IndexedPhysicsGroup) -> Self {
Self { Self {
count: value.groups.len() as u32, count: value.groups.len() as u32,
groups:value.groups.into_iter().map(|group_id|group_id.get()).collect(), groups: value
.groups
.into_iter()
.map(|group_id| group_id.get())
.collect(),
} }
} }
} }
@ -153,36 +164,79 @@ pub struct Mesh{
impl Into<strafesnet_common::model::Mesh> for Mesh { impl Into<strafesnet_common::model::Mesh> for Mesh {
fn into(self) -> strafesnet_common::model::Mesh { fn into(self) -> strafesnet_common::model::Mesh {
strafesnet_common::model::Mesh { strafesnet_common::model::Mesh {
unique_pos:self.unique_pos.into_iter().map(strafesnet_common::integer::vec3::raw_array).collect(), unique_pos: self
unique_normal:self.unique_normal.into_iter().map(strafesnet_common::integer::vec3::raw_array).collect(), .unique_pos
unique_tex:self.unique_tex.into_iter().map(strafesnet_common::model::TextureCoordinate::from_array).collect(), .into_iter()
unique_color:self.unique_color.into_iter().map(strafesnet_common::model::Color4::from_array).collect(), .map(strafesnet_common::integer::vec3::raw_array)
unique_vertices:self.unique_vertices.into_iter().map(|vert|strafesnet_common::model::IndexedVertex{ .collect(),
unique_normal: self
.unique_normal
.into_iter()
.map(strafesnet_common::integer::vec3::raw_array)
.collect(),
unique_tex: self
.unique_tex
.into_iter()
.map(strafesnet_common::model::TextureCoordinate::from_array)
.collect(),
unique_color: self
.unique_color
.into_iter()
.map(strafesnet_common::model::Color4::from_array)
.collect(),
unique_vertices: self
.unique_vertices
.into_iter()
.map(|vert| strafesnet_common::model::IndexedVertex {
pos: strafesnet_common::model::PositionId::new(vert.pos), pos: strafesnet_common::model::PositionId::new(vert.pos),
tex: strafesnet_common::model::TextureCoordinateId::new(vert.tex), tex: strafesnet_common::model::TextureCoordinateId::new(vert.tex),
normal: strafesnet_common::model::NormalId::new(vert.normal), normal: strafesnet_common::model::NormalId::new(vert.normal),
color: strafesnet_common::model::ColorId::new(vert.color), color: strafesnet_common::model::ColorId::new(vert.color),
}).collect(), })
polygon_groups:self.polygon_groups.into_iter().map(|group| .collect(),
polygon_groups: self
.polygon_groups
.into_iter()
.map(|group| {
strafesnet_common::model::PolygonGroup::PolygonList( strafesnet_common::model::PolygonGroup::PolygonList(
strafesnet_common::model::PolygonList::new( strafesnet_common::model::PolygonList::new(
group.polys.into_iter().map(|vert| group
vert.vertices.into_iter().map(strafesnet_common::model::VertexId::new).collect() .polys
).collect() .into_iter()
.map(|vert| {
vert.vertices
.into_iter()
.map(strafesnet_common::model::VertexId::new)
.collect()
})
.collect(),
),
) )
) })
).collect(), .collect(),
graphics_groups:self.graphics_groups.into_iter().map(|group| graphics_groups: self
strafesnet_common::model::IndexedGraphicsGroup{ .graphics_groups
.into_iter()
.map(|group| strafesnet_common::model::IndexedGraphicsGroup {
render: strafesnet_common::model::RenderConfigId::new(group.render), render: strafesnet_common::model::RenderConfigId::new(group.render),
groups:group.groups.into_iter().map(strafesnet_common::model::PolygonGroupId::new).collect(), groups: group
} .groups
).collect(), .into_iter()
physics_groups:self.physics_groups.into_iter().map(|group| .map(strafesnet_common::model::PolygonGroupId::new)
strafesnet_common::model::IndexedPhysicsGroup{ .collect(),
groups:group.groups.into_iter().map(strafesnet_common::model::PolygonGroupId::new).collect(), })
} .collect(),
).collect(), physics_groups: self
.physics_groups
.into_iter()
.map(|group| strafesnet_common::model::IndexedPhysicsGroup {
groups: group
.groups
.into_iter()
.map(strafesnet_common::model::PolygonGroupId::new)
.collect(),
})
.collect(),
} }
} }
} }
@ -199,30 +253,30 @@ impl From<strafesnet_common::model::Mesh> for Mesh{
graphics_groups: value.graphics_groups.len() as u32, graphics_groups: value.graphics_groups.len() as u32,
physics_groups: value.physics_groups.len() as u32, physics_groups: value.physics_groups.len() as u32,
}, },
unique_pos:value.unique_pos.into_iter() unique_pos: value
.unique_pos
.into_iter()
.map(|pos| pos.map(|t| t.to_raw()).to_array()) .map(|pos| pos.map(|t| t.to_raw()).to_array())
.collect(), .collect(),
unique_normal:value.unique_normal.into_iter() unique_normal: value
.unique_normal
.into_iter()
.map(|normal| normal.map(|t| t.to_raw()).to_array()) .map(|normal| normal.map(|t| t.to_raw()).to_array())
.collect(), .collect(),
unique_tex:value.unique_tex.into_iter() unique_tex: value
.unique_tex
.into_iter()
.map(|tex| tex.to_array()) .map(|tex| tex.to_array())
.collect(), .collect(),
unique_color:value.unique_color.into_iter() unique_color: value
.unique_color
.into_iter()
.map(|color| color.to_array()) .map(|color| color.to_array())
.collect(), .collect(),
unique_vertices:value.unique_vertices.into_iter() unique_vertices: value.unique_vertices.into_iter().map(Into::into).collect(),
.map(Into::into) polygon_groups: value.polygon_groups.into_iter().map(Into::into).collect(),
.collect(), graphics_groups: value.graphics_groups.into_iter().map(Into::into).collect(),
polygon_groups:value.polygon_groups.into_iter() physics_groups: value.physics_groups.into_iter().map(Into::into).collect(),
.map(Into::into)
.collect(),
graphics_groups:value.graphics_groups.into_iter()
.map(Into::into)
.collect(),
physics_groups:value.physics_groups.into_iter()
.map(Into::into)
.collect(),
} }
} }
} }
@ -240,31 +294,43 @@ impl Into<strafesnet_common::model::Model> for Model{
let [_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b] = self.transform; let [_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b] = self.transform;
strafesnet_common::model::Model { strafesnet_common::model::Model {
mesh: strafesnet_common::model::MeshId::new(self.mesh), mesh: strafesnet_common::model::MeshId::new(self.mesh),
attributes:strafesnet_common::gameplay_attributes::CollisionAttributesId::new(self.attributes), attributes: strafesnet_common::gameplay_attributes::CollisionAttributesId::new(
self.attributes,
),
color: strafesnet_common::model::Color4::from_array(self.color), color: strafesnet_common::model::Color4::from_array(self.color),
transform: strafesnet_common::integer::Planar64Affine3::new( transform: strafesnet_common::integer::Planar64Affine3::new(
strafesnet_common::integer::Planar64Mat3::from_cols([ strafesnet_common::integer::Planar64Mat3::from_cols([
strafesnet_common::integer::vec3::raw_xyz(_0, _1, _2), strafesnet_common::integer::vec3::raw_xyz(_0, _1, _2),
strafesnet_common::integer::vec3::raw_xyz(_3, _4, _5), strafesnet_common::integer::vec3::raw_xyz(_3, _4, _5),
strafesnet_common::integer::vec3::raw_xyz(_6,_7,_8) strafesnet_common::integer::vec3::raw_xyz(_6, _7, _8),
]), ]),
strafesnet_common::integer::vec3::raw_xyz(_9,_a,_b) strafesnet_common::integer::vec3::raw_xyz(_9, _a, _b),
), ),
} }
} }
} }
impl From<strafesnet_common::model::Model> for Model { impl From<strafesnet_common::model::Model> for Model {
fn from(value: strafesnet_common::model::Model) -> Self { fn from(value: strafesnet_common::model::Model) -> Self {
let ( let ([_0, _1, _2], [_3, _4, _5], [_6, _7, _8], [_9, _a, _b]) = (
[_0,_1,_2], value
[_3,_4,_5], .transform
[_6,_7,_8], .matrix3
[_9,_a,_b] .x_axis
)=( .map(|t| t.to_raw())
value.transform.matrix3.x_axis.map(|t|t.to_raw()).to_array(), .to_array(),
value.transform.matrix3.y_axis.map(|t|t.to_raw()).to_array(), value
value.transform.matrix3.z_axis.map(|t|t.to_raw()).to_array(), .transform
value.transform.translation.map(|t|t.to_raw()).to_array() .matrix3
.y_axis
.map(|t| t.to_raw())
.to_array(),
value
.transform
.matrix3
.z_axis
.map(|t| t.to_raw())
.to_array(),
value.transform.translation.map(|t| t.to_raw()).to_array(),
); );
Self { Self {
mesh: value.mesh.get(), mesh: value.mesh.get(),

View File

@ -1,5 +1,5 @@
use strafesnet_common::aabb; use strafesnet_common::aabb;
use strafesnet_common::integer::{self,vec3,Time,Planar64,Planar64Vec3}; use strafesnet_common::integer::{self, vec3, Planar64, Planar64Vec3, Time};
#[derive(Clone, Copy, Debug, Hash)] #[derive(Clone, Copy, Debug, Hash)]
pub struct Body<T> { pub struct Body<T> {
pub position: Planar64Vec3, //I64 where 2^32 = 1 u pub position: Planar64Vec3, //I64 where 2^32 = 1 u
@ -20,10 +20,16 @@ impl<T> std::ops::Neg for Body<T>{
} }
impl<T> Body<T> impl<T> Body<T>
where Time<T>:Copy, where
Time<T>: Copy,
{ {
pub const ZERO: Self = Self::new(vec3::ZERO, vec3::ZERO, vec3::ZERO, Time::ZERO); pub const ZERO: Self = Self::new(vec3::ZERO, vec3::ZERO, vec3::ZERO, Time::ZERO);
pub const fn new(position:Planar64Vec3,velocity:Planar64Vec3,acceleration:Planar64Vec3,time:Time<T>)->Self{ pub const fn new(
position: Planar64Vec3,
velocity: Planar64Vec3,
acceleration: Planar64Vec3,
time: Time<T>,
) -> Self {
Self { Self {
position, position,
velocity, velocity,
@ -35,7 +41,9 @@ impl<T> Body<T>
let dt = time - self.time; let dt = time - self.time;
self.position self.position
+ (self.velocity * dt).map(|elem| elem.divide().fix_1()) + (self.velocity * dt).map(|elem| elem.divide().fix_1())
+self.acceleration.map(|elem|(dt*dt*elem/2).divide().fix_1()) + self
.acceleration
.map(|elem| (dt * dt * elem / 2).divide().fix_1())
} }
pub fn extrapolated_velocity(&self, time: Time<T>) -> Planar64Vec3 { pub fn extrapolated_velocity(&self, time: Time<T>) -> Planar64Vec3 {
let dt = time - self.time; let dt = time - self.time;
@ -46,7 +54,10 @@ impl<T> Body<T>
self.velocity = self.extrapolated_velocity(time); self.velocity = self.extrapolated_velocity(time);
self.time = time; self.time = time;
} }
pub fn extrapolated_position_ratio_dt<Num,Den,N1,D1,N2,N3,D2,N4,T1>(&self,dt:integer::Ratio<Num,Den>)->Planar64Vec3 pub fn extrapolated_position_ratio_dt<Num, Den, N1, D1, N2, N3, D2, N4, T1>(
&self,
dt: integer::Ratio<Num, Den>,
) -> Planar64Vec3
where where
// Why? // Why?
// All of this can be removed with const generics because the type can be specified as // All of this can be removed with const generics because the type can be specified as
@ -67,10 +78,15 @@ impl<T> Body<T>
{ {
// a*dt^2/2 + v*dt + p // a*dt^2/2 + v*dt + p
// (a*dt/2+v)*dt+p // (a*dt/2+v)*dt+p
(self.acceleration.map(|elem|dt*elem/2)+self.velocity).map(|elem|dt.mul_ratio(elem)) (self.acceleration.map(|elem| dt * elem / 2) + self.velocity)
.map(|elem|elem.divide().fix())+self.position .map(|elem| dt.mul_ratio(elem))
.map(|elem| elem.divide().fix())
+ self.position
} }
pub fn extrapolated_velocity_ratio_dt<Num,Den,N1,T1>(&self,dt:integer::Ratio<Num,Den>)->Planar64Vec3 pub fn extrapolated_velocity_ratio_dt<Num, Den, N1, T1>(
&self,
dt: integer::Ratio<Num, Den>,
) -> Planar64Vec3
where where
Num: Copy, Num: Copy,
Den: Copy, Den: Copy,
@ -122,11 +138,14 @@ impl<T> Body<T>
} }
} }
} }
} }
impl<T> std::fmt::Display for Body<T> { impl<T> std::fmt::Display for Body<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,"p({}) v({}) a({}) t({})",self.position,self.velocity,self.acceleration,self.time) write!(
f,
"p({}) v({}) a({}) t({})",
self.position, self.velocity, self.acceleration, self.time
)
} }
} }
@ -135,15 +154,13 @@ pub struct VirtualBody<'a,T>{
body1: &'a Body<T>, body1: &'a Body<T>,
} }
impl<T> VirtualBody<'_, T> impl<T> VirtualBody<'_, T>
where Time<T>:Copy, where
Time<T>: Copy,
{ {
pub const fn relative<'a>(body0: &'a Body<T>, body1: &'a Body<T>) -> VirtualBody<'a, T> { pub const fn relative<'a>(body0: &'a Body<T>, body1: &'a Body<T>) -> VirtualBody<'a, T> {
//(p0,v0,a0,t0) //(p0,v0,a0,t0)
//(p1,v1,a1,t1) //(p1,v1,a1,t1)
VirtualBody{ VirtualBody { body0, body1 }
body0,
body1,
}
} }
pub fn extrapolated_position(&self, time: Time<T>) -> Planar64Vec3 { pub fn extrapolated_position(&self, time: Time<T>) -> Planar64Vec3 {
self.body1.extrapolated_position(time) - self.body0.extrapolated_position(time) self.body1.extrapolated_position(time) - self.body0.extrapolated_position(time)
@ -155,6 +172,11 @@ impl<T> VirtualBody<'_,T>
self.body1.acceleration - self.body0.acceleration self.body1.acceleration - self.body0.acceleration
} }
pub fn body(&self, time: Time<T>) -> Body<T> { pub fn body(&self, time: Time<T>) -> Body<T> {
Body::new(self.extrapolated_position(time),self.extrapolated_velocity(time),self.acceleration(),time) Body::new(
self.extrapolated_position(time),
self.extrapolated_velocity(time),
self.acceleration(),
time,
)
} }
} }

View File

@ -1,6 +1,6 @@
use crate::model_physics::{GigaTime,FEV,MeshQuery,DirectedEdge}; use crate::model_physics::{DirectedEdge, GigaTime, MeshQuery, FEV};
use strafesnet_common::integer::{Fixed,Ratio,vec3::Vector3}; use crate::physics::{Body, Time};
use crate::physics::{Time,Body}; use strafesnet_common::integer::{vec3::Vector3, Fixed, Ratio};
enum Transition<M: MeshQuery> { enum Transition<M: MeshQuery> {
Miss, Miss,
@ -23,7 +23,13 @@ impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>>> FEV<M>
<F as core::ops::Mul<Fixed<1, 32>>>::Output: core::iter::Sum, <F as core::ops::Mul<Fixed<1, 32>>>::Output: core::iter::Sum,
<M as MeshQuery>::Offset: core::ops::Sub<<F as std::ops::Mul<Fixed<1, 32>>>::Output>, <M as MeshQuery>::Offset: core::ops::Sub<<F as std::ops::Mul<Fixed<1, 32>>>::Output>,
{ {
fn next_transition(&self,body_time:GigaTime,mesh:&M,body:&Body,mut best_time:GigaTime)->Transition<M>{ fn next_transition(
&self,
body_time: GigaTime,
mesh: &M,
body: &Body,
mut best_time: GigaTime,
) -> Transition<M> {
//conflicting derivative means it crosses in the wrong direction. //conflicting derivative means it crosses in the wrong direction.
//if the transition time is equal to an already tested transition, do not replace the current best. //if the transition time is equal to an already tested transition, do not replace the current best.
let mut best_transition = Transition::Miss; let mut best_transition = Transition::Miss;
@ -35,8 +41,15 @@ impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>>> FEV<M>
let (n, d) = mesh.face_nd(face_id); let (n, d) = mesh.face_nd(face_id);
//TODO: use higher precision d value? //TODO: use higher precision d value?
//use the mesh transform translation instead of baking it into the d value. //use the mesh transform translation instead of baking it into the d value.
for dt in Fixed::<4,128>::zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ for dt in Fixed::<4, 128>::zeroes2(
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){ (n.dot(body.position) - d) * 2,
n.dot(body.velocity) * 2,
n.dot(body.acceleration),
) {
if body_time.le_ratio(dt)
&& dt.lt_ratio(best_time)
&& n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative()
{
best_time = dt; best_time = dt;
best_transition = Transition::Hit(face_id, dt); best_transition = Transition::Hit(face_id, dt);
break; break;
@ -49,28 +62,45 @@ impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>>> FEV<M>
let verts = mesh.edge_verts(directed_edge_id.as_undirected()); let verts = mesh.edge_verts(directed_edge_id.as_undirected());
//WARNING: d is moved out of the *2 block because of adding two vertices! //WARNING: d is moved out of the *2 block because of adding two vertices!
//WARNING: precision is swept under the rug! //WARNING: precision is swept under the rug!
for dt in Fixed::<4,128>::zeroes2(n.dot(body.position*2-(mesh.vert(verts[0])+mesh.vert(verts[1]))).fix_4(),n.dot(body.velocity).fix_4()*2,n.dot(body.acceleration).fix_4()){ for dt in Fixed::<4, 128>::zeroes2(
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){ n.dot(body.position * 2 - (mesh.vert(verts[0]) + mesh.vert(verts[1])))
.fix_4(),
n.dot(body.velocity).fix_4() * 2,
n.dot(body.acceleration).fix_4(),
) {
if body_time.le_ratio(dt)
&& dt.lt_ratio(best_time)
&& n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative()
{
best_time = dt; best_time = dt;
best_transition=Transition::Next(FEV::Edge(directed_edge_id.as_undirected()),dt); best_transition =
Transition::Next(FEV::Edge(directed_edge_id.as_undirected()), dt);
break; break;
} }
} }
} }
//if none: //if none:
}, }
&FEV::Edge(edge_id) => { &FEV::Edge(edge_id) => {
//test each face collision time, ignoring roots with zero or conflicting derivative //test each face collision time, ignoring roots with zero or conflicting derivative
let edge_n = mesh.edge_n(edge_id); let edge_n = mesh.edge_n(edge_id);
let edge_verts = mesh.edge_verts(edge_id); let edge_verts = mesh.edge_verts(edge_id);
let delta_pos=body.position*2-(mesh.vert(edge_verts[0])+mesh.vert(edge_verts[1])); let delta_pos =
body.position * 2 - (mesh.vert(edge_verts[0]) + mesh.vert(edge_verts[1]));
for (i, &edge_face_id) in mesh.edge_faces(edge_id).iter().enumerate() { for (i, &edge_face_id) in mesh.edge_faces(edge_id).iter().enumerate() {
let face_n = mesh.face_nd(edge_face_id).0; let face_n = mesh.face_nd(edge_face_id).0;
//edge_n gets parity from the order of edge_faces //edge_n gets parity from the order of edge_faces
let n = face_n.cross(edge_n) * ((i as i64) * 2 - 1); let n = face_n.cross(edge_n) * ((i as i64) * 2 - 1);
//WARNING yada yada d *2 //WARNING yada yada d *2
for dt in Fixed::<4,128>::zeroes2(n.dot(delta_pos).fix_4(),n.dot(body.velocity).fix_4()*2,n.dot(body.acceleration).fix_4()){ for dt in Fixed::<4, 128>::zeroes2(
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){ n.dot(delta_pos).fix_4(),
n.dot(body.velocity).fix_4() * 2,
n.dot(body.acceleration).fix_4(),
) {
if body_time.le_ratio(dt)
&& dt.lt_ratio(best_time)
&& n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative()
{
best_time = dt; best_time = dt;
best_transition = Transition::Next(FEV::Face(edge_face_id), dt); best_transition = Transition::Next(FEV::Face(edge_face_id), dt);
break; break;
@ -81,8 +111,15 @@ impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>>> FEV<M>
for (i, &vert_id) in edge_verts.iter().enumerate() { for (i, &vert_id) in edge_verts.iter().enumerate() {
//vertex normal gets parity from vert index //vertex normal gets parity from vert index
let n = edge_n * (1 - 2 * (i as i64)); let n = edge_n * (1 - 2 * (i as i64));
for dt in Fixed::<2,64>::zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ for dt in Fixed::<2, 64>::zeroes2(
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){ (n.dot(body.position - mesh.vert(vert_id))) * 2,
n.dot(body.velocity) * 2,
n.dot(body.acceleration),
) {
if body_time.le_ratio(dt)
&& dt.lt_ratio(best_time)
&& n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative()
{
let dt = Ratio::new(dt.num.fix_4(), dt.den.fix_4()); let dt = Ratio::new(dt.num.fix_4(), dt.den.fix_4());
best_time = dt; best_time = dt;
best_transition = Transition::Next(FEV::Vert(vert_id), dt); best_transition = Transition::Next(FEV::Vert(vert_id), dt);
@ -91,27 +128,41 @@ impl<F:Copy,M:MeshQuery<Normal=Vector3<F>,Offset=Fixed<4,128>>> FEV<M>
} }
} }
//if none: //if none:
}, }
&FEV::Vert(vert_id) => { &FEV::Vert(vert_id) => {
//test each edge collision time, ignoring roots with zero or conflicting derivative //test each edge collision time, ignoring roots with zero or conflicting derivative
for &directed_edge_id in mesh.vert_edges(vert_id).iter() { for &directed_edge_id in mesh.vert_edges(vert_id).iter() {
//edge is directed away from vertex, but we want the dot product to turn out negative //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); let n = -mesh.directed_edge_n(directed_edge_id);
for dt in Fixed::<2,64>::zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ for dt in Fixed::<2, 64>::zeroes2(
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){ (n.dot(body.position - mesh.vert(vert_id))) * 2,
n.dot(body.velocity) * 2,
n.dot(body.acceleration),
) {
if body_time.le_ratio(dt)
&& dt.lt_ratio(best_time)
&& n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative()
{
let dt = Ratio::new(dt.num.fix_4(), dt.den.fix_4()); let dt = Ratio::new(dt.num.fix_4(), dt.den.fix_4());
best_time = dt; best_time = dt;
best_transition=Transition::Next(FEV::Edge(directed_edge_id.as_undirected()),dt); best_transition =
Transition::Next(FEV::Edge(directed_edge_id.as_undirected()), dt);
break; break;
} }
} }
} }
//if none: //if none:
}, }
} }
best_transition best_transition
} }
pub fn crawl(mut self,mesh:&M,relative_body:&Body,start_time:Time,time_limit:Time)->CrawlResult<M>{ pub fn crawl(
mut self,
mesh: &M,
relative_body: &Body,
start_time: Time,
time_limit: Time,
) -> CrawlResult<M> {
let mut body_time = { let mut body_time = {
let r = (start_time - relative_body.time).to_ratio(); let r = (start_time - relative_body.time).to_ratio();
Ratio::new(r.num.fix_4(), r.den.fix_4()) Ratio::new(r.num.fix_4(), r.den.fix_4())

View File

@ -34,13 +34,19 @@ pub fn read<R:Read+std::io::Seek>(input:R)->Result<DataStructure,ReadError>{
let peek = std::io::BufRead::fill_buf(&mut buf).map_err(ReadError::Io)?; let peek = std::io::BufRead::fill_buf(&mut buf).map_err(ReadError::Io)?;
match &peek[0..4] { match &peek[0..4] {
#[cfg(feature = "roblox")] #[cfg(feature = "roblox")]
b"<rob"=>Ok(DataStructure::Roblox(strafesnet_rbx_loader::read(buf).map_err(ReadError::Roblox)?)), b"<rob" => Ok(DataStructure::Roblox(
strafesnet_rbx_loader::read(buf).map_err(ReadError::Roblox)?,
)),
#[cfg(feature = "source")] #[cfg(feature = "source")]
b"VBSP"=>Ok(DataStructure::Source(strafesnet_bsp_loader::read(buf).map_err(ReadError::Source)?)), b"VBSP" => Ok(DataStructure::Source(
strafesnet_bsp_loader::read(buf).map_err(ReadError::Source)?,
)),
#[cfg(feature = "snf")] #[cfg(feature = "snf")]
b"SNFM" => Ok(DataStructure::StrafesNET( b"SNFM" => Ok(DataStructure::StrafesNET(
strafesnet_snf::read_map(buf).map_err(ReadError::StrafesNET)? strafesnet_snf::read_map(buf)
.into_complete_map().map_err(ReadError::StrafesNETMap)? .map_err(ReadError::StrafesNET)?
.into_complete_map()
.map_err(ReadError::StrafesNETMap)?,
)), )),
_ => Err(ReadError::UnknownFileFormat), _ => Err(ReadError::UnknownFileFormat),
} }
@ -59,7 +65,9 @@ impl std::fmt::Display for LoadError{
} }
impl std::error::Error for LoadError {} impl std::error::Error for LoadError {}
pub fn load<P:AsRef<std::path::Path>>(path:P)->Result<strafesnet_common::map::CompleteMap,LoadError>{ pub fn load<P: AsRef<std::path::Path>>(
path: P,
) -> Result<strafesnet_common::map::CompleteMap, LoadError> {
//blocking because it's simpler... //blocking because it's simpler...
let file = std::fs::File::open(path).map_err(LoadError::File)?; let file = std::fs::File::open(path).map_err(LoadError::File)?;
match read(file).map_err(LoadError::ReadError)? { match read(file).map_err(LoadError::ReadError)? {
@ -83,24 +91,33 @@ pub fn load<P:AsRef<std::path::Path>>(path:P)->Result<strafesnet_common::map::Co
let meshpart_meshes = mesh_loader.load_meshes().map_err(LoadError::Io)?; let meshpart_meshes = mesh_loader.load_meshes().map_err(LoadError::Io)?;
let map_step2 = map_step1.add_meshpart_meshes_and_calculate_attributes( let map_step2 = map_step1.add_meshpart_meshes_and_calculate_attributes(
meshpart_meshes.into_iter().map(|(mesh_id,loader_model)| meshpart_meshes.into_iter().map(|(mesh_id, loader_model)| {
(mesh_id,strafesnet_rbx_loader::data::RobloxMeshBytes::new(loader_model.get())) (
mesh_id,
strafesnet_rbx_loader::data::RobloxMeshBytes::new(loader_model.get()),
) )
}),
); );
let (textures,render_configs)=loader.into_render_configs().map_err(LoadError::Io)?.consume(); let (textures, render_configs) = loader
.into_render_configs()
.map_err(LoadError::Io)?
.consume();
let map = map_step2.add_render_configs_and_textures( let map = map_step2.add_render_configs_and_textures(
render_configs.into_iter(), render_configs.into_iter(),
textures.into_iter().map(|(texture_id,texture)| textures.into_iter().map(|(texture_id, texture)| {
(texture_id,match texture{ (
texture_id,
match texture {
strafesnet_deferred_loader::texture::Texture::ImageDDS(data) => data, strafesnet_deferred_loader::texture::Texture::ImageDDS(data) => data,
}) },
) )
}),
); );
Ok(map) Ok(map)
}, }
#[cfg(feature = "source")] #[cfg(feature = "source")]
DataStructure::Source(bsp) => { DataStructure::Source(bsp) => {
let mut loader = strafesnet_deferred_loader::source_legacy(); let mut loader = strafesnet_deferred_loader::source_legacy();
@ -117,28 +134,37 @@ pub fn load<P:AsRef<std::path::Path>>(path:P)->Result<strafesnet_common::map::Co
let map_step2 = map_step1.add_prop_meshes( let map_step2 = map_step1.add_prop_meshes(
//the type conflagulator 9000 //the type conflagulator 9000
prop_meshes.into_iter().map(|(mesh_id,loader_model)| prop_meshes.into_iter().map(|(mesh_id, loader_model)| {
(mesh_id,strafesnet_bsp_loader::data::ModelData{ (
mesh_id,
strafesnet_bsp_loader::data::ModelData {
mdl: strafesnet_bsp_loader::data::MdlData::new(loader_model.mdl.get()), mdl: strafesnet_bsp_loader::data::MdlData::new(loader_model.mdl.get()),
vtx: strafesnet_bsp_loader::data::VtxData::new(loader_model.vtx.get()), vtx: strafesnet_bsp_loader::data::VtxData::new(loader_model.vtx.get()),
vvd: strafesnet_bsp_loader::data::VvdData::new(loader_model.vvd.get()), vvd: strafesnet_bsp_loader::data::VvdData::new(loader_model.vvd.get()),
}) },
), )
}),
|name| texture_loader.acquire_render_config_id(name), |name| texture_loader.acquire_render_config_id(name),
); );
let (textures,render_configs)=loader.into_render_configs().map_err(LoadError::Io)?.consume(); let (textures, render_configs) = loader
.into_render_configs()
.map_err(LoadError::Io)?
.consume();
let map = map_step2.add_render_configs_and_textures( let map = map_step2.add_render_configs_and_textures(
render_configs.into_iter(), render_configs.into_iter(),
textures.into_iter().map(|(texture_id,texture)| textures.into_iter().map(|(texture_id, texture)| {
(texture_id,match texture{ (
texture_id,
match texture {
strafesnet_deferred_loader::texture::Texture::ImageDDS(data) => data, strafesnet_deferred_loader::texture::Texture::ImageDDS(data) => data,
}) },
), )
}),
); );
Ok(map) Ok(map)
}, }
} }
} }

View File

@ -1,10 +1,15 @@
use crate::model_graphics::{
self, GraphicsMeshOwnedRenderConfig, GraphicsModelColor4, GraphicsModelOwned, GraphicsVertex,
IndexedGraphicsMeshOwnedRenderConfig, IndexedGraphicsMeshOwnedRenderConfigId,
};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{HashSet,HashMap}; use std::collections::{HashMap, HashSet};
use strafesnet_common::map;
use strafesnet_common::integer; use strafesnet_common::integer;
use strafesnet_common::model::{self, ColorId, NormalId, PolygonIter, PositionId, RenderConfigId, TextureCoordinateId, VertexId}; use strafesnet_common::map;
use strafesnet_common::model::{
self, ColorId, NormalId, PolygonIter, PositionId, RenderConfigId, TextureCoordinateId, VertexId,
};
use wgpu::{util::DeviceExt, AstcBlock, AstcChannel}; use wgpu::{util::DeviceExt, AstcBlock, AstcChannel};
use crate::model_graphics::{self,IndexedGraphicsMeshOwnedRenderConfig,IndexedGraphicsMeshOwnedRenderConfigId,GraphicsMeshOwnedRenderConfig,GraphicsModelColor4,GraphicsModelOwned,GraphicsVertex};
struct Indices { struct Indices {
count: u32, count: u32,
@ -12,7 +17,11 @@ struct Indices{
format: wgpu::IndexFormat, format: wgpu::IndexFormat,
} }
impl Indices { impl Indices {
fn new<T:bytemuck::Pod>(device:&wgpu::Device,indices:&Vec<T>,format:wgpu::IndexFormat)->Self{ fn new<T: bytemuck::Pod>(
device: &wgpu::Device,
indices: &Vec<T>,
format: wgpu::IndexFormat,
) -> Self {
Self { Self {
buf: device.create_buffer_init(&wgpu::util::BufferInitDescriptor { buf: device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Index"), label: Some("Index"),
@ -72,7 +81,8 @@ impl GraphicsCamera{
} }
pub fn world(&self, pos: glam::Vec3, angles: glam::Vec2) -> glam::Mat4 { pub fn world(&self, pos: glam::Vec3, angles: glam::Vec2) -> glam::Mat4 {
//f32 good enough for view matrix //f32 good enough for view matrix
glam::Mat4::from_translation(pos)*glam::Mat4::from_euler(glam::EulerRot::YXZ,angles.x,angles.y,0f32) glam::Mat4::from_translation(pos)
* glam::Mat4::from_euler(glam::EulerRot::YXZ, angles.x, angles.y, 0f32)
} }
pub fn to_uniform_data(&self, pos: glam::Vec3, angles: glam::Vec2) -> [f32; 16 * 4] { pub fn to_uniform_data(&self, pos: glam::Vec3, angles: glam::Vec2) -> [f32; 16 * 4] {
@ -138,18 +148,29 @@ impl GraphicsState{
self.models.clear(); self.models.clear();
} }
pub fn load_user_settings(&mut self, user_settings: &crate::settings::UserSettings) { pub fn load_user_settings(&mut self, user_settings: &crate::settings::UserSettings) {
self.camera.fov=user_settings.calculate_fov(1.0,&self.camera.screen_size).as_vec2(); self.camera.fov = user_settings
.calculate_fov(1.0, &self.camera.screen_size)
.as_vec2();
} }
pub fn generate_models(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,map:&map::CompleteMap){ pub fn generate_models(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
map: &map::CompleteMap,
) {
//generate texture view per texture //generate texture view per texture
let texture_views:HashMap<strafesnet_common::model::TextureId,wgpu::TextureView>=map.textures.iter().enumerate().filter_map(|(texture_id,texture_data)|{ let texture_views: HashMap<strafesnet_common::model::TextureId, wgpu::TextureView> = map
.textures
.iter()
.enumerate()
.filter_map(|(texture_id, texture_data)| {
let texture_id = model::TextureId::new(texture_id as u32); let texture_id = model::TextureId::new(texture_id as u32);
let image = match ddsfile::Dds::read(std::io::Cursor::new(texture_data)) { let image = match ddsfile::Dds::read(std::io::Cursor::new(texture_data)) {
Ok(image) => image, Ok(image) => image,
Err(e) => { Err(e) => {
println!("Error loading texture: {e}"); println!("Error loading texture: {e}");
return None; return None;
}, }
}; };
let (mut width, mut height) = (image.get_width(), image.get_height()); let (mut width, mut height) = (image.get_width(), image.get_height());
@ -161,11 +182,11 @@ impl GraphicsState{
width = width / 4 * 4; width = width / 4 * 4;
height = height / 4 * 4; height = height / 4 * 4;
wgpu::TextureFormat::Bc7RgbaUnormSrgb wgpu::TextureFormat::Bc7RgbaUnormSrgb
}, }
other => { other => {
println!("unsupported texture format{:?}", other); println!("unsupported texture format{:?}", other);
return None; return None;
}, }
}; };
let size = wgpu::Extent3d { let size = wgpu::Extent3d {
@ -195,30 +216,47 @@ impl GraphicsState{
wgpu::util::TextureDataOrder::LayerMajor, wgpu::util::TextureDataOrder::LayerMajor,
&image.data, &image.data,
); );
Some((texture_id,texture.create_view(&wgpu::TextureViewDescriptor{ Some((
texture_id,
texture.create_view(&wgpu::TextureViewDescriptor {
label: Some(format!("Texture{} View", texture_id.get()).as_str()), label: Some(format!("Texture{} View", texture_id.get()).as_str()),
dimension: Some(wgpu::TextureViewDimension::D2), dimension: Some(wgpu::TextureViewDimension::D2),
..wgpu::TextureViewDescriptor::default() ..wgpu::TextureViewDescriptor::default()
}))) }),
}).collect(); ))
})
.collect();
let num_textures = texture_views.len(); let num_textures = texture_views.len();
//split groups with different textures into separate models //split groups with different textures into separate models
//the models received here are supposed to be tightly packed,i.e. no code needs to check if two models are using the same groups. //the models received here are supposed to be tightly packed,i.e. no code needs to check if two models are using the same groups.
let indexed_models_len = map.models.len(); let indexed_models_len = map.models.len();
//models split into graphics_group.RenderConfigId //models split into graphics_group.RenderConfigId
let mut owned_mesh_id_from_mesh_id_render_config_id:HashMap<model::MeshId,HashMap<RenderConfigId,IndexedGraphicsMeshOwnedRenderConfigId>>=HashMap::new(); let mut owned_mesh_id_from_mesh_id_render_config_id: HashMap<
let mut unique_render_config_models:Vec<IndexedGraphicsMeshOwnedRenderConfig>=Vec::with_capacity(indexed_models_len); model::MeshId,
HashMap<RenderConfigId, IndexedGraphicsMeshOwnedRenderConfigId>,
> = HashMap::new();
let mut unique_render_config_models: Vec<IndexedGraphicsMeshOwnedRenderConfig> =
Vec::with_capacity(indexed_models_len);
for model in &map.models { for model in &map.models {
//wow //wow
let instance = GraphicsModelOwned { let instance = GraphicsModelOwned {
transform: model.transform.into(), transform: model.transform.into(),
normal_transform:glam::Mat3::from_cols_array_2d(&model.transform.matrix3.to_array().map(|row|row.map(Into::into))).inverse().transpose(), normal_transform: glam::Mat3::from_cols_array_2d(
&model
.transform
.matrix3
.to_array()
.map(|row| row.map(Into::into)),
)
.inverse()
.transpose(),
color: GraphicsModelColor4::new(model.color), color: GraphicsModelColor4::new(model.color),
}; };
//get or create owned mesh map //get or create owned mesh map
let owned_mesh_map = owned_mesh_id_from_mesh_id_render_config_id let owned_mesh_map = owned_mesh_id_from_mesh_id_render_config_id
.entry(model.mesh).or_insert_with(||{ .entry(model.mesh)
.or_insert_with(|| {
let mut owned_mesh_map = HashMap::new(); let mut owned_mesh_map = HashMap::new();
//add mesh if renderid never before seen for this model //add mesh if renderid never before seen for this model
//add instance //add instance
@ -228,30 +266,58 @@ impl GraphicsState{
for graphics_group in mesh.graphics_groups.iter() { for graphics_group in mesh.graphics_groups.iter() {
//get or create owned mesh //get or create owned mesh
let owned_mesh_id = owned_mesh_map let owned_mesh_id = owned_mesh_map
.entry(graphics_group.render).or_insert_with(||{ .entry(graphics_group.render)
.or_insert_with(|| {
//create //create
let owned_mesh_id=IndexedGraphicsMeshOwnedRenderConfigId::new(unique_render_config_models.len() as u32); let owned_mesh_id = IndexedGraphicsMeshOwnedRenderConfigId::new(
unique_render_config_models.push(IndexedGraphicsMeshOwnedRenderConfig{ unique_render_config_models.len() as u32,
unique_pos:mesh.unique_pos.iter().map(|v|v.to_array().map(Into::into)).collect(), );
unique_tex:mesh.unique_tex.iter().map(|v|*v.as_ref()).collect(), unique_render_config_models.push(
unique_normal:mesh.unique_normal.iter().map(|v|v.to_array().map(Into::into)).collect(), IndexedGraphicsMeshOwnedRenderConfig {
unique_color:mesh.unique_color.iter().map(|v|*v.as_ref()).collect(), unique_pos: mesh
.unique_pos
.iter()
.map(|v| v.to_array().map(Into::into))
.collect(),
unique_tex: mesh
.unique_tex
.iter()
.map(|v| *v.as_ref())
.collect(),
unique_normal: mesh
.unique_normal
.iter()
.map(|v| v.to_array().map(Into::into))
.collect(),
unique_color: mesh
.unique_color
.iter()
.map(|v| *v.as_ref())
.collect(),
unique_vertices: mesh.unique_vertices.clone(), unique_vertices: mesh.unique_vertices.clone(),
render_config: graphics_group.render, render_config: graphics_group.render,
polys:model::PolygonGroup::PolygonList(model::PolygonList::new(Vec::new())), polys: model::PolygonGroup::PolygonList(
model::PolygonList::new(Vec::new()),
),
instances: Vec::new(), instances: Vec::new(),
}); },
);
owned_mesh_id owned_mesh_id
}); });
let owned_mesh=unique_render_config_models.get_mut(owned_mesh_id.get() as usize).unwrap(); let owned_mesh = unique_render_config_models
.get_mut(owned_mesh_id.get() as usize)
.unwrap();
match &mut owned_mesh.polys { match &mut owned_mesh.polys {
model::PolygonGroup::PolygonList(polygon_list)=>polygon_list.extend( model::PolygonGroup::PolygonList(polygon_list) => polygon_list
graphics_group.groups.iter().flat_map(|polygon_group_id|{ .extend(
mesh.polygon_groups[polygon_group_id.get() as usize].polys() graphics_group
.groups
.iter()
.flat_map(|polygon_group_id| {
mesh.polygon_groups[polygon_group_id.get() as usize]
.polys()
}) })
.map(|vertex_id_slice| .map(|vertex_id_slice| vertex_id_slice.to_vec()),
vertex_id_slice.to_vec()
)
), ),
} }
} }
@ -259,7 +325,9 @@ impl GraphicsState{
owned_mesh_map owned_mesh_map
}); });
for owned_mesh_id in owned_mesh_map.values() { for owned_mesh_id in owned_mesh_map.values() {
let owned_mesh=unique_render_config_models.get_mut(owned_mesh_id.get() as usize).unwrap(); let owned_mesh = unique_render_config_models
.get_mut(owned_mesh_id.get() as usize)
.unwrap();
let render_config = &map.render_configs[owned_mesh.render_config.get() as usize]; let render_config = &map.render_configs[owned_mesh.render_config.get() as usize];
if model.color.w == 0.0 && render_config.texture.is_none() { if model.color.w == 0.0 && render_config.texture.is_none() {
continue; continue;
@ -324,60 +392,91 @@ impl GraphicsState{
let model = &unique_render_config_models[model_id]; let model = &unique_render_config_models[model_id];
let instance = &model.instances[instance_id]; let instance = &model.instances[instance_id];
//just hash word slices LOL //just hash word slices LOL
let map_pos_id:Vec<PositionId>=model.unique_pos.iter().map(|untransformed_pos|{ let map_pos_id: Vec<PositionId> = model
let pos=instance.transform.transform_point3(glam::Vec3::from_array(untransformed_pos.clone())).to_array(); .unique_pos
.iter()
.map(|untransformed_pos| {
let pos = instance
.transform
.transform_point3(glam::Vec3::from_array(
untransformed_pos.clone(),
))
.to_array();
let h = bytemuck::cast::<[f32; 3], [u32; 3]>(pos); let h = bytemuck::cast::<[f32; 3], [u32; 3]>(pos);
PositionId::new(*pos_id_from.entry(h).or_insert_with(|| { PositionId::new(*pos_id_from.entry(h).or_insert_with(|| {
let pos_id = unique_pos.len(); let pos_id = unique_pos.len();
unique_pos.push(pos); unique_pos.push(pos);
pos_id pos_id
}) as u32) }) as u32)
}).collect(); })
let map_tex_id:Vec<TextureCoordinateId>=model.unique_tex.iter().map(|&tex|{ .collect();
let map_tex_id: Vec<TextureCoordinateId> = model
.unique_tex
.iter()
.map(|&tex| {
let h = bytemuck::cast::<[f32; 2], [u32; 2]>(tex); let h = bytemuck::cast::<[f32; 2], [u32; 2]>(tex);
TextureCoordinateId::new(*tex_id_from.entry(h).or_insert_with(||{ TextureCoordinateId::new(*tex_id_from.entry(h).or_insert_with(
|| {
let tex_id = unique_tex.len(); let tex_id = unique_tex.len();
unique_tex.push(tex); unique_tex.push(tex);
tex_id tex_id
}) as u32) },
}).collect(); ) as u32)
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(); .collect();
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 = bytemuck::cast::<[f32; 3], [u32; 3]>(normal); let h = bytemuck::cast::<[f32; 3], [u32; 3]>(normal);
NormalId::new(*normal_id_from.entry(h).or_insert_with(|| { NormalId::new(*normal_id_from.entry(h).or_insert_with(|| {
let normal_id = unique_normal.len(); let normal_id = unique_normal.len();
unique_normal.push(normal); unique_normal.push(normal);
normal_id normal_id
}) as u32) }) as u32)
}).collect(); })
let map_color_id:Vec<ColorId>=model.unique_color.iter().map(|&color|{ .collect();
let map_color_id: Vec<ColorId> = model
.unique_color
.iter()
.map(|&color| {
let h = bytemuck::cast::<[f32; 4], [u32; 4]>(color); let h = bytemuck::cast::<[f32; 4], [u32; 4]>(color);
ColorId::new(*color_id_from.entry(h).or_insert_with(|| { ColorId::new(*color_id_from.entry(h).or_insert_with(|| {
let color_id = unique_color.len(); let color_id = unique_color.len();
unique_color.push(color); unique_color.push(color);
color_id color_id
}) as u32) }) as u32)
}).collect(); })
.collect();
//map the indexed vertices onto new indices //map the indexed vertices onto new indices
//creating the vertex map is slightly different because the vertices are directly hashable //creating the vertex map is slightly different because the vertices are directly hashable
let map_vertex_id:Vec<VertexId>=model.unique_vertices.iter().map(|unmapped_vertex|{ let map_vertex_id: Vec<VertexId> = model
.unique_vertices
.iter()
.map(|unmapped_vertex| {
let vertex = model::IndexedVertex { let vertex = model::IndexedVertex {
pos: map_pos_id[unmapped_vertex.pos.get() as usize], pos: map_pos_id[unmapped_vertex.pos.get() as usize],
tex: map_tex_id[unmapped_vertex.tex.get() as usize], tex: map_tex_id[unmapped_vertex.tex.get() as usize],
normal: map_normal_id[unmapped_vertex.normal.get() as usize], normal: map_normal_id[unmapped_vertex.normal.get() as usize],
color: map_color_id[unmapped_vertex.color.get() as usize], color: map_color_id[unmapped_vertex.color.get() as usize],
}; };
VertexId::new(*vertex_id_from.entry(vertex.clone()).or_insert_with(||{ VertexId::new(*vertex_id_from.entry(vertex.clone()).or_insert_with(
|| {
let vertex_id = unique_vertices.len(); let vertex_id = unique_vertices.len();
unique_vertices.push(vertex); unique_vertices.push(vertex);
vertex_id vertex_id
}) as u32) },
}).collect(); ) as u32)
polys.extend(model.polys.polys().map(|poly| })
poly.iter().map(|vertex_id| .collect();
map_vertex_id[vertex_id.get() as usize] polys.extend(model.polys.polys().map(|poly| {
).collect() poly.iter()
)); .map(|vertex_id| map_vertex_id[vertex_id.get() as usize])
.collect()
}));
} }
//push model into dedup //push model into dedup
deduplicated_models.push(IndexedGraphicsMeshOwnedRenderConfig { deduplicated_models.push(IndexedGraphicsMeshOwnedRenderConfig {
@ -391,7 +490,7 @@ impl GraphicsState{
instances: vec![GraphicsModelOwned { instances: vec![GraphicsModelOwned {
transform: glam::Mat4::IDENTITY, transform: glam::Mat4::IDENTITY,
normal_transform: glam::Mat3::IDENTITY, normal_transform: glam::Mat3::IDENTITY,
color color,
}], }],
}); });
} }
@ -406,14 +505,16 @@ impl GraphicsState{
//de-index models //de-index models
let deduplicated_models_len = deduplicated_models.len(); let deduplicated_models_len = deduplicated_models.len();
let models:Vec<GraphicsMeshOwnedRenderConfig>=deduplicated_models.into_iter().map(|model|{ let models: Vec<GraphicsMeshOwnedRenderConfig> = deduplicated_models
.into_iter()
.map(|model| {
let mut vertices = Vec::new(); let mut vertices = Vec::new();
let mut index_from_vertex = HashMap::new(); //::<IndexedVertex,usize> let mut index_from_vertex = HashMap::new(); //::<IndexedVertex,usize>
//this mut be combined in a more complex way if the models use different render patterns per group //this mut be combined in a more complex way if the models use different render patterns per group
let mut indices = Vec::new(); let mut indices = Vec::new();
for poly in model.polys.polys() { for poly in model.polys.polys() {
let mut poly_vertices=poly.iter() let mut poly_vertices = poly.iter().map(|&vertex_index| {
.map(|&vertex_index|*index_from_vertex.entry(vertex_index).or_insert_with(||{ *index_from_vertex.entry(vertex_index).or_insert_with(|| {
let i = vertices.len(); let i = vertices.len();
let vertex = &model.unique_vertices[vertex_index.get() as usize]; let vertex = &model.unique_vertices[vertex_index.get() as usize];
vertices.push(GraphicsVertex { vertices.push(GraphicsVertex {
@ -423,7 +524,8 @@ impl GraphicsState{
color: model.unique_color[vertex.color.get() as usize], color: model.unique_color[vertex.color.get() as usize],
}); });
i i
})); })
});
let a = poly_vertices.next().unwrap(); let a = poly_vertices.next().unwrap();
let mut b = poly_vertices.next().unwrap(); let mut b = poly_vertices.next().unwrap();
@ -438,18 +540,30 @@ impl GraphicsState{
indices: if (u32::MAX as usize) < vertices.len() { indices: if (u32::MAX as usize) < vertices.len() {
panic!("Model has too many vertices!") panic!("Model has too many vertices!")
} else if (u16::MAX as usize) < vertices.len() { } else if (u16::MAX as usize) < vertices.len() {
model_graphics::Indices::U32(indices.into_iter().map(|vertex_idx|vertex_idx as u32).collect()) model_graphics::Indices::U32(
indices
.into_iter()
.map(|vertex_idx| vertex_idx as u32)
.collect(),
)
} else { } else {
model_graphics::Indices::U16(indices.into_iter().map(|vertex_idx|vertex_idx as u16).collect()) model_graphics::Indices::U16(
indices
.into_iter()
.map(|vertex_idx| vertex_idx as u16)
.collect(),
)
}, },
vertices, vertices,
render_config: model.render_config, render_config: model.render_config,
} }
}).collect(); })
.collect();
//.into_iter() the modeldata vec so entities can be /moved/ to models.entities //.into_iter() the modeldata vec so entities can be /moved/ to models.entities
let mut model_count = 0; let mut model_count = 0;
let mut instance_count = 0; let mut instance_count = 0;
let uniform_buffer_binding_size=crate::setup::required_limits().max_uniform_buffer_binding_size as usize; let uniform_buffer_binding_size =
crate::setup::required_limits().max_uniform_buffer_binding_size as usize;
let chunk_size = uniform_buffer_binding_size / MODEL_BUFFER_SIZE_BYTES; let chunk_size = uniform_buffer_binding_size / MODEL_BUFFER_SIZE_BYTES;
self.models.reserve(models.len()); self.models.reserve(models.len());
for model in models.into_iter() { for model in models.into_iter() {
@ -465,9 +579,10 @@ impl GraphicsState{
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
}); });
let render_config = &map.render_configs[model.render_config.get() as usize]; let render_config = &map.render_configs[model.render_config.get() as usize];
let texture_view=render_config.texture.and_then(|texture_id| let texture_view = render_config
texture_views.get(&texture_id) .texture
).unwrap_or(&self.temp_squid_texture_view); .and_then(|texture_id| texture_views.get(&texture_id))
.unwrap_or(&self.temp_squid_texture_view);
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &self.bind_group_layouts.model, layout: &self.bind_group_layouts.model,
entries: &[ entries: &[
@ -496,8 +611,12 @@ impl GraphicsState{
instance_count: instances_chunk.len() as u32, instance_count: instances_chunk.len() as u32,
vertex_buf, vertex_buf,
indices: match &model.indices { indices: match &model.indices {
model_graphics::Indices::U32(indices)=>Indices::new(device,indices,wgpu::IndexFormat::Uint32), model_graphics::Indices::U32(indices) => {
model_graphics::Indices::U16(indices)=>Indices::new(device,indices,wgpu::IndexFormat::Uint16), Indices::new(device, indices, wgpu::IndexFormat::Uint32)
}
model_graphics::Indices::U16(indices) => {
Indices::new(device, indices, wgpu::IndexFormat::Uint16)
}
}, },
bind_group, bind_group,
}); });
@ -516,10 +635,10 @@ impl GraphicsState{
queue: &wgpu::Queue, queue: &wgpu::Queue,
config: &wgpu::SurfaceConfiguration, config: &wgpu::SurfaceConfiguration,
) -> Self { ) -> Self {
let camera_bind_group_layout=device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor{ let camera_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None, label: None,
entries:&[ entries: &[wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry{
binding: 0, binding: 0,
visibility: wgpu::ShaderStages::VERTEX, visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer { ty: wgpu::BindingType::Buffer {
@ -528,10 +647,10 @@ impl GraphicsState{
min_binding_size: None, min_binding_size: None,
}, },
count: None, count: None,
}, }],
],
}); });
let skybox_texture_bind_group_layout=device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor{ let skybox_texture_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Skybox Texture Bind Group Layout"), label: Some("Skybox Texture Bind Group Layout"),
entries: &[ entries: &[
wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry {
@ -552,7 +671,8 @@ impl GraphicsState{
}, },
], ],
}); });
let model_bind_group_layout=device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor{ let model_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Model Bind Group Layout"), label: Some("Model Bind Group Layout"),
entries: &[ entries: &[
wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry {
@ -616,7 +736,8 @@ impl GraphicsState{
let device_features = device.features(); let device_features = device.features();
let skybox_texture_view = { let skybox_texture_view = {
let skybox_format=if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC){ let skybox_format =
if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC) {
println!("Using ASTC"); println!("Using ASTC");
wgpu::TextureFormat::Astc { wgpu::TextureFormat::Astc {
block: AstcBlock::B4x4, block: AstcBlock::B4x4,
@ -722,7 +843,8 @@ impl GraphicsState{
}) })
}; };
let model_pipeline_layout=device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor{ let model_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None, label: None,
bind_group_layouts: &[ bind_group_layouts: &[
&camera_bind_group_layout, &camera_bind_group_layout,
@ -733,10 +855,7 @@ impl GraphicsState{
}); });
let sky_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { let sky_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None, label: None,
bind_group_layouts:&[ bind_group_layouts: &[&camera_bind_group_layout, &skybox_texture_bind_group_layout],
&camera_bind_group_layout,
&skybox_texture_bind_group_layout,
],
push_constant_ranges: &[], push_constant_ranges: &[],
}); });
@ -816,12 +935,10 @@ impl GraphicsState{
}); });
let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &camera_bind_group_layout, layout: &camera_bind_group_layout,
entries:&[ entries: &[wgpu::BindGroupEntry {
wgpu::BindGroupEntry{
binding: 0, binding: 0,
resource: camera_buf.as_entire_binding(), resource: camera_buf.as_entire_binding(),
}, }],
],
label: Some("Camera"), label: Some("Camera"),
}); });
@ -845,7 +962,7 @@ impl GraphicsState{
Self { Self {
pipelines: GraphicsPipelines { pipelines: GraphicsPipelines {
skybox: sky_pipeline, skybox: sky_pipeline,
model:model_pipeline model: model_pipeline,
}, },
bind_groups: GraphicsBindGroups { bind_groups: GraphicsBindGroups {
camera: camera_bind_group, camera: camera_bind_group,
@ -856,8 +973,12 @@ impl GraphicsState{
models: Vec::new(), models: Vec::new(),
depth_view, depth_view,
staging_belt: wgpu::util::StagingBelt::new(0x100), staging_belt: wgpu::util::StagingBelt::new(0x100),
bind_group_layouts:GraphicsBindGroupLayouts{model:model_bind_group_layout}, bind_group_layouts: GraphicsBindGroupLayouts {
samplers:GraphicsSamplers{repeat:repeat_sampler}, model: model_bind_group_layout,
},
samplers: GraphicsSamplers {
repeat: repeat_sampler,
},
temp_squid_texture_view: squid_texture_view, temp_squid_texture_view: squid_texture_view,
} }
} }
@ -880,12 +1001,18 @@ impl GraphicsState{
) { ) {
//TODO:use scheduled frame times to create beautiful smoothing simulation physics extrapolation assuming no input //TODO:use scheduled frame times to create beautiful smoothing simulation physics extrapolation assuming no input
let mut encoder=device.create_command_encoder(&wgpu::CommandEncoderDescriptor{label:None}); let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
// update rotation // update rotation
let camera_uniforms = self.camera.to_uniform_data( let camera_uniforms = self.camera.to_uniform_data(
frame_state.body.extrapolated_position(frame_state.time).map(Into::<f32>::into).to_array().into(), frame_state
frame_state.camera.simulate_move_angles(glam::IVec2::ZERO) .body
.extrapolated_position(frame_state.time)
.map(Into::<f32>::into)
.to_array()
.into(),
frame_state.camera.simulate_move_angles(glam::IVec2::ZERO),
); );
self.staging_belt self.staging_belt
.write_buffer( .write_buffer(

View File

@ -27,7 +27,7 @@ pub fn new<'a>(
Instruction::ChangeMap(map) => { Instruction::ChangeMap(map) => {
graphics.clear(); graphics.clear();
graphics.generate_models(&device, &queue, &map); graphics.generate_models(&device, &queue, &map);
}, }
Instruction::Resize(size, user_settings) => { Instruction::Resize(size, user_settings) => {
resize = Some((size, user_settings)); resize = Some((size, user_settings));
} }

View File

@ -1,18 +1,18 @@
mod body; mod body;
mod compat_worker;
mod face_crawler;
mod file; mod file;
mod graphics;
mod graphics_worker;
mod model_graphics;
mod model_physics;
mod physics;
mod physics_worker;
mod push_solve;
mod settings;
mod setup; mod setup;
mod window; mod window;
mod worker; mod worker;
mod physics;
mod graphics;
mod settings;
mod push_solve;
mod face_crawler;
mod compat_worker;
mod model_physics;
mod model_graphics;
mod physics_worker;
mod graphics_worker;
const TITLE: &'static str = concat!("Strafe Client v", env!("CARGO_PKG_VERSION")); const TITLE: &'static str = concat!("Strafe Client v", env!("CARGO_PKG_VERSION"));

View File

@ -1,8 +1,8 @@
use std::borrow::{Borrow, Cow}; use std::borrow::{Borrow, Cow};
use std::collections::{HashSet,HashMap}; use std::collections::{HashMap, HashSet};
use strafesnet_common::integer::vec3::Vector3; use strafesnet_common::integer::vec3::Vector3;
use strafesnet_common::model::{self,MeshId,PolygonIter};
use strafesnet_common::integer::{self, vec3, Fixed, Planar64, Planar64Vec3, Ratio}; use strafesnet_common::integer::{self, vec3, Fixed, Planar64, Planar64Vec3, Ratio};
use strafesnet_common::model::{self, MeshId, PolygonIter};
use strafesnet_common::physics::Time; use strafesnet_common::physics::Time;
type Body = crate::body::Body<strafesnet_common::physics::TimeInner>; type Body = crate::body::Body<strafesnet_common::physics::TimeInner>;
@ -80,13 +80,20 @@ pub trait MeshQuery{
} }
fn directed_edge_n(&self, directed_edge_id: Self::Edge) -> Planar64Vec3 { fn directed_edge_n(&self, directed_edge_id: Self::Edge) -> Planar64Vec3 {
let verts = self.edge_verts(directed_edge_id.as_undirected()); let verts = self.edge_verts(directed_edge_id.as_undirected());
(self.vert(verts[1].clone())-self.vert(verts[0].clone()))*((directed_edge_id.parity() as i64)*2-1) (self.vert(verts[1].clone()) - self.vert(verts[0].clone()))
* ((directed_edge_id.parity() as i64) * 2 - 1)
} }
fn vert(&self, vert_id: Self::Vert) -> Planar64Vec3; fn vert(&self, vert_id: Self::Vert) -> Planar64Vec3;
fn face_nd(&self, face_id: Self::Face) -> (Self::Normal, Self::Offset); fn face_nd(&self, face_id: Self::Face) -> (Self::Normal, Self::Offset);
fn face_edges(&self, face_id: Self::Face) -> Cow<Vec<Self::Edge>>; fn face_edges(&self, face_id: Self::Face) -> Cow<Vec<Self::Edge>>;
fn edge_faces(&self,edge_id:<Self::Edge as DirectedEdge>::UndirectedEdge)->Cow<[Self::Face;2]>; fn edge_faces(
fn edge_verts(&self,edge_id:<Self::Edge as DirectedEdge>::UndirectedEdge)->Cow<[Self::Vert;2]>; &self,
edge_id: <Self::Edge as DirectedEdge>::UndirectedEdge,
) -> Cow<[Self::Face; 2]>;
fn edge_verts(
&self,
edge_id: <Self::Edge as DirectedEdge>::UndirectedEdge,
) -> Cow<[Self::Vert; 2]>;
fn vert_edges(&self, vert_id: Self::Vert) -> Cow<Vec<Self::Edge>>; fn vert_edges(&self, vert_id: Self::Vert) -> Cow<Vec<Self::Edge>>;
fn vert_faces(&self, vert_id: Self::Vert) -> Cow<Vec<Self::Face>>; fn vert_faces(&self, vert_id: Self::Vert) -> Cow<Vec<Self::Face>>;
} }
@ -147,12 +154,30 @@ impl PhysicsMesh{
//go go gadget debug print mesh //go go gadget debug print mesh
let data = PhysicsMeshData { let data = PhysicsMeshData {
faces: vec![ faces: vec![
Face{normal:vec3::raw_xyz( 4294967296, 0, 0),dot:Planar64::raw(4294967296)}, Face {
Face{normal:vec3::raw_xyz( 0, 4294967296, 0),dot:Planar64::raw(4294967296)}, normal: vec3::raw_xyz(4294967296, 0, 0),
Face{normal:vec3::raw_xyz( 0, 0, 4294967296),dot:Planar64::raw(4294967296)}, dot: Planar64::raw(4294967296),
Face{normal:vec3::raw_xyz(-4294967296, 0, 0),dot:Planar64::raw(4294967296)}, },
Face{normal:vec3::raw_xyz( 0,-4294967296, 0),dot:Planar64::raw(4294967296)}, Face {
Face{normal:vec3::raw_xyz( 0, 0,-4294967296),dot:Planar64::raw(4294967296)} normal: vec3::raw_xyz(0, 4294967296, 0),
dot: Planar64::raw(4294967296),
},
Face {
normal: vec3::raw_xyz(0, 0, 4294967296),
dot: Planar64::raw(4294967296),
},
Face {
normal: vec3::raw_xyz(-4294967296, 0, 0),
dot: Planar64::raw(4294967296),
},
Face {
normal: vec3::raw_xyz(0, -4294967296, 0),
dot: Planar64::raw(4294967296),
},
Face {
normal: vec3::raw_xyz(0, 0, -4294967296),
dot: Planar64::raw(4294967296),
},
], ],
verts: vec![ verts: vec![
Vert(vec3::raw_xyz(4294967296, -4294967296, -4294967296)), Vert(vec3::raw_xyz(4294967296, -4294967296, -4294967296)),
@ -162,44 +187,226 @@ impl PhysicsMesh{
Vert(vec3::raw_xyz(-4294967296, 4294967296, -4294967296)), Vert(vec3::raw_xyz(-4294967296, 4294967296, -4294967296)),
Vert(vec3::raw_xyz(-4294967296, 4294967296, 4294967296)), Vert(vec3::raw_xyz(-4294967296, 4294967296, 4294967296)),
Vert(vec3::raw_xyz(-4294967296, -4294967296, 4294967296)), Vert(vec3::raw_xyz(-4294967296, -4294967296, 4294967296)),
Vert(vec3::raw_xyz(-4294967296,-4294967296,-4294967296)) Vert(vec3::raw_xyz(-4294967296, -4294967296, -4294967296)),
] ],
}; };
let mesh_topology = PhysicsMeshTopology { let mesh_topology = PhysicsMeshTopology {
faces: (0..data.faces.len() as u32).map(MeshFaceId::new).collect(), faces: (0..data.faces.len() as u32).map(MeshFaceId::new).collect(),
verts: (0..data.verts.len() as u32).map(MeshVertId::new).collect(), verts: (0..data.verts.len() as u32).map(MeshVertId::new).collect(),
face_topology: vec![ face_topology: vec![
FaceRefs{edges:vec![SubmeshDirectedEdgeId((9223372036854775808u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775809u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775810u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(3)]}, FaceRefs {
FaceRefs{edges:vec![SubmeshDirectedEdgeId((9223372036854775812u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775813u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(6),SubmeshDirectedEdgeId(1)]}, edges: vec![
FaceRefs{edges:vec![SubmeshDirectedEdgeId(7),SubmeshDirectedEdgeId(2),SubmeshDirectedEdgeId((9223372036854775814u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775816u64-(1<<63)+(1<<31)) as u32)]}, SubmeshDirectedEdgeId(
FaceRefs{edges:vec![SubmeshDirectedEdgeId(8),SubmeshDirectedEdgeId(5),SubmeshDirectedEdgeId((9223372036854775817u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(10)]}, (9223372036854775808u64 - (1 << 63) + (1 << 31)) as u32,
FaceRefs{edges:vec![SubmeshDirectedEdgeId((9223372036854775815u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775818u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(11),SubmeshDirectedEdgeId((9223372036854775811u64-(1<<63)+(1<<31)) as u32)]}, ),
FaceRefs{edges:vec![SubmeshDirectedEdgeId(4),SubmeshDirectedEdgeId(0),SubmeshDirectedEdgeId((9223372036854775819u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(9)]} SubmeshDirectedEdgeId(
(9223372036854775809u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(
(9223372036854775810u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(3),
],
},
FaceRefs {
edges: vec![
SubmeshDirectedEdgeId(
(9223372036854775812u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(
(9223372036854775813u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(6),
SubmeshDirectedEdgeId(1),
],
},
FaceRefs {
edges: vec![
SubmeshDirectedEdgeId(7),
SubmeshDirectedEdgeId(2),
SubmeshDirectedEdgeId(
(9223372036854775814u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(
(9223372036854775816u64 - (1 << 63) + (1 << 31)) as u32,
),
],
},
FaceRefs {
edges: vec![
SubmeshDirectedEdgeId(8),
SubmeshDirectedEdgeId(5),
SubmeshDirectedEdgeId(
(9223372036854775817u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(10),
],
},
FaceRefs {
edges: vec![
SubmeshDirectedEdgeId(
(9223372036854775815u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(
(9223372036854775818u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(11),
SubmeshDirectedEdgeId(
(9223372036854775811u64 - (1 << 63) + (1 << 31)) as u32,
),
],
},
FaceRefs {
edges: vec![
SubmeshDirectedEdgeId(4),
SubmeshDirectedEdgeId(0),
SubmeshDirectedEdgeId(
(9223372036854775819u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(9),
],
},
], ],
edge_topology: vec![ edge_topology: vec![
EdgeRefs{faces:[SubmeshFaceId(0),SubmeshFaceId(5)],verts:[SubmeshVertId(0),SubmeshVertId(1)]}, EdgeRefs {
EdgeRefs{faces:[SubmeshFaceId(0),SubmeshFaceId(1)],verts:[SubmeshVertId(1),SubmeshVertId(2)]}, faces: [SubmeshFaceId(0), SubmeshFaceId(5)],
EdgeRefs{faces:[SubmeshFaceId(0),SubmeshFaceId(2)],verts:[SubmeshVertId(2),SubmeshVertId(3)]}, verts: [SubmeshVertId(0), SubmeshVertId(1)],
EdgeRefs{faces:[SubmeshFaceId(4),SubmeshFaceId(0)],verts:[SubmeshVertId(0),SubmeshVertId(3)]}, },
EdgeRefs{faces:[SubmeshFaceId(1),SubmeshFaceId(5)],verts:[SubmeshVertId(1),SubmeshVertId(4)]}, EdgeRefs {
EdgeRefs{faces:[SubmeshFaceId(1),SubmeshFaceId(3)],verts:[SubmeshVertId(4),SubmeshVertId(5)]}, faces: [SubmeshFaceId(0), SubmeshFaceId(1)],
EdgeRefs{faces:[SubmeshFaceId(2),SubmeshFaceId(1)],verts:[SubmeshVertId(2),SubmeshVertId(5)]}, verts: [SubmeshVertId(1), SubmeshVertId(2)],
EdgeRefs{faces:[SubmeshFaceId(4),SubmeshFaceId(2)],verts:[SubmeshVertId(3),SubmeshVertId(6)]}, },
EdgeRefs{faces:[SubmeshFaceId(2),SubmeshFaceId(3)],verts:[SubmeshVertId(5),SubmeshVertId(6)]}, EdgeRefs {
EdgeRefs{faces:[SubmeshFaceId(3),SubmeshFaceId(5)],verts:[SubmeshVertId(4),SubmeshVertId(7)]}, faces: [SubmeshFaceId(0), SubmeshFaceId(2)],
EdgeRefs{faces:[SubmeshFaceId(4),SubmeshFaceId(3)],verts:[SubmeshVertId(6),SubmeshVertId(7)]}, verts: [SubmeshVertId(2), SubmeshVertId(3)],
EdgeRefs{faces:[SubmeshFaceId(5),SubmeshFaceId(4)],verts:[SubmeshVertId(0),SubmeshVertId(7)]} },
EdgeRefs {
faces: [SubmeshFaceId(4), SubmeshFaceId(0)],
verts: [SubmeshVertId(0), SubmeshVertId(3)],
},
EdgeRefs {
faces: [SubmeshFaceId(1), SubmeshFaceId(5)],
verts: [SubmeshVertId(1), SubmeshVertId(4)],
},
EdgeRefs {
faces: [SubmeshFaceId(1), SubmeshFaceId(3)],
verts: [SubmeshVertId(4), SubmeshVertId(5)],
},
EdgeRefs {
faces: [SubmeshFaceId(2), SubmeshFaceId(1)],
verts: [SubmeshVertId(2), SubmeshVertId(5)],
},
EdgeRefs {
faces: [SubmeshFaceId(4), SubmeshFaceId(2)],
verts: [SubmeshVertId(3), SubmeshVertId(6)],
},
EdgeRefs {
faces: [SubmeshFaceId(2), SubmeshFaceId(3)],
verts: [SubmeshVertId(5), SubmeshVertId(6)],
},
EdgeRefs {
faces: [SubmeshFaceId(3), SubmeshFaceId(5)],
verts: [SubmeshVertId(4), SubmeshVertId(7)],
},
EdgeRefs {
faces: [SubmeshFaceId(4), SubmeshFaceId(3)],
verts: [SubmeshVertId(6), SubmeshVertId(7)],
},
EdgeRefs {
faces: [SubmeshFaceId(5), SubmeshFaceId(4)],
verts: [SubmeshVertId(0), SubmeshVertId(7)],
},
], ],
vert_topology: vec![ vert_topology: vec![
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(4),SubmeshFaceId(5)],edges:vec![SubmeshDirectedEdgeId((9223372036854775811u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775819u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775808u64-(1<<63)+(1<<31)) as u32)]}, VertRefs {
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(5),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId((9223372036854775812u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId(0),SubmeshDirectedEdgeId((9223372036854775809u64-(1<<63)+(1<<31)) as u32)]}, faces: vec![SubmeshFaceId(0), SubmeshFaceId(4), SubmeshFaceId(5)],
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(2),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(1),SubmeshDirectedEdgeId((9223372036854775810u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775814u64-(1<<63)+(1<<31)) as u32)]}, edges: vec![
VertRefs{faces:vec![SubmeshFaceId(0),SubmeshFaceId(2),SubmeshFaceId(4)],edges:vec![SubmeshDirectedEdgeId(2),SubmeshDirectedEdgeId(3),SubmeshDirectedEdgeId((9223372036854775815u64-(1<<63)+(1<<31)) as u32)]}, SubmeshDirectedEdgeId(
VertRefs{faces:vec![SubmeshFaceId(3),SubmeshFaceId(5),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(4),SubmeshDirectedEdgeId((9223372036854775817u64-(1<<63)+(1<<31)) as u32),SubmeshDirectedEdgeId((9223372036854775813u64-(1<<63)+(1<<31)) as u32)]}, (9223372036854775811u64 - (1 << 63) + (1 << 31)) as u32,
VertRefs{faces:vec![SubmeshFaceId(2),SubmeshFaceId(3),SubmeshFaceId(1)],edges:vec![SubmeshDirectedEdgeId(5),SubmeshDirectedEdgeId(6),SubmeshDirectedEdgeId((9223372036854775816u64-(1<<63)+(1<<31)) as u32)]}, ),
VertRefs{faces:vec![SubmeshFaceId(2),SubmeshFaceId(3),SubmeshFaceId(4)],edges:vec![SubmeshDirectedEdgeId(7),SubmeshDirectedEdgeId(8),SubmeshDirectedEdgeId((9223372036854775818u64-(1<<63)+(1<<31)) as u32)]}, SubmeshDirectedEdgeId(
VertRefs{faces:vec![SubmeshFaceId(4),SubmeshFaceId(3),SubmeshFaceId(5)],edges:vec![SubmeshDirectedEdgeId(10),SubmeshDirectedEdgeId(11),SubmeshDirectedEdgeId(9)]} (9223372036854775819u64 - (1 << 63) + (1 << 31)) as u32,
] ),
SubmeshDirectedEdgeId(
(9223372036854775808u64 - (1 << 63) + (1 << 31)) as u32,
),
],
},
VertRefs {
faces: vec![SubmeshFaceId(0), SubmeshFaceId(5), SubmeshFaceId(1)],
edges: vec![
SubmeshDirectedEdgeId(
(9223372036854775812u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(0),
SubmeshDirectedEdgeId(
(9223372036854775809u64 - (1 << 63) + (1 << 31)) as u32,
),
],
},
VertRefs {
faces: vec![SubmeshFaceId(0), SubmeshFaceId(2), SubmeshFaceId(1)],
edges: vec![
SubmeshDirectedEdgeId(1),
SubmeshDirectedEdgeId(
(9223372036854775810u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(
(9223372036854775814u64 - (1 << 63) + (1 << 31)) as u32,
),
],
},
VertRefs {
faces: vec![SubmeshFaceId(0), SubmeshFaceId(2), SubmeshFaceId(4)],
edges: vec![
SubmeshDirectedEdgeId(2),
SubmeshDirectedEdgeId(3),
SubmeshDirectedEdgeId(
(9223372036854775815u64 - (1 << 63) + (1 << 31)) as u32,
),
],
},
VertRefs {
faces: vec![SubmeshFaceId(3), SubmeshFaceId(5), SubmeshFaceId(1)],
edges: vec![
SubmeshDirectedEdgeId(4),
SubmeshDirectedEdgeId(
(9223372036854775817u64 - (1 << 63) + (1 << 31)) as u32,
),
SubmeshDirectedEdgeId(
(9223372036854775813u64 - (1 << 63) + (1 << 31)) as u32,
),
],
},
VertRefs {
faces: vec![SubmeshFaceId(2), SubmeshFaceId(3), SubmeshFaceId(1)],
edges: vec![
SubmeshDirectedEdgeId(5),
SubmeshDirectedEdgeId(6),
SubmeshDirectedEdgeId(
(9223372036854775816u64 - (1 << 63) + (1 << 31)) as u32,
),
],
},
VertRefs {
faces: vec![SubmeshFaceId(2), SubmeshFaceId(3), SubmeshFaceId(4)],
edges: vec![
SubmeshDirectedEdgeId(7),
SubmeshDirectedEdgeId(8),
SubmeshDirectedEdgeId(
(9223372036854775818u64 - (1 << 63) + (1 << 31)) as u32,
),
],
},
VertRefs {
faces: vec![SubmeshFaceId(4), SubmeshFaceId(3), SubmeshFaceId(5)],
edges: vec![
SubmeshDirectedEdgeId(10),
SubmeshDirectedEdgeId(11),
SubmeshDirectedEdgeId(9),
],
},
],
}; };
Self { Self {
data, data,
@ -255,11 +462,14 @@ struct VertRefGuy{
struct EdgeRefVerts([SubmeshVertId; 2]); struct EdgeRefVerts([SubmeshVertId; 2]);
impl EdgeRefVerts { impl EdgeRefVerts {
const fn new(v0: SubmeshVertId, v1: SubmeshVertId) -> (Self, bool) { const fn new(v0: SubmeshVertId, v1: SubmeshVertId) -> (Self, bool) {
(if v0.0<v1.0{ (
if v0.0 < v1.0 {
Self([v0, v1]) Self([v0, v1])
} else { } else {
Self([v1, v0]) Self([v1, v0])
},v0.0<v1.0) },
v0.0 < v1.0,
)
} }
} }
struct EdgeRefFaces([SubmeshFaceId; 2]); struct EdgeRefFaces([SubmeshFaceId; 2]);
@ -283,11 +493,15 @@ impl EdgePool{
edge_id edge_id
} else { } else {
let edge_id = SubmeshEdgeId::new(self.edge_guys.len() as u32); let edge_id = SubmeshEdgeId::new(self.edge_guys.len() as u32);
self.edge_guys.push((edge_ref_verts.clone(),EdgeRefFaces::new())); self.edge_guys
.push((edge_ref_verts.clone(), EdgeRefFaces::new()));
self.edge_id_from_guy.insert(edge_ref_verts, edge_id); self.edge_id_from_guy.insert(edge_ref_verts, edge_id);
edge_id edge_id
}; };
(&mut unsafe{self.edge_guys.get_unchecked_mut(edge_id.get() as usize)}.1,edge_id) (
&mut unsafe { self.edge_guys.get_unchecked_mut(edge_id.get() as usize) }.1,
edge_id,
)
} }
} }
@ -316,14 +530,19 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
//the same face is not allowed to be in multiple polygon groups //the same face is not allowed to be in multiple polygon groups
let mut faces = Vec::new(); let mut faces = Vec::new();
let mut face_id_from_face = HashMap::new(); let mut face_id_from_face = HashMap::new();
let mut mesh_topologies:Vec<PhysicsMeshTopology>=mesh.physics_groups.iter().map(|physics_group|{ let mut mesh_topologies: Vec<PhysicsMeshTopology> = mesh
.physics_groups
.iter()
.map(|physics_group| {
//construct submesh //construct submesh
let mut submesh_faces = Vec::new(); //these contain a map from submeshId->meshId let mut submesh_faces = Vec::new(); //these contain a map from submeshId->meshId
let mut submesh_verts = Vec::new(); let mut submesh_verts = Vec::new();
let mut submesh_vert_id_from_mesh_vert_id=HashMap::<MeshVertId,SubmeshVertId>::new(); let mut submesh_vert_id_from_mesh_vert_id =
HashMap::<MeshVertId, SubmeshVertId>::new();
//lazy closure //lazy closure
let mut get_submesh_vert_id = |vert_id: MeshVertId| { let mut get_submesh_vert_id = |vert_id: MeshVertId| {
if let Some(&submesh_vert_id)=submesh_vert_id_from_mesh_vert_id.get(&vert_id){ if let Some(&submesh_vert_id) = submesh_vert_id_from_mesh_vert_id.get(&vert_id)
{
submesh_vert_id submesh_vert_id
} else { } else {
let submesh_vert_id = SubmeshVertId::new(submesh_verts.len() as u32); let submesh_vert_id = SubmeshVertId::new(submesh_verts.len() as u32);
@ -342,9 +561,19 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
//one face per poly //one face per poly
let mut normal = Vector3::new([Fixed::ZERO, Fixed::ZERO, Fixed::ZERO]); let mut normal = Vector3::new([Fixed::ZERO, Fixed::ZERO, Fixed::ZERO]);
let len = poly_vertices.len(); let len = poly_vertices.len();
let face_edges=poly_vertices.into_iter().enumerate().map(|(i,vert_id)|{ let face_edges = poly_vertices
let vert0_id=MeshVertId::new(mesh.unique_vertices[vert_id.get() as usize].pos.get() as u32); .into_iter()
let vert1_id=MeshVertId::new(mesh.unique_vertices[poly_vertices[(i+1)%len].get() as usize].pos.get() as u32); .enumerate()
.map(|(i, vert_id)| {
let vert0_id = MeshVertId::new(
mesh.unique_vertices[vert_id.get() as usize].pos.get() as u32,
);
let vert1_id = MeshVertId::new(
mesh.unique_vertices
[poly_vertices[(i + 1) % len].get() as usize]
.pos
.get() as u32,
);
//index submesh verts //index submesh verts
let submesh_vert0_id = get_submesh_vert_id(vert0_id); let submesh_vert0_id = get_submesh_vert_id(vert0_id);
let submesh_vert1_id = get_submesh_vert_id(vert1_id); let submesh_vert1_id = get_submesh_vert_id(vert1_id);
@ -357,25 +586,38 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
(v0.x - v1.x) * (v0.y + v1.y), (v0.x - v1.x) * (v0.y + v1.y),
]); ]);
//get/create edge and push face into it //get/create edge and push face into it
let (edge_ref_verts,is_sorted)=EdgeRefVerts::new(submesh_vert0_id,submesh_vert1_id); let (edge_ref_verts, is_sorted) =
EdgeRefVerts::new(submesh_vert0_id, submesh_vert1_id);
let (edge_ref_faces, edge_id) = edge_pool.push(edge_ref_verts); let (edge_ref_faces, edge_id) = edge_pool.push(edge_ref_verts);
//polygon vertices as assumed to be listed clockwise //polygon vertices as assumed to be listed clockwise
//populate the edge face on the left or right depending on how the edge vertices got sorted //populate the edge face on the left or right depending on how the edge vertices got sorted
edge_ref_faces.push(!is_sorted as usize, submesh_face_id); edge_ref_faces.push(!is_sorted as usize, submesh_face_id);
//index edges & face into vertices //index edges & face into vertices
{ {
let vert_ref_guy=unsafe{vert_ref_guys.get_unchecked_mut(submesh_vert0_id.get() as usize)}; let vert_ref_guy = unsafe {
vert_ref_guys
.get_unchecked_mut(submesh_vert0_id.get() as usize)
};
vert_ref_guy.edges.insert(edge_id.as_directed(is_sorted)); vert_ref_guy.edges.insert(edge_id.as_directed(is_sorted));
vert_ref_guy.faces.insert(submesh_face_id); vert_ref_guy.faces.insert(submesh_face_id);
unsafe{vert_ref_guys.get_unchecked_mut(submesh_vert1_id.get() as usize)}.edges.insert(edge_id.as_directed(!is_sorted)); unsafe {
vert_ref_guys
.get_unchecked_mut(submesh_vert1_id.get() as usize)
}
.edges
.insert(edge_id.as_directed(!is_sorted));
} }
//return directed_edge_id //return directed_edge_id
edge_id.as_directed(is_sorted) edge_id.as_directed(is_sorted)
}).collect(); })
.collect();
let mut dot = Fixed::ZERO; let mut dot = Fixed::ZERO;
// find the average dot // find the average dot
for &v in poly_vertices { for &v in poly_vertices {
dot+=normal.dot(mesh.unique_pos[mesh.unique_vertices[v.get() as usize].pos.get() as usize]); dot += normal.dot(
mesh.unique_pos
[mesh.unique_vertices[v.get() as usize].pos.get() as usize],
);
} }
//assume face hash is stable, and there are no flush faces... //assume face hash is stable, and there are no flush faces...
let face = Face { let face = Face {
@ -398,26 +640,35 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{
PhysicsMeshTopology { PhysicsMeshTopology {
faces: submesh_faces, faces: submesh_faces,
verts: submesh_verts, verts: submesh_verts,
face_topology:face_ref_guys.into_iter().map(|face_ref_guy|{ face_topology: face_ref_guys
FaceRefs{edges:face_ref_guy.0} .into_iter()
}).collect(), .map(|face_ref_guy| FaceRefs {
edge_topology:edge_pool.edge_guys.into_iter().map(|(edge_ref_verts,edge_ref_faces)| edges: face_ref_guy.0,
EdgeRefs{faces:edge_ref_faces.0,verts:edge_ref_verts.0} })
).collect(), .collect(),
vert_topology:vert_ref_guys.into_iter().map(|vert_ref_guy| edge_topology: edge_pool
VertRefs{ .edge_guys
.into_iter()
.map(|(edge_ref_verts, edge_ref_faces)| EdgeRefs {
faces: edge_ref_faces.0,
verts: edge_ref_verts.0,
})
.collect(),
vert_topology: vert_ref_guys
.into_iter()
.map(|vert_ref_guy| VertRefs {
edges: vert_ref_guy.edges.into_iter().collect(), edges: vert_ref_guy.edges.into_iter().collect(),
faces: vert_ref_guy.faces.into_iter().collect(), faces: vert_ref_guy.faces.into_iter().collect(),
})
.collect(),
} }
).collect(), })
} .collect();
}).collect();
Ok(Self { Ok(Self {
data:PhysicsMeshData{ data: PhysicsMeshData { faces, verts },
faces, complete_mesh: mesh_topologies
verts, .pop()
}, .ok_or(PhysicsMeshError::NoPhysicsGroups)?,
complete_mesh:mesh_topologies.pop().ok_or(PhysicsMeshError::NoPhysicsGroups)?,
submeshes: mesh_topologies, submeshes: mesh_topologies,
}) })
} }
@ -435,7 +686,10 @@ impl MeshQuery for PhysicsMeshView<'_>{
type Offset = Planar64; type Offset = Planar64;
fn face_nd(&self, face_id: SubmeshFaceId) -> (Planar64Vec3, Planar64) { fn face_nd(&self, face_id: SubmeshFaceId) -> (Planar64Vec3, Planar64) {
let face_idx = self.topology.faces[face_id.get() as usize].get() as usize; let face_idx = self.topology.faces[face_id.get() as usize].get() as usize;
(self.data.faces[face_idx].normal,self.data.faces[face_idx].dot) (
self.data.faces[face_idx].normal,
self.data.faces[face_idx].dot,
)
} }
//ideally I never calculate the vertex position, but I have to for the graphical meshes... //ideally I never calculate the vertex position, but I have to for the graphical meshes...
fn vert(&self, vert_id: SubmeshVertId) -> Planar64Vec3 { fn vert(&self, vert_id: SubmeshVertId) -> Planar64Vec3 {
@ -483,24 +737,33 @@ impl TransformedMesh<'_>{
view: PhysicsMeshView<'a>, view: PhysicsMeshView<'a>,
transform: &'a PhysicsMeshTransform, transform: &'a PhysicsMeshTransform,
) -> TransformedMesh<'a> { ) -> TransformedMesh<'a> {
TransformedMesh{ TransformedMesh { view, transform }
view,
transform,
}
} }
pub fn verts<'a>(&'a self) -> impl Iterator<Item = vec3::Vector3<Fixed<2, 64>>> + 'a { pub fn verts<'a>(&'a self) -> impl Iterator<Item = vec3::Vector3<Fixed<2, 64>>> + 'a {
self.view.data.verts.iter().map(|&Vert(pos)|self.transform.vertex.transform_point3(pos)) self.view
.data
.verts
.iter()
.map(|&Vert(pos)| self.transform.vertex.transform_point3(pos))
} }
fn farthest_vert(&self, dir: Planar64Vec3) -> SubmeshVertId { fn farthest_vert(&self, dir: Planar64Vec3) -> SubmeshVertId {
//this happens to be well-defined. there are no virtual virtices //this happens to be well-defined. there are no virtual virtices
SubmeshVertId::new( SubmeshVertId::new(
self.view.topology.verts.iter() self.view
.topology
.verts
.iter()
.enumerate() .enumerate()
.max_by_key(|(_,&vert_id)| .max_by_key(|(_, &vert_id)| {
dir.dot(self.transform.vertex.transform_point3(self.view.data.verts[vert_id.get() as usize].0)) dir.dot(
self.transform
.vertex
.transform_point3(self.view.data.verts[vert_id.get() as usize].0),
) )
})
//assume there is more than zero vertices. //assume there is more than zero vertices.
.unwrap().0 as u32 .unwrap()
.0 as u32,
) )
} }
} }
@ -513,11 +776,15 @@ impl MeshQuery for TransformedMesh<'_>{
fn face_nd(&self, face_id: SubmeshFaceId) -> (Self::Normal, Self::Offset) { fn face_nd(&self, face_id: SubmeshFaceId) -> (Self::Normal, Self::Offset) {
let (n, d) = self.view.face_nd(face_id); let (n, d) = self.view.face_nd(face_id);
let transformed_n = self.transform.normal * n; let transformed_n = self.transform.normal * n;
let transformed_d=d*self.transform.det+transformed_n.dot(self.transform.vertex.translation); let transformed_d =
d * self.transform.det + transformed_n.dot(self.transform.vertex.translation);
(transformed_n, transformed_d) (transformed_n, transformed_d)
} }
fn vert(&self, vert_id: SubmeshVertId) -> Planar64Vec3 { fn vert(&self, vert_id: SubmeshVertId) -> Planar64Vec3 {
self.transform.vertex.transform_point3(self.view.vert(vert_id)).fix_1() self.transform
.vertex
.transform_point3(self.view.vert(vert_id))
.fix_1()
} }
#[inline] #[inline]
fn face_edges(&self, face_id: SubmeshFaceId) -> Cow<Vec<SubmeshDirectedEdgeId>> { fn face_edges(&self, face_id: SubmeshFaceId) -> Cow<Vec<SubmeshDirectedEdgeId>> {
@ -559,8 +826,12 @@ impl UndirectedEdge for MinkowskiEdge{
type DirectedEdge = MinkowskiDirectedEdge; type DirectedEdge = MinkowskiDirectedEdge;
fn as_directed(&self, parity: bool) -> Self::DirectedEdge { fn as_directed(&self, parity: bool) -> Self::DirectedEdge {
match self { match self {
MinkowskiEdge::VertEdge(v0,e1)=>MinkowskiDirectedEdge::VertEdge(*v0,e1.as_directed(parity)), MinkowskiEdge::VertEdge(v0, e1) => {
MinkowskiEdge::EdgeVert(e0,v1)=>MinkowskiDirectedEdge::EdgeVert(e0.as_directed(parity),*v1), MinkowskiDirectedEdge::VertEdge(*v0, e1.as_directed(parity))
}
MinkowskiEdge::EdgeVert(e0, v1) => {
MinkowskiDirectedEdge::EdgeVert(e0.as_directed(parity), *v1)
}
} }
} }
} }
@ -574,14 +845,19 @@ impl DirectedEdge for MinkowskiDirectedEdge{
type UndirectedEdge = MinkowskiEdge; type UndirectedEdge = MinkowskiEdge;
fn as_undirected(&self) -> Self::UndirectedEdge { fn as_undirected(&self) -> Self::UndirectedEdge {
match self { match self {
MinkowskiDirectedEdge::VertEdge(v0,e1)=>MinkowskiEdge::VertEdge(*v0,e1.as_undirected()), MinkowskiDirectedEdge::VertEdge(v0, e1) => {
MinkowskiDirectedEdge::EdgeVert(e0,v1)=>MinkowskiEdge::EdgeVert(e0.as_undirected(),*v1), MinkowskiEdge::VertEdge(*v0, e1.as_undirected())
}
MinkowskiDirectedEdge::EdgeVert(e0, v1) => {
MinkowskiEdge::EdgeVert(e0.as_undirected(), *v1)
}
} }
} }
fn parity(&self) -> bool { fn parity(&self) -> bool {
match self { match self {
MinkowskiDirectedEdge::VertEdge(_,e) MinkowskiDirectedEdge::VertEdge(_, e) | MinkowskiDirectedEdge::EdgeVert(e, _) => {
|MinkowskiDirectedEdge::EdgeVert(e,_)=>e.parity(), e.parity()
}
} }
} }
} }
@ -614,16 +890,25 @@ enum EV{
pub type GigaTime = Ratio<Fixed<4, 128>, Fixed<4, 128>>; pub type GigaTime = Ratio<Fixed<4, 128>, Fixed<4, 128>>;
impl MinkowskiMesh<'_> { impl MinkowskiMesh<'_> {
pub fn minkowski_sum<'a>(mesh0:TransformedMesh<'a>,mesh1:TransformedMesh<'a>)->MinkowskiMesh<'a>{ pub fn minkowski_sum<'a>(
MinkowskiMesh{ mesh0: TransformedMesh<'a>,
mesh0, mesh1: TransformedMesh<'a>,
mesh1, ) -> MinkowskiMesh<'a> {
} MinkowskiMesh { mesh0, mesh1 }
} }
fn farthest_vert(&self, dir: Planar64Vec3) -> MinkowskiVert { fn farthest_vert(&self, dir: Planar64Vec3) -> MinkowskiVert {
MinkowskiVert::VertVert(self.mesh0.farthest_vert(dir),self.mesh1.farthest_vert(-dir)) MinkowskiVert::VertVert(
self.mesh0.farthest_vert(dir),
self.mesh1.farthest_vert(-dir),
)
} }
fn next_transition_vert(&self,vert_id:MinkowskiVert,best_distance_squared:&mut Fixed<2,64>,infinity_dir:Planar64Vec3,point:Planar64Vec3)->Transition{ fn next_transition_vert(
&self,
vert_id: MinkowskiVert,
best_distance_squared: &mut Fixed<2, 64>,
infinity_dir: Planar64Vec3,
point: Planar64Vec3,
) -> Transition {
let mut best_transition = Transition::Done; let mut best_transition = Transition::Done;
for &directed_edge_id in self.vert_edges(vert_id).iter() { for &directed_edge_id in self.vert_edges(vert_id).iter() {
let edge_n = self.directed_edge_n(directed_edge_id); let edge_n = self.directed_edge_n(directed_edge_id);
@ -643,7 +928,13 @@ impl MinkowskiMesh<'_>{
} }
best_transition best_transition
} }
fn final_ev(&self,vert_id:MinkowskiVert,best_distance_squared:&mut Fixed<2,64>,infinity_dir:Planar64Vec3,point:Planar64Vec3)->EV{ fn final_ev(
&self,
vert_id: MinkowskiVert,
best_distance_squared: &mut Fixed<2, 64>,
infinity_dir: Planar64Vec3,
point: Planar64Vec3,
) -> EV {
let mut best_transition = EV::Vert(vert_id); let mut best_transition = EV::Vert(vert_id);
let diff = point - self.vert(vert_id); let diff = point - self.vert(vert_id);
for &directed_edge_id in self.vert_edges(vert_id).iter() { for &directed_edge_id in self.vert_edges(vert_id).iter() {
@ -668,20 +959,32 @@ impl MinkowskiMesh<'_>{
} }
best_transition best_transition
} }
fn crawl_boundaries(&self,mut vert_id:MinkowskiVert,infinity_dir:Planar64Vec3,point:Planar64Vec3)->EV{ fn crawl_boundaries(
&self,
mut vert_id: MinkowskiVert,
infinity_dir: Planar64Vec3,
point: Planar64Vec3,
) -> EV {
let mut best_distance_squared = { let mut best_distance_squared = {
let diff = point - self.vert(vert_id); let diff = point - self.vert(vert_id);
diff.dot(diff) diff.dot(diff)
}; };
loop { loop {
match self.next_transition_vert(vert_id,&mut best_distance_squared,infinity_dir,point){ match self.next_transition_vert(
Transition::Done=>return self.final_ev(vert_id,&mut best_distance_squared,infinity_dir,point), vert_id,
&mut best_distance_squared,
infinity_dir,
point,
) {
Transition::Done => {
return self.final_ev(vert_id, &mut best_distance_squared, infinity_dir, point)
}
Transition::Vert(new_vert_id) => vert_id = new_vert_id, Transition::Vert(new_vert_id) => vert_id = new_vert_id,
} }
} }
} }
/// This function drops a vertex down to an edge or a face if the path from infinity did not cross any vertex-edge boundaries but the point is supposed to have already crossed a boundary down from a vertex /// This function drops a vertex down to an edge or a face if the path from infinity did not cross any vertex-edge boundaries but the point is supposed to have already crossed a boundary down from a vertex
fn infinity_fev(&self,infinity_dir:Planar64Vec3,point:Planar64Vec3)->FEV::<MinkowskiMesh>{ fn infinity_fev(&self, infinity_dir: Planar64Vec3, point: Planar64Vec3) -> FEV<MinkowskiMesh> {
//start on any vertex //start on any vertex
//cross uncrossable vertex-edge boundaries until you find the closest vertex or edge //cross uncrossable vertex-edge boundaries until you find the closest vertex or edge
//cross edge-face boundary if it's uncrossable //cross edge-face boundary if it's uncrossable
@ -709,7 +1012,7 @@ impl MinkowskiMesh<'_>{
} }
} }
FEV::Edge(edge_id) FEV::Edge(edge_id)
}, }
} }
} }
fn closest_fev_not_inside(&self, mut infinity_body: Body) -> Option<FEV<MinkowskiMesh>> { fn closest_fev_not_inside(&self, mut infinity_body: Body) -> Option<FEV<MinkowskiMesh>> {
@ -726,8 +1029,13 @@ impl MinkowskiMesh<'_>{
} }
}) })
} }
pub fn predict_collision_in(&self,relative_body:&Body,time_limit:Time)->Option<(MinkowskiFace,GigaTime)>{ pub fn predict_collision_in(
self.closest_fev_not_inside(relative_body.clone()).map_or(None,|fev|{ &self,
relative_body: &Body,
time_limit: Time,
) -> Option<(MinkowskiFace, GigaTime)> {
self.closest_fev_not_inside(relative_body.clone())
.map_or(None, |fev| {
//continue forwards along the body parabola //continue forwards along the body parabola
match fev.crawl(self, relative_body, relative_body.time, time_limit) { match fev.crawl(self, relative_body, relative_body.time, time_limit) {
crate::face_crawler::CrawlResult::Miss(_) => None, crate::face_crawler::CrawlResult::Miss(_) => None,
@ -735,7 +1043,11 @@ impl MinkowskiMesh<'_>{
} }
}) })
} }
pub fn predict_collision_out(&self,relative_body:&Body,time_limit:Time)->Option<(MinkowskiFace,GigaTime)>{ pub fn predict_collision_out(
&self,
relative_body: &Body,
time_limit: Time,
) -> Option<(MinkowskiFace, GigaTime)> {
//create an extrapolated body at time_limit //create an extrapolated body at time_limit
let infinity_body = Body::new( let infinity_body = Body::new(
relative_body.extrapolated_position(time_limit), relative_body.extrapolated_position(time_limit),
@ -743,15 +1055,26 @@ impl MinkowskiMesh<'_>{
relative_body.acceleration, relative_body.acceleration,
-time_limit, -time_limit,
); );
self.closest_fev_not_inside(infinity_body).map_or(None,|fev|{ self.closest_fev_not_inside(infinity_body)
.map_or(None, |fev| {
//continue backwards along the body parabola //continue backwards along the body parabola
match fev.crawl(self,&-relative_body.clone(),-time_limit,-relative_body.time){ match fev.crawl(
self,
&-relative_body.clone(),
-time_limit,
-relative_body.time,
) {
crate::face_crawler::CrawlResult::Miss(_) => None, crate::face_crawler::CrawlResult::Miss(_) => None,
crate::face_crawler::CrawlResult::Hit(face, time) => Some((face, -time)), //no need to test -time<time_limit because of the first step crate::face_crawler::CrawlResult::Hit(face, time) => Some((face, -time)), //no need to test -time<time_limit because of the first step
} }
}) })
} }
pub fn predict_collision_face_out(&self,relative_body:&Body,time_limit:Time,contact_face_id:MinkowskiFace)->Option<(MinkowskiEdge,GigaTime)>{ pub fn predict_collision_face_out(
&self,
relative_body: &Body,
time_limit: Time,
contact_face_id: MinkowskiFace,
) -> Option<(MinkowskiEdge, GigaTime)> {
//no algorithm needed, there is only one state and two cases (Edge,None) //no algorithm needed, there is only one state and two cases (Edge,None)
//determine when it passes an edge ("sliding off" case) //determine when it passes an edge ("sliding off" case)
let mut best_time = { let mut best_time = {
@ -768,8 +1091,16 @@ impl MinkowskiMesh<'_>{
let d = n.dot(self.vert(verts[0]) + self.vert(verts[1])); let d = n.dot(self.vert(verts[0]) + self.vert(verts[1]));
//WARNING! d outside of *2 //WARNING! d outside of *2
//WARNING: truncated precision //WARNING: truncated precision
for dt in Fixed::<4,128>::zeroes2(((n.dot(relative_body.position))*2-d).fix_4(),n.dot(relative_body.velocity).fix_4()*2,n.dot(relative_body.acceleration).fix_4()){ for dt in Fixed::<4, 128>::zeroes2(
if Ratio::new(Planar64::ZERO,Planar64::EPSILON).le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(relative_body.extrapolated_velocity_ratio_dt(dt)).is_negative(){ ((n.dot(relative_body.position)) * 2 - d).fix_4(),
n.dot(relative_body.velocity).fix_4() * 2,
n.dot(relative_body.acceleration).fix_4(),
) {
if Ratio::new(Planar64::ZERO, Planar64::EPSILON).le_ratio(dt)
&& dt.lt_ratio(best_time)
&& n.dot(relative_body.extrapolated_velocity_ratio_dt(dt))
.is_negative()
{
best_time = dt; best_time = dt;
best_edge = Some(directed_edge_id); best_edge = Some(directed_edge_id);
break; break;
@ -790,10 +1121,7 @@ impl MinkowskiMesh<'_>{
//movement must escape the mesh forwards and backwards in time, //movement must escape the mesh forwards and backwards in time,
//otherwise the point is not inside the mesh //otherwise the point is not inside the mesh
self.infinity_in(infinity_body) self.infinity_in(infinity_body)
.is_some_and(|_| .is_some_and(|_| self.infinity_in(-infinity_body).is_some())
self.infinity_in(-infinity_body)
.is_some()
)
} }
} }
impl MeshQuery for MinkowskiMesh<'_> { impl MeshQuery for MinkowskiMesh<'_> {
@ -808,7 +1136,7 @@ impl MeshQuery for MinkowskiMesh<'_>{
MinkowskiFace::VertFace(v0, f1) => { MinkowskiFace::VertFace(v0, f1) => {
let (n, d) = self.mesh1.face_nd(f1); let (n, d) = self.mesh1.face_nd(f1);
(-n, d - n.dot(self.mesh0.vert(v0))) (-n, d - n.dot(self.mesh0.vert(v0)))
}, }
MinkowskiFace::EdgeEdge(e0, e1, parity) => { MinkowskiFace::EdgeEdge(e0, e1, parity) => {
let edge0_n = self.mesh0.edge_n(e0); let edge0_n = self.mesh0.edge_n(e0);
let edge1_n = self.mesh1.edge_n(e1); let edge1_n = self.mesh1.edge_n(e1);
@ -817,28 +1145,31 @@ impl MeshQuery for MinkowskiMesh<'_>{
let n = edge0_n.cross(edge1_n); let n = edge0_n.cross(edge1_n);
let e0d = n.dot(self.mesh0.vert(e0v0) + self.mesh0.vert(e0v1)); let e0d = n.dot(self.mesh0.vert(e0v0) + self.mesh0.vert(e0v1));
let e1d = n.dot(self.mesh1.vert(e1v0) + self.mesh1.vert(e1v1)); let e1d = n.dot(self.mesh1.vert(e1v0) + self.mesh1.vert(e1v1));
((n*(parity as i64*4-2)).fix_3(),((e0d-e1d)*(parity as i64*2-1)).fix_4()) (
}, (n * (parity as i64 * 4 - 2)).fix_3(),
((e0d - e1d) * (parity as i64 * 2 - 1)).fix_4(),
)
}
MinkowskiFace::FaceVert(f0, v1) => { MinkowskiFace::FaceVert(f0, v1) => {
let (n, d) = self.mesh0.face_nd(f0); let (n, d) = self.mesh0.face_nd(f0);
(n, d - n.dot(self.mesh1.vert(v1))) (n, d - n.dot(self.mesh1.vert(v1)))
}, }
} }
} }
fn vert(&self, vert_id: MinkowskiVert) -> Planar64Vec3 { fn vert(&self, vert_id: MinkowskiVert) -> Planar64Vec3 {
match vert_id { match vert_id {
MinkowskiVert::VertVert(v0,v1)=>{ MinkowskiVert::VertVert(v0, v1) => self.mesh0.vert(v0) - self.mesh1.vert(v1),
self.mesh0.vert(v0)-self.mesh1.vert(v1)
},
} }
} }
fn face_edges(&self, face_id: MinkowskiFace) -> Cow<Vec<MinkowskiDirectedEdge>> { fn face_edges(&self, face_id: MinkowskiFace) -> Cow<Vec<MinkowskiDirectedEdge>> {
match face_id { match face_id {
MinkowskiFace::VertFace(v0,f1)=>{ MinkowskiFace::VertFace(v0, f1) => Cow::Owned(
Cow::Owned(self.mesh1.face_edges(f1).iter().map(|&edge_id1|{ self.mesh1
MinkowskiDirectedEdge::VertEdge(v0,edge_id1.reverse()) .face_edges(f1)
}).collect()) .iter()
}, .map(|&edge_id1| MinkowskiDirectedEdge::VertEdge(v0, edge_id1.reverse()))
.collect(),
),
MinkowskiFace::EdgeEdge(e0, e1, parity) => { MinkowskiFace::EdgeEdge(e0, e1, parity) => {
let e0v = self.mesh0.edge_verts(e0); let e0v = self.mesh0.edge_verts(e0);
let e1v = self.mesh1.edge_verts(e1); let e1v = self.mesh1.edge_verts(e1);
@ -850,12 +1181,14 @@ impl MeshQuery for MinkowskiMesh<'_>{
MinkowskiDirectedEdge::VertEdge(e0v[1], e1.as_directed(!parity)), MinkowskiDirectedEdge::VertEdge(e0v[1], e1.as_directed(!parity)),
MinkowskiDirectedEdge::EdgeVert(e0.as_directed(parity), e1v[1]), MinkowskiDirectedEdge::EdgeVert(e0.as_directed(parity), e1v[1]),
]) ])
}, }
MinkowskiFace::FaceVert(f0,v1)=>{ MinkowskiFace::FaceVert(f0, v1) => Cow::Owned(
Cow::Owned(self.mesh0.face_edges(f0).iter().map(|&edge_id0|{ self.mesh0
MinkowskiDirectedEdge::EdgeVert(edge_id0,v1) .face_edges(f0)
}).collect()) .iter()
}, .map(|&edge_id0| MinkowskiDirectedEdge::EdgeVert(edge_id0, v1))
.collect(),
),
} }
} }
fn edge_faces(&self, edge_id: MinkowskiEdge) -> Cow<[MinkowskiFace; 2]> { fn edge_faces(&self, edge_id: MinkowskiEdge) -> Cow<[MinkowskiFace; 2]> {
@ -864,9 +1197,11 @@ impl MeshQuery for MinkowskiMesh<'_>{
//faces are listed backwards from the minkowski mesh //faces are listed backwards from the minkowski mesh
let v0e = self.mesh0.vert_edges(v0); let v0e = self.mesh0.vert_edges(v0);
let &[e1f0, e1f1] = self.mesh1.edge_faces(e1).borrow(); let &[e1f0, e1f1] = self.mesh1.edge_faces(e1).borrow();
Cow::Owned([(e1f1,false),(e1f0,true)].map(|(edge_face_id1,face_parity)|{ Cow::Owned(
[(e1f1, false), (e1f0, true)].map(|(edge_face_id1, face_parity)| {
let mut best_edge = None; let mut best_edge = None;
let mut best_d:Ratio<Fixed<8,256>,Fixed<8,256>>=Ratio::new(Fixed::ZERO,Fixed::ONE); let mut best_d: Ratio<Fixed<8, 256>, Fixed<8, 256>> =
Ratio::new(Fixed::ZERO, Fixed::ONE);
let edge_face1_n = self.mesh1.face_nd(edge_face_id1).0; let edge_face1_n = self.mesh1.face_nd(edge_face_id1).0;
let edge_face1_nn = edge_face1_n.dot(edge_face1_n); let edge_face1_nn = edge_face1_n.dot(edge_face1_n);
for &directed_edge_id0 in v0e.iter() { for &directed_edge_id0 in v0e.iter() {
@ -886,17 +1221,26 @@ impl MeshQuery for MinkowskiMesh<'_>{
} }
best_edge.map_or( best_edge.map_or(
MinkowskiFace::VertFace(v0, edge_face_id1), MinkowskiFace::VertFace(v0, edge_face_id1),
|directed_edge_id0|MinkowskiFace::EdgeEdge(directed_edge_id0.as_undirected(),e1,directed_edge_id0.parity()^face_parity) |directed_edge_id0| {
MinkowskiFace::EdgeEdge(
directed_edge_id0.as_undirected(),
e1,
directed_edge_id0.parity() ^ face_parity,
) )
}))
}, },
)
}),
)
}
MinkowskiEdge::EdgeVert(e0, v1) => { MinkowskiEdge::EdgeVert(e0, v1) => {
//tracking index with an external variable because .enumerate() is not available //tracking index with an external variable because .enumerate() is not available
let v1e = self.mesh1.vert_edges(v1); let v1e = self.mesh1.vert_edges(v1);
let &[e0f0, e0f1] = self.mesh0.edge_faces(e0).borrow(); let &[e0f0, e0f1] = self.mesh0.edge_faces(e0).borrow();
Cow::Owned([(e0f0,true),(e0f1,false)].map(|(edge_face_id0,face_parity)|{ Cow::Owned(
[(e0f0, true), (e0f1, false)].map(|(edge_face_id0, face_parity)| {
let mut best_edge = None; let mut best_edge = None;
let mut best_d:Ratio<Fixed<8,256>,Fixed<8,256>>=Ratio::new(Fixed::ZERO,Fixed::ONE); let mut best_d: Ratio<Fixed<8, 256>, Fixed<8, 256>> =
Ratio::new(Fixed::ZERO, Fixed::ONE);
let edge_face0_n = self.mesh0.face_nd(edge_face_id0).0; let edge_face0_n = self.mesh0.face_nd(edge_face_id0).0;
let edge_face0_nn = edge_face0_n.dot(edge_face0_n); let edge_face0_nn = edge_face0_n.dot(edge_face0_n);
for &directed_edge_id1 in v1e.iter() { for &directed_edge_id1 in v1e.iter() {
@ -913,24 +1257,31 @@ impl MeshQuery for MinkowskiMesh<'_>{
} }
best_edge.map_or( best_edge.map_or(
MinkowskiFace::FaceVert(edge_face_id0, v1), MinkowskiFace::FaceVert(edge_face_id0, v1),
|directed_edge_id1|MinkowskiFace::EdgeEdge(e0,directed_edge_id1.as_undirected(),directed_edge_id1.parity()^face_parity) |directed_edge_id1| {
MinkowskiFace::EdgeEdge(
e0,
directed_edge_id1.as_undirected(),
directed_edge_id1.parity() ^ face_parity,
) )
}))
}, },
)
}),
)
}
} }
} }
fn edge_verts(&self, edge_id: MinkowskiEdge) -> Cow<[MinkowskiVert; 2]> { fn edge_verts(&self, edge_id: MinkowskiEdge) -> Cow<[MinkowskiVert; 2]> {
match edge_id { match edge_id {
MinkowskiEdge::VertEdge(v0,e1)=>{ MinkowskiEdge::VertEdge(v0, e1) => Cow::Owned(
Cow::Owned(self.mesh1.edge_verts(e1).map(|vert_id1|{ self.mesh1
MinkowskiVert::VertVert(v0,vert_id1) .edge_verts(e1)
})) .map(|vert_id1| MinkowskiVert::VertVert(v0, vert_id1)),
}, ),
MinkowskiEdge::EdgeVert(e0,v1)=>{ MinkowskiEdge::EdgeVert(e0, v1) => Cow::Owned(
Cow::Owned(self.mesh0.edge_verts(e0).map(|vert_id0|{ self.mesh0
MinkowskiVert::VertVert(vert_id0,v1) .edge_verts(e0)
})) .map(|vert_id0| MinkowskiVert::VertVert(vert_id0, v1)),
}, ),
} }
} }
fn vert_edges(&self, vert_id: MinkowskiVert) -> Cow<Vec<MinkowskiDirectedEdge>> { fn vert_edges(&self, vert_id: MinkowskiVert) -> Cow<Vec<MinkowskiDirectedEdge>> {
@ -940,8 +1291,14 @@ impl MeshQuery for MinkowskiMesh<'_>{
//detect shared volume when the other mesh is mirrored along a test edge dir //detect shared volume when the other mesh is mirrored along a test edge dir
let v0f = self.mesh0.vert_faces(v0); let v0f = self.mesh0.vert_faces(v0);
let v1f = self.mesh1.vert_faces(v1); let v1f = self.mesh1.vert_faces(v1);
let v0f_n:Vec<_>=v0f.iter().map(|&face_id|self.mesh0.face_nd(face_id).0).collect(); let v0f_n: Vec<_> = v0f
let v1f_n:Vec<_>=v1f.iter().map(|&face_id|self.mesh1.face_nd(face_id).0).collect(); .iter()
.map(|&face_id| self.mesh0.face_nd(face_id).0)
.collect();
let v1f_n: Vec<_> = v1f
.iter()
.map(|&face_id| self.mesh1.face_nd(face_id).0)
.collect();
let the_len = v0f.len() + v1f.len(); let the_len = v0f.len() + v1f.len();
for &directed_edge_id in self.mesh0.vert_edges(v0).iter() { for &directed_edge_id in self.mesh0.vert_edges(v0).iter() {
let n = self.mesh0.directed_edge_n(directed_edge_id); let n = self.mesh0.directed_edge_n(directed_edge_id);
@ -972,7 +1329,7 @@ impl MeshQuery for MinkowskiMesh<'_>{
} }
} }
Cow::Owned(edges) Cow::Owned(edges)
}, }
} }
} }
fn vert_faces(&self, _vert_id: MinkowskiVert) -> Cow<Vec<MinkowskiFace>> { fn vert_faces(&self, _vert_id: MinkowskiVert) -> Cow<Vec<MinkowskiFace>> {
@ -1006,8 +1363,18 @@ fn is_empty_volume(normals:Vec<Vector3<Fixed<3,96>>>)->bool{
#[test] #[test]
fn test_is_empty_volume() { fn test_is_empty_volume() {
assert!(!is_empty_volume([vec3::X.fix_3(),vec3::Y.fix_3(),vec3::Z.fix_3()].to_vec())); assert!(!is_empty_volume(
assert!(is_empty_volume([vec3::X.fix_3(),vec3::Y.fix_3(),vec3::Z.fix_3(),vec3::NEG_X.fix_3()].to_vec())); [vec3::X.fix_3(), vec3::Y.fix_3(), vec3::Z.fix_3()].to_vec()
));
assert!(is_empty_volume(
[
vec3::X.fix_3(),
vec3::Y.fix_3(),
vec3::Z.fix_3(),
vec3::NEG_X.fix_3()
]
.to_vec()
));
} }
#[test] #[test]

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,11 @@
use strafesnet_common::mouse::MouseState;
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
use strafesnet_common::physics::{Time as PhysicsTime,TimeInner as PhysicsTimeInner,Instruction as PhysicsInputInstruction};
use strafesnet_common::instruction::TimedInstruction;
use strafesnet_common::timer::{Scaled,Timer,TimerState};
use mouse_interpolator::MouseInterpolator; use mouse_interpolator::MouseInterpolator;
use strafesnet_common::instruction::TimedInstruction;
use strafesnet_common::mouse::MouseState;
use strafesnet_common::physics::{
Instruction as PhysicsInputInstruction, Time as PhysicsTime, TimeInner as PhysicsTimeInner,
};
use strafesnet_common::session::{Time as SessionTime, TimeInner as SessionTimeInner};
use strafesnet_common::timer::{Scaled, Timer, TimerState};
pub struct FrameState { pub struct FrameState {
pub body: crate::physics::Body, pub body: crate::physics::Body,
@ -24,7 +25,10 @@ pub enum InputInstruction{
Jump(bool), Jump(bool),
Zoom(bool), Zoom(bool),
ResetAndRestart, ResetAndRestart,
ResetAndSpawn(strafesnet_common::gameplay_modes::ModeId,strafesnet_common::gameplay_modes::StageId), ResetAndSpawn(
strafesnet_common::gameplay_modes::ModeId,
strafesnet_common::gameplay_modes::StageId,
),
PracticeFly, PracticeFly,
} }
pub enum Instruction { pub enum Instruction {
@ -43,13 +47,13 @@ pub struct MouseInterpolator{
//"PlayerController" //"PlayerController"
user_settings: crate::settings::UserSettings, user_settings: crate::settings::UserSettings,
//"MouseInterpolator" //"MouseInterpolator"
timeline:std::collections::VecDeque<TimedInstruction<PhysicsInputInstruction,PhysicsTimeInner>>, timeline:
std::collections::VecDeque<TimedInstruction<PhysicsInputInstruction, PhysicsTimeInner>>,
last_mouse_time: PhysicsTime, last_mouse_time: PhysicsTime,
mouse_blocking: bool, mouse_blocking: bool,
//"Simulation" //"Simulation"
timer: Timer<Scaled<SessionTimeInner, PhysicsTimeInner>>, timer: Timer<Scaled<SessionTimeInner, PhysicsTimeInner>>,
physics: crate::physics::PhysicsContext, physics: crate::physics::PhysicsContext,
} }
impl MouseInterpolator { impl MouseInterpolator {
pub fn new( pub fn new(
@ -65,12 +69,19 @@ impl MouseInterpolator{
user_settings, user_settings,
} }
} }
fn push_mouse_instruction(&mut self,ins:&TimedInstruction<Instruction,SessionTimeInner>,m:glam::IVec2){ fn push_mouse_instruction(
&mut self,
ins: &TimedInstruction<Instruction, SessionTimeInner>,
m: glam::IVec2,
) {
if self.mouse_blocking { if self.mouse_blocking {
//tell the game state which is living in the past about its future //tell the game state which is living in the past about its future
self.timeline.push_front(TimedInstruction { self.timeline.push_front(TimedInstruction {
time: self.last_mouse_time, time: self.last_mouse_time,
instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:self.timer.time(ins.time),pos:m}), instruction: PhysicsInputInstruction::SetNextMouse(MouseState {
time: self.timer.time(ins.time),
pos: m,
}),
}); });
} else { } else {
//mouse has just started moving again after being still for longer than 10ms. //mouse has just started moving again after being still for longer than 10ms.
@ -78,8 +89,14 @@ impl MouseInterpolator{
self.timeline.push_front(TimedInstruction { self.timeline.push_front(TimedInstruction {
time: self.last_mouse_time, time: self.last_mouse_time,
instruction: PhysicsInputInstruction::ReplaceMouse( instruction: PhysicsInputInstruction::ReplaceMouse(
MouseState{time:self.last_mouse_time,pos:self.physics.get_next_mouse().pos}, MouseState {
MouseState{time:self.timer.time(ins.time),pos:m} time: self.last_mouse_time,
pos: self.physics.get_next_mouse().pos,
},
MouseState {
time: self.timer.time(ins.time),
pos: m,
},
), ),
}); });
//delay physics execution until we have an interpolation target //delay physics execution until we have an interpolation target
@ -96,7 +113,10 @@ impl MouseInterpolator{
} }
/// returns should_empty_queue /// returns should_empty_queue
/// may or may not mutate internal state XD! /// may or may not mutate internal state XD!
fn map_instruction(&mut self,ins:&TimedInstruction<Instruction,SessionTimeInner>)->bool{ fn map_instruction(
&mut self,
ins: &TimedInstruction<Instruction, SessionTimeInner>,
) -> bool {
let mut update_mouse_blocking = true; let mut update_mouse_blocking = true;
match &ins.instruction { match &ins.instruction {
Instruction::Input(input_instruction) => match input_instruction { Instruction::Input(input_instruction) => match input_instruction {
@ -105,26 +125,54 @@ impl MouseInterpolator{
self.push_mouse_instruction(ins, m); self.push_mouse_instruction(ins, m);
} }
update_mouse_blocking = false; update_mouse_blocking = false;
}, }
&InputInstruction::MoveForward(s)=>self.push(ins.time,PhysicsInputInstruction::SetMoveForward(s)), &InputInstruction::MoveForward(s) => {
&InputInstruction::MoveLeft(s)=>self.push(ins.time,PhysicsInputInstruction::SetMoveLeft(s)), self.push(ins.time, PhysicsInputInstruction::SetMoveForward(s))
&InputInstruction::MoveBack(s)=>self.push(ins.time,PhysicsInputInstruction::SetMoveBack(s)), }
&InputInstruction::MoveRight(s)=>self.push(ins.time,PhysicsInputInstruction::SetMoveRight(s)), &InputInstruction::MoveLeft(s) => {
&InputInstruction::MoveUp(s)=>self.push(ins.time,PhysicsInputInstruction::SetMoveUp(s)), self.push(ins.time, PhysicsInputInstruction::SetMoveLeft(s))
&InputInstruction::MoveDown(s)=>self.push(ins.time,PhysicsInputInstruction::SetMoveDown(s)), }
&InputInstruction::Jump(s)=>self.push(ins.time,PhysicsInputInstruction::SetJump(s)), &InputInstruction::MoveBack(s) => {
&InputInstruction::Zoom(s)=>self.push(ins.time,PhysicsInputInstruction::SetZoom(s)), self.push(ins.time, PhysicsInputInstruction::SetMoveBack(s))
}
&InputInstruction::MoveRight(s) => {
self.push(ins.time, PhysicsInputInstruction::SetMoveRight(s))
}
&InputInstruction::MoveUp(s) => {
self.push(ins.time, PhysicsInputInstruction::SetMoveUp(s))
}
&InputInstruction::MoveDown(s) => {
self.push(ins.time, PhysicsInputInstruction::SetMoveDown(s))
}
&InputInstruction::Jump(s) => {
self.push(ins.time, PhysicsInputInstruction::SetJump(s))
}
&InputInstruction::Zoom(s) => {
self.push(ins.time, PhysicsInputInstruction::SetZoom(s))
}
&InputInstruction::ResetAndSpawn(mode_id, stage_id) => { &InputInstruction::ResetAndSpawn(mode_id, stage_id) => {
self.push(ins.time, PhysicsInputInstruction::Reset); self.push(ins.time, PhysicsInputInstruction::Reset);
self.push(ins.time,PhysicsInputInstruction::SetSensitivity(self.user_settings.calculate_sensitivity())); self.push(
ins.time,
PhysicsInputInstruction::SetSensitivity(
self.user_settings.calculate_sensitivity(),
),
);
self.push(ins.time, PhysicsInputInstruction::Spawn(mode_id, stage_id)); self.push(ins.time, PhysicsInputInstruction::Spawn(mode_id, stage_id));
}, }
InputInstruction::ResetAndRestart => { InputInstruction::ResetAndRestart => {
self.push(ins.time, PhysicsInputInstruction::Reset); self.push(ins.time, PhysicsInputInstruction::Reset);
self.push(ins.time,PhysicsInputInstruction::SetSensitivity(self.user_settings.calculate_sensitivity())); self.push(
ins.time,
PhysicsInputInstruction::SetSensitivity(
self.user_settings.calculate_sensitivity(),
),
);
self.push(ins.time, PhysicsInputInstruction::Restart); self.push(ins.time, PhysicsInputInstruction::Restart);
}, }
InputInstruction::PracticeFly=>self.push(ins.time,PhysicsInputInstruction::PracticeFly), InputInstruction::PracticeFly => {
self.push(ins.time, PhysicsInputInstruction::PracticeFly)
}
}, },
//do these really need to idle the physics? //do these really need to idle the physics?
//sending None dumps the instruction queue //sending None dumps the instruction queue
@ -136,7 +184,7 @@ impl MouseInterpolator{
println!("Cannot SetPaused: {e}"); println!("Cannot SetPaused: {e}");
} }
self.push(ins.time, PhysicsInputInstruction::Idle); self.push(ins.time, PhysicsInputInstruction::Idle);
}, }
} }
if update_mouse_blocking { if update_mouse_blocking {
//this returns the bool for us //this returns the bool for us
@ -151,7 +199,10 @@ impl MouseInterpolator{
//push an event to extrapolate no movement from //push an event to extrapolate no movement from
self.timeline.push_front(TimedInstruction { self.timeline.push_front(TimedInstruction {
time: self.last_mouse_time, time: self.last_mouse_time,
instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:self.timer.time(time),pos:self.physics.get_next_mouse().pos}), instruction: PhysicsInputInstruction::SetNextMouse(MouseState {
time: self.timer.time(time),
pos: self.physics.get_next_mouse().pos,
}),
}); });
self.last_mouse_time = self.timer.time(time); self.last_mouse_time = self.timer.time(time);
//stop blocking. the mouse is not moving so the physics does not need to live in the past and wait for interpolation targets. //stop blocking. the mouse is not moving so the physics does not need to live in the past and wait for interpolation targets.
@ -163,7 +214,9 @@ impl MouseInterpolator{
//shitty mice are 125Hz which is 8ms so this should cover that. //shitty mice are 125Hz which is 8ms so this should cover that.
//setting this to 100us still doesn't print even though it's 10x lower than the polling rate, //setting this to 100us still doesn't print even though it's 10x lower than the polling rate,
//so mouse events are probably not handled separately from drawing and fire right before it :( //so mouse events are probably not handled separately from drawing and fire right before it :(
if PhysicsTime::from_millis(10)<self.timer.time(time)-self.physics.get_next_mouse().time{ if PhysicsTime::from_millis(10)
< self.timer.time(time) - self.physics.get_next_mouse().time
{
self.unblock_mouse(time); self.unblock_mouse(time);
true true
} else { } else {
@ -181,7 +234,10 @@ impl MouseInterpolator{
self.physics.run_input_instruction(instruction); self.physics.run_input_instruction(instruction);
} }
} }
pub fn handle_instruction(&mut self,ins:&TimedInstruction<Instruction,SessionTimeInner>){ pub fn handle_instruction(
&mut self,
ins: &TimedInstruction<Instruction, SessionTimeInner>,
) {
let should_empty_queue = self.map_instruction(ins); let should_empty_queue = self.map_instruction(ins);
if should_empty_queue { if should_empty_queue {
self.empty_queue(); self.empty_queue();
@ -224,26 +280,34 @@ pub fn new<'a>(
user_settings: crate::settings::UserSettings, user_settings: crate::settings::UserSettings,
) -> crate::compat_worker::QNWorker<'a, TimedInstruction<Instruction, SessionTimeInner>> { ) -> crate::compat_worker::QNWorker<'a, TimedInstruction<Instruction, SessionTimeInner>> {
let physics = crate::physics::PhysicsContext::default(); let physics = crate::physics::PhysicsContext::default();
let mut interpolator=MouseInterpolator::new( let mut interpolator = MouseInterpolator::new(physics, user_settings);
physics, crate::compat_worker::QNWorker::new(
user_settings move |ins: TimedInstruction<Instruction, SessionTimeInner>| {
);
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<Instruction,SessionTimeInner>|{
interpolator.handle_instruction(&ins); interpolator.handle_instruction(&ins);
match ins.instruction { match ins.instruction {
Instruction::Render => { Instruction::Render => {
let frame_state = interpolator.get_frame_state(ins.time); let frame_state = interpolator.get_frame_state(ins.time);
graphics_worker.send(crate::graphics_worker::Instruction::Render(frame_state)).unwrap(); graphics_worker
}, .send(crate::graphics_worker::Instruction::Render(frame_state))
.unwrap();
}
Instruction::Resize(size) => { Instruction::Resize(size) => {
graphics_worker.send(crate::graphics_worker::Instruction::Resize(size,interpolator.user_settings().clone())).unwrap(); graphics_worker
}, .send(crate::graphics_worker::Instruction::Resize(
size,
interpolator.user_settings().clone(),
))
.unwrap();
}
Instruction::ChangeMap(map) => { Instruction::ChangeMap(map) => {
interpolator.change_map(ins.time, &map); interpolator.change_map(ins.time, &map);
graphics_worker.send(crate::graphics_worker::Instruction::ChangeMap(map)).unwrap(); graphics_worker
}, .send(crate::graphics_worker::Instruction::ChangeMap(map))
.unwrap();
}
Instruction::Input(_) => (), Instruction::Input(_) => (),
Instruction::SetPaused(_) => (), Instruction::SetPaused(_) => (),
} }
}) },
)
} }

View File

@ -1,4 +1,8 @@
use strafesnet_common::integer::{self,vec3::{self,Vector3},Fixed,Planar64,Planar64Vec3,Ratio}; use strafesnet_common::integer::{
self,
vec3::{self, Vector3},
Fixed, Planar64, Planar64Vec3, Ratio,
};
// This algorithm is based on Lua code // This algorithm is based on Lua code
// written by Trey Reynolds in 2021 // written by Trey Reynolds in 2021
@ -49,7 +53,8 @@ impl Contact{
} }
/// Calculate the time of intersection. (previously get_touch_time) /// Calculate the time of intersection. (previously get_touch_time)
fn solve(&self, ray: &Ray) -> Ratio<Fixed<2, 64>, Fixed<2, 64>> { fn solve(&self, ray: &Ray) -> Ratio<Fixed<2, 64>, Fixed<2, 64>> {
(self.position-ray.origin).dot(self.normal)/(ray.direction-self.velocity).dot(self.normal) (self.position - ray.origin).dot(self.normal)
/ (ray.direction - self.velocity).dot(self.normal)
} }
} }
@ -75,7 +80,11 @@ fn solve2(c0:&Contact,c1:&Contact)->Option<Ratio<Vector3<Fixed<5,160>>,Fixed<4,1
let d1 = c1.normal.dot(c1.position); let d1 = c1.normal.dot(c1.position);
Some((c1.normal.cross(u0_u1) * d0 + u0_u1.cross(c0.normal) * d1) / det) Some((c1.normal.cross(u0_u1) * d0 + u0_u1.cross(c0.normal) * d1) / det)
} }
fn solve3(c0:&Contact,c1:&Contact,c2:&Contact)->Option<Ratio<Vector3<Fixed<4,128>>,Fixed<3,96>>>{ fn solve3(
c0: &Contact,
c1: &Contact,
c2: &Contact,
) -> Option<Ratio<Vector3<Fixed<4, 128>>, Fixed<3, 96>>> {
const EPSILON: Fixed<3, 96> = Fixed::from_bits(Fixed::<3, 96>::ONE.to_bits().shr(10)); const EPSILON: Fixed<3, 96> = Fixed::from_bits(Fixed::<3, 96>::ONE.to_bits().shr(10));
let n0_n1 = c0.normal.cross(c1.normal); let n0_n1 = c0.normal.cross(c1.normal);
let det = c2.normal.dot(n0_n1); let det = c2.normal.dot(n0_n1);
@ -85,10 +94,18 @@ fn solve3(c0:&Contact,c1:&Contact,c2:&Contact)->Option<Ratio<Vector3<Fixed<4,128
let d0 = c0.normal.dot(c0.position); let d0 = c0.normal.dot(c0.position);
let d1 = c1.normal.dot(c1.position); let d1 = c1.normal.dot(c1.position);
let d2 = c2.normal.dot(c2.position); let d2 = c2.normal.dot(c2.position);
Some((c1.normal.cross(c2.normal)*d0+c2.normal.cross(c0.normal)*d1+c0.normal.cross(c1.normal)*d2)/det) Some(
(c1.normal.cross(c2.normal) * d0
+ c2.normal.cross(c0.normal) * d1
+ c0.normal.cross(c1.normal) * d2)
/ det,
)
} }
fn decompose1(point:Planar64Vec3,u0:Planar64Vec3)->Option<[Ratio<Fixed<2,64>,Fixed<2,64>>;1]>{ fn decompose1(
point: Planar64Vec3,
u0: Planar64Vec3,
) -> Option<[Ratio<Fixed<2, 64>, Fixed<2, 64>>; 1]> {
let det = u0.dot(u0); let det = u0.dot(u0);
if det == Fixed::ZERO { if det == Fixed::ZERO {
return None; return None;
@ -96,7 +113,11 @@ fn decompose1(point:Planar64Vec3,u0:Planar64Vec3)->Option<[Ratio<Fixed<2,64>,Fix
let s0 = u0.dot(point) / det; let s0 = u0.dot(point) / det;
Some([s0]) Some([s0])
} }
fn decompose2(point:Planar64Vec3,u0:Planar64Vec3,u1:Planar64Vec3)->Option<[Ratio<Fixed<4,128>,Fixed<4,128>>;2]>{ fn decompose2(
point: Planar64Vec3,
u0: Planar64Vec3,
u1: Planar64Vec3,
) -> Option<[Ratio<Fixed<4, 128>, Fixed<4, 128>>; 2]> {
let u0_u1 = u0.cross(u1); let u0_u1 = u0.cross(u1);
let det = u0_u1.dot(u0_u1); let det = u0_u1.dot(u0_u1);
if det == Fixed::ZERO { if det == Fixed::ZERO {
@ -106,7 +127,12 @@ fn decompose2(point:Planar64Vec3,u0:Planar64Vec3,u1:Planar64Vec3)->Option<[Ratio
let s1 = u0_u1.dot(u0.cross(point)) / det; let s1 = u0_u1.dot(u0.cross(point)) / det;
Some([s0, s1]) Some([s0, s1])
} }
fn decompose3(point:Planar64Vec3,u0:Planar64Vec3,u1:Planar64Vec3,u2:Planar64Vec3)->Option<[Ratio<Fixed<3,96>,Fixed<3,96>>;3]>{ fn decompose3(
point: Planar64Vec3,
u0: Planar64Vec3,
u1: Planar64Vec3,
u2: Planar64Vec3,
) -> Option<[Ratio<Fixed<3, 96>, Fixed<3, 96>>; 3]> {
let det = u0.cross(u1).dot(u2); let det = u0.cross(u1).dot(u2);
if det == Fixed::ZERO { if det == Fixed::ZERO {
return None; return None;
@ -117,20 +143,11 @@ fn decompose3(point:Planar64Vec3,u0:Planar64Vec3,u1:Planar64Vec3,u2:Planar64Vec3
Some([s0, s1, s2]) Some([s0, s1, s2])
} }
fn is_space_enclosed_2( fn is_space_enclosed_2(a: Planar64Vec3, b: Planar64Vec3) -> bool {
a:Planar64Vec3, a.cross(b) == Vector3::new([Fixed::ZERO; 3]) && a.dot(b).is_negative()
b:Planar64Vec3,
)->bool{
a.cross(b)==Vector3::new([Fixed::ZERO;3])
&&a.dot(b).is_negative()
} }
fn is_space_enclosed_3( fn is_space_enclosed_3(a: Planar64Vec3, b: Planar64Vec3, c: Planar64Vec3) -> bool {
a:Planar64Vec3, a.cross(b).dot(c) == Fixed::ZERO && {
b:Planar64Vec3,
c:Planar64Vec3
)->bool{
a.cross(b).dot(c)==Fixed::ZERO
&&{
let det_abac = a.cross(b).dot(a.cross(c)); let det_abac = a.cross(b).dot(a.cross(c));
let det_abbc = a.cross(b).dot(b.cross(c)); let det_abbc = a.cross(b).dot(b.cross(c));
let det_acbc = a.cross(c).dot(b.cross(c)); let det_acbc = a.cross(c).dot(b.cross(c));
@ -139,15 +156,10 @@ fn is_space_enclosed_3(
&& !(-det_acbc * det_abac).is_positive() && !(-det_acbc * det_abac).is_positive()
|| is_space_enclosed_2(a, b) || is_space_enclosed_2(a, b)
|| is_space_enclosed_2(a, c) || is_space_enclosed_2(a, c)
||is_space_enclosed_2(b,c) || is_space_enclosed_2(b, c);
} }
} }
fn is_space_enclosed_4( fn is_space_enclosed_4(a: Planar64Vec3, b: Planar64Vec3, c: Planar64Vec3, d: Planar64Vec3) -> bool {
a:Planar64Vec3,
b:Planar64Vec3,
c:Planar64Vec3,
d:Planar64Vec3,
)->bool{
let det_abc = a.cross(b).dot(c); let det_abc = a.cross(b).dot(c);
let det_abd = a.cross(b).dot(d); let det_abd = a.cross(b).dot(d);
let det_acd = a.cross(c).dot(d); let det_acd = a.cross(c).dot(d);
@ -161,11 +173,14 @@ fn is_space_enclosed_4(
|| is_space_enclosed_3(a, b, c) || is_space_enclosed_3(a, b, c)
|| is_space_enclosed_3(a, b, d) || is_space_enclosed_3(a, b, d)
|| is_space_enclosed_3(a, c, d) || is_space_enclosed_3(a, c, d)
||is_space_enclosed_3(b,c,d) || is_space_enclosed_3(b, c, d);
} }
const fn get_push_ray_0(point: Planar64Vec3) -> Option<Ray> { const fn get_push_ray_0(point: Planar64Vec3) -> Option<Ray> {
Some(Ray{origin:point,direction:vec3::ZERO}) Some(Ray {
origin: point,
direction: vec3::ZERO,
})
} }
fn get_push_ray_1(point: Planar64Vec3, c0: &Contact) -> Option<Ray> { fn get_push_ray_1(point: Planar64Vec3, c0: &Contact) -> Option<Ray> {
let direction = solve1(c0)?.divide().fix_1(); let direction = solve1(c0)?.divide().fix_1();
@ -173,9 +188,7 @@ fn get_push_ray_1(point:Planar64Vec3,c0:&Contact)->Option<Ray>{
if s0.lt_ratio(RATIO_ZERO) { if s0.lt_ratio(RATIO_ZERO) {
return None; return None;
} }
let origin=point+solve1( let origin = point + solve1(&c0.relative_to(point))?.divide().fix_1();
&c0.relative_to(point),
)?.divide().fix_1();
Some(Ray { origin, direction }) Some(Ray { origin, direction })
} }
fn get_push_ray_2(point: Planar64Vec3, c0: &Contact, c1: &Contact) -> Option<Ray> { fn get_push_ray_2(point: Planar64Vec3, c0: &Contact, c1: &Contact) -> Option<Ray> {
@ -184,10 +197,10 @@ fn get_push_ray_2(point:Planar64Vec3,c0:&Contact,c1:&Contact)->Option<Ray>{
if s0.lt_ratio(RATIO_ZERO) || s1.lt_ratio(RATIO_ZERO) { if s0.lt_ratio(RATIO_ZERO) || s1.lt_ratio(RATIO_ZERO) {
return None; return None;
} }
let origin=point+solve2( let origin = point
&c0.relative_to(point), + solve2(&c0.relative_to(point), &c1.relative_to(point))?
&c1.relative_to(point), .divide()
)?.divide().fix_1(); .fix_1();
Some(Ray { origin, direction }) Some(Ray { origin, direction })
} }
fn get_push_ray_3(point: Planar64Vec3, c0: &Contact, c1: &Contact, c2: &Contact) -> Option<Ray> { fn get_push_ray_3(point: Planar64Vec3, c0: &Contact, c1: &Contact, c2: &Contact) -> Option<Ray> {
@ -196,11 +209,14 @@ fn get_push_ray_3(point:Planar64Vec3,c0:&Contact,c1:&Contact,c2:&Contact)->Optio
if s0.lt_ratio(RATIO_ZERO) || s1.lt_ratio(RATIO_ZERO) || s2.lt_ratio(RATIO_ZERO) { if s0.lt_ratio(RATIO_ZERO) || s1.lt_ratio(RATIO_ZERO) || s2.lt_ratio(RATIO_ZERO) {
return None; return None;
} }
let origin=point+solve3( let origin = point
+ solve3(
&c0.relative_to(point), &c0.relative_to(point),
&c1.relative_to(point), &c1.relative_to(point),
&c2.relative_to(point), &c2.relative_to(point),
)?.divide().fix_1(); )?
.divide()
.fix_1();
Some(Ray { origin, direction }) Some(Ray { origin, direction })
} }
@ -211,10 +227,13 @@ const fn get_best_push_ray_and_conts_0<'a>(point:Planar64Vec3)->Option<(Ray,Cont
} }
} }
fn get_best_push_ray_and_conts_1(point: Planar64Vec3, c0: &Contact) -> Option<(Ray, Conts)> { fn get_best_push_ray_and_conts_1(point: Planar64Vec3, c0: &Contact) -> Option<(Ray, Conts)> {
get_push_ray_1(point,c0) get_push_ray_1(point, c0).map(|ray| (ray, Conts::from_iter([c0])))
.map(|ray|(ray,Conts::from_iter([c0])))
} }
fn get_best_push_ray_and_conts_2<'a>(point:Planar64Vec3,c0:&'a Contact,c1:&'a Contact)->Option<(Ray,Conts<'a>)>{ fn get_best_push_ray_and_conts_2<'a>(
point: Planar64Vec3,
c0: &'a Contact,
c1: &'a Contact,
) -> Option<(Ray, Conts<'a>)> {
if is_space_enclosed_2(c0.normal, c1.normal) { if is_space_enclosed_2(c0.normal, c1.normal) {
return None; return None;
} }
@ -228,7 +247,12 @@ fn get_best_push_ray_and_conts_2<'a>(point:Planar64Vec3,c0:&'a Contact,c1:&'a Co
} }
return None; return None;
} }
fn get_best_push_ray_and_conts_3<'a>(point:Planar64Vec3,c0:&'a Contact,c1:&'a Contact,c2:&'a Contact)->Option<(Ray,Conts<'a>)>{ fn get_best_push_ray_and_conts_3<'a>(
point: Planar64Vec3,
c0: &'a Contact,
c1: &'a Contact,
c2: &'a Contact,
) -> Option<(Ray, Conts<'a>)> {
if is_space_enclosed_3(c0.normal, c1.normal, c2.normal) { if is_space_enclosed_3(c0.normal, c1.normal, c2.normal) {
return None; return None;
} }
@ -247,13 +271,20 @@ fn get_best_push_ray_and_conts_3<'a>(point:Planar64Vec3,c0:&'a Contact,c1:&'a Co
} }
if let Some(ray) = get_push_ray_1(point, c0) { if let Some(ray) = get_push_ray_1(point, c0) {
if !c1.relative_dot(ray.direction).is_negative() if !c1.relative_dot(ray.direction).is_negative()
&&!c2.relative_dot(ray.direction).is_negative(){ && !c2.relative_dot(ray.direction).is_negative()
{
return Some((ray, Conts::from_iter([c0]))); return Some((ray, Conts::from_iter([c0])));
} }
} }
return None; return None;
} }
fn get_best_push_ray_and_conts_4<'a>(point:Planar64Vec3,c0:&'a Contact,c1:&'a Contact,c2:&'a Contact,c3:&'a Contact)->Option<(Ray,Conts<'a>)>{ fn get_best_push_ray_and_conts_4<'a>(
point: Planar64Vec3,
c0: &'a Contact,
c1: &'a Contact,
c2: &'a Contact,
c3: &'a Contact,
) -> Option<(Ray, Conts<'a>)> {
if is_space_enclosed_4(c0.normal, c1.normal, c2.normal, c3.normal) { if is_space_enclosed_4(c0.normal, c1.normal, c2.normal, c3.normal) {
return None; return None;
} }
@ -269,11 +300,11 @@ fn get_best_push_ray_and_conts_4<'a>(point:Planar64Vec3,c0:&'a Contact,c1:&'a Co
let best_err = err012.max(err013).max(err023); let best_err = err012.max(err013).max(err023);
if best_err == err012 { if best_err == err012 {
return Some((ray012,conts012)) return Some((ray012, conts012));
} else if best_err == err013 { } else if best_err == err013 {
return Some((ray013,conts013)) return Some((ray013, conts013));
} else if best_err == err023 { } else if best_err == err023 {
return Some((ray023,conts023)) return Some((ray023, conts023));
} }
unreachable!() unreachable!()
} }
@ -292,12 +323,17 @@ fn get_best_push_ray_and_conts<'a>(
} }
} }
fn get_first_touch<'a>(contacts:&'a Vec<Contact>,ray:&Ray,conts:&Conts)->Option<(Ratio<Fixed<2,64>,Fixed<2,64>>,&'a Contact)>{ fn get_first_touch<'a>(
contacts.iter() contacts: &'a Vec<Contact>,
.filter(|&contact| ray: &Ray,
conts: &Conts,
) -> Option<(Ratio<Fixed<2, 64>, Fixed<2, 64>>, &'a Contact)> {
contacts
.iter()
.filter(|&contact| {
!conts.iter().any(|&c| std::ptr::eq(c, contact)) !conts.iter().any(|&c| std::ptr::eq(c, contact))
&& contact.relative_dot(ray.direction).is_negative() && contact.relative_dot(ray.direction).is_negative()
) })
.map(|contact| (contact.solve(ray), contact)) .map(|contact| (contact.solve(ray), contact))
.min_by_key(|&(t, _)| t) .min_by_key(|&(t, _)| t)
} }
@ -338,16 +374,11 @@ mod tests{
use super::*; use super::*;
#[test] #[test]
fn test_push_solve() { fn test_push_solve() {
let contacts=vec![ let contacts = vec![Contact {
Contact{
position: vec3::ZERO, position: vec3::ZERO,
velocity: vec3::Y, velocity: vec3::Y,
normal: vec3::Y, normal: vec3::Y,
} }];
]; assert_eq!(Some(vec3::ZERO), push_solve(&contacts, vec3::NEG_Y));
assert_eq!(
Some(vec3::ZERO),
push_solve(&contacts,vec3::NEG_Y)
);
} }
} }

View File

@ -16,7 +16,10 @@ enum Fov{
} }
impl Default for Fov { impl Default for Fov {
fn default() -> Self { fn default() -> Self {
Fov::SpecifyYDeriveX{x:DerivedFov::FromScreenAspect,y:1.0} Fov::SpecifyYDeriveX {
x: DerivedFov::FromScreenAspect,
y: 1.0,
}
} }
} }
#[derive(Clone)] #[derive(Clone)]
@ -31,7 +34,10 @@ enum Sensitivity{
} }
impl Default for Sensitivity { impl Default for Sensitivity {
fn default() -> Self { fn default() -> Self {
Sensitivity::SpecifyXDeriveY{x:Ratio64::ONE*524288,y:DerivedSensitivity::FromRatio(Ratio64::ONE)} Sensitivity::SpecifyXDeriveY {
x: Ratio64::ONE * 524288,
y: DerivedSensitivity::FromRatio(Ratio64::ONE),
}
} }
} }
@ -45,11 +51,15 @@ impl UserSettings{
zoom * match &self.fov { zoom * match &self.fov {
&Fov::Exactly { x, y } => glam::dvec2(x, y), &Fov::Exactly { x, y } => glam::dvec2(x, y),
Fov::SpecifyXDeriveY { x, y } => match y { Fov::SpecifyXDeriveY { x, y } => match y {
DerivedFov::FromScreenAspect=>glam::dvec2(*x,x*(screen_size.y as f64/screen_size.x as f64)), DerivedFov::FromScreenAspect => {
glam::dvec2(*x, x * (screen_size.y as f64 / screen_size.x as f64))
}
DerivedFov::FromAspect(ratio) => glam::dvec2(*x, x * ratio.ratio), DerivedFov::FromAspect(ratio) => glam::dvec2(*x, x * ratio.ratio),
}, },
Fov::SpecifyYDeriveX { x, y } => match x { Fov::SpecifyYDeriveX { x, y } => match x {
DerivedFov::FromScreenAspect=>glam::dvec2(y*(screen_size.x as f64/screen_size.y as f64),*y), DerivedFov::FromScreenAspect => {
glam::dvec2(y * (screen_size.x as f64 / screen_size.y as f64), *y)
}
DerivedFov::FromAspect(ratio) => glam::dvec2(y * ratio.ratio, *y), DerivedFov::FromAspect(ratio) => glam::dvec2(y * ratio.ratio, *y),
}, },
} }
@ -58,11 +68,15 @@ impl UserSettings{
match &self.sensitivity { match &self.sensitivity {
Sensitivity::Exactly { x, y } => Ratio64Vec2::new(x.clone(), y.clone()), Sensitivity::Exactly { x, y } => Ratio64Vec2::new(x.clone(), y.clone()),
Sensitivity::SpecifyXDeriveY { x, y } => match y { Sensitivity::SpecifyXDeriveY { x, y } => match y {
DerivedSensitivity::FromRatio(ratio)=>Ratio64Vec2::new(x.clone(),x.mul_ref(ratio)), DerivedSensitivity::FromRatio(ratio) => {
Ratio64Vec2::new(x.clone(), x.mul_ref(ratio))
} }
},
Sensitivity::SpecifyYDeriveX { x, y } => match x { Sensitivity::SpecifyYDeriveX { x, y } => match x {
DerivedSensitivity::FromRatio(ratio)=>Ratio64Vec2::new(y.mul_ref(ratio),y.clone()), DerivedSensitivity::FromRatio(ratio) => {
Ratio64Vec2::new(y.mul_ref(ratio), y.clone())
} }
},
} }
} }
} }
@ -77,33 +91,42 @@ Sensitivity::DeriveY{x:0.0.001,y:DerivedSensitivity{ratio:1.0}}
pub fn read_user_settings() -> UserSettings { pub fn read_user_settings() -> UserSettings {
let mut cfg = configparser::ini::Ini::new(); let mut cfg = configparser::ini::Ini::new();
if let Ok(_) = cfg.load("settings.conf") { if let Ok(_) = cfg.load("settings.conf") {
let (cfg_fov_x,cfg_fov_y)=(cfg.getfloat("camera","fov_x"),cfg.getfloat("camera","fov_y")); let (cfg_fov_x, cfg_fov_y) = (
cfg.getfloat("camera", "fov_x"),
cfg.getfloat("camera", "fov_y"),
);
let fov = match (cfg_fov_x, cfg_fov_y) { let fov = match (cfg_fov_x, cfg_fov_y) {
(Ok(Some(fov_x)),Ok(Some(fov_y)))=>Fov::Exactly { (Ok(Some(fov_x)), Ok(Some(fov_y))) => Fov::Exactly { x: fov_x, y: fov_y },
x:fov_x,
y:fov_y
},
(Ok(Some(fov_x)), Ok(None)) => Fov::SpecifyXDeriveY { (Ok(Some(fov_x)), Ok(None)) => Fov::SpecifyXDeriveY {
x: fov_x, x: fov_x,
y:if let Ok(Some(fov_y_from_x_ratio))=cfg.getfloat("camera","fov_y_from_x_ratio"){ y: if let Ok(Some(fov_y_from_x_ratio)) =
DerivedFov::FromAspect(Ratio{ratio:fov_y_from_x_ratio}) cfg.getfloat("camera", "fov_y_from_x_ratio")
{
DerivedFov::FromAspect(Ratio {
ratio: fov_y_from_x_ratio,
})
} else { } else {
DerivedFov::FromScreenAspect DerivedFov::FromScreenAspect
} },
}, },
(Ok(None), Ok(Some(fov_y))) => Fov::SpecifyYDeriveX { (Ok(None), Ok(Some(fov_y))) => Fov::SpecifyYDeriveX {
x:if let Ok(Some(fov_x_from_y_ratio))=cfg.getfloat("camera","fov_x_from_y_ratio"){ x: if let Ok(Some(fov_x_from_y_ratio)) =
DerivedFov::FromAspect(Ratio{ratio:fov_x_from_y_ratio}) cfg.getfloat("camera", "fov_x_from_y_ratio")
{
DerivedFov::FromAspect(Ratio {
ratio: fov_x_from_y_ratio,
})
} else { } else {
DerivedFov::FromScreenAspect DerivedFov::FromScreenAspect
}, },
y: fov_y, y: fov_y,
}, },
_=>{ _ => Fov::default(),
Fov::default()
},
}; };
let (cfg_sensitivity_x,cfg_sensitivity_y)=(cfg.getfloat("camera","sensitivity_x"),cfg.getfloat("camera","sensitivity_y")); let (cfg_sensitivity_x, cfg_sensitivity_y) = (
cfg.getfloat("camera", "sensitivity_x"),
cfg.getfloat("camera", "sensitivity_y"),
);
let sensitivity = match (cfg_sensitivity_x, cfg_sensitivity_y) { let sensitivity = match (cfg_sensitivity_x, cfg_sensitivity_y) {
(Ok(Some(sensitivity_x)), Ok(Some(sensitivity_y))) => Sensitivity::Exactly { (Ok(Some(sensitivity_x)), Ok(Some(sensitivity_y))) => Sensitivity::Exactly {
x: Ratio64::try_from(sensitivity_x).unwrap(), x: Ratio64::try_from(sensitivity_x).unwrap(),
@ -111,28 +134,31 @@ pub fn read_user_settings()->UserSettings{
}, },
(Ok(Some(sensitivity_x)), Ok(None)) => Sensitivity::SpecifyXDeriveY { (Ok(Some(sensitivity_x)), Ok(None)) => Sensitivity::SpecifyXDeriveY {
x: Ratio64::try_from(sensitivity_x).unwrap(), x: Ratio64::try_from(sensitivity_x).unwrap(),
y:if let Ok(Some(sensitivity_y_from_x_ratio))=cfg.getfloat("camera","sensitivity_y_from_x_ratio"){ y: if let Ok(Some(sensitivity_y_from_x_ratio)) =
DerivedSensitivity::FromRatio(Ratio64::try_from(sensitivity_y_from_x_ratio).unwrap()) cfg.getfloat("camera", "sensitivity_y_from_x_ratio")
{
DerivedSensitivity::FromRatio(
Ratio64::try_from(sensitivity_y_from_x_ratio).unwrap(),
)
} else { } else {
DerivedSensitivity::FromRatio(Ratio64::ONE) DerivedSensitivity::FromRatio(Ratio64::ONE)
}, },
}, },
(Ok(None), Ok(Some(sensitivity_y))) => Sensitivity::SpecifyYDeriveX { (Ok(None), Ok(Some(sensitivity_y))) => Sensitivity::SpecifyYDeriveX {
x:if let Ok(Some(sensitivity_x_from_y_ratio))=cfg.getfloat("camera","sensitivity_x_from_y_ratio"){ x: if let Ok(Some(sensitivity_x_from_y_ratio)) =
DerivedSensitivity::FromRatio(Ratio64::try_from(sensitivity_x_from_y_ratio).unwrap()) cfg.getfloat("camera", "sensitivity_x_from_y_ratio")
{
DerivedSensitivity::FromRatio(
Ratio64::try_from(sensitivity_x_from_y_ratio).unwrap(),
)
} else { } else {
DerivedSensitivity::FromRatio(Ratio64::ONE) DerivedSensitivity::FromRatio(Ratio64::ONE)
}, },
y: Ratio64::try_from(sensitivity_y).unwrap(), y: Ratio64::try_from(sensitivity_y).unwrap(),
}, },
_=>{ _ => Sensitivity::default(),
Sensitivity::default()
},
}; };
UserSettings{ UserSettings { fov, sensitivity }
fov,
sensitivity,
}
} else { } else {
UserSettings::default() UserSettings::default()
} }

View File

@ -4,8 +4,7 @@ use strafesnet_common::integer;
use strafesnet_common::session::TimeInner as SessionTimeInner; use strafesnet_common::session::TimeInner as SessionTimeInner;
fn optional_features() -> wgpu::Features { fn optional_features() -> wgpu::Features {
wgpu::Features::TEXTURE_COMPRESSION_ASTC wgpu::Features::TEXTURE_COMPRESSION_ASTC | wgpu::Features::TEXTURE_COMPRESSION_ETC2
|wgpu::Features::TEXTURE_COMPRESSION_ETC2
} }
fn required_features() -> wgpu::Features { fn required_features() -> wgpu::Features {
wgpu::Features::TEXTURE_COMPRESSION_BC wgpu::Features::TEXTURE_COMPRESSION_BC
@ -25,7 +24,10 @@ struct SetupContextPartial1{
backends: wgpu::Backends, backends: wgpu::Backends,
instance: wgpu::Instance, instance: wgpu::Instance,
} }
fn create_window(title:&str,event_loop:&winit::event_loop::EventLoop<()>)->Result<winit::window::Window,winit::error::OsError>{ fn create_window(
title: &str,
event_loop: &winit::event_loop::EventLoop<()>,
) -> Result<winit::window::Window, winit::error::OsError> {
let mut attr = winit::window::WindowAttributes::default(); let mut attr = winit::window::WindowAttributes::default();
attr = attr.with_title(title); attr = attr.with_title(title);
#[cfg(windows_OFF)] // TODO #[cfg(windows_OFF)] // TODO
@ -48,7 +50,10 @@ fn create_instance()->SetupContextPartial1{
} }
} }
impl SetupContextPartial1 { impl SetupContextPartial1 {
fn create_surface<'a>(self,window:&'a winit::window::Window)->Result<SetupContextPartial2<'a>,wgpu::CreateSurfaceError>{ fn create_surface<'a>(
self,
window: &'a winit::window::Window,
) -> Result<SetupContextPartial2<'a>, wgpu::CreateSurfaceError> {
Ok(SetupContextPartial2 { Ok(SetupContextPartial2 {
backends: self.backends, backends: self.backends,
surface: self.instance.create_surface(window)?, surface: self.instance.create_surface(window)?,
@ -99,7 +104,6 @@ impl<'a> SetupContextPartial2<'a>{
panic!("No suitable GPU adapters found on the system!"); panic!("No suitable GPU adapters found on the system!");
} }
let adapter_info = adapter.get_info(); let adapter_info = adapter.get_info();
println!("Using {} ({:?})", adapter_info.name, adapter_info.backend); println!("Using {} ({:?})", adapter_info.name, adapter_info.backend);
@ -138,11 +142,11 @@ impl<'a> SetupContextPartial3<'a>{
let needed_limits = required_limits().using_resolution(self.adapter.limits()); let needed_limits = required_limits().using_resolution(self.adapter.limits());
let trace_dir = std::env::var("WGPU_TRACE"); let trace_dir = std::env::var("WGPU_TRACE");
let (device, queue)=pollster::block_on(self.adapter let (device, queue) = pollster::block_on(self.adapter.request_device(
.request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
required_features: (optional_features & self.adapter.features()) | required_features, required_features: (optional_features & self.adapter.features())
| required_features,
required_limits: needed_limits, required_limits: needed_limits,
memory_hints: wgpu::MemoryHints::Performance, memory_hints: wgpu::MemoryHints::Performance,
}, },
@ -168,7 +172,8 @@ struct SetupContextPartial4<'a>{
} }
impl<'a> SetupContextPartial4<'a> { impl<'a> SetupContextPartial4<'a> {
fn configure_surface(self, size: &'a winit::dpi::PhysicalSize<u32>) -> SetupContext<'a> { fn configure_surface(self, size: &'a winit::dpi::PhysicalSize<u32>) -> SetupContext<'a> {
let mut config=self.surface let mut config = self
.surface
.get_default_config(&self.adapter, size.width, size.height) .get_default_config(&self.adapter, size.width, size.height)
.expect("Surface isn't supported by the adapter."); .expect("Surface isn't supported by the adapter.");
let surface_view_format = config.format.add_srgb_suffix(); let surface_view_format = config.format.add_srgb_suffix();
@ -215,17 +220,18 @@ pub fn setup_and_start(title:&str){
//dedicated thread to ping request redraw back and resize the window doesn't seem logical //dedicated thread to ping request redraw back and resize the window doesn't seem logical
//the thread that spawns the physics thread //the thread that spawns the physics thread
let mut window_thread=crate::window::worker( let mut window_thread = crate::window::worker(&window, setup_context);
&window,
setup_context,
);
if let Some(arg) = std::env::args().nth(1) { if let Some(arg) = std::env::args().nth(1) {
let path = std::path::PathBuf::from(arg); let path = std::path::PathBuf::from(arg);
window_thread.send(TimedInstruction{ window_thread
.send(TimedInstruction {
time: integer::Time::ZERO, time: integer::Time::ZERO,
instruction:WindowInstruction::WindowEvent(winit::event::WindowEvent::DroppedFile(path)), instruction: WindowInstruction::WindowEvent(
}).unwrap(); winit::event::WindowEvent::DroppedFile(path),
),
})
.unwrap();
}; };
println!("Entering event loop..."); println!("Entering event loop...");
@ -235,8 +241,10 @@ pub fn setup_and_start(title:&str){
fn run_event_loop( fn run_event_loop(
event_loop: winit::event_loop::EventLoop<()>, event_loop: winit::event_loop::EventLoop<()>,
mut window_thread:crate::compat_worker::QNWorker<TimedInstruction<WindowInstruction,SessionTimeInner>>, mut window_thread: crate::compat_worker::QNWorker<
root_time:std::time::Instant TimedInstruction<WindowInstruction, SessionTimeInner>,
>,
root_time: std::time::Instant,
) -> Result<(), winit::error::EventLoopError> { ) -> Result<(), winit::error::EventLoopError> {
event_loop.run(move |event,elwt|{ event_loop.run(move |event,elwt|{
let time=integer::Time::from_nanos(root_time.elapsed().as_nanos() as i64); let time=integer::Time::from_nanos(root_time.elapsed().as_nanos() as i64);

View File

@ -1,6 +1,6 @@
use crate::physics_worker::InputInstruction; use crate::physics_worker::InputInstruction;
use strafesnet_common::integer;
use strafesnet_common::instruction::TimedInstruction; use strafesnet_common::instruction::TimedInstruction;
use strafesnet_common::integer;
use strafesnet_common::session::{Time as SessionTime, TimeInner as SessionTimeInner}; use strafesnet_common::session::{Time as SessionTime, TimeInner as SessionTimeInner};
pub enum WindowInstruction { pub enum WindowInstruction {
@ -17,7 +17,10 @@ struct WindowContext<'a>{
mouse: strafesnet_common::mouse::MouseState<SessionTimeInner>, //std::sync::Arc<std::sync::Mutex<>> mouse: strafesnet_common::mouse::MouseState<SessionTimeInner>, //std::sync::Arc<std::sync::Mutex<>>
screen_size: glam::UVec2, screen_size: glam::UVec2,
window: &'a winit::window::Window, window: &'a winit::window::Window,
physics_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<crate::physics_worker::Instruction,SessionTimeInner>>, physics_thread: crate::compat_worker::QNWorker<
'a,
TimedInstruction<crate::physics_worker::Instruction, SessionTimeInner>,
>,
} }
impl WindowContext<'_> { impl WindowContext<'_> {
@ -28,71 +31,112 @@ impl WindowContext<'_>{
match event { match event {
winit::event::WindowEvent::DroppedFile(path) => { winit::event::WindowEvent::DroppedFile(path) => {
match crate::file::load(path.as_path()) { match crate::file::load(path.as_path()) {
Ok(map)=>self.physics_thread.send(TimedInstruction{time,instruction:crate::physics_worker::Instruction::ChangeMap(map)}).unwrap(), Ok(map) => self
.physics_thread
.send(TimedInstruction {
time,
instruction: crate::physics_worker::Instruction::ChangeMap(map),
})
.unwrap(),
Err(e) => println!("Failed to load map: {e}"), Err(e) => println!("Failed to load map: {e}"),
} }
}, }
winit::event::WindowEvent::Focused(state) => { winit::event::WindowEvent::Focused(state) => {
//pause unpause //pause unpause
self.physics_thread.send(TimedInstruction{ self.physics_thread
.send(TimedInstruction {
time, time,
instruction: crate::physics_worker::Instruction::SetPaused(!state), instruction: crate::physics_worker::Instruction::SetPaused(!state),
}).unwrap(); })
.unwrap();
//recalculate pressed keys on focus //recalculate pressed keys on focus
}, }
winit::event::WindowEvent::KeyboardInput { winit::event::WindowEvent::KeyboardInput {
event:winit::event::KeyEvent{state,logical_key,repeat:false,..}, event:
winit::event::KeyEvent {
state,
logical_key,
repeat: false,
..
},
.. ..
} => { } => {
match (logical_key, state) { match (logical_key, state) {
(winit::keyboard::Key::Named(winit::keyboard::NamedKey::Tab),winit::event::ElementState::Pressed)=>{ (
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Tab),
winit::event::ElementState::Pressed,
) => {
self.manual_mouse_lock = false; self.manual_mouse_lock = false;
match self.window.set_cursor_position(self.get_middle_of_screen()) { match self.window.set_cursor_position(self.get_middle_of_screen()) {
Ok(()) => (), Ok(()) => (),
Err(e) => println!("Could not set cursor position: {:?}", e), Err(e) => println!("Could not set cursor position: {:?}", e),
} }
match self.window.set_cursor_grab(winit::window::CursorGrabMode::None){ match self
.window
.set_cursor_grab(winit::window::CursorGrabMode::None)
{
Ok(()) => (), Ok(()) => (),
Err(e) => println!("Could not release cursor: {:?}", e), Err(e) => println!("Could not release cursor: {:?}", e),
} }
self.window.set_cursor_visible(state.is_pressed()); self.window.set_cursor_visible(state.is_pressed());
}, }
(winit::keyboard::Key::Named(winit::keyboard::NamedKey::Tab),winit::event::ElementState::Released)=>{ (
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Tab),
winit::event::ElementState::Released,
) => {
//if cursor is outside window don't lock but apparently there's no get pos function //if cursor is outside window don't lock but apparently there's no get pos function
//let pos=window.get_cursor_pos(); //let pos=window.get_cursor_pos();
match self.window.set_cursor_grab(winit::window::CursorGrabMode::Locked){ match self
.window
.set_cursor_grab(winit::window::CursorGrabMode::Locked)
{
Ok(()) => (), Ok(()) => (),
Err(_) => { Err(_) => {
match self.window.set_cursor_grab(winit::window::CursorGrabMode::Confined){ match self
.window
.set_cursor_grab(winit::window::CursorGrabMode::Confined)
{
Ok(()) => (), Ok(()) => (),
Err(e) => { Err(e) => {
self.manual_mouse_lock = true; self.manual_mouse_lock = true;
println!("Could not confine cursor: {:?}", e) println!("Could not confine cursor: {:?}", e)
}, }
} }
} }
} }
self.window.set_cursor_visible(state.is_pressed()); self.window.set_cursor_visible(state.is_pressed());
}, }
(winit::keyboard::Key::Named(winit::keyboard::NamedKey::F11),winit::event::ElementState::Pressed)=>{ (
winit::keyboard::Key::Named(winit::keyboard::NamedKey::F11),
winit::event::ElementState::Pressed,
) => {
if self.window.fullscreen().is_some() { if self.window.fullscreen().is_some() {
self.window.set_fullscreen(None); self.window.set_fullscreen(None);
} else { } else {
self.window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(None))); self.window
.set_fullscreen(Some(winit::window::Fullscreen::Borderless(None)));
} }
}, }
(winit::keyboard::Key::Named(winit::keyboard::NamedKey::Escape),winit::event::ElementState::Pressed)=>{ (
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Escape),
winit::event::ElementState::Pressed,
) => {
self.manual_mouse_lock = false; self.manual_mouse_lock = false;
match self.window.set_cursor_grab(winit::window::CursorGrabMode::None){ match self
.window
.set_cursor_grab(winit::window::CursorGrabMode::None)
{
Ok(()) => (), Ok(()) => (),
Err(e) => println!("Could not release cursor: {:?}", e), Err(e) => println!("Could not release cursor: {:?}", e),
} }
self.window.set_cursor_visible(true); self.window.set_cursor_visible(true);
}, }
(keycode, state) => { (keycode, state) => {
let s = state.is_pressed(); let s = state.is_pressed();
if let Some(input_instruction) = match keycode { if let Some(input_instruction) = match keycode {
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Space)=>Some(InputInstruction::Jump(s)), winit::keyboard::Key::Named(winit::keyboard::NamedKey::Space) => {
Some(InputInstruction::Jump(s))
}
winit::keyboard::Key::Character(key) => match key.as_str() { winit::keyboard::Key::Character(key) => match key.as_str() {
"W" | "w" => Some(InputInstruction::MoveForward(s)), "W" | "w" => Some(InputInstruction::MoveForward(s)),
"A" | "a" => Some(InputInstruction::MoveLeft(s)), "A" | "a" => Some(InputInstruction::MoveLeft(s)),
@ -101,24 +145,39 @@ impl WindowContext<'_>{
"E" | "e" => Some(InputInstruction::MoveUp(s)), "E" | "e" => Some(InputInstruction::MoveUp(s)),
"Q" | "q" => Some(InputInstruction::MoveDown(s)), "Q" | "q" => Some(InputInstruction::MoveDown(s)),
"Z" | "z" => Some(InputInstruction::Zoom(s)), "Z" | "z" => Some(InputInstruction::Zoom(s)),
"R"|"r"=>if s{ "R" | "r" => {
if s {
//mouse needs to be reset since the position is absolute //mouse needs to be reset since the position is absolute
self.mouse=strafesnet_common::mouse::MouseState::default(); self.mouse =
strafesnet_common::mouse::MouseState::default();
Some(InputInstruction::ResetAndRestart) Some(InputInstruction::ResetAndRestart)
}else{None}, } else {
"F"|"f"=>if s{Some(InputInstruction::PracticeFly)}else{None}, None
}
}
"F" | "f" => {
if s {
Some(InputInstruction::PracticeFly)
} else {
None
}
}
_ => None, _ => None,
}, },
_ => None, _ => None,
} { } {
self.physics_thread.send(TimedInstruction{ self.physics_thread
.send(TimedInstruction {
time, time,
instruction:crate::physics_worker::Instruction::Input(input_instruction), instruction: crate::physics_worker::Instruction::Input(
}).unwrap(); input_instruction,
),
})
.unwrap();
}
}
} }
},
} }
},
_ => (), _ => (),
} }
} }
@ -139,22 +198,29 @@ impl WindowContext<'_>{
//which is fine because they run all the time. //which is fine because they run all the time.
let delta = glam::ivec2(delta.0 as i32, delta.1 as i32); let delta = glam::ivec2(delta.0 as i32, delta.1 as i32);
self.mouse.pos += delta; self.mouse.pos += delta;
self.physics_thread.send(TimedInstruction{ self.physics_thread
.send(TimedInstruction {
time, time,
instruction:crate::physics_worker::Instruction::Input(InputInstruction::MoveMouse(self.mouse.pos)), instruction: crate::physics_worker::Instruction::Input(
}).unwrap(); InputInstruction::MoveMouse(self.mouse.pos),
}, ),
winit::event::DeviceEvent::MouseWheel { })
delta, .unwrap();
}=>{ }
println!("mousewheel {:?}",delta); winit::event::DeviceEvent::MouseWheel { delta } => {
if false{//self.physics.style.use_scroll{ println!("mousewheel {:?}", delta);
self.physics_thread.send(TimedInstruction{ if false {
time, //self.physics.style.use_scroll{
instruction:crate::physics_worker::Instruction::Input(InputInstruction::Jump(true)),//activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump self.physics_thread
}).unwrap(); .send(TimedInstruction {
time,
instruction: crate::physics_worker::Instruction::Input(
InputInstruction::Jump(true),
), //activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump
})
.unwrap();
}
} }
},
_ => (), _ => (),
} }
} }
@ -166,52 +232,61 @@ pub fn worker<'a>(
// WindowContextSetup::new // WindowContextSetup::new
let user_settings = crate::settings::read_user_settings(); let user_settings = crate::settings::read_user_settings();
let mut graphics=crate::graphics::GraphicsState::new(&setup_context.device,&setup_context.queue,&setup_context.config); let mut graphics = crate::graphics::GraphicsState::new(
&setup_context.device,
&setup_context.queue,
&setup_context.config,
);
graphics.load_user_settings(&user_settings); graphics.load_user_settings(&user_settings);
//WindowContextSetup::into_context //WindowContextSetup::into_context
let screen_size = glam::uvec2(setup_context.config.width, setup_context.config.height); let screen_size = glam::uvec2(setup_context.config.width, setup_context.config.height);
let graphics_thread=crate::graphics_worker::new(graphics,setup_context.config,setup_context.surface,setup_context.device,setup_context.queue); let graphics_thread = crate::graphics_worker::new(
graphics,
setup_context.config,
setup_context.surface,
setup_context.device,
setup_context.queue,
);
let mut window_context = WindowContext { let mut window_context = WindowContext {
manual_mouse_lock: false, manual_mouse_lock: false,
mouse: strafesnet_common::mouse::MouseState::default(), mouse: strafesnet_common::mouse::MouseState::default(),
//make sure to update this!!!!! //make sure to update this!!!!!
screen_size, screen_size,
window, window,
physics_thread:crate::physics_worker::new( physics_thread: crate::physics_worker::new(graphics_thread, user_settings),
graphics_thread,
user_settings,
),
}; };
//WindowContextSetup::into_worker //WindowContextSetup::into_worker
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<WindowInstruction,SessionTimeInner>|{ crate::compat_worker::QNWorker::new(
match ins.instruction{ move |ins: TimedInstruction<WindowInstruction, SessionTimeInner>| match ins.instruction {
WindowInstruction::RequestRedraw => { WindowInstruction::RequestRedraw => {
window_context.window.request_redraw(); window_context.window.request_redraw();
} }
WindowInstruction::WindowEvent(window_event) => { WindowInstruction::WindowEvent(window_event) => {
window_context.window_event(ins.time, window_event); window_context.window_event(ins.time, window_event);
}, }
WindowInstruction::DeviceEvent(device_event) => { WindowInstruction::DeviceEvent(device_event) => {
window_context.device_event(ins.time, device_event); window_context.device_event(ins.time, device_event);
},
WindowInstruction::Resize(size)=>{
window_context.physics_thread.send(
TimedInstruction{
time:ins.time,
instruction:crate::physics_worker::Instruction::Resize(size)
} }
).unwrap(); WindowInstruction::Resize(size) => {
window_context
.physics_thread
.send(TimedInstruction {
time: ins.time,
instruction: crate::physics_worker::Instruction::Resize(size),
})
.unwrap();
} }
WindowInstruction::Render => { WindowInstruction::Render => {
window_context.physics_thread.send( window_context
TimedInstruction{ .physics_thread
.send(TimedInstruction {
time: ins.time, time: ins.time,
instruction:crate::physics_worker::Instruction::Render instruction: crate::physics_worker::Instruction::Render,
}
).unwrap();
}
}
}) })
.unwrap();
}
},
)
} }

View File

@ -1,6 +1,6 @@
use std::thread;
use std::sync::{mpsc,Arc};
use parking_lot::Mutex; use parking_lot::Mutex;
use std::sync::{mpsc, Arc};
use std::thread;
//WorkerPool //WorkerPool
struct Pool(u32); struct Pool(u32);
@ -110,10 +110,12 @@ pub struct QNWorker<'a,Task:Send>{
} }
impl<'a, Task: Send + 'a> QNWorker<'a, Task> { impl<'a, Task: Send + 'a> QNWorker<'a, Task> {
pub fn new<F:FnMut(Task)+Send+'a>(scope:&'a thread::Scope<'a,'_>,mut f:F)->QNWorker<'a,Task>{ pub fn new<F: FnMut(Task) + Send + 'a>(
scope: &'a thread::Scope<'a, '_>,
mut f: F,
) -> QNWorker<'a, Task> {
let (sender, receiver) = mpsc::channel::<Task>(); let (sender, receiver) = mpsc::channel::<Task>();
let handle=scope.spawn(move ||{ let handle = scope.spawn(move || loop {
loop {
match receiver.recv() { match receiver.recv() {
Ok(task) => f(task), Ok(task) => f(task),
Err(_) => { Err(_) => {
@ -121,12 +123,8 @@ impl<'a,Task:Send+'a> QNWorker<'a,Task>{
break; break;
} }
} }
}
}); });
Self{ Self { sender, handle }
sender,
handle,
}
} }
pub fn send(&self, task: Task) -> Result<(), mpsc::SendError<Task>> { pub fn send(&self, task: Task) -> Result<(), mpsc::SendError<Task>> {
self.sender.send(task) self.sender.send(task)
@ -146,10 +144,12 @@ pub struct INWorker<'a,Task:Send>{
} }
impl<'a, Task: Send + 'a> INWorker<'a, Task> { impl<'a, Task: Send + 'a> INWorker<'a, Task> {
pub fn new<F:FnMut(Task)+Send+'a>(scope:&'a thread::Scope<'a,'_>,mut f:F)->INWorker<'a,Task>{ pub fn new<F: FnMut(Task) + Send + 'a>(
scope: &'a thread::Scope<'a, '_>,
mut f: F,
) -> INWorker<'a, Task> {
let (sender, receiver) = mpsc::sync_channel::<Task>(1); let (sender, receiver) = mpsc::sync_channel::<Task>(1);
let handle=scope.spawn(move ||{ let handle = scope.spawn(move || loop {
loop {
match receiver.recv() { match receiver.recv() {
Ok(task) => f(task), Ok(task) => f(task),
Err(_) => { Err(_) => {
@ -157,12 +157,8 @@ impl<'a,Task:Send+'a> INWorker<'a,Task>{
break; break;
} }
} }
}
}); });
Self{ Self { sender, handle }
sender,
handle,
}
} }
//blocking! //blocking!
pub fn blocking_send(&self, task: Task) -> Result<(), mpsc::SendError<Task>> { pub fn blocking_send(&self, task: Task) -> Result<(), mpsc::SendError<Task>> {
@ -177,14 +173,24 @@ impl<'a,Task:Send+'a> INWorker<'a,Task>{
mod test { mod test {
use super::{thread, QRWorker}; use super::{thread, QRWorker};
type Body = crate::physics::Body; type Body = crate::physics::Body;
use strafesnet_common::{integer,instruction}; use strafesnet_common::{instruction, integer};
#[test] //How to run this test with printing: cargo test --release -- --nocapture #[test] //How to run this test with printing: cargo test --release -- --nocapture
fn test_worker() { fn test_worker() {
// Create the worker thread // Create the worker thread
let test_body=Body::new(integer::vec3::ONE,integer::vec3::ONE,integer::vec3::ONE,integer::Time::ZERO); let test_body = Body::new(
let worker=QRWorker::new(Body::ZERO, integer::vec3::ONE,
|_|Body::new(integer::vec3::ONE,integer::vec3::ONE,integer::vec3::ONE,integer::Time::ZERO) integer::vec3::ONE,
integer::vec3::ONE,
integer::Time::ZERO,
); );
let worker = QRWorker::new(Body::ZERO, |_| {
Body::new(
integer::vec3::ONE,
integer::vec3::ONE,
integer::vec3::ONE,
integer::Time::ZERO,
)
});
// Send tasks to the worker // Send tasks to the worker
for _ in 0..5 { for _ in 0..5 {