Compare commits
58 Commits
file-forma
...
integer-un
| Author | SHA1 | Date | |
|---|---|---|---|
| 22fa3ee81b | |||
| 3a8655c343 | |||
| 691c3e0482 | |||
| 1dfc566453 | |||
| 762f10fb01 | |||
| 8fba543684 | |||
| 8c90eb1d94 | |||
| b9e200e070 | |||
| e0e55c6883 | |||
| 0195511e49 | |||
| 7b09b3333b | |||
| cf202f52f0 | |||
| 35e8856e0f | |||
| 1271797a66 | |||
| 6bb9db739c | |||
| 9152237f2c | |||
| 282329fb33 | |||
| c88451c0f0 | |||
| 5f1d732b59 | |||
| d33b830338 | |||
| 80b1d25a13 | |||
| bf6f37fa00 | |||
| fa8ea26ddc | |||
| f5d6280e0a | |||
| 4e98e9a577 | |||
| 8fea9e0025 | |||
| ac2f1d3eac | |||
| bcab0d92fd | |||
| 36a5298b6d | |||
| cea85a099d | |||
| 9cc1674624 | |||
| 7d33f69a47 | |||
| 9cb42009cb | |||
| bcd421c4dd | |||
| 4d62042549 | |||
| fcf4d05baa | |||
| 2f33a28c95 | |||
| d939fbff94 | |||
| 9ca2f0a194 | |||
| 4bbd11dbb6 | |||
| 10a293e789 | |||
| 01b5769dc0 | |||
| 7f7b0d92e6 | |||
| 3b7a1d5dff | |||
| 7309949dd0 | |||
| 43a0eef5d1 | |||
| 76cd82967a | |||
| 69712847e3 | |||
| a8f82a14a9 | |||
| 101c92cba4 | |||
| 54ec21c490 | |||
| f16bc043c4 | |||
| 4616fd7b3b | |||
| b6b63b4c85 | |||
| c21c587edc | |||
| 9a12265881 | |||
| 3ff73ed0bc | |||
| 57386334af |
@@ -12,12 +12,12 @@ use crate::aabb::Aabb;
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct BvhNode{
|
pub struct BvhNode{
|
||||||
children:Vec<Self>,
|
children:Vec<Self>,
|
||||||
models:Vec<usize>,
|
models:Vec<u32>,
|
||||||
aabb:Aabb,
|
aabb:Aabb,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BvhNode{
|
impl BvhNode{
|
||||||
pub fn the_tester<F:FnMut(usize)>(&self,aabb:&Aabb,f:&mut F){
|
pub fn the_tester<F:FnMut(u32)>(&self,aabb:&Aabb,f:&mut F){
|
||||||
for &model in &self.models{
|
for &model in &self.models{
|
||||||
f(model);
|
f(model);
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ fn generate_bvh_node(boxen:Vec<(usize,Aabb)>)->BvhNode{
|
|||||||
let n=boxen.len();
|
let n=boxen.len();
|
||||||
if n<20{
|
if n<20{
|
||||||
let mut aabb=Aabb::default();
|
let mut aabb=Aabb::default();
|
||||||
let models=boxen.into_iter().map(|b|{aabb.join(&b.1);b.0}).collect();
|
let models=boxen.into_iter().map(|b|{aabb.join(&b.1);b.0 as u32}).collect();
|
||||||
BvhNode{
|
BvhNode{
|
||||||
children:Vec::new(),
|
children:Vec::new(),
|
||||||
models,
|
models,
|
||||||
|
|||||||
@@ -421,17 +421,14 @@ impl Planar64{
|
|||||||
pub const fn get(&self)->i64{
|
pub const fn get(&self)->i64{
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
pub fn sqrt(&self)->Self{
|
|
||||||
Planar64(unsafe{(((self.0 as i128)<<32) as f64).sqrt().to_int_unchecked()})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const PLANAR64_ONE_FLOAT32:f32=(1u64<<32) as f32;
|
const PLANAR64_FLOAT32_ONE:f32=(1u64<<32) as f32;
|
||||||
const PLANAR64_CONVERT_TO_FLOAT32:f32=1.0/PLANAR64_ONE_FLOAT32;
|
const PLANAR64_FLOAT32_MUL:f32=1.0/PLANAR64_FLOAT32_ONE;
|
||||||
const PLANAR64_ONE_FLOAT64:f64=(1u64<<32) as f64;
|
const PLANAR64_FLOAT64_ONE:f64=(1u64<<32) as f64;
|
||||||
impl Into<f32> for Planar64{
|
impl Into<f32> for Planar64{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into(self)->f32{
|
fn into(self)->f32{
|
||||||
self.0 as f32*PLANAR64_CONVERT_TO_FLOAT32
|
self.0 as f32*PLANAR64_FLOAT32_MUL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<Ratio64> for Planar64{
|
impl From<Ratio64> for Planar64{
|
||||||
@@ -531,14 +528,7 @@ impl std::ops::Mul<Planar64> for Planar64{
|
|||||||
type Output=Planar64;
|
type Output=Planar64;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, rhs: Self) -> Self::Output {
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
Planar64(((self.0 as i128*rhs.0 as i128)>>32) as i64)
|
Planar64((((self.0 as i128)*(rhs.0 as i128))>>32) as i64)
|
||||||
}
|
|
||||||
}
|
|
||||||
impl std::ops::Mul<Time> for Planar64{
|
|
||||||
type Output=Planar64;
|
|
||||||
#[inline]
|
|
||||||
fn mul(self,rhs:Time)->Self::Output{
|
|
||||||
Planar64(((self.0 as i128*rhs.0 as i128)/1_000_000_000) as i64)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl std::ops::Div<i64> for Planar64{
|
impl std::ops::Div<i64> for Planar64{
|
||||||
@@ -581,10 +571,6 @@ impl Planar64Vec3{
|
|||||||
Self(glam::i64vec3((x as i64)<<32,(y as i64)<<32,(z as i64)<<32))
|
Self(glam::i64vec3((x as i64)<<32,(y as i64)<<32,(z as i64)<<32))
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn raw(x:i64,y:i64,z:i64)->Self{
|
|
||||||
Self(glam::i64vec3(x,y,z))
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn x(&self)->Planar64{
|
pub fn x(&self)->Planar64{
|
||||||
Planar64(self.0.x)
|
Planar64(self.0.x)
|
||||||
}
|
}
|
||||||
@@ -654,7 +640,7 @@ impl Into<glam::Vec3> for Planar64Vec3{
|
|||||||
self.0.x as f32,
|
self.0.x as f32,
|
||||||
self.0.y as f32,
|
self.0.y as f32,
|
||||||
self.0.z as f32,
|
self.0.z as f32,
|
||||||
)*PLANAR64_CONVERT_TO_FLOAT32
|
)*PLANAR64_FLOAT32_MUL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TryFrom<[f32;3]> for Planar64Vec3{
|
impl TryFrom<[f32;3]> for Planar64Vec3{
|
||||||
@@ -819,27 +805,10 @@ impl Planar64Mat3{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_rotation_yx(yaw:Angle32,pitch:Angle32)->Self{
|
|
||||||
let xtheta=yaw.0 as f64*ANGLE32_TO_FLOAT64_RADIANS;
|
|
||||||
let (xs,xc)=xtheta.sin_cos();
|
|
||||||
let (xc,xs)=(xc*PLANAR64_ONE_FLOAT64,xs*PLANAR64_ONE_FLOAT64);
|
|
||||||
let ytheta=pitch.0 as f64*ANGLE32_TO_FLOAT64_RADIANS;
|
|
||||||
let (ys,yc)=ytheta.sin_cos();
|
|
||||||
let (yc,ys)=(yc*PLANAR64_ONE_FLOAT64,ys*PLANAR64_ONE_FLOAT64);
|
|
||||||
//TODO: fix this rounding towards 0
|
|
||||||
let (xc,xs):(i64,i64)=(unsafe{xc.to_int_unchecked()},unsafe{xs.to_int_unchecked()});
|
|
||||||
let (yc,ys):(i64,i64)=(unsafe{yc.to_int_unchecked()},unsafe{ys.to_int_unchecked()});
|
|
||||||
Self::from_cols(
|
|
||||||
Planar64Vec3(glam::i64vec3(xc,0,-xs)),
|
|
||||||
Planar64Vec3(glam::i64vec3(((xs as i128*ys as i128)>>32) as i64,yc,((xc as i128*ys as i128)>>32) as i64)),
|
|
||||||
Planar64Vec3(glam::i64vec3(((xs as i128*yc as i128)>>32) as i64,-ys,((xc as i128*yc as i128)>>32) as i64)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn from_rotation_y(angle:Angle32)->Self{
|
pub fn from_rotation_y(angle:Angle32)->Self{
|
||||||
let theta=angle.0 as f64*ANGLE32_TO_FLOAT64_RADIANS;
|
let theta=angle.0 as f64*ANGLE32_TO_FLOAT64_RADIANS;
|
||||||
let (s,c)=theta.sin_cos();
|
let (s,c)=theta.sin_cos();
|
||||||
let (c,s)=(c*PLANAR64_ONE_FLOAT64,s*PLANAR64_ONE_FLOAT64);
|
let (c,s)=(c*PLANAR64_FLOAT64_ONE,s*PLANAR64_FLOAT64_ONE);
|
||||||
//TODO: fix this rounding towards 0
|
//TODO: fix this rounding towards 0
|
||||||
let (c,s):(i64,i64)=(unsafe{c.to_int_unchecked()},unsafe{s.to_int_unchecked()});
|
let (c,s):(i64,i64)=(unsafe{c.to_int_unchecked()},unsafe{s.to_int_unchecked()});
|
||||||
Self::from_cols(
|
Self::from_cols(
|
||||||
@@ -920,8 +889,8 @@ impl Into<glam::Mat4> for Planar64Affine3{
|
|||||||
self.matrix3.x_axis.0.x as f32,self.matrix3.x_axis.0.y as f32,self.matrix3.x_axis.0.z as f32,0.0,
|
self.matrix3.x_axis.0.x as f32,self.matrix3.x_axis.0.y as f32,self.matrix3.x_axis.0.z as f32,0.0,
|
||||||
self.matrix3.y_axis.0.x as f32,self.matrix3.y_axis.0.y as f32,self.matrix3.y_axis.0.z as f32,0.0,
|
self.matrix3.y_axis.0.x as f32,self.matrix3.y_axis.0.y as f32,self.matrix3.y_axis.0.z as f32,0.0,
|
||||||
self.matrix3.z_axis.0.x as f32,self.matrix3.z_axis.0.y as f32,self.matrix3.z_axis.0.z as f32,0.0,
|
self.matrix3.z_axis.0.x as f32,self.matrix3.z_axis.0.y as f32,self.matrix3.z_axis.0.z as f32,0.0,
|
||||||
self.translation.0.x as f32,self.translation.0.y as f32,self.translation.0.z as f32,PLANAR64_ONE_FLOAT32
|
self.translation.0.x as f32,self.translation.0.y as f32,self.translation.0.z as f32,PLANAR64_FLOAT32_ONE
|
||||||
])*PLANAR64_CONVERT_TO_FLOAT32
|
])*PLANAR64_FLOAT32_MUL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TryFrom<glam::Affine3A> for Planar64Affine3{
|
impl TryFrom<glam::Affine3A> for Planar64Affine3{
|
||||||
@@ -942,12 +911,4 @@ impl std::fmt::Display for Planar64Affine3{
|
|||||||
Into::<f32>::into(self.matrix3.z_axis.x()),Into::<f32>::into(self.matrix3.z_axis.y()),Into::<f32>::into(self.matrix3.z_axis.z()),
|
Into::<f32>::into(self.matrix3.z_axis.x()),Into::<f32>::into(self.matrix3.z_axis.y()),Into::<f32>::into(self.matrix3.z_axis.z()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sqrt(){
|
|
||||||
let r=Planar64::int(400);
|
|
||||||
println!("r{}",r.get());
|
|
||||||
let s=r.sqrt();
|
|
||||||
println!("s{}",s.get());
|
|
||||||
}
|
}
|
||||||
@@ -50,29 +50,20 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse
|
|||||||
let mut contacting=crate::model::ContactingAttributes::default();
|
let mut contacting=crate::model::ContactingAttributes::default();
|
||||||
let mut force_can_collide=can_collide;
|
let mut force_can_collide=can_collide;
|
||||||
match name{
|
match name{
|
||||||
"Water"=>{
|
//"Water"=>intersecting.water=Some(crate::model::IntersectingWater{density:1.0,drag:1.0}),
|
||||||
force_can_collide=false;
|
"Accelerator"=>{force_can_collide=false;intersecting.accelerator=Some(crate::model::IntersectingAccelerator{acceleration:velocity})},
|
||||||
//TODO: read stupid CustomPhysicalProperties
|
|
||||||
intersecting.water=Some(crate::model::IntersectingWater{density:Planar64::ONE,viscosity:Planar64::ONE/10,current:velocity});
|
|
||||||
},
|
|
||||||
"Accelerator"=>{
|
|
||||||
//although the new game supports collidable accelerators, this is a roblox compatability map loader
|
|
||||||
force_can_collide=false;
|
|
||||||
general.accelerator=Some(crate::model::GameMechanicAccelerator{acceleration:velocity});
|
|
||||||
},
|
|
||||||
"SetVelocity"=>general.trajectory=Some(crate::model::GameMechanicSetTrajectory::Velocity(velocity)),
|
|
||||||
"MapFinish"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Finish})},
|
"MapFinish"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Finish})},
|
||||||
"MapAnticheat"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Anitcheat})},
|
"MapAnticheat"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Anitcheat})},
|
||||||
"Platform"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{
|
"Platform"=>general.stage_element=Some(crate::model::GameMechanicStageElement{
|
||||||
mode_id:0,
|
mode_id:0,
|
||||||
stage_id:0,
|
stage_id:0,
|
||||||
force:false,
|
force:false,
|
||||||
behaviour:crate::model::StageElementBehaviour::Platform,
|
behaviour:crate::model::StageElementBehaviour::Platform,
|
||||||
})),
|
}),
|
||||||
other=>{
|
other=>{
|
||||||
if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Spawn|SpawnAt|Trigger|Teleport|Platform)(\d+)$")
|
if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Spawn|SpawnAt|Trigger|Teleport|Platform)(\d+)$")
|
||||||
.captures(other){
|
.captures(other){
|
||||||
general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{
|
general.stage_element=Some(crate::model::GameMechanicStageElement{
|
||||||
mode_id:0,
|
mode_id:0,
|
||||||
stage_id:captures[3].parse::<u32>().unwrap(),
|
stage_id:captures[3].parse::<u32>().unwrap(),
|
||||||
force:match captures.get(1){
|
force:match captures.get(1){
|
||||||
@@ -81,28 +72,12 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse
|
|||||||
},
|
},
|
||||||
behaviour:match &captures[2]{
|
behaviour:match &captures[2]{
|
||||||
"Spawn"|"SpawnAt"=>crate::model::StageElementBehaviour::SpawnAt,
|
"Spawn"|"SpawnAt"=>crate::model::StageElementBehaviour::SpawnAt,
|
||||||
//cancollide false so you don't hit the side
|
|
||||||
//NOT a decoration
|
|
||||||
"Trigger"=>{force_can_collide=false;crate::model::StageElementBehaviour::Trigger},
|
"Trigger"=>{force_can_collide=false;crate::model::StageElementBehaviour::Trigger},
|
||||||
"Teleport"=>{force_can_collide=false;crate::model::StageElementBehaviour::Teleport},
|
"Teleport"=>{force_can_collide=false;crate::model::StageElementBehaviour::Teleport},
|
||||||
"Platform"=>crate::model::StageElementBehaviour::Platform,
|
"Platform"=>crate::model::StageElementBehaviour::Platform,
|
||||||
_=>panic!("regex1[2] messed up bad"),
|
_=>panic!("regex1[2] messed up bad"),
|
||||||
}
|
}
|
||||||
}));
|
})
|
||||||
}else if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Jump)(\d+)$")
|
|
||||||
.captures(other){
|
|
||||||
general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{
|
|
||||||
mode_id:0,
|
|
||||||
stage_id:0,
|
|
||||||
force:match captures.get(1){
|
|
||||||
Some(m)=>m.as_str()=="Force",
|
|
||||||
None=>false,
|
|
||||||
},
|
|
||||||
behaviour:match &captures[2]{
|
|
||||||
"Jump"=>crate::model::StageElementBehaviour::JumpLimit(captures[3].parse::<u32>().unwrap()),
|
|
||||||
_=>panic!("regex4[1] messed up bad"),
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}else if let Some(captures)=lazy_regex::regex!(r"^Bonus(Finish|Anticheat)(\d+)$")
|
}else if let Some(captures)=lazy_regex::regex!(r"^Bonus(Finish|Anticheat)(\d+)$")
|
||||||
.captures(other){
|
.captures(other){
|
||||||
force_can_collide=false;
|
force_can_collide=false;
|
||||||
@@ -111,33 +86,35 @@ fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_interse
|
|||||||
"Anticheat"=>general.zone=Some(crate::model::GameMechanicZone{mode_id:captures[2].parse::<u32>().unwrap(),behaviour:crate::model::ZoneBehaviour::Anitcheat}),
|
"Anticheat"=>general.zone=Some(crate::model::GameMechanicZone{mode_id:captures[2].parse::<u32>().unwrap(),behaviour:crate::model::ZoneBehaviour::Anitcheat}),
|
||||||
_=>panic!("regex2[1] messed up bad"),
|
_=>panic!("regex2[1] messed up bad"),
|
||||||
}
|
}
|
||||||
}else if let Some(captures)=lazy_regex::regex!(r"^(WormholeIn)(\d+)$")
|
|
||||||
.captures(other){
|
|
||||||
force_can_collide=false;
|
|
||||||
match &captures[1]{
|
|
||||||
"WormholeIn"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::Wormhole(crate::model::GameMechanicWormhole{destination_model_id:captures[2].parse::<u32>().unwrap()})),
|
|
||||||
_=>panic!("regex3[1] messed up bad"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//need some way to skip this
|
//need some way to skip this
|
||||||
if velocity!=Planar64Vec3::ZERO{
|
if velocity!=Planar64Vec3::ZERO{
|
||||||
general.booster=Some(crate::model::GameMechanicBooster::Velocity(velocity));
|
general.booster=Some(crate::model::GameMechanicBooster{velocity});
|
||||||
}
|
}
|
||||||
match force_can_collide{
|
match force_can_collide{
|
||||||
true=>{
|
true=>{
|
||||||
match name{
|
match name{
|
||||||
"Bounce"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Elastic(u32::MAX)),
|
//"Bounce"=>(),
|
||||||
"Surf"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Surf),
|
"Surf"=>contacting.surf=Some(crate::model::ContactingSurf{}),
|
||||||
"Ladder"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Ladder(crate::model::ContactingLadder{sticky:true})),
|
"Ladder"=>contacting.ladder=Some(crate::model::ContactingLadder{sticky:true}),
|
||||||
_=>(),
|
other=>{
|
||||||
|
//REGEX!!!!
|
||||||
|
//Jump#
|
||||||
|
//WormholeIn#
|
||||||
|
}
|
||||||
}
|
}
|
||||||
crate::model::CollisionAttributes::Contact{contacting,general}
|
crate::model::CollisionAttributes::Contact{contacting,general}
|
||||||
},
|
},
|
||||||
false=>if force_intersecting
|
false=>if force_intersecting
|
||||||
||general.any()
|
||general.jump_limit.is_some()
|
||||||
||intersecting.any()
|
||general.booster.is_some()
|
||||||
|
||general.zone.is_some()
|
||||||
|
||general.stage_element.is_some()
|
||||||
|
||general.wormhole.is_some()
|
||||||
|
||intersecting.water.is_some()
|
||||||
|
||intersecting.accelerator.is_some()
|
||||||
{
|
{
|
||||||
crate::model::CollisionAttributes::Intersect{intersecting,general}
|
crate::model::CollisionAttributes::Intersect{intersecting,general}
|
||||||
}else{
|
}else{
|
||||||
@@ -263,17 +240,16 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::Index
|
|||||||
if let Some(attr)=match &object.name[..]{
|
if let Some(attr)=match &object.name[..]{
|
||||||
"MapStart"=>{
|
"MapStart"=>{
|
||||||
spawn_point=model_transform.transform_point3(Planar64Vec3::ZERO)+Planar64Vec3::Y*5/2;
|
spawn_point=model_transform.transform_point3(Planar64Vec3::ZERO)+Planar64Vec3::Y*5/2;
|
||||||
Some(crate::model::TempIndexedAttributes::Start(crate::model::TempAttrStart{mode_id:0}))
|
Some(crate::model::TempIndexedAttributes::Start{mode_id:0})
|
||||||
},
|
},
|
||||||
"UnorderedCheckpoint"=>Some(crate::model::TempIndexedAttributes::UnorderedCheckpoint(crate::model::TempAttrUnorderedCheckpoint{mode_id:0})),
|
"UnorderedCheckpoint"=>Some(crate::model::TempIndexedAttributes::UnorderedCheckpoint{mode_id:0}),
|
||||||
other=>{
|
other=>{
|
||||||
let regman=lazy_regex::regex!(r"^(BonusStart|Spawn|ForceSpawn|OrderedCheckpoint|WormholeOut)(\d+)$");
|
let regman=lazy_regex::regex!(r"^(BonusStart|Spawn|ForceSpawn|OrderedCheckpoint)(\d+)$");
|
||||||
if let Some(captures) = regman.captures(other) {
|
if let Some(captures) = regman.captures(other) {
|
||||||
match &captures[1]{
|
match &captures[1]{
|
||||||
"BonusStart"=>Some(crate::model::TempIndexedAttributes::Start(crate::model::TempAttrStart{mode_id:captures[2].parse::<u32>().unwrap()})),
|
"BonusStart"=>Some(crate::model::TempIndexedAttributes::Start{mode_id:captures[2].parse::<u32>().unwrap()}),
|
||||||
"Spawn"|"ForceSpawn"=>Some(crate::model::TempIndexedAttributes::Spawn(crate::model::TempAttrSpawn{mode_id:0,stage_id:captures[2].parse::<u32>().unwrap()})),
|
"Spawn"|"ForceSpawn"=>Some(crate::model::TempIndexedAttributes::Spawn{mode_id:0,stage_id:captures[2].parse::<u32>().unwrap()}),
|
||||||
"OrderedCheckpoint"=>Some(crate::model::TempIndexedAttributes::OrderedCheckpoint(crate::model::TempAttrOrderedCheckpoint{mode_id:0,checkpoint_id:captures[2].parse::<u32>().unwrap()})),
|
"OrderedCheckpoint"=>Some(crate::model::TempIndexedAttributes::OrderedCheckpoint{mode_id:0,checkpoint_id:captures[2].parse::<u32>().unwrap()}),
|
||||||
"WormholeOut"=>Some(crate::model::TempIndexedAttributes::Wormhole(crate::model::TempAttrWormhole{wormhole_id:captures[2].parse::<u32>().unwrap()})),
|
|
||||||
_=>None,
|
_=>None,
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
187
src/main.rs
187
src/main.rs
@@ -11,7 +11,6 @@ mod model_graphics;
|
|||||||
mod zeroes;
|
mod zeroes;
|
||||||
mod worker;
|
mod worker;
|
||||||
mod physics;
|
mod physics;
|
||||||
mod sniffer;
|
|
||||||
mod settings;
|
mod settings;
|
||||||
mod framework;
|
mod framework;
|
||||||
mod primitives;
|
mod primitives;
|
||||||
@@ -231,14 +230,10 @@ impl GlobalState{
|
|||||||
Some(ModelGraphicsInstance{
|
Some(ModelGraphicsInstance{
|
||||||
transform: instance.transform.into(),
|
transform: instance.transform.into(),
|
||||||
normal_transform: Into::<glam::Mat3>::into(instance.transform.matrix3).inverse().transpose(),
|
normal_transform: Into::<glam::Mat3>::into(instance.transform.matrix3).inverse().transpose(),
|
||||||
color:model_graphics::ModelGraphicsColor4::from(instance.color),
|
color: instance.color,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
//skip pushing a model if all instances are invisible
|
|
||||||
if instances.len()==0{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//check each group, if it's using a new texture then make a new clone of the model
|
//check each group, if it's using a new texture then make a new clone of the model
|
||||||
let id=unique_texture_models.len();
|
let id=unique_texture_models.len();
|
||||||
let mut unique_textures=Vec::new();
|
let mut unique_textures=Vec::new();
|
||||||
@@ -267,173 +262,9 @@ impl GlobalState{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//check every model to see if it's using the same (texture,color) but has few instances, if it is combine it into one model
|
|
||||||
//1. collect unique instances of texture and color, note model id
|
|
||||||
//2. for each model id, check if removing it from the pool decreases both the model count and instance count by more than one
|
|
||||||
//3. transpose all models that stay in the set
|
|
||||||
|
|
||||||
//best plan: benchmark set_bind_group, set_vertex_buffer, set_index_buffer and draw_indexed
|
|
||||||
//check if the estimated render performance is better by transposing multiple model instances into one model instance
|
|
||||||
|
|
||||||
//for now: just deduplicate single models...
|
|
||||||
let mut deduplicated_models=Vec::with_capacity(indexed_models_len);//use indexed_models_len because the list will likely get smaller instead of bigger
|
|
||||||
let mut unique_texture_color=std::collections::HashMap::new();//texture->color->vec![(model_id,instance_id)]
|
|
||||||
for (model_id,model) in unique_texture_models.iter().enumerate(){
|
|
||||||
//for now: filter out models with more than one instance
|
|
||||||
if 1<model.instances.len(){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//populate hashmap
|
|
||||||
let unique_color=if let Some(unique_color)=unique_texture_color.get_mut(&model.texture){
|
|
||||||
unique_color
|
|
||||||
}else{
|
|
||||||
//make new hashmap
|
|
||||||
let unique_color=std::collections::HashMap::new();
|
|
||||||
unique_texture_color.insert(model.texture,unique_color);
|
|
||||||
unique_texture_color.get_mut(&model.texture).unwrap()
|
|
||||||
};
|
|
||||||
//separate instances by color
|
|
||||||
for (instance_id,instance) in model.instances.iter().enumerate(){
|
|
||||||
let model_instance_list=if let Some(model_instance_list)=unique_color.get_mut(&instance.color){
|
|
||||||
model_instance_list
|
|
||||||
}else{
|
|
||||||
//make new hashmap
|
|
||||||
let model_instance_list=Vec::new();
|
|
||||||
unique_color.insert(instance.color.clone(),model_instance_list);
|
|
||||||
unique_color.get_mut(&instance.color).unwrap()
|
|
||||||
};
|
|
||||||
//add model instance to list
|
|
||||||
model_instance_list.push((model_id,instance_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//populate a hashset of models selected for transposition
|
|
||||||
//construct transposed models
|
|
||||||
let mut selected_model_instances=std::collections::HashSet::new();
|
|
||||||
for (texture,unique_color) in unique_texture_color.into_iter(){
|
|
||||||
for (color,model_instance_list) in unique_color.into_iter(){
|
|
||||||
//world transforming one model does not meet the definition of deduplicaiton
|
|
||||||
if 1<model_instance_list.len(){
|
|
||||||
//create model
|
|
||||||
let mut unique_pos=Vec::new();
|
|
||||||
let mut pos_id_from=std::collections::HashMap::new();
|
|
||||||
let mut unique_tex=Vec::new();
|
|
||||||
let mut tex_id_from=std::collections::HashMap::new();
|
|
||||||
let mut unique_normal=Vec::new();
|
|
||||||
let mut normal_id_from=std::collections::HashMap::new();
|
|
||||||
let mut unique_color=Vec::new();
|
|
||||||
let mut color_id_from=std::collections::HashMap::new();
|
|
||||||
let mut unique_vertices=Vec::new();
|
|
||||||
let mut vertex_id_from=std::collections::HashMap::new();
|
|
||||||
|
|
||||||
let mut polys=Vec::new();
|
|
||||||
//transform instance vertices
|
|
||||||
for (model_id,instance_id) in model_instance_list.into_iter(){
|
|
||||||
//populate hashset to prevent these models from being copied
|
|
||||||
selected_model_instances.insert(model_id);
|
|
||||||
//there is only one instance per model
|
|
||||||
let model=&unique_texture_models[model_id];
|
|
||||||
let instance=&model.instances[instance_id];
|
|
||||||
//just hash word slices LOL
|
|
||||||
let map_pos_id:Vec<u32>=model.unique_pos.iter().map(|untransformed_pos|{
|
|
||||||
let pos=instance.transform.transform_point3(glam::Vec3::from_array(untransformed_pos.clone())).to_array();
|
|
||||||
let h=pos.map(|v|bytemuck::cast::<f32,u32>(v));
|
|
||||||
(if let Some(&pos_id)=pos_id_from.get(&h){
|
|
||||||
pos_id
|
|
||||||
}else{
|
|
||||||
let pos_id=unique_pos.len();
|
|
||||||
unique_pos.push(pos.clone());
|
|
||||||
pos_id_from.insert(h,pos_id);
|
|
||||||
pos_id
|
|
||||||
}) as u32
|
|
||||||
}).collect();
|
|
||||||
let map_tex_id:Vec<u32>=model.unique_tex.iter().map(|tex|{
|
|
||||||
let h=tex.map(|v|bytemuck::cast::<f32,u32>(v));
|
|
||||||
(if let Some(&tex_id)=tex_id_from.get(&h){
|
|
||||||
tex_id
|
|
||||||
}else{
|
|
||||||
let tex_id=unique_tex.len();
|
|
||||||
unique_tex.push(tex.clone());
|
|
||||||
tex_id_from.insert(h,tex_id);
|
|
||||||
tex_id
|
|
||||||
}) as u32
|
|
||||||
}).collect();
|
|
||||||
let map_normal_id:Vec<u32>=model.unique_normal.iter().map(|untransformed_normal|{
|
|
||||||
let normal=(instance.normal_transform*glam::Vec3::from_array(untransformed_normal.clone())).to_array();
|
|
||||||
let h=normal.map(|v|bytemuck::cast::<f32,u32>(v));
|
|
||||||
(if let Some(&normal_id)=normal_id_from.get(&h){
|
|
||||||
normal_id
|
|
||||||
}else{
|
|
||||||
let normal_id=unique_normal.len();
|
|
||||||
unique_normal.push(normal.clone());
|
|
||||||
normal_id_from.insert(h,normal_id);
|
|
||||||
normal_id
|
|
||||||
}) as u32
|
|
||||||
}).collect();
|
|
||||||
let map_color_id:Vec<u32>=model.unique_color.iter().map(|color|{
|
|
||||||
let h=color.map(|v|bytemuck::cast::<f32,u32>(v));
|
|
||||||
(if let Some(&color_id)=color_id_from.get(&h){
|
|
||||||
color_id
|
|
||||||
}else{
|
|
||||||
let color_id=unique_color.len();
|
|
||||||
unique_color.push(color.clone());
|
|
||||||
color_id_from.insert(h,color_id);
|
|
||||||
color_id
|
|
||||||
}) as u32
|
|
||||||
}).collect();
|
|
||||||
//map the indexed vertices onto new indices
|
|
||||||
//creating the vertex map is slightly different because the vertices are directly hashable
|
|
||||||
let map_vertex_id:Vec<u32>=model.unique_vertices.iter().map(|unmapped_vertex|{
|
|
||||||
let vertex=model::IndexedVertex{
|
|
||||||
pos:map_pos_id[unmapped_vertex.pos as usize] as u32,
|
|
||||||
tex:map_tex_id[unmapped_vertex.tex as usize] as u32,
|
|
||||||
normal:map_normal_id[unmapped_vertex.normal as usize] as u32,
|
|
||||||
color:map_color_id[unmapped_vertex.color as usize] as u32,
|
|
||||||
};
|
|
||||||
(if let Some(&vertex_id)=vertex_id_from.get(&vertex){
|
|
||||||
vertex_id
|
|
||||||
}else{
|
|
||||||
let vertex_id=unique_vertices.len();
|
|
||||||
unique_vertices.push(vertex.clone());
|
|
||||||
vertex_id_from.insert(vertex,vertex_id);
|
|
||||||
vertex_id
|
|
||||||
}) as u32
|
|
||||||
}).collect();
|
|
||||||
for group in &model.groups{
|
|
||||||
for poly in &group.polys{
|
|
||||||
polys.push(model::IndexedPolygon{vertices:poly.vertices.iter().map(|&vertex_id|map_vertex_id[vertex_id as usize]).collect()});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//push model into dedup
|
|
||||||
deduplicated_models.push(model_graphics::IndexedModelGraphicsSingleTexture{
|
|
||||||
unique_pos,
|
|
||||||
unique_tex,
|
|
||||||
unique_normal,
|
|
||||||
unique_color,
|
|
||||||
unique_vertices,
|
|
||||||
texture,
|
|
||||||
groups:vec![model_graphics::IndexedGroupFixedTexture{
|
|
||||||
polys
|
|
||||||
}],
|
|
||||||
instances:vec![model_graphics::ModelGraphicsInstance{
|
|
||||||
transform:glam::Mat4::IDENTITY,
|
|
||||||
normal_transform:glam::Mat3::IDENTITY,
|
|
||||||
color
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//fill untouched models
|
|
||||||
for (model_id,model) in unique_texture_models.into_iter().enumerate(){
|
|
||||||
if !selected_model_instances.contains(&model_id){
|
|
||||||
deduplicated_models.push(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//de-index models
|
//de-index models
|
||||||
let deduplicated_models_len=deduplicated_models.len();
|
let mut models=Vec::with_capacity(unique_texture_models.len());
|
||||||
let models:Vec<model_graphics::ModelGraphicsSingleTexture>=deduplicated_models.into_iter().map(|model|{
|
for model in unique_texture_models.into_iter(){
|
||||||
let mut vertices = Vec::new();
|
let mut vertices = Vec::new();
|
||||||
let mut index_from_vertex = std::collections::HashMap::new();//::<IndexedVertex,usize>
|
let mut index_from_vertex = std::collections::HashMap::new();//::<IndexedVertex,usize>
|
||||||
let mut entities = Vec::new();
|
let mut entities = Vec::new();
|
||||||
@@ -463,13 +294,13 @@ impl GlobalState{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
entities.push(indices);
|
entities.push(indices);
|
||||||
model_graphics::ModelGraphicsSingleTexture{
|
models.push(model_graphics::ModelGraphicsSingleTexture{
|
||||||
instances:model.instances,
|
instances:model.instances,
|
||||||
vertices,
|
vertices,
|
||||||
entities,
|
entities,
|
||||||
texture:model.texture,
|
texture:model.texture,
|
||||||
}
|
});
|
||||||
}).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;
|
||||||
@@ -541,7 +372,6 @@ impl GlobalState{
|
|||||||
println!("Texture References={}",num_textures);
|
println!("Texture References={}",num_textures);
|
||||||
println!("Textures Loaded={}",texture_views.len());
|
println!("Textures Loaded={}",texture_views.len());
|
||||||
println!("Indexed Models={}",indexed_models_len);
|
println!("Indexed Models={}",indexed_models_len);
|
||||||
println!("Deduplicated Models={}",deduplicated_models_len);
|
|
||||||
println!("Graphics Objects: {}",self.graphics.models.len());
|
println!("Graphics Objects: {}",self.graphics.models.len());
|
||||||
println!("Graphics Instances: {}",instance_count);
|
println!("Graphics Instances: {}",instance_count);
|
||||||
}
|
}
|
||||||
@@ -563,7 +393,7 @@ fn get_instances_buffer_data(instances:&[ModelGraphicsInstance]) -> Vec<f32> {
|
|||||||
raw.extend_from_slice(AsRef::<[f32; 3]>::as_ref(&mi.normal_transform.z_axis));
|
raw.extend_from_slice(AsRef::<[f32; 3]>::as_ref(&mi.normal_transform.z_axis));
|
||||||
raw.extend_from_slice(&[0.0]);
|
raw.extend_from_slice(&[0.0]);
|
||||||
//color
|
//color
|
||||||
raw.extend_from_slice(AsRef::<[f32; 4]>::as_ref(&mi.color.get()));
|
raw.extend_from_slice(AsRef::<[f32; 4]>::as_ref(&mi.color));
|
||||||
raw.append(&mut v);
|
raw.append(&mut v);
|
||||||
}
|
}
|
||||||
raw
|
raw
|
||||||
@@ -932,7 +762,7 @@ impl framework::Example for GlobalState {
|
|||||||
let screen_size=glam::uvec2(config.width,config.height);
|
let screen_size=glam::uvec2(config.width,config.height);
|
||||||
|
|
||||||
let camera=GraphicsCamera::new(screen_size,user_settings.calculate_fov(1.0,&screen_size).as_vec2());
|
let camera=GraphicsCamera::new(screen_size,user_settings.calculate_fov(1.0,&screen_size).as_vec2());
|
||||||
let camera_uniforms = camera.to_uniform_data(physics.output().adjust_mouse(&physics::MouseState::default()));
|
let camera_uniforms = camera.to_uniform_data(physics.output().adjust_mouse(&physics.next_mouse));
|
||||||
let camera_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let camera_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Camera"),
|
label: Some("Camera"),
|
||||||
contents: bytemuck::cast_slice(&camera_uniforms),
|
contents: bytemuck::cast_slice(&camera_uniforms),
|
||||||
@@ -1064,7 +894,6 @@ impl framework::Example for GlobalState {
|
|||||||
self.graphics.clear();
|
self.graphics.clear();
|
||||||
|
|
||||||
let mut physics=physics::PhysicsState::default();
|
let mut physics=physics::PhysicsState::default();
|
||||||
//physics.spawn()
|
|
||||||
physics.game.stage_id=0;
|
physics.game.stage_id=0;
|
||||||
physics.spawn_point=spawn_point;
|
physics.spawn_point=spawn_point;
|
||||||
physics.process_instruction(instruction::TimedInstruction{
|
physics.process_instruction(instruction::TimedInstruction{
|
||||||
|
|||||||
162
src/model.rs
162
src/model.rs
@@ -1,4 +1,4 @@
|
|||||||
use crate::integer::{Time,Planar64,Planar64Vec3,Planar64Affine3};
|
use crate::integer::{Planar64,Planar64Vec3,Planar64Affine3};
|
||||||
pub type TextureCoordinate=glam::Vec2;
|
pub type TextureCoordinate=glam::Vec2;
|
||||||
pub type Color4=glam::Vec4;
|
pub type Color4=glam::Vec4;
|
||||||
#[derive(Clone,Hash,PartialEq,Eq)]
|
#[derive(Clone,Hash,PartialEq,Eq)]
|
||||||
@@ -50,63 +50,53 @@ pub struct IndexedModelInstances{
|
|||||||
}
|
}
|
||||||
//stage description referencing flattened ids is spooky, but the map loading is meant to be deterministic.
|
//stage description referencing flattened ids is spooky, but the map loading is meant to be deterministic.
|
||||||
pub struct ModeDescription{
|
pub struct ModeDescription{
|
||||||
pub start:usize,//start=model_id
|
pub start:u32,//start=model_id
|
||||||
pub spawns:Vec<usize>,//spawns[spawn_id]=model_id
|
pub spawns:Vec<u32>,//spawns[spawn_id]=model_id
|
||||||
pub ordered_checkpoints:Vec<usize>,//ordered_checkpoints[checkpoint_id]=model_id
|
pub ordered_checkpoints:Vec<u32>,//ordered_checkpoints[checkpoint_id]=model_id
|
||||||
pub unordered_checkpoints:Vec<usize>,//unordered_checkpoints[checkpoint_id]=model_id
|
pub unordered_checkpoints:Vec<u32>,//unordered_checkpoints[checkpoint_id]=model_id
|
||||||
pub spawn_from_stage_id:std::collections::HashMap::<u32,usize>,
|
pub spawn_from_stage_id:std::collections::HashMap::<u32,usize>,
|
||||||
pub ordered_checkpoint_from_checkpoint_id:std::collections::HashMap::<u32,usize>,
|
pub ordered_checkpoint_from_checkpoint_id:std::collections::HashMap::<u32,usize>,
|
||||||
}
|
}
|
||||||
impl ModeDescription{
|
impl ModeDescription{
|
||||||
pub fn get_spawn_model_id(&self,stage_id:u32)->Option<&usize>{
|
pub fn get_spawn_model_id(&self,stage_id:u32)->Option<&u32>{
|
||||||
self.spawns.get(*self.spawn_from_stage_id.get(&stage_id)?)
|
if let Some(&spawn)=self.spawn_from_stage_id.get(&stage_id){
|
||||||
|
self.spawns.get(spawn)
|
||||||
|
}else{
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn get_ordered_checkpoint_model_id(&self,checkpoint_id:u32)->Option<&usize>{
|
pub fn get_ordered_checkpoint_model_id(&self,checkpoint_id:u32)->Option<&u32>{
|
||||||
self.ordered_checkpoints.get(*self.ordered_checkpoint_from_checkpoint_id.get(&checkpoint_id)?)
|
if let Some(&checkpoint)=self.ordered_checkpoint_from_checkpoint_id.get(&checkpoint_id){
|
||||||
|
self.ordered_checkpoints.get(checkpoint)
|
||||||
|
}else{
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//I don't want this code to exist!
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TempAttrStart{
|
|
||||||
pub mode_id:u32,
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TempAttrSpawn{
|
|
||||||
pub mode_id:u32,
|
|
||||||
pub stage_id:u32,
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TempAttrOrderedCheckpoint{
|
|
||||||
pub mode_id:u32,
|
|
||||||
pub checkpoint_id:u32,
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TempAttrUnorderedCheckpoint{
|
|
||||||
pub mode_id:u32,
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TempAttrWormhole{
|
|
||||||
pub wormhole_id:u32,
|
|
||||||
}
|
|
||||||
pub enum TempIndexedAttributes{
|
pub enum TempIndexedAttributes{
|
||||||
Start(TempAttrStart),
|
Start{
|
||||||
Spawn(TempAttrSpawn),
|
mode_id:u32,
|
||||||
OrderedCheckpoint(TempAttrOrderedCheckpoint),
|
},
|
||||||
UnorderedCheckpoint(TempAttrUnorderedCheckpoint),
|
Spawn{
|
||||||
Wormhole(TempAttrWormhole),
|
mode_id:u32,
|
||||||
|
stage_id:u32,
|
||||||
|
},
|
||||||
|
OrderedCheckpoint{
|
||||||
|
mode_id:u32,
|
||||||
|
checkpoint_id:u32,
|
||||||
|
},
|
||||||
|
UnorderedCheckpoint{
|
||||||
|
mode_id:u32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
//you have this effect while in contact
|
//you have this effect while in contact
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
pub struct ContactingSurf{}
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ContactingLadder{
|
pub struct ContactingLadder{
|
||||||
pub sticky:bool
|
pub sticky:bool
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum ContactingBehaviour{
|
|
||||||
Surf,
|
|
||||||
Ladder(ContactingLadder),
|
|
||||||
Elastic(u32),//[1/2^32,1] 0=None (elasticity+1)/2^32
|
|
||||||
}
|
|
||||||
//you have this effect while intersecting
|
//you have this effect while intersecting
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct IntersectingWater{
|
pub struct IntersectingWater{
|
||||||
@@ -114,37 +104,18 @@ pub struct IntersectingWater{
|
|||||||
pub density:Planar64,
|
pub density:Planar64,
|
||||||
pub current:Planar64Vec3,
|
pub current:Planar64Vec3,
|
||||||
}
|
}
|
||||||
//All models can be given these attributes
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GameMechanicAccelerator{
|
pub struct IntersectingAccelerator{
|
||||||
pub acceleration:Planar64Vec3
|
pub acceleration:Planar64Vec3
|
||||||
}
|
}
|
||||||
|
//All models can be given these attributes
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum GameMechanicBooster{
|
pub struct GameMechanicJumpLimit{
|
||||||
Affine(Planar64Affine3),//capable of SetVelocity,DotVelocity,normal booster,bouncy part,redirect velocity, and much more
|
pub count:u32,
|
||||||
Velocity(Planar64Vec3),//straight up boost velocity adds to your current velocity
|
|
||||||
Energy{direction:Planar64Vec3,energy:Planar64},//increase energy in direction
|
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum TrajectoryChoice{
|
pub struct GameMechanicBooster{
|
||||||
HighArcLongDuration,//underhand lob at target: less horizontal speed and more air time
|
pub velocity:Planar64Vec3,
|
||||||
LowArcShortDuration,//overhand throw at target: more horizontal speed and less air time
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum GameMechanicSetTrajectory{
|
|
||||||
AirTime(Time),//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
|
|
||||||
TargetPointTime{//launch on a trajectory that will land at a target point in a set amount of time
|
|
||||||
target_point:Planar64Vec3,
|
|
||||||
time:Time,//short time = fast and direct, long time = launch high in the air, negative time = wrong way
|
|
||||||
},
|
|
||||||
TrajectoryTargetPoint{//launch at a fixed speed and land at a target point
|
|
||||||
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
|
|
||||||
trajectory_choice:TrajectoryChoice,
|
|
||||||
},
|
|
||||||
Velocity(Planar64Vec3),//SetVelocity
|
|
||||||
DotVelocity{direction:Planar64Vec3,dot:Planar64},//set your velocity in a specific direction without touching other directions
|
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ZoneBehaviour{
|
pub enum ZoneBehaviour{
|
||||||
@@ -159,10 +130,10 @@ pub struct GameMechanicZone{
|
|||||||
pub behaviour:ZoneBehaviour,
|
pub behaviour:ZoneBehaviour,
|
||||||
}
|
}
|
||||||
// enum TrapCondition{
|
// enum TrapCondition{
|
||||||
// FasterThan(Planar64),
|
// FasterThan(i64),
|
||||||
// SlowerThan(Planar64),
|
// SlowerThan(i64),
|
||||||
// InRange(Planar64,Planar64),
|
// InRange(i64,i64),
|
||||||
// OutsideRange(Planar64,Planar64),
|
// OutsideRange(i64,i64),
|
||||||
// }
|
// }
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum StageElementBehaviour{
|
pub enum StageElementBehaviour{
|
||||||
@@ -171,7 +142,6 @@ pub enum StageElementBehaviour{
|
|||||||
Trigger,
|
Trigger,
|
||||||
Teleport,
|
Teleport,
|
||||||
Platform,
|
Platform,
|
||||||
JumpLimit(u32),
|
|
||||||
//Speedtrap(TrapCondition),//Acts as a trigger with a speed condition
|
//Speedtrap(TrapCondition),//Acts as a trigger with a speed condition
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -182,54 +152,28 @@ pub struct GameMechanicStageElement{
|
|||||||
pub behaviour:StageElementBehaviour
|
pub behaviour:StageElementBehaviour
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GameMechanicWormhole{
|
pub struct GameMechanicWormhole{//(position,angles)*=origin.transform.inverse()*destination.transform
|
||||||
//destination does not need to be another wormhole
|
pub model_id:u32,
|
||||||
//this defines a one way portal to a destination model transform
|
|
||||||
//two of these can create a two way wormhole
|
|
||||||
pub destination_model_id:u32,
|
|
||||||
//(position,angles)*=origin.transform.inverse()*destination.transform
|
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum TeleportBehaviour{
|
|
||||||
StageElement(GameMechanicStageElement),
|
|
||||||
Wormhole(GameMechanicWormhole),
|
|
||||||
}
|
|
||||||
//attributes listed in order of handling
|
|
||||||
#[derive(Default,Clone)]
|
#[derive(Default,Clone)]
|
||||||
pub struct GameMechanicAttributes{
|
pub struct GameMechanicAttributes{
|
||||||
pub zone:Option<GameMechanicZone>,
|
pub jump_limit:Option<GameMechanicJumpLimit>,
|
||||||
pub booster:Option<GameMechanicBooster>,
|
pub booster:Option<GameMechanicBooster>,
|
||||||
pub trajectory:Option<GameMechanicSetTrajectory>,
|
pub zone:Option<GameMechanicZone>,
|
||||||
pub teleport_behaviour:Option<TeleportBehaviour>,
|
pub stage_element:Option<GameMechanicStageElement>,
|
||||||
pub accelerator:Option<GameMechanicAccelerator>,
|
pub wormhole:Option<GameMechanicWormhole>,//stage_element and wormhole are in conflict
|
||||||
}
|
|
||||||
impl GameMechanicAttributes{
|
|
||||||
pub fn any(&self)->bool{
|
|
||||||
self.booster.is_some()
|
|
||||||
||self.trajectory.is_some()
|
|
||||||
||self.zone.is_some()
|
|
||||||
||self.teleport_behaviour.is_some()
|
|
||||||
||self.accelerator.is_some()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[derive(Default,Clone)]
|
#[derive(Default,Clone)]
|
||||||
pub struct ContactingAttributes{
|
pub struct ContactingAttributes{
|
||||||
|
pub elasticity:Option<u32>,//[1/2^32,1] 0=None (elasticity+1)/2^32
|
||||||
//friction?
|
//friction?
|
||||||
pub contact_behaviour:Option<ContactingBehaviour>,
|
pub surf:Option<ContactingSurf>,
|
||||||
}
|
pub ladder:Option<ContactingLadder>,
|
||||||
impl ContactingAttributes{
|
|
||||||
pub fn any(&self)->bool{
|
|
||||||
self.contact_behaviour.is_some()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[derive(Default,Clone)]
|
#[derive(Default,Clone)]
|
||||||
pub struct IntersectingAttributes{
|
pub struct IntersectingAttributes{
|
||||||
pub water:Option<IntersectingWater>,
|
pub water:Option<IntersectingWater>,
|
||||||
}
|
pub accelerator:Option<IntersectingAccelerator>,
|
||||||
impl IntersectingAttributes{
|
|
||||||
pub fn any(&self)->bool{
|
|
||||||
self.water.is_some()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//Spawn(u32) NO! spawns are indexed in the map header instead of marked with attibutes
|
//Spawn(u32) NO! spawns are indexed in the map header instead of marked with attibutes
|
||||||
pub enum CollisionAttributes{
|
pub enum CollisionAttributes{
|
||||||
|
|||||||
@@ -27,29 +27,9 @@ pub struct ModelGraphicsSingleTexture{
|
|||||||
pub entities: Vec<Vec<u16>>,
|
pub entities: Vec<Vec<u16>>,
|
||||||
pub texture: Option<u32>,
|
pub texture: Option<u32>,
|
||||||
}
|
}
|
||||||
#[derive(Clone,PartialEq)]
|
|
||||||
pub struct ModelGraphicsColor4(glam::Vec4);
|
|
||||||
impl ModelGraphicsColor4{
|
|
||||||
pub const fn get(&self)->glam::Vec4{
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<glam::Vec4> for ModelGraphicsColor4{
|
|
||||||
fn from(value:glam::Vec4)->Self{
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl std::hash::Hash for ModelGraphicsColor4{
|
|
||||||
fn hash<H: std::hash::Hasher>(&self,state:&mut H) {
|
|
||||||
for &f in self.0.as_ref(){
|
|
||||||
bytemuck::cast::<f32,u32>(f).hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Eq for ModelGraphicsColor4{}
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ModelGraphicsInstance{
|
pub struct ModelGraphicsInstance{
|
||||||
pub transform:glam::Mat4,
|
pub transform:glam::Mat4,
|
||||||
pub normal_transform:glam::Mat3,
|
pub normal_transform:glam::Mat3,
|
||||||
pub color:ModelGraphicsColor4,
|
pub color:glam::Vec4,
|
||||||
}
|
}
|
||||||
912
src/physics.rs
912
src/physics.rs
File diff suppressed because it is too large
Load Diff
@@ -174,7 +174,7 @@ pub fn unit_cornerwedge()->crate::model::IndexedModel{
|
|||||||
generate_partial_unit_cornerwedge(t)
|
generate_partial_unit_cornerwedge(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct FaceDescription{
|
pub struct FaceDescription{
|
||||||
pub texture:Option<u32>,
|
pub texture:Option<u32>,
|
||||||
pub transform:glam::Affine2,
|
pub transform:glam::Affine2,
|
||||||
|
|||||||
134
src/sniffer.rs
134
src/sniffer.rs
@@ -1,134 +0,0 @@
|
|||||||
//file format "sniff"
|
|
||||||
|
|
||||||
/* spec
|
|
||||||
|
|
||||||
//begin global header
|
|
||||||
|
|
||||||
//global metadata (32 bytes)
|
|
||||||
b"SNFB"
|
|
||||||
u32 format_version
|
|
||||||
u64 priming_bytes
|
|
||||||
//how many bytes of the file must be read to guarantee all of the expected
|
|
||||||
//format-specific metadata is available to facilitate streaming the remaining contents
|
|
||||||
//used by the database to guarantee that it serves at least the bare minimum
|
|
||||||
u128 resource_uuid
|
|
||||||
//identifies the file from anywhere for any other file
|
|
||||||
|
|
||||||
//global block layout (variable size)
|
|
||||||
u64 num_blocks
|
|
||||||
for block_id in 0..num_blocks{
|
|
||||||
u64 first_byte
|
|
||||||
}
|
|
||||||
|
|
||||||
//end global header
|
|
||||||
|
|
||||||
//begin blocks
|
|
||||||
|
|
||||||
//each block is compressed with zstd or gz or something
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* block types
|
|
||||||
BLOCK_MAP_HEADER:
|
|
||||||
StyleInfoOverrides style_info_overrides
|
|
||||||
//bvh goes here
|
|
||||||
u64 num_nodes
|
|
||||||
//node 0 parent node is implied to be None
|
|
||||||
for node_id in 1..num_nodes{
|
|
||||||
u64 parent_node
|
|
||||||
}
|
|
||||||
//block 0 is the current block, not part of the map data
|
|
||||||
u64 num_spacial_blocks
|
|
||||||
for block_id in 1..num_spacial_blocks{
|
|
||||||
u64 node_id
|
|
||||||
u64 block_id
|
|
||||||
Aabb block_extents
|
|
||||||
}
|
|
||||||
//ideally spacial blocks are sorted from distance to start zone
|
|
||||||
//texture blocks are inserted before the first spacial block they are used in
|
|
||||||
|
|
||||||
BLOCK_MAP_RESOURCE:
|
|
||||||
//an individual one of the following:
|
|
||||||
- model (IndexedModel)
|
|
||||||
- shader (compiled SPIR-V)
|
|
||||||
- image (JpegXL)
|
|
||||||
- sound (Opus)
|
|
||||||
- video (AV1)
|
|
||||||
- animation (Trey thing)
|
|
||||||
|
|
||||||
BLOCK_MAP_OBJECT:
|
|
||||||
//an individual one of the following:
|
|
||||||
- model instance
|
|
||||||
- located resource
|
|
||||||
//for a list of resources, parse the object.
|
|
||||||
|
|
||||||
BLOCK_BOT_HEADER:
|
|
||||||
u128 map_resource_uuid //which map is this bot running
|
|
||||||
u128 time_resource_uuid //resource database time
|
|
||||||
//don't include style info in bot header because it's in the physics state
|
|
||||||
//blocks are laid out in chronological order, but indices may jump around.
|
|
||||||
u64 num_segments
|
|
||||||
for _ in 0..num_segments{
|
|
||||||
i64 time //physics_state timestamp
|
|
||||||
u64 block_id
|
|
||||||
}
|
|
||||||
|
|
||||||
BLOCK_BOT_SEGMENT:
|
|
||||||
//format version indicates what version of these structures to use
|
|
||||||
PhysicsState physics_state
|
|
||||||
//to read, greedily decode instructions until eof
|
|
||||||
loop{
|
|
||||||
//delta encode as much as possible (time,mousepos)
|
|
||||||
//strafe ticks are implied
|
|
||||||
//physics can be implied in an input-only bot file
|
|
||||||
TimedInstruction<PhysicsInstruction> instruction
|
|
||||||
}
|
|
||||||
|
|
||||||
BLOCK_DEMO_HEADER:
|
|
||||||
//timeline of loading maps, player equipment, bots
|
|
||||||
*/
|
|
||||||
struct InputInstructionCodecState{
|
|
||||||
mouse_pos:glam::IVec2,
|
|
||||||
time:crate::integer::Time,
|
|
||||||
}
|
|
||||||
//8B - 12B
|
|
||||||
impl InputInstructionCodecState{
|
|
||||||
pub fn encode(&mut self,ins:&crate::instruction::TimedInstruction<crate::physics::InputInstruction>)->([u8;12],usize){
|
|
||||||
let dt=ins.time-self.time;
|
|
||||||
self.time=ins.time;
|
|
||||||
let mut data=[0u8;12];
|
|
||||||
[data[0],data[1],data[2],data[3]]=(dt.nanos() as u32).to_le_bytes();//4B
|
|
||||||
//instruction id packed with game control parity bit. This could be 1 byte but it ruins the alignment
|
|
||||||
[data[4],data[5],data[6],data[7]]=ins.instruction.id().to_le_bytes();//4B
|
|
||||||
match &ins.instruction{
|
|
||||||
&crate::physics::InputInstruction::MoveMouse(m)=>{//4B
|
|
||||||
let dm=m-self.mouse_pos;
|
|
||||||
[data[8],data[9]]=(dm.x as i16).to_le_bytes();
|
|
||||||
[data[10],data[11]]=(dm.y as i16).to_le_bytes();
|
|
||||||
self.mouse_pos=m;
|
|
||||||
(data,12)
|
|
||||||
},
|
|
||||||
//0B
|
|
||||||
crate::physics::InputInstruction::MoveRight(_)
|
|
||||||
|crate::physics::InputInstruction::MoveUp(_)
|
|
||||||
|crate::physics::InputInstruction::MoveBack(_)
|
|
||||||
|crate::physics::InputInstruction::MoveLeft(_)
|
|
||||||
|crate::physics::InputInstruction::MoveDown(_)
|
|
||||||
|crate::physics::InputInstruction::MoveForward(_)
|
|
||||||
|crate::physics::InputInstruction::Jump(_)
|
|
||||||
|crate::physics::InputInstruction::Zoom(_)
|
|
||||||
|crate::physics::InputInstruction::Reset
|
|
||||||
|crate::physics::InputInstruction::Idle=>(data,8),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//everything must be 4 byte aligned, it's all going to be compressed so don't think too had about saving less than 4 bytes
|
|
||||||
//TODO: Omit (mouse only?) instructions that don't surround an actual physics instruction
|
|
||||||
fn write_input_instruction<W:std::io::Write>(state:&mut InputInstructionCodecState,w:&mut W,ins:&crate::instruction::TimedInstruction<crate::physics::InputInstruction>)->Result<usize,std::io::Error>{
|
|
||||||
//TODO: insert idle instruction if gap is over u32 nanoseconds
|
|
||||||
//TODO: don't write idle instructions
|
|
||||||
//OR: end the data block! the full state at the start of the next block will contain an absolute timestamp
|
|
||||||
let (data,size)=state.encode(ins);
|
|
||||||
w.write(&data[0..size])//8B-12B
|
|
||||||
}
|
|
||||||
@@ -100,7 +100,7 @@ fn test_worker() {
|
|||||||
};
|
};
|
||||||
worker.send(task).unwrap();
|
worker.send(task).unwrap();
|
||||||
|
|
||||||
println!("value={}",worker.grab_clone());
|
println!("value={:?}",worker.grab_clone());
|
||||||
|
|
||||||
// wait long enough to see print from final task
|
// wait long enough to see print from final task
|
||||||
thread::sleep(std::time::Duration::from_secs(1));
|
thread::sleep(std::time::Duration::from_secs(1));
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ pub fn zeroes2(a0:Planar64,a1:Planar64,a2:Planar64) -> Vec<Planar64>{
|
|||||||
if a2==Planar64::ZERO{
|
if a2==Planar64::ZERO{
|
||||||
return zeroes1(a0, a1);
|
return zeroes1(a0, a1);
|
||||||
}
|
}
|
||||||
let radicand=a1.get() as i128*a1.get() as i128-a2.get() as i128*a0.get() as i128*4;
|
let mut radicand=a1.get() as i128*a1.get() as i128-a2.get() as i128*a0.get() as i128*4;
|
||||||
if 0<radicand {
|
if 0<radicand {
|
||||||
//start with f64 sqrt
|
//start with f64 sqrt
|
||||||
let planar_radicand=Planar64::raw(unsafe{(radicand as f64).sqrt().to_int_unchecked()});
|
let planar_radicand=Planar64::raw(unsafe{(radicand as f64).sqrt().to_int_unchecked()});
|
||||||
|
|||||||
Reference in New Issue
Block a user