Compare commits
38 Commits
load-bsp2
...
file-forma
Author | SHA1 | Date | |
---|---|---|---|
a6dd7f3111 | |||
a6c51654e5 | |||
abbab00eea | |||
99db653c14 | |||
e9ba0c694c | |||
261854cfa5 | |||
e3eb040675 | |||
fdb8f93b0b | |||
a2ce319cb2 | |||
a79157da88 | |||
7be7d2c0df | |||
cb6b0acd44 | |||
cbcf047c3f | |||
6e5de4aa46 | |||
cc776e7cb4 | |||
5a66ac46b9 | |||
38f6e1df3f | |||
849dcf98f7 | |||
d04d1be27e | |||
35bfd1d366 | |||
586bf8ce89 | |||
127b205401 | |||
4f596ca5d7 | |||
87f781a656 | |||
cd9cf164e9 | |||
497ca93071 | |||
747f628f04 | |||
7e1cf7041a | |||
50543ffcea | |||
54498f20f9 | |||
2240b80656 | |||
d18f2168e4 | |||
381b7b3c2f | |||
0d6741a81c | |||
2e8cdf968c | |||
dd0ac7cc7e | |||
e2af6fc4ed | |||
bdc0dd1b3b |
104
src/aabb.rs
104
src/aabb.rs
@ -1,3 +1,5 @@
|
|||||||
|
use crate::integer::Planar64Vec3;
|
||||||
|
|
||||||
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
|
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
|
||||||
pub enum AabbFace{
|
pub enum AabbFace{
|
||||||
Right,//+X
|
Right,//+X
|
||||||
@ -8,84 +10,80 @@ pub enum AabbFace{
|
|||||||
Front,
|
Front,
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Aabb {
|
pub struct Aabb{
|
||||||
pub min: glam::Vec3,
|
pub min:Planar64Vec3,
|
||||||
pub max: glam::Vec3,
|
pub max:Planar64Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Aabb {
|
impl Default for Aabb {
|
||||||
fn default() -> Self {
|
fn default()->Self {
|
||||||
Aabb::new()
|
Self{min:Planar64Vec3::MAX,max:Planar64Vec3::MIN}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Aabb {
|
impl Aabb{
|
||||||
const VERTEX_DATA: [glam::Vec3; 8] = [
|
const VERTEX_DATA:[Planar64Vec3;8]=[
|
||||||
glam::vec3(1., -1., -1.),
|
Planar64Vec3::int( 1,-1,-1),
|
||||||
glam::vec3(1., 1., -1.),
|
Planar64Vec3::int( 1, 1,-1),
|
||||||
glam::vec3(1., 1., 1.),
|
Planar64Vec3::int( 1, 1, 1),
|
||||||
glam::vec3(1., -1., 1.),
|
Planar64Vec3::int( 1,-1, 1),
|
||||||
glam::vec3(-1., -1., 1.),
|
Planar64Vec3::int(-1,-1, 1),
|
||||||
glam::vec3(-1., 1., 1.),
|
Planar64Vec3::int(-1, 1, 1),
|
||||||
glam::vec3(-1., 1., -1.),
|
Planar64Vec3::int(-1, 1,-1),
|
||||||
glam::vec3(-1., -1., -1.),
|
Planar64Vec3::int(-1,-1,-1),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn grow(&mut self,point:Planar64Vec3){
|
||||||
Self {min: glam::Vec3::INFINITY,max: glam::Vec3::NEG_INFINITY}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn grow(&mut self, point:glam::Vec3){
|
|
||||||
self.min=self.min.min(point);
|
self.min=self.min.min(point);
|
||||||
self.max=self.max.max(point);
|
self.max=self.max.max(point);
|
||||||
}
|
}
|
||||||
pub fn join(&mut self, aabb:&Aabb){
|
pub fn join(&mut self,aabb:&Aabb){
|
||||||
self.min=self.min.min(aabb.min);
|
self.min=self.min.min(aabb.min);
|
||||||
self.max=self.max.max(aabb.max);
|
self.max=self.max.max(aabb.max);
|
||||||
}
|
}
|
||||||
pub fn inflate(&mut self, hs:glam::Vec3){
|
pub fn inflate(&mut self,hs:Planar64Vec3){
|
||||||
self.min-=hs;
|
self.min-=hs;
|
||||||
self.max+=hs;
|
self.max+=hs;
|
||||||
}
|
}
|
||||||
pub fn intersects(&self,aabb:&Aabb)->bool{
|
pub fn intersects(&self,aabb:&Aabb)->bool{
|
||||||
(self.min.cmplt(aabb.max)&aabb.min.cmplt(self.max)).all()
|
(self.min.cmplt(aabb.max)&aabb.min.cmplt(self.max)).all()
|
||||||
}
|
}
|
||||||
pub fn normal(face:AabbFace) -> glam::Vec3 {
|
pub fn normal(face:AabbFace)->Planar64Vec3{
|
||||||
match face {
|
match face {
|
||||||
AabbFace::Right => glam::vec3(1.,0.,0.),
|
AabbFace::Right=>Planar64Vec3::int(1,0,0),
|
||||||
AabbFace::Top => glam::vec3(0.,1.,0.),
|
AabbFace::Top=>Planar64Vec3::int(0,1,0),
|
||||||
AabbFace::Back => glam::vec3(0.,0.,1.),
|
AabbFace::Back=>Planar64Vec3::int(0,0,1),
|
||||||
AabbFace::Left => glam::vec3(-1.,0.,0.),
|
AabbFace::Left=>Planar64Vec3::int(-1,0,0),
|
||||||
AabbFace::Bottom => glam::vec3(0.,-1.,0.),
|
AabbFace::Bottom=>Planar64Vec3::int(0,-1,0),
|
||||||
AabbFace::Front => glam::vec3(0.,0.,-1.),
|
AabbFace::Front=>Planar64Vec3::int(0,0,-1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn unit_vertices() -> [glam::Vec3;8] {
|
pub fn unit_vertices()->[Planar64Vec3;8] {
|
||||||
return Self::VERTEX_DATA;
|
return Self::VERTEX_DATA;
|
||||||
}
|
}
|
||||||
pub fn face(&self,face:AabbFace) -> Aabb {
|
// pub fn face(&self,face:AabbFace)->Aabb {
|
||||||
let mut aabb=self.clone();
|
// let mut aabb=self.clone();
|
||||||
//in this implementation face = worldspace aabb face
|
// //in this implementation face = worldspace aabb face
|
||||||
match face {
|
// match face {
|
||||||
AabbFace::Right => aabb.min.x=aabb.max.x,
|
// AabbFace::Right => aabb.min.x=aabb.max.x,
|
||||||
AabbFace::Top => aabb.min.y=aabb.max.y,
|
// AabbFace::Top => aabb.min.y=aabb.max.y,
|
||||||
AabbFace::Back => aabb.min.z=aabb.max.z,
|
// AabbFace::Back => aabb.min.z=aabb.max.z,
|
||||||
AabbFace::Left => aabb.max.x=aabb.min.x,
|
// AabbFace::Left => aabb.max.x=aabb.min.x,
|
||||||
AabbFace::Bottom => aabb.max.y=aabb.min.y,
|
// AabbFace::Bottom => aabb.max.y=aabb.min.y,
|
||||||
AabbFace::Front => aabb.max.z=aabb.min.z,
|
// AabbFace::Front => aabb.max.z=aabb.min.z,
|
||||||
}
|
// }
|
||||||
return aabb;
|
// return aabb;
|
||||||
}
|
// }
|
||||||
pub fn center(&self)->glam::Vec3{
|
pub fn center(&self)->Planar64Vec3{
|
||||||
return (self.min+self.max)/2.0
|
return self.min.midpoint(self.max)
|
||||||
}
|
}
|
||||||
//probably use floats for area & volume because we don't care about precision
|
//probably use floats for area & volume because we don't care about precision
|
||||||
pub fn area_weight(&self)->f32{
|
// pub fn area_weight(&self)->f32{
|
||||||
let d=self.max-self.min;
|
// let d=self.max-self.min;
|
||||||
d.x*d.y+d.y*d.z+d.z*d.x
|
// d.x*d.y+d.y*d.z+d.z*d.x
|
||||||
}
|
// }
|
||||||
pub fn volume(&self)->f32{
|
// pub fn volume(&self)->f32{
|
||||||
let d=self.max-self.min;
|
// let d=self.max-self.min;
|
||||||
d.x*d.y*d.z
|
// d.x*d.y*d.z
|
||||||
}
|
// }
|
||||||
}
|
}
|
16
src/bvh.rs
16
src/bvh.rs
@ -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<u32>,
|
models:Vec<usize>,
|
||||||
aabb:Aabb,
|
aabb:Aabb,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BvhNode{
|
impl BvhNode{
|
||||||
pub fn the_tester<F:FnMut(u32)>(&self,aabb:&Aabb,f:&mut F){
|
pub fn the_tester<F:FnMut(usize)>(&self,aabb:&Aabb,f:&mut F){
|
||||||
for &model in &self.models{
|
for &model in &self.models{
|
||||||
f(model);
|
f(model);
|
||||||
}
|
}
|
||||||
@ -36,8 +36,8 @@ pub fn generate_bvh(boxen:Vec<Aabb>)->BvhNode{
|
|||||||
fn generate_bvh_node(boxen:Vec<(usize,Aabb)>)->BvhNode{
|
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::new();
|
let mut aabb=Aabb::default();
|
||||||
let models=boxen.into_iter().map(|b|{aabb.join(&b.1);b.0 as u32}).collect();
|
let models=boxen.into_iter().map(|b|{aabb.join(&b.1);b.0}).collect();
|
||||||
BvhNode{
|
BvhNode{
|
||||||
children:Vec::new(),
|
children:Vec::new(),
|
||||||
models,
|
models,
|
||||||
@ -51,9 +51,9 @@ fn generate_bvh_node(boxen:Vec<(usize,Aabb)>)->BvhNode{
|
|||||||
for (i,aabb) in boxen.iter(){
|
for (i,aabb) in boxen.iter(){
|
||||||
let center=aabb.center();
|
let center=aabb.center();
|
||||||
octant.insert(*i,0);
|
octant.insert(*i,0);
|
||||||
sort_x.push((*i,center.x));
|
sort_x.push((*i,center.x()));
|
||||||
sort_y.push((*i,center.y));
|
sort_y.push((*i,center.y()));
|
||||||
sort_z.push((*i,center.z));
|
sort_z.push((*i,center.z()));
|
||||||
}
|
}
|
||||||
sort_x.sort_by(|tup0,tup1|tup0.1.partial_cmp(&tup1.1).unwrap());
|
sort_x.sort_by(|tup0,tup1|tup0.1.partial_cmp(&tup1.1).unwrap());
|
||||||
sort_y.sort_by(|tup0,tup1|tup0.1.partial_cmp(&tup1.1).unwrap());
|
sort_y.sort_by(|tup0,tup1|tup0.1.partial_cmp(&tup1.1).unwrap());
|
||||||
@ -92,7 +92,7 @@ fn generate_bvh_node(boxen:Vec<(usize,Aabb)>)->BvhNode{
|
|||||||
};
|
};
|
||||||
list_list[list_id].push((i,aabb));
|
list_list[list_id].push((i,aabb));
|
||||||
}
|
}
|
||||||
let mut aabb=Aabb::new();
|
let mut aabb=Aabb::default();
|
||||||
let children=list_list.into_iter().map(|b|{
|
let children=list_list.into_iter().map(|b|{
|
||||||
let node=generate_bvh_node(b);
|
let node=generate_bvh_node(b);
|
||||||
aabb.join(&node.aabb);
|
aabb.join(&node.aabb);
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
|
use crate::integer::Time;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TimedInstruction<I> {
|
pub struct TimedInstruction<I>{
|
||||||
pub time: crate::physics::TIME,
|
pub time:Time,
|
||||||
pub instruction: I,
|
pub instruction:I,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait InstructionEmitter<I> {
|
pub trait InstructionEmitter<I>{
|
||||||
fn next_instruction(&self, time_limit:crate::physics::TIME) -> Option<TimedInstruction<I>>;
|
fn next_instruction(&self,time_limit:Time)->Option<TimedInstruction<I>>;
|
||||||
}
|
}
|
||||||
pub trait InstructionConsumer<I> {
|
pub trait InstructionConsumer<I>{
|
||||||
fn process_instruction(&mut self, instruction:TimedInstruction<I>);
|
fn process_instruction(&mut self, instruction:TimedInstruction<I>);
|
||||||
}
|
}
|
||||||
|
|
||||||
//PROPER PRIVATE FIELDS!!!
|
//PROPER PRIVATE FIELDS!!!
|
||||||
pub struct InstructionCollector<I> {
|
pub struct InstructionCollector<I>{
|
||||||
time: crate::physics::TIME,
|
time:Time,
|
||||||
instruction: Option<I>,
|
instruction:Option<I>,
|
||||||
}
|
}
|
||||||
impl<I> InstructionCollector<I> {
|
impl<I> InstructionCollector<I>{
|
||||||
pub fn new(time:crate::physics::TIME) -> Self {
|
pub fn new(time:Time)->Self{
|
||||||
Self{
|
Self{
|
||||||
time,
|
time,
|
||||||
instruction:None
|
instruction:None
|
||||||
@ -25,24 +27,24 @@ impl<I> InstructionCollector<I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect(&mut self,instruction:Option<TimedInstruction<I>>){
|
pub fn collect(&mut self,instruction:Option<TimedInstruction<I>>){
|
||||||
match instruction {
|
match instruction{
|
||||||
Some(unwrap_instruction) => {
|
Some(unwrap_instruction)=>{
|
||||||
if unwrap_instruction.time<self.time {
|
if unwrap_instruction.time<self.time {
|
||||||
self.time=unwrap_instruction.time;
|
self.time=unwrap_instruction.time;
|
||||||
self.instruction=Some(unwrap_instruction.instruction);
|
self.instruction=Some(unwrap_instruction.instruction);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => (),
|
None=>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn instruction(self) -> Option<TimedInstruction<I>> {
|
pub fn instruction(self)->Option<TimedInstruction<I>>{
|
||||||
//STEAL INSTRUCTION AND DESTROY INSTRUCTIONCOLLECTOR
|
//STEAL INSTRUCTION AND DESTROY INSTRUCTIONCOLLECTOR
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
953
src/integer.rs
Normal file
953
src/integer.rs
Normal file
@ -0,0 +1,953 @@
|
|||||||
|
//integer units
|
||||||
|
#[derive(Clone,Copy,Hash,PartialEq,PartialOrd,Debug)]
|
||||||
|
pub struct Time(i64);
|
||||||
|
impl Time{
|
||||||
|
pub const ZERO:Self=Self(0);
|
||||||
|
pub const ONE_SECOND:Self=Self(1_000_000_000);
|
||||||
|
pub const ONE_MILLISECOND:Self=Self(1_000_000);
|
||||||
|
pub const ONE_MICROSECOND:Self=Self(1_000);
|
||||||
|
pub const ONE_NANOSECOND:Self=Self(1);
|
||||||
|
#[inline]
|
||||||
|
pub fn from_secs(num:i64)->Self{
|
||||||
|
Self(Self::ONE_SECOND.0*num)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn from_millis(num:i64)->Self{
|
||||||
|
Self(Self::ONE_MILLISECOND.0*num)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn from_micros(num:i64)->Self{
|
||||||
|
Self(Self::ONE_MICROSECOND.0*num)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn from_nanos(num:i64)->Self{
|
||||||
|
Self(Self::ONE_NANOSECOND.0*num)
|
||||||
|
}
|
||||||
|
//should I have checked subtraction? force all time variables to be positive?
|
||||||
|
#[inline]
|
||||||
|
pub fn nanos(&self)->i64{
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Planar64> for Time{
|
||||||
|
#[inline]
|
||||||
|
fn from(value:Planar64)->Self{
|
||||||
|
Time((((value.0 as i128)*1_000_000_000)>>32) as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for Time{
|
||||||
|
#[inline]
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Neg for Time{
|
||||||
|
type Output=Time;
|
||||||
|
#[inline]
|
||||||
|
fn neg(self)->Self::Output {
|
||||||
|
Time(-self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Add<Time> for Time{
|
||||||
|
type Output=Time;
|
||||||
|
#[inline]
|
||||||
|
fn add(self,rhs:Self)->Self::Output {
|
||||||
|
Time(self.0+rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Sub<Time> for Time{
|
||||||
|
type Output=Time;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self,rhs:Self)->Self::Output {
|
||||||
|
Time(self.0-rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<Time> for Time{
|
||||||
|
type Output=Time;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self,rhs:Time)->Self::Output{
|
||||||
|
Self((((self.0 as i128)*(rhs.0 as i128))/1_000_000_000) as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Div<i64> for Time{
|
||||||
|
type Output=Time;
|
||||||
|
#[inline]
|
||||||
|
fn div(self,rhs:i64)->Self::Output {
|
||||||
|
Time(self.0/rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
const fn gcd(mut a:u64,mut b:u64)->u64{
|
||||||
|
while b!=0{
|
||||||
|
(a,b)=(b,a.rem_euclid(b));
|
||||||
|
};
|
||||||
|
a
|
||||||
|
}
|
||||||
|
#[derive(Clone,Hash)]
|
||||||
|
pub struct Ratio64{
|
||||||
|
num:i64,
|
||||||
|
den:u64,
|
||||||
|
}
|
||||||
|
impl Ratio64{
|
||||||
|
pub const ZERO:Self=Ratio64{num:0,den:1};
|
||||||
|
pub const ONE:Self=Ratio64{num:1,den:1};
|
||||||
|
#[inline]
|
||||||
|
pub const fn new(num:i64,den:u64)->Option<Ratio64>{
|
||||||
|
if den==0{
|
||||||
|
None
|
||||||
|
}else{
|
||||||
|
let d=gcd(num.unsigned_abs(),den);
|
||||||
|
Some(Self{num:num/d as i64,den:den/d})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn mul_int(&self,rhs:i64)->i64{
|
||||||
|
rhs*self.num/self.den as i64
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn rhs_div_int(&self,rhs:i64)->i64{
|
||||||
|
rhs*self.den as i64/self.num
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn mul_ref(&self,rhs:&Ratio64)->Ratio64{
|
||||||
|
let (num,den)=(self.num*rhs.num,self.den*rhs.den);
|
||||||
|
let d=gcd(num.unsigned_abs(),den);
|
||||||
|
Self{
|
||||||
|
num:num/d as i64,
|
||||||
|
den:den/d,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//from num_traits crate
|
||||||
|
#[inline]
|
||||||
|
fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
|
||||||
|
let bits: u32 = f.to_bits();
|
||||||
|
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
|
||||||
|
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
|
||||||
|
let mantissa = if exponent == 0 {
|
||||||
|
(bits & 0x7fffff) << 1
|
||||||
|
} else {
|
||||||
|
(bits & 0x7fffff) | 0x800000
|
||||||
|
};
|
||||||
|
// Exponent bias + mantissa shift
|
||||||
|
exponent -= 127 + 23;
|
||||||
|
(mantissa as u64, exponent, sign)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
|
||||||
|
let bits: u64 = f.to_bits();
|
||||||
|
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
|
||||||
|
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
|
||||||
|
let mantissa = if exponent == 0 {
|
||||||
|
(bits & 0xfffffffffffff) << 1
|
||||||
|
} else {
|
||||||
|
(bits & 0xfffffffffffff) | 0x10000000000000
|
||||||
|
};
|
||||||
|
// Exponent bias + mantissa shift
|
||||||
|
exponent -= 1023 + 52;
|
||||||
|
(mantissa, exponent, sign)
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Ratio64TryFromFloatError{
|
||||||
|
Nan,
|
||||||
|
Infinite,
|
||||||
|
Subnormal,
|
||||||
|
HighlyNegativeExponent(i16),
|
||||||
|
HighlyPositiveExponent(i16),
|
||||||
|
}
|
||||||
|
const MAX_DENOMINATOR:u128=u64::MAX as u128;
|
||||||
|
#[inline]
|
||||||
|
fn ratio64_from_mes((m,e,s):(u64,i16,i8))->Result<Ratio64,Ratio64TryFromFloatError>{
|
||||||
|
if e< -127{
|
||||||
|
//this can also just be zero
|
||||||
|
Err(Ratio64TryFromFloatError::HighlyNegativeExponent(e))
|
||||||
|
}else if e< -63{
|
||||||
|
//approximate input ratio within denominator limit
|
||||||
|
let mut target_num=m as u128;
|
||||||
|
let mut target_den=1u128<<-e;
|
||||||
|
|
||||||
|
let mut num=1;
|
||||||
|
let mut den=0;
|
||||||
|
let mut prev_num=0;
|
||||||
|
let mut prev_den=1;
|
||||||
|
|
||||||
|
while target_den!=0{
|
||||||
|
let whole=target_num/target_den;
|
||||||
|
(target_num,target_den)=(target_den,target_num-whole*target_den);
|
||||||
|
let new_num=whole*num+prev_num;
|
||||||
|
let new_den=whole*den+prev_den;
|
||||||
|
if MAX_DENOMINATOR<new_den{
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
(prev_num,prev_den)=(num,den);
|
||||||
|
(num,den)=(new_num,new_den);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Ratio64::new(num as i64,den as u64).unwrap())
|
||||||
|
}else if e<0{
|
||||||
|
Ok(Ratio64::new((m as i64)*(s as i64),1<<-e).unwrap())
|
||||||
|
}else if (64-m.leading_zeros() as i16)+e<64{
|
||||||
|
Ok(Ratio64::new((m as i64)*(s as i64)*(1<<e),1).unwrap())
|
||||||
|
}else{
|
||||||
|
Err(Ratio64TryFromFloatError::HighlyPositiveExponent(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<f32> for Ratio64{
|
||||||
|
type Error=Ratio64TryFromFloatError;
|
||||||
|
#[inline]
|
||||||
|
fn try_from(value:f32)->Result<Self,Self::Error>{
|
||||||
|
match value.classify(){
|
||||||
|
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||||
|
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||||
|
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||||
|
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
||||||
|
std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f32(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<f64> for Ratio64{
|
||||||
|
type Error=Ratio64TryFromFloatError;
|
||||||
|
#[inline]
|
||||||
|
fn try_from(value:f64)->Result<Self,Self::Error>{
|
||||||
|
match value.classify(){
|
||||||
|
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||||
|
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||||
|
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||||
|
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
||||||
|
std::num::FpCategory::Normal=>ratio64_from_mes(integer_decode_f64(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<Ratio64> for Ratio64{
|
||||||
|
type Output=Ratio64;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self,rhs:Ratio64)->Self::Output{
|
||||||
|
let (num,den)=(self.num*rhs.num,self.den*rhs.den);
|
||||||
|
let d=gcd(num.unsigned_abs(),den);
|
||||||
|
Self{
|
||||||
|
num:num/d as i64,
|
||||||
|
den:den/d,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<i64> for Ratio64{
|
||||||
|
type Output=Ratio64;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self,rhs:i64)->Self::Output {
|
||||||
|
Self{
|
||||||
|
num:self.num*rhs,
|
||||||
|
den:self.den,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Div<u64> for Ratio64{
|
||||||
|
type Output=Ratio64;
|
||||||
|
#[inline]
|
||||||
|
fn div(self,rhs:u64)->Self::Output {
|
||||||
|
Self{
|
||||||
|
num:self.num,
|
||||||
|
den:self.den*rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone,Hash)]
|
||||||
|
pub struct Ratio64Vec2{
|
||||||
|
pub x:Ratio64,
|
||||||
|
pub y:Ratio64,
|
||||||
|
}
|
||||||
|
impl Ratio64Vec2{
|
||||||
|
pub const ONE:Self=Self{x:Ratio64::ONE,y:Ratio64::ONE};
|
||||||
|
#[inline]
|
||||||
|
pub fn new(x:Ratio64,y:Ratio64)->Self{
|
||||||
|
Self{x,y}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn mul_int(&self,rhs:glam::I64Vec2)->glam::I64Vec2{
|
||||||
|
glam::i64vec2(
|
||||||
|
self.x.mul_int(rhs.x),
|
||||||
|
self.y.mul_int(rhs.y),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<i64> for Ratio64Vec2{
|
||||||
|
type Output=Ratio64Vec2;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self,rhs:i64)->Self::Output {
|
||||||
|
Self{
|
||||||
|
x:self.x*rhs,
|
||||||
|
y:self.y*rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///[-pi,pi) = [-2^31,2^31-1]
|
||||||
|
#[derive(Clone,Copy,Hash)]
|
||||||
|
pub struct Angle32(i32);
|
||||||
|
impl Angle32{
|
||||||
|
pub const FRAC_PI_2:Self=Self(1<<30);
|
||||||
|
pub const PI:Self=Self(-1<<31);
|
||||||
|
#[inline]
|
||||||
|
pub fn wrap_from_i64(theta:i64)->Self{
|
||||||
|
//take lower bits
|
||||||
|
//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()))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn clamp_from_i64(theta:i64)->Self{
|
||||||
|
//the assembly is a bit confusing for this, I thought it was checking the same thing twice
|
||||||
|
//but it's just checking and then overwriting the value for both upper and lower bounds.
|
||||||
|
Self(theta.clamp(i32::MIN as i64,i32::MAX as i64) as i32)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn get(&self)->i32{
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
/// Clamps the value towards the midpoint of the range.
|
||||||
|
/// Note that theta_min can be larger than theta_max and it will wrap clamp the other way around
|
||||||
|
#[inline]
|
||||||
|
pub fn clamp(&self,theta_min:Self,theta_max:Self)->Self{
|
||||||
|
//((max-min as u32)/2 as i32)+min
|
||||||
|
let midpoint=((
|
||||||
|
u32::from_ne_bytes(theta_max.0.to_ne_bytes())
|
||||||
|
.wrapping_sub(u32::from_ne_bytes(theta_min.0.to_ne_bytes()))
|
||||||
|
/2
|
||||||
|
) as i32)//(u32::MAX/2) as i32 ALWAYS works
|
||||||
|
.wrapping_add(theta_min.0);
|
||||||
|
//(theta-mid).clamp(max-mid,min-mid)+mid
|
||||||
|
Self(
|
||||||
|
self.0.wrapping_sub(midpoint)
|
||||||
|
.max(theta_min.0.wrapping_sub(midpoint))
|
||||||
|
.min(theta_max.0.wrapping_sub(midpoint))
|
||||||
|
.wrapping_add(midpoint)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
#[inline]
|
||||||
|
pub fn cos(&self)->Unit32{
|
||||||
|
//TODO: fix this rounding towards 0
|
||||||
|
Unit32(unsafe{((self.0 as f64*ANGLE32_TO_FLOAT64_RADIANS).cos()*UNIT32_ONE_FLOAT64).to_int_unchecked()})
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn sin(&self)->Unit32{
|
||||||
|
//TODO: fix this rounding towards 0
|
||||||
|
Unit32(unsafe{((self.0 as f64*ANGLE32_TO_FLOAT64_RADIANS).sin()*UNIT32_ONE_FLOAT64).to_int_unchecked()})
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
const ANGLE32_TO_FLOAT64_RADIANS:f64=std::f64::consts::PI/((1i64<<31) as f64);
|
||||||
|
impl Into<f32> for Angle32{
|
||||||
|
#[inline]
|
||||||
|
fn into(self)->f32{
|
||||||
|
(self.0 as f64*ANGLE32_TO_FLOAT64_RADIANS) as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Neg for Angle32{
|
||||||
|
type Output=Angle32;
|
||||||
|
#[inline]
|
||||||
|
fn neg(self)->Self::Output{
|
||||||
|
Angle32(self.0.wrapping_neg())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Add<Angle32> for Angle32{
|
||||||
|
type Output=Angle32;
|
||||||
|
#[inline]
|
||||||
|
fn add(self,rhs:Self)->Self::Output {
|
||||||
|
Angle32(self.0.wrapping_add(rhs.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Sub<Angle32> for Angle32{
|
||||||
|
type Output=Angle32;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self,rhs:Self)->Self::Output {
|
||||||
|
Angle32(self.0.wrapping_sub(rhs.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<i32> for Angle32{
|
||||||
|
type Output=Angle32;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self,rhs:i32)->Self::Output {
|
||||||
|
Angle32(self.0.wrapping_mul(rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<Angle32> for Angle32{
|
||||||
|
type Output=Angle32;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self,rhs:Self)->Self::Output {
|
||||||
|
Angle32(self.0.wrapping_mul(rhs.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unit type unused for now, may revive it for map files
|
||||||
|
///[-1.0,1.0] = [-2^30,2^30]
|
||||||
|
pub struct Unit32(i32);
|
||||||
|
impl Unit32{
|
||||||
|
#[inline]
|
||||||
|
pub fn as_planar64(&self) -> Planar64{
|
||||||
|
Planar64(4*(self.0 as i64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const UNIT32_ONE_FLOAT64=((1<<30) as f64);
|
||||||
|
///[-1.0,1.0] = [-2^30,2^30]
|
||||||
|
pub struct Unit32Vec3(glam::IVec3);
|
||||||
|
impl TryFrom<[f32;3]> for Unit32Vec3{
|
||||||
|
type Error=Unit32TryFromFloatError;
|
||||||
|
fn try_from(value:[f32;3])->Result<Self,Self::Error>{
|
||||||
|
Ok(Self(glam::ivec3(
|
||||||
|
Unit32::try_from(Planar64::try_from(value[0])?)?.0,
|
||||||
|
Unit32::try_from(Planar64::try_from(value[1])?)?.0,
|
||||||
|
Unit32::try_from(Planar64::try_from(value[2])?)?.0,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
///[-1.0,1.0] = [-2^32,2^32]
|
||||||
|
#[derive(Clone,Copy,Hash,Eq,Ord,PartialEq,PartialOrd)]
|
||||||
|
pub struct Planar64(i64);
|
||||||
|
impl Planar64{
|
||||||
|
pub const ZERO:Self=Self(0);
|
||||||
|
pub const ONE:Self=Self(1<<32);
|
||||||
|
#[inline]
|
||||||
|
pub const fn int(num:i32)->Self{
|
||||||
|
Self(Self::ONE.0*num as i64)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const fn raw(num:i64)->Self{
|
||||||
|
Self(num)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const fn get(&self)->i64{
|
||||||
|
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_CONVERT_TO_FLOAT32:f32=1.0/PLANAR64_ONE_FLOAT32;
|
||||||
|
const PLANAR64_ONE_FLOAT64:f64=(1u64<<32) as f64;
|
||||||
|
impl Into<f32> for Planar64{
|
||||||
|
#[inline]
|
||||||
|
fn into(self)->f32{
|
||||||
|
self.0 as f32*PLANAR64_CONVERT_TO_FLOAT32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Ratio64> for Planar64{
|
||||||
|
#[inline]
|
||||||
|
fn from(ratio:Ratio64)->Self{
|
||||||
|
Self((((ratio.num as i128)<<32)/ratio.den as i128) as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Planar64TryFromFloatError{
|
||||||
|
Nan,
|
||||||
|
Infinite,
|
||||||
|
Subnormal,
|
||||||
|
HighlyNegativeExponent(i16),
|
||||||
|
HighlyPositiveExponent(i16),
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn planar64_from_mes((m,e,s):(u64,i16,i8))->Result<Planar64,Planar64TryFromFloatError>{
|
||||||
|
let e32=e+32;
|
||||||
|
if e32<0&&(m>>-e32)==0{//shifting m will underflow to 0
|
||||||
|
Ok(Planar64::ZERO)
|
||||||
|
// println!("m{} e{} s{}",m,e,s);
|
||||||
|
// println!("f={}",(m as f64)*(2.0f64.powf(e as f64))*(s as f64));
|
||||||
|
// Err(Planar64TryFromFloatError::HighlyNegativeExponent(e))
|
||||||
|
}else if (64-m.leading_zeros() as i16)+e32<64{//shifting m will not overflow
|
||||||
|
if e32<0{
|
||||||
|
Ok(Planar64((m as i64)*(s as i64)>>-e32))
|
||||||
|
}else{
|
||||||
|
Ok(Planar64((m as i64)*(s as i64)<<e32))
|
||||||
|
}
|
||||||
|
}else{//if shifting m will overflow (prev check failed)
|
||||||
|
Err(Planar64TryFromFloatError::HighlyPositiveExponent(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<f32> for Planar64{
|
||||||
|
type Error=Planar64TryFromFloatError;
|
||||||
|
#[inline]
|
||||||
|
fn try_from(value:f32)->Result<Self,Self::Error>{
|
||||||
|
match value.classify(){
|
||||||
|
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||||
|
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||||
|
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||||
|
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
||||||
|
std::num::FpCategory::Normal=>planar64_from_mes(integer_decode_f32(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<f64> for Planar64{
|
||||||
|
type Error=Planar64TryFromFloatError;
|
||||||
|
#[inline]
|
||||||
|
fn try_from(value:f64)->Result<Self,Self::Error>{
|
||||||
|
match value.classify(){
|
||||||
|
std::num::FpCategory::Nan=>Err(Self::Error::Nan),
|
||||||
|
std::num::FpCategory::Infinite=>Err(Self::Error::Infinite),
|
||||||
|
std::num::FpCategory::Zero=>Ok(Self::ZERO),
|
||||||
|
std::num::FpCategory::Subnormal=>Err(Self::Error::Subnormal),
|
||||||
|
std::num::FpCategory::Normal=>planar64_from_mes(integer_decode_f64(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for Planar64{
|
||||||
|
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||||
|
write!(f,"{:.3}",
|
||||||
|
Into::<f32>::into(*self),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Neg for Planar64{
|
||||||
|
type Output=Planar64;
|
||||||
|
#[inline]
|
||||||
|
fn neg(self)->Self::Output{
|
||||||
|
Planar64(-self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Add<Planar64> for Planar64{
|
||||||
|
type Output=Planar64;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Planar64(self.0+rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Sub<Planar64> for Planar64{
|
||||||
|
type Output=Planar64;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Planar64(self.0-rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<i64> for Planar64{
|
||||||
|
type Output=Planar64;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rhs: i64) -> Self::Output {
|
||||||
|
Planar64(self.0*rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<Planar64> for Planar64{
|
||||||
|
type Output=Planar64;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
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{
|
||||||
|
type Output=Planar64;
|
||||||
|
#[inline]
|
||||||
|
fn div(self, rhs: i64) -> Self::Output {
|
||||||
|
Planar64(self.0/rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Div<Planar64> for Planar64{
|
||||||
|
type Output=Planar64;
|
||||||
|
#[inline]
|
||||||
|
fn div(self, rhs: Planar64) -> Self::Output {
|
||||||
|
Planar64((((self.0 as i128)<<32)/rhs.0 as i128) as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// impl PartialOrd<i64> for Planar64{
|
||||||
|
// fn partial_cmp(&self, other: &i64) -> Option<std::cmp::Ordering> {
|
||||||
|
// self.0.partial_cmp(other)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
///[-1.0,1.0] = [-2^32,2^32]
|
||||||
|
#[derive(Clone,Copy,Default,Hash,Eq,PartialEq)]
|
||||||
|
pub struct Planar64Vec3(glam::I64Vec3);
|
||||||
|
impl Planar64Vec3{
|
||||||
|
pub const ZERO:Self=Planar64Vec3(glam::I64Vec3::ZERO);
|
||||||
|
pub const ONE:Self=Self::int(1,1,1);
|
||||||
|
pub const X:Self=Self::int(1,0,0);
|
||||||
|
pub const Y:Self=Self::int(0,1,0);
|
||||||
|
pub const Z:Self=Self::int(0,0,1);
|
||||||
|
pub const NEG_X:Self=Self::int(-1,0,0);
|
||||||
|
pub const NEG_Y:Self=Self::int(0,-1,0);
|
||||||
|
pub const NEG_Z:Self=Self::int(0,0,-1);
|
||||||
|
pub const MIN:Self=Planar64Vec3(glam::I64Vec3::MIN);
|
||||||
|
pub const MAX:Self=Planar64Vec3(glam::I64Vec3::MAX);
|
||||||
|
#[inline]
|
||||||
|
pub const fn int(x:i32,y:i32,z:i32)->Self{
|
||||||
|
Self(glam::i64vec3((x as i64)<<32,(y as i64)<<32,(z as i64)<<32))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const fn raw(x:i64,y:i64,z:i64)->Self{
|
||||||
|
Self(glam::i64vec3(x,y,z))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn x(&self)->Planar64{
|
||||||
|
Planar64(self.0.x)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn y(&self)->Planar64{
|
||||||
|
Planar64(self.0.y)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn z(&self)->Planar64{
|
||||||
|
Planar64(self.0.z)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn min(&self,rhs:Self)->Self{
|
||||||
|
Self(glam::i64vec3(
|
||||||
|
self.0.x.min(rhs.0.x),
|
||||||
|
self.0.y.min(rhs.0.y),
|
||||||
|
self.0.z.min(rhs.0.z),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn max(&self,rhs:Self)->Self{
|
||||||
|
Self(glam::i64vec3(
|
||||||
|
self.0.x.max(rhs.0.x),
|
||||||
|
self.0.y.max(rhs.0.y),
|
||||||
|
self.0.z.max(rhs.0.z),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn midpoint(&self,rhs:Self)->Self{
|
||||||
|
Self((self.0+rhs.0)/2)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn cmplt(&self,rhs:Self)->glam::BVec3{
|
||||||
|
self.0.cmplt(rhs.0)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn dot(&self,rhs:Self)->Planar64{
|
||||||
|
Planar64(((
|
||||||
|
(self.0.x as i128)*(rhs.0.x as i128)+
|
||||||
|
(self.0.y as i128)*(rhs.0.y as i128)+
|
||||||
|
(self.0.z as i128)*(rhs.0.z as i128)
|
||||||
|
)>>32) as i64)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn length(&self)->Planar64{
|
||||||
|
let radicand=(self.0.x as i128)*(self.0.x as i128)+(self.0.y as i128)*(self.0.y as i128)+(self.0.z as i128)*(self.0.z as i128);
|
||||||
|
Planar64(unsafe{(radicand as f64).sqrt().to_int_unchecked()})
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn with_length(&self,length:Planar64)->Self{
|
||||||
|
let radicand=(self.0.x as i128)*(self.0.x as i128)+(self.0.y as i128)*(self.0.y as i128)+(self.0.z as i128)*(self.0.z as i128);
|
||||||
|
let self_length:i128=unsafe{(radicand as f64).sqrt().to_int_unchecked()};
|
||||||
|
//self.0*length/self_length
|
||||||
|
Planar64Vec3(
|
||||||
|
glam::i64vec3(
|
||||||
|
((self.0.x as i128)*(length.0 as i128)/self_length) as i64,
|
||||||
|
((self.0.y as i128)*(length.0 as i128)/self_length) as i64,
|
||||||
|
((self.0.z as i128)*(length.0 as i128)/self_length) as i64,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<glam::Vec3> for Planar64Vec3{
|
||||||
|
#[inline]
|
||||||
|
fn into(self)->glam::Vec3{
|
||||||
|
glam::vec3(
|
||||||
|
self.0.x as f32,
|
||||||
|
self.0.y as f32,
|
||||||
|
self.0.z as f32,
|
||||||
|
)*PLANAR64_CONVERT_TO_FLOAT32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<[f32;3]> for Planar64Vec3{
|
||||||
|
type Error=Planar64TryFromFloatError;
|
||||||
|
#[inline]
|
||||||
|
fn try_from(value:[f32;3])->Result<Self,Self::Error>{
|
||||||
|
Ok(Self(glam::i64vec3(
|
||||||
|
Planar64::try_from(value[0])?.0,
|
||||||
|
Planar64::try_from(value[1])?.0,
|
||||||
|
Planar64::try_from(value[2])?.0,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<glam::Vec3A> for Planar64Vec3{
|
||||||
|
type Error=Planar64TryFromFloatError;
|
||||||
|
#[inline]
|
||||||
|
fn try_from(value:glam::Vec3A)->Result<Self,Self::Error>{
|
||||||
|
Ok(Self(glam::i64vec3(
|
||||||
|
Planar64::try_from(value.x)?.0,
|
||||||
|
Planar64::try_from(value.y)?.0,
|
||||||
|
Planar64::try_from(value.z)?.0,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for Planar64Vec3{
|
||||||
|
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||||
|
write!(f,"{:.3},{:.3},{:.3}",
|
||||||
|
Into::<f32>::into(self.x()),Into::<f32>::into(self.y()),Into::<f32>::into(self.z()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Neg for Planar64Vec3{
|
||||||
|
type Output=Planar64Vec3;
|
||||||
|
#[inline]
|
||||||
|
fn neg(self)->Self::Output{
|
||||||
|
Planar64Vec3(-self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Add<Planar64Vec3> for Planar64Vec3{
|
||||||
|
type Output=Planar64Vec3;
|
||||||
|
#[inline]
|
||||||
|
fn add(self,rhs:Planar64Vec3) -> Self::Output {
|
||||||
|
Planar64Vec3(self.0+rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::AddAssign<Planar64Vec3> for Planar64Vec3{
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self,rhs:Planar64Vec3){
|
||||||
|
*self=*self+rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Sub<Planar64Vec3> for Planar64Vec3{
|
||||||
|
type Output=Planar64Vec3;
|
||||||
|
#[inline]
|
||||||
|
fn sub(self,rhs:Planar64Vec3) -> Self::Output {
|
||||||
|
Planar64Vec3(self.0-rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::SubAssign<Planar64Vec3> for Planar64Vec3{
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self,rhs:Planar64Vec3){
|
||||||
|
*self=*self-rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<Planar64Vec3> for Planar64Vec3{
|
||||||
|
type Output=Planar64Vec3;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rhs: Planar64Vec3) -> Self::Output {
|
||||||
|
Planar64Vec3(glam::i64vec3(
|
||||||
|
(((self.0.x as i128)*(rhs.0.x as i128))>>32) as i64,
|
||||||
|
(((self.0.y as i128)*(rhs.0.y as i128))>>32) as i64,
|
||||||
|
(((self.0.z as i128)*(rhs.0.z as i128))>>32) as i64
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<Planar64> for Planar64Vec3{
|
||||||
|
type Output=Planar64Vec3;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rhs: Planar64) -> Self::Output {
|
||||||
|
Planar64Vec3(glam::i64vec3(
|
||||||
|
(((self.0.x as i128)*(rhs.0 as i128))>>32) as i64,
|
||||||
|
(((self.0.y as i128)*(rhs.0 as i128))>>32) as i64,
|
||||||
|
(((self.0.z as i128)*(rhs.0 as i128))>>32) as i64
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<i64> for Planar64Vec3{
|
||||||
|
type Output=Planar64Vec3;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self,rhs:i64)->Self::Output {
|
||||||
|
Planar64Vec3(glam::i64vec3(
|
||||||
|
self.0.x*rhs,
|
||||||
|
self.0.y*rhs,
|
||||||
|
self.0.z*rhs
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<Time> for Planar64Vec3{
|
||||||
|
type Output=Planar64Vec3;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self,rhs:Time)->Self::Output{
|
||||||
|
Planar64Vec3(glam::i64vec3(
|
||||||
|
(((self.0.x as i128)*(rhs.0 as i128))/1_000_000_000) as i64,
|
||||||
|
(((self.0.y as i128)*(rhs.0 as i128))/1_000_000_000) as i64,
|
||||||
|
(((self.0.z as i128)*(rhs.0 as i128))/1_000_000_000) as i64
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Div<i64> for Planar64Vec3{
|
||||||
|
type Output=Planar64Vec3;
|
||||||
|
#[inline]
|
||||||
|
fn div(self,rhs:i64)->Self::Output{
|
||||||
|
Planar64Vec3(glam::i64vec3(
|
||||||
|
self.0.x/rhs,
|
||||||
|
self.0.y/rhs,
|
||||||
|
self.0.z/rhs,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///[-1.0,1.0] = [-2^32,2^32]
|
||||||
|
#[derive(Clone,Copy)]
|
||||||
|
pub struct Planar64Mat3{
|
||||||
|
x_axis:Planar64Vec3,
|
||||||
|
y_axis:Planar64Vec3,
|
||||||
|
z_axis:Planar64Vec3,
|
||||||
|
}
|
||||||
|
impl Default for Planar64Mat3{
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self{
|
||||||
|
x_axis:Planar64Vec3::X,
|
||||||
|
y_axis:Planar64Vec3::Y,
|
||||||
|
z_axis:Planar64Vec3::Z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Mul<Planar64Vec3> for Planar64Mat3{
|
||||||
|
type Output=Planar64Vec3;
|
||||||
|
#[inline]
|
||||||
|
fn mul(self,rhs:Planar64Vec3) -> Self::Output {
|
||||||
|
self.x_axis*rhs.x()
|
||||||
|
+self.y_axis*rhs.y()
|
||||||
|
+self.z_axis*rhs.z()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Planar64Mat3{
|
||||||
|
#[inline]
|
||||||
|
pub fn from_cols(x_axis:Planar64Vec3,y_axis:Planar64Vec3,z_axis:Planar64Vec3)->Self{
|
||||||
|
Self{
|
||||||
|
x_axis,
|
||||||
|
y_axis,
|
||||||
|
z_axis,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn int_from_cols_array(array:[i32;9])->Self{
|
||||||
|
Self{
|
||||||
|
x_axis:Planar64Vec3::int(array[0],array[1],array[2]),
|
||||||
|
y_axis:Planar64Vec3::int(array[3],array[4],array[5]),
|
||||||
|
z_axis:Planar64Vec3::int(array[6],array[7],array[8]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[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{
|
||||||
|
let theta=angle.0 as f64*ANGLE32_TO_FLOAT64_RADIANS;
|
||||||
|
let (s,c)=theta.sin_cos();
|
||||||
|
let (c,s)=(c*PLANAR64_ONE_FLOAT64,s*PLANAR64_ONE_FLOAT64);
|
||||||
|
//TODO: fix this rounding towards 0
|
||||||
|
let (c,s):(i64,i64)=(unsafe{c.to_int_unchecked()},unsafe{s.to_int_unchecked()});
|
||||||
|
Self::from_cols(
|
||||||
|
Planar64Vec3(glam::i64vec3(c,0,-s)),
|
||||||
|
Planar64Vec3::Y,
|
||||||
|
Planar64Vec3(glam::i64vec3(s,0,c)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<glam::Mat3> for Planar64Mat3{
|
||||||
|
#[inline]
|
||||||
|
fn into(self)->glam::Mat3{
|
||||||
|
glam::Mat3::from_cols(
|
||||||
|
self.x_axis.into(),
|
||||||
|
self.y_axis.into(),
|
||||||
|
self.z_axis.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<glam::Mat3A> for Planar64Mat3{
|
||||||
|
type Error=Planar64TryFromFloatError;
|
||||||
|
#[inline]
|
||||||
|
fn try_from(value:glam::Mat3A)->Result<Self,Self::Error>{
|
||||||
|
Ok(Self{
|
||||||
|
x_axis:Planar64Vec3::try_from(value.x_axis)?,
|
||||||
|
y_axis:Planar64Vec3::try_from(value.y_axis)?,
|
||||||
|
z_axis:Planar64Vec3::try_from(value.z_axis)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for Planar64Mat3{
|
||||||
|
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||||
|
write!(f,"\n{:.3},{:.3},{:.3}\n{:.3},{:.3},{:.3}\n{:.3},{:.3},{:.3}",
|
||||||
|
Into::<f32>::into(self.x_axis.x()),Into::<f32>::into(self.x_axis.y()),Into::<f32>::into(self.x_axis.z()),
|
||||||
|
Into::<f32>::into(self.y_axis.x()),Into::<f32>::into(self.y_axis.y()),Into::<f32>::into(self.y_axis.z()),
|
||||||
|
Into::<f32>::into(self.z_axis.x()),Into::<f32>::into(self.z_axis.y()),Into::<f32>::into(self.z_axis.z()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::Div<i64> for Planar64Mat3{
|
||||||
|
type Output=Planar64Mat3;
|
||||||
|
#[inline]
|
||||||
|
fn div(self,rhs:i64)->Self::Output{
|
||||||
|
Planar64Mat3{
|
||||||
|
x_axis:self.x_axis/rhs,
|
||||||
|
y_axis:self.y_axis/rhs,
|
||||||
|
z_axis:self.z_axis/rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///[-1.0,1.0] = [-2^32,2^32]
|
||||||
|
#[derive(Clone,Copy,Default)]
|
||||||
|
pub struct Planar64Affine3{
|
||||||
|
pub matrix3:Planar64Mat3,//includes scale above 1
|
||||||
|
pub translation:Planar64Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Planar64Affine3{
|
||||||
|
#[inline]
|
||||||
|
pub fn new(matrix3:Planar64Mat3,translation:Planar64Vec3)->Self{
|
||||||
|
Self{matrix3,translation}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn transform_point3(&self,point:Planar64Vec3) -> Planar64Vec3{
|
||||||
|
Planar64Vec3(
|
||||||
|
self.translation.0
|
||||||
|
+(self.matrix3.x_axis*point.x()).0
|
||||||
|
+(self.matrix3.y_axis*point.y()).0
|
||||||
|
+(self.matrix3.z_axis*point.z()).0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<glam::Mat4> for Planar64Affine3{
|
||||||
|
#[inline]
|
||||||
|
fn into(self)->glam::Mat4{
|
||||||
|
glam::Mat4::from_cols_array(&[
|
||||||
|
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.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
|
||||||
|
])*PLANAR64_CONVERT_TO_FLOAT32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<glam::Affine3A> for Planar64Affine3{
|
||||||
|
type Error=Planar64TryFromFloatError;
|
||||||
|
fn try_from(value: glam::Affine3A)->Result<Self, Self::Error> {
|
||||||
|
Ok(Self{
|
||||||
|
matrix3:Planar64Mat3::try_from(value.matrix3)?,
|
||||||
|
translation:Planar64Vec3::try_from(value.translation)?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for Planar64Affine3{
|
||||||
|
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||||
|
write!(f,"translation: {:.3},{:.3},{:.3}\nmatrix3:\n{:.3},{:.3},{:.3}\n{:.3},{:.3},{:.3}\n{:.3},{:.3},{:.3}",
|
||||||
|
Into::<f32>::into(self.translation.x()),Into::<f32>::into(self.translation.y()),Into::<f32>::into(self.translation.z()),
|
||||||
|
Into::<f32>::into(self.matrix3.x_axis.x()),Into::<f32>::into(self.matrix3.x_axis.y()),Into::<f32>::into(self.matrix3.x_axis.z()),
|
||||||
|
Into::<f32>::into(self.matrix3.y_axis.x()),Into::<f32>::into(self.matrix3.y_axis.y()),Into::<f32>::into(self.matrix3.y_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());
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
use crate::primitives;
|
use crate::primitives;
|
||||||
|
use crate::integer::{Planar64,Planar64Vec3,Planar64Mat3,Planar64Affine3};
|
||||||
|
|
||||||
fn class_is_a(class: &str, superclass: &str) -> bool {
|
fn class_is_a(class: &str, superclass: &str) -> bool {
|
||||||
if class==superclass {
|
if class==superclass {
|
||||||
@ -30,26 +31,48 @@ fn get_texture_refs(dom:&rbx_dom_weak::WeakDom) -> Vec<rbx_dom_weak::types::Ref>
|
|||||||
//next class
|
//next class
|
||||||
objects
|
objects
|
||||||
}
|
}
|
||||||
fn get_attributes(name:&str,can_collide:bool,velocity:glam::Vec3,force_intersecting:bool)->crate::model::CollisionAttributes{
|
fn planar64_affine3_from_roblox(cf:&rbx_dom_weak::types::CFrame,size:&rbx_dom_weak::types::Vector3)->Planar64Affine3{
|
||||||
|
Planar64Affine3::new(
|
||||||
|
Planar64Mat3::from_cols(
|
||||||
|
Planar64Vec3::try_from([cf.orientation.x.x,cf.orientation.y.x,cf.orientation.z.x]).unwrap()
|
||||||
|
*Planar64::try_from(size.x/2.0).unwrap(),
|
||||||
|
Planar64Vec3::try_from([cf.orientation.x.y,cf.orientation.y.y,cf.orientation.z.y]).unwrap()
|
||||||
|
*Planar64::try_from(size.y/2.0).unwrap(),
|
||||||
|
Planar64Vec3::try_from([cf.orientation.x.z,cf.orientation.y.z,cf.orientation.z.z]).unwrap()
|
||||||
|
*Planar64::try_from(size.z/2.0).unwrap(),
|
||||||
|
),
|
||||||
|
Planar64Vec3::try_from([cf.position.x,cf.position.y,cf.position.z]).unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_intersecting:bool)->crate::model::CollisionAttributes{
|
||||||
let mut general=crate::model::GameMechanicAttributes::default();
|
let mut general=crate::model::GameMechanicAttributes::default();
|
||||||
let mut intersecting=crate::model::IntersectingAttributes::default();
|
let mut intersecting=crate::model::IntersectingAttributes::default();
|
||||||
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"=>intersecting.water=Some(crate::model::IntersectingWater{density:1.0,drag:1.0}),
|
"Water"=>{
|
||||||
"Accelerator"=>{force_can_collide=false;intersecting.accelerator=Some(crate::model::IntersectingAccelerator{acceleration:velocity})},
|
force_can_collide=false;
|
||||||
|
//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.stage_element=Some(crate::model::GameMechanicStageElement{
|
"Platform"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(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.stage_element=Some(crate::model::GameMechanicStageElement{
|
general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(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){
|
||||||
@ -58,12 +81,28 @@ fn get_attributes(name:&str,can_collide:bool,velocity:glam::Vec3,force_intersect
|
|||||||
},
|
},
|
||||||
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;
|
||||||
@ -72,35 +111,33 @@ fn get_attributes(name:&str,can_collide:bool,velocity:glam::Vec3,force_intersect
|
|||||||
"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!=glam::Vec3::ZERO{
|
if velocity!=Planar64Vec3::ZERO{
|
||||||
general.booster=Some(crate::model::GameMechanicBooster{velocity});
|
general.booster=Some(crate::model::GameMechanicBooster::Velocity(velocity));
|
||||||
}
|
}
|
||||||
match force_can_collide{
|
match force_can_collide{
|
||||||
true=>{
|
true=>{
|
||||||
match name{
|
match name{
|
||||||
//"Bounce"=>(),
|
"Bounce"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Elastic(u32::MAX)),
|
||||||
"Surf"=>contacting.surf=Some(crate::model::ContactingSurf{}),
|
"Surf"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Surf),
|
||||||
"Ladder"=>contacting.ladder=Some(crate::model::ContactingLadder{sticky:true}),
|
"Ladder"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Ladder(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.jump_limit.is_some()
|
||general.any()
|
||||||
||general.booster.is_some()
|
||intersecting.any()
|
||||||
||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{
|
||||||
@ -189,7 +226,7 @@ enum RobloxBasePartDescription{
|
|||||||
}
|
}
|
||||||
pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::IndexedModelInstances{
|
pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::IndexedModelInstances{
|
||||||
//IndexedModelInstances includes textures
|
//IndexedModelInstances includes textures
|
||||||
let mut spawn_point=glam::Vec3::ZERO;
|
let mut spawn_point=Planar64Vec3::ZERO;
|
||||||
|
|
||||||
let mut indexed_models=Vec::new();
|
let mut indexed_models=Vec::new();
|
||||||
let mut model_id_from_description=std::collections::HashMap::<RobloxBasePartDescription,usize>::new();
|
let mut model_id_from_description=std::collections::HashMap::<RobloxBasePartDescription,usize>::new();
|
||||||
@ -218,36 +255,25 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::Index
|
|||||||
object.properties.get("CanCollide"),
|
object.properties.get("CanCollide"),
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
let model_transform=glam::Affine3A::from_translation(
|
let model_transform=planar64_affine3_from_roblox(cf,size);
|
||||||
glam::Vec3::new(cf.position.x,cf.position.y,cf.position.z)
|
|
||||||
)
|
|
||||||
* glam::Affine3A::from_mat3(
|
|
||||||
glam::Mat3::from_cols(
|
|
||||||
glam::Vec3::new(cf.orientation.x.x,cf.orientation.y.x,cf.orientation.z.x),
|
|
||||||
glam::Vec3::new(cf.orientation.x.y,cf.orientation.y.y,cf.orientation.z.y),
|
|
||||||
glam::Vec3::new(cf.orientation.x.z,cf.orientation.y.z,cf.orientation.z.z),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
* glam::Affine3A::from_scale(
|
|
||||||
glam::Vec3::new(size.x,size.y,size.z)/2.0
|
|
||||||
);
|
|
||||||
|
|
||||||
//push TempIndexedAttributes
|
//push TempIndexedAttributes
|
||||||
let mut force_intersecting=false;
|
let mut force_intersecting=false;
|
||||||
let mut temp_indexing_attributes=Vec::new();
|
let mut temp_indexing_attributes=Vec::new();
|
||||||
if let Some(attr)=match &object.name[..]{
|
if let Some(attr)=match &object.name[..]{
|
||||||
"MapStart"=>{
|
"MapStart"=>{
|
||||||
spawn_point=model_transform.transform_point3(glam::Vec3::ZERO)+glam::vec3(0.0,2.5,0.0);
|
spawn_point=model_transform.transform_point3(Planar64Vec3::ZERO)+Planar64Vec3::Y*5/2;
|
||||||
Some(crate::model::TempIndexedAttributes::Start{mode_id:0})
|
Some(crate::model::TempIndexedAttributes::Start(crate::model::TempAttrStart{mode_id:0}))
|
||||||
},
|
},
|
||||||
"UnorderedCheckpoint"=>Some(crate::model::TempIndexedAttributes::UnorderedCheckpoint{mode_id:0}),
|
"UnorderedCheckpoint"=>Some(crate::model::TempIndexedAttributes::UnorderedCheckpoint(crate::model::TempAttrUnorderedCheckpoint{mode_id:0})),
|
||||||
other=>{
|
other=>{
|
||||||
let regman=lazy_regex::regex!(r"^(BonusStart|Spawn|ForceSpawn|OrderedCheckpoint)(\d+)$");
|
let regman=lazy_regex::regex!(r"^(BonusStart|Spawn|ForceSpawn|OrderedCheckpoint|WormholeOut)(\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{mode_id:captures[2].parse::<u32>().unwrap()}),
|
"BonusStart"=>Some(crate::model::TempIndexedAttributes::Start(crate::model::TempAttrStart{mode_id:captures[2].parse::<u32>().unwrap()})),
|
||||||
"Spawn"|"ForceSpawn"=>Some(crate::model::TempIndexedAttributes::Spawn{mode_id:0,stage_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()})),
|
||||||
"OrderedCheckpoint"=>Some(crate::model::TempIndexedAttributes::OrderedCheckpoint{mode_id:0,checkpoint_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()})),
|
||||||
|
"WormholeOut"=>Some(crate::model::TempIndexedAttributes::Wormhole(crate::model::TempAttrWormhole{wormhole_id:captures[2].parse::<u32>().unwrap()})),
|
||||||
_=>None,
|
_=>None,
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@ -463,7 +489,7 @@ pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::Index
|
|||||||
indexed_models[model_id].instances.push(crate::model::ModelInstance {
|
indexed_models[model_id].instances.push(crate::model::ModelInstance {
|
||||||
transform:model_transform,
|
transform:model_transform,
|
||||||
color:glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency),
|
color:glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency),
|
||||||
attributes:get_attributes(&object.name,*can_collide,glam::vec3(velocity.x,velocity.y,velocity.z),force_intersecting),
|
attributes:get_attributes(&object.name,*can_collide,Planar64Vec3::try_from([velocity.x,velocity.y,velocity.z]).unwrap(),force_intersecting),
|
||||||
temp_indexing:temp_indexing_attributes,
|
temp_indexing:temp_indexing_attributes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
355
src/main.rs
355
src/main.rs
@ -1,20 +1,23 @@
|
|||||||
use std::{borrow::Cow, time::Instant};
|
use std::{borrow::Cow, time::Instant};
|
||||||
use wgpu::{util::DeviceExt, AstcBlock, AstcChannel};
|
use wgpu::{util::DeviceExt, AstcBlock, AstcChannel};
|
||||||
use model::{Vertex,ModelInstance,ModelGraphicsInstance};
|
use model_graphics::{GraphicsVertex,ModelGraphicsInstance};
|
||||||
use physics::{InputInstruction, PhysicsInstruction};
|
use physics::{InputInstruction, PhysicsInstruction};
|
||||||
use instruction::{TimedInstruction, InstructionConsumer};
|
use instruction::{TimedInstruction, InstructionConsumer};
|
||||||
|
|
||||||
mod bvh;
|
mod bvh;
|
||||||
mod aabb;
|
mod aabb;
|
||||||
mod model;
|
mod model;
|
||||||
|
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;
|
||||||
mod instruction;
|
mod instruction;
|
||||||
mod load_roblox;
|
mod load_roblox;
|
||||||
|
mod integer;
|
||||||
|
|
||||||
struct Entity {
|
struct Entity {
|
||||||
index_count: u32,
|
index_count: u32,
|
||||||
@ -226,12 +229,16 @@ impl GlobalState{
|
|||||||
None
|
None
|
||||||
}else{
|
}else{
|
||||||
Some(ModelGraphicsInstance{
|
Some(ModelGraphicsInstance{
|
||||||
transform: glam::Mat4::from(instance.transform),
|
transform: instance.transform.into(),
|
||||||
normal_transform: glam::Mat3::from(instance.transform.matrix3.inverse().transpose()),
|
normal_transform: Into::<glam::Mat3>::into(instance.transform.matrix3).inverse().transpose(),
|
||||||
color: instance.color,
|
color:model_graphics::ModelGraphicsColor4::from(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();
|
||||||
@ -243,11 +250,11 @@ impl GlobalState{
|
|||||||
//create new texture_index
|
//create new texture_index
|
||||||
let texture_index=unique_textures.len();
|
let texture_index=unique_textures.len();
|
||||||
unique_textures.push(group.texture);
|
unique_textures.push(group.texture);
|
||||||
unique_texture_models.push(model::IndexedModelSingleTexture{
|
unique_texture_models.push(model_graphics::IndexedModelGraphicsSingleTexture{
|
||||||
unique_pos:model.unique_pos.clone(),
|
unique_pos:model.unique_pos.iter().map(|&v|*Into::<glam::Vec3>::into(v).as_ref()).collect(),
|
||||||
unique_tex:model.unique_tex.clone(),
|
unique_tex:model.unique_tex.iter().map(|v|*v.as_ref()).collect(),
|
||||||
unique_normal:model.unique_normal.clone(),
|
unique_normal:model.unique_normal.iter().map(|&v|*Into::<glam::Vec3>::into(v).as_ref()).collect(),
|
||||||
unique_color:model.unique_color.clone(),
|
unique_color:model.unique_color.iter().map(|v|*v.as_ref()).collect(),
|
||||||
unique_vertices:model.unique_vertices.clone(),
|
unique_vertices:model.unique_vertices.clone(),
|
||||||
texture:group.texture,
|
texture:group.texture,
|
||||||
groups:Vec::new(),
|
groups:Vec::new(),
|
||||||
@ -255,14 +262,178 @@ impl GlobalState{
|
|||||||
});
|
});
|
||||||
texture_index
|
texture_index
|
||||||
};
|
};
|
||||||
unique_texture_models[id+texture_index].groups.push(model::IndexedGroupFixedTexture{
|
unique_texture_models[id+texture_index].groups.push(model_graphics::IndexedGroupFixedTexture{
|
||||||
polys:group.polys,
|
polys:group.polys,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//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 mut models=Vec::with_capacity(unique_texture_models.len());
|
let deduplicated_models_len=deduplicated_models.len();
|
||||||
for model in unique_texture_models.into_iter(){
|
let models:Vec<model_graphics::ModelGraphicsSingleTexture>=deduplicated_models.into_iter().map(|model|{
|
||||||
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();
|
||||||
@ -278,7 +449,7 @@ impl GlobalState{
|
|||||||
}else{
|
}else{
|
||||||
let i=vertices.len() as u16;
|
let i=vertices.len() as u16;
|
||||||
let vertex=&model.unique_vertices[vertex_index as usize];
|
let vertex=&model.unique_vertices[vertex_index as usize];
|
||||||
vertices.push(Vertex {
|
vertices.push(model_graphics::GraphicsVertex{
|
||||||
pos: model.unique_pos[vertex.pos as usize],
|
pos: model.unique_pos[vertex.pos as usize],
|
||||||
tex: model.unique_tex[vertex.tex as usize],
|
tex: model.unique_tex[vertex.tex as usize],
|
||||||
normal: model.unique_normal[vertex.normal as usize],
|
normal: model.unique_normal[vertex.normal as usize],
|
||||||
@ -292,13 +463,13 @@ impl GlobalState{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
entities.push(indices);
|
entities.push(indices);
|
||||||
models.push(model::ModelSingleTexture{
|
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;
|
||||||
@ -370,6 +541,7 @@ 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);
|
||||||
}
|
}
|
||||||
@ -391,7 +563,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));
|
raw.extend_from_slice(AsRef::<[f32; 4]>::as_ref(&mi.color.get()));
|
||||||
raw.append(&mut v);
|
raw.append(&mut v);
|
||||||
}
|
}
|
||||||
raw
|
raw
|
||||||
@ -417,50 +589,50 @@ impl framework::Example for GlobalState {
|
|||||||
//wee
|
//wee
|
||||||
let user_settings=settings::read_user_settings();
|
let user_settings=settings::read_user_settings();
|
||||||
let mut indexed_models = Vec::new();
|
let mut indexed_models = Vec::new();
|
||||||
indexed_models.append(&mut model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/teslacyberv3.0.obj")[..]).unwrap(),*glam::Vec4::ONE.as_ref()));
|
indexed_models.append(&mut model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/teslacyberv3.0.obj")[..]).unwrap(),glam::Vec4::ONE));
|
||||||
indexed_models.push(primitives::unit_sphere());
|
indexed_models.push(primitives::unit_sphere());
|
||||||
indexed_models.push(primitives::unit_cylinder());
|
indexed_models.push(primitives::unit_cylinder());
|
||||||
indexed_models.push(primitives::unit_cube());
|
indexed_models.push(primitives::unit_cube());
|
||||||
println!("models.len = {:?}", indexed_models.len());
|
println!("models.len = {:?}", indexed_models.len());
|
||||||
indexed_models[0].instances.push(ModelInstance{
|
indexed_models[0].instances.push(model::ModelInstance{
|
||||||
transform:glam::Affine3A::from_translation(glam::vec3(10.,0.,-10.)),
|
transform:integer::Planar64Affine3::try_from(glam::Affine3A::from_translation(glam::vec3(10.,0.,-10.))).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
//quad monkeys
|
//quad monkeys
|
||||||
indexed_models[1].instances.push(ModelInstance{
|
indexed_models[1].instances.push(model::ModelInstance{
|
||||||
transform:glam::Affine3A::from_translation(glam::vec3(10.,5.,10.)),
|
transform:integer::Planar64Affine3::try_from(glam::Affine3A::from_translation(glam::vec3(10.,5.,10.))).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
indexed_models[1].instances.push(ModelInstance{
|
indexed_models[1].instances.push(model::ModelInstance{
|
||||||
transform:glam::Affine3A::from_translation(glam::vec3(20.,5.,10.)),
|
transform:integer::Planar64Affine3::try_from(glam::Affine3A::from_translation(glam::vec3(20.,5.,10.))).unwrap(),
|
||||||
color:glam::vec4(1.0,0.0,0.0,1.0),
|
color:glam::vec4(1.0,0.0,0.0,1.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
indexed_models[1].instances.push(ModelInstance{
|
indexed_models[1].instances.push(model::ModelInstance{
|
||||||
transform:glam::Affine3A::from_translation(glam::vec3(10.,5.,20.)),
|
transform:integer::Planar64Affine3::try_from(glam::Affine3A::from_translation(glam::vec3(10.,5.,20.))).unwrap(),
|
||||||
color:glam::vec4(0.0,1.0,0.0,1.0),
|
color:glam::vec4(0.0,1.0,0.0,1.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
indexed_models[1].instances.push(ModelInstance{
|
indexed_models[1].instances.push(model::ModelInstance{
|
||||||
transform:glam::Affine3A::from_translation(glam::vec3(20.,5.,20.)),
|
transform:integer::Planar64Affine3::try_from(glam::Affine3A::from_translation(glam::vec3(20.,5.,20.))).unwrap(),
|
||||||
color:glam::vec4(0.0,0.0,1.0,1.0),
|
color:glam::vec4(0.0,0.0,1.0,1.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
//decorative monkey
|
//decorative monkey
|
||||||
indexed_models[1].instances.push(ModelInstance{
|
indexed_models[1].instances.push(model::ModelInstance{
|
||||||
transform:glam::Affine3A::from_translation(glam::vec3(15.,10.,15.)),
|
transform:integer::Planar64Affine3::try_from(glam::Affine3A::from_translation(glam::vec3(15.,10.,15.))).unwrap(),
|
||||||
color:glam::vec4(0.5,0.5,0.5,0.5),
|
color:glam::vec4(0.5,0.5,0.5,0.5),
|
||||||
attributes:model::CollisionAttributes::Decoration,
|
attributes:model::CollisionAttributes::Decoration,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
//teapot
|
//teapot
|
||||||
indexed_models[2].instances.push(ModelInstance{
|
indexed_models[2].instances.push(model::ModelInstance{
|
||||||
transform:glam::Affine3A::from_scale_rotation_translation(glam::vec3(0.5, 1.0, 0.2),glam::quat(-0.22248298016985793,-0.839457167990537,-0.05603504040830783,-0.49261857546227916),glam::vec3(-10.,7.,10.)),
|
transform:integer::Planar64Affine3::try_from(glam::Affine3A::from_scale_rotation_translation(glam::vec3(0.5, 1.0, 0.2),glam::quat(-0.22248298016985793,-0.839457167990537,-0.05603504040830783,-0.49261857546227916),glam::vec3(-10.,7.,10.))).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
//ground
|
//ground
|
||||||
indexed_models[3].instances.push(ModelInstance{
|
indexed_models[3].instances.push(model::ModelInstance{
|
||||||
transform:glam::Affine3A::from_translation(glam::vec3(0.,0.,0.))*glam::Affine3A::from_scale(glam::vec3(160.0, 1.0, 160.0)),
|
transform:integer::Planar64Affine3::try_from(glam::Affine3A::from_translation(glam::vec3(0.,0.,0.))*glam::Affine3A::from_scale(glam::vec3(160.0, 1.0, 160.0))).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -728,7 +900,7 @@ impl framework::Example for GlobalState {
|
|||||||
module: &shader,
|
module: &shader,
|
||||||
entry_point: "vs_entity_texture",
|
entry_point: "vs_entity_texture",
|
||||||
buffers: &[wgpu::VertexBufferLayout {
|
buffers: &[wgpu::VertexBufferLayout {
|
||||||
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
array_stride: std::mem::size_of::<GraphicsVertex>() as wgpu::BufferAddress,
|
||||||
step_mode: wgpu::VertexStepMode::Vertex,
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
attributes: &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x2, 2 => Float32x3, 3 => Float32x4],
|
attributes: &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x2, 2 => Float32x3, 3 => Float32x4],
|
||||||
}],
|
}],
|
||||||
@ -760,7 +932,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.next_mouse));
|
let camera_uniforms = camera.to_uniform_data(physics.output().adjust_mouse(&physics::MouseState::default()));
|
||||||
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),
|
||||||
@ -818,7 +990,7 @@ impl framework::Example for GlobalState {
|
|||||||
let indexed_model_instances=model::IndexedModelInstances{
|
let indexed_model_instances=model::IndexedModelInstances{
|
||||||
textures:Vec::new(),
|
textures:Vec::new(),
|
||||||
models:indexed_models,
|
models:indexed_models,
|
||||||
spawn_point:glam::Vec3::Y*50.0,
|
spawn_point:integer::Planar64Vec3::Y*50,
|
||||||
modes:Vec::new(),
|
modes:Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -892,6 +1064,7 @@ 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{
|
||||||
@ -918,61 +1091,23 @@ impl framework::Example for GlobalState {
|
|||||||
|
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
fn update(&mut self, window: &winit::window::Window, device: &wgpu::Device, queue: &wgpu::Queue, event: winit::event::WindowEvent) {
|
fn update(&mut self, window: &winit::window::Window, device: &wgpu::Device, queue: &wgpu::Queue, event: winit::event::WindowEvent) {
|
||||||
|
let time=integer::Time::from_nanos(self.start_time.elapsed().as_nanos() as i64);
|
||||||
match event {
|
match event {
|
||||||
winit::event::WindowEvent::DroppedFile(path) => self.load_file(path,device,queue),
|
winit::event::WindowEvent::DroppedFile(path) => self.load_file(path,device,queue),
|
||||||
winit::event::WindowEvent::Focused(state)=>{
|
winit::event::WindowEvent::Focused(state)=>{
|
||||||
//pause unpause
|
//pause unpause
|
||||||
//recalculate pressed keys on focus
|
//recalculate pressed keys on focus
|
||||||
}
|
},
|
||||||
_=>(),
|
winit::event::WindowEvent::KeyboardInput {
|
||||||
}
|
input:winit::event::KeyboardInput{state, virtual_keycode,..},
|
||||||
}
|
|
||||||
|
|
||||||
fn device_event(&mut self, window: &winit::window::Window, event: winit::event::DeviceEvent) {
|
|
||||||
//there's no way this is the best way get a timestamp.
|
|
||||||
let time=self.start_time.elapsed().as_nanos() as i64;
|
|
||||||
match event {
|
|
||||||
winit::event::DeviceEvent::Key(winit::event::KeyboardInput {
|
|
||||||
state,
|
|
||||||
scancode: keycode,
|
|
||||||
..
|
..
|
||||||
}) => {
|
}=>{
|
||||||
let s=match state {
|
let s=match state {
|
||||||
winit::event::ElementState::Pressed => true,
|
winit::event::ElementState::Pressed => true,
|
||||||
winit::event::ElementState::Released => false,
|
winit::event::ElementState::Released => false,
|
||||||
};
|
};
|
||||||
if let Some(input_instruction)=match keycode {
|
match virtual_keycode{
|
||||||
17=>Some(InputInstruction::MoveForward(s)),//W
|
Some(winit::event::VirtualKeyCode::Tab)=>{
|
||||||
30=>Some(InputInstruction::MoveLeft(s)),//A
|
|
||||||
31=>Some(InputInstruction::MoveBack(s)),//S
|
|
||||||
32=>Some(InputInstruction::MoveRight(s)),//D
|
|
||||||
18=>Some(InputInstruction::MoveUp(s)),//E
|
|
||||||
16=>Some(InputInstruction::MoveDown(s)),//Q
|
|
||||||
57=>Some(InputInstruction::Jump(s)),//Space
|
|
||||||
44=>Some(InputInstruction::Zoom(s)),//Z
|
|
||||||
19=>if s{Some(InputInstruction::Reset)}else{None},//R
|
|
||||||
87=>{//F11
|
|
||||||
if s{
|
|
||||||
if window.fullscreen().is_some(){
|
|
||||||
window.set_fullscreen(None);
|
|
||||||
}else{
|
|
||||||
window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(None)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
},
|
|
||||||
01=>{//Esc
|
|
||||||
if s{
|
|
||||||
self.manual_mouse_lock=false;
|
|
||||||
match window.set_cursor_grab(winit::window::CursorGrabMode::None){
|
|
||||||
Ok(())=>(),
|
|
||||||
Err(e)=>println!("Could not release cursor: {:?}",e),
|
|
||||||
}
|
|
||||||
window.set_cursor_visible(true);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
},
|
|
||||||
15=>{//Tab
|
|
||||||
if s{
|
if s{
|
||||||
self.manual_mouse_lock=false;
|
self.manual_mouse_lock=false;
|
||||||
match window.set_cursor_position(winit::dpi::PhysicalPosition::new(self.graphics.camera.screen_size.x as f32/2.0, self.graphics.camera.screen_size.y as f32/2.0)){
|
match window.set_cursor_position(winit::dpi::PhysicalPosition::new(self.graphics.camera.screen_size.x as f32/2.0, self.graphics.camera.screen_size.y as f32/2.0)){
|
||||||
@ -1000,16 +1135,56 @@ impl framework::Example for GlobalState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
window.set_cursor_visible(s);
|
window.set_cursor_visible(s);
|
||||||
None
|
|
||||||
},
|
},
|
||||||
_ => {println!("scancode {}",keycode);None},
|
Some(winit::event::VirtualKeyCode::F11)=>{
|
||||||
}{
|
if s{
|
||||||
self.physics_thread.send(TimedInstruction{
|
if window.fullscreen().is_some(){
|
||||||
time,
|
window.set_fullscreen(None);
|
||||||
instruction:input_instruction,
|
}else{
|
||||||
}).unwrap();
|
window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(None)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(winit::event::VirtualKeyCode::Escape)=>{
|
||||||
|
if s{
|
||||||
|
self.manual_mouse_lock=false;
|
||||||
|
match window.set_cursor_grab(winit::window::CursorGrabMode::None){
|
||||||
|
Ok(())=>(),
|
||||||
|
Err(e)=>println!("Could not release cursor: {:?}",e),
|
||||||
|
}
|
||||||
|
window.set_cursor_visible(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(keycode)=>{
|
||||||
|
if let Some(input_instruction)=match keycode {
|
||||||
|
winit::event::VirtualKeyCode::W => Some(InputInstruction::MoveForward(s)),
|
||||||
|
winit::event::VirtualKeyCode::A => Some(InputInstruction::MoveLeft(s)),
|
||||||
|
winit::event::VirtualKeyCode::S => Some(InputInstruction::MoveBack(s)),
|
||||||
|
winit::event::VirtualKeyCode::D => Some(InputInstruction::MoveRight(s)),
|
||||||
|
winit::event::VirtualKeyCode::E => Some(InputInstruction::MoveUp(s)),
|
||||||
|
winit::event::VirtualKeyCode::Q => Some(InputInstruction::MoveDown(s)),
|
||||||
|
winit::event::VirtualKeyCode::Space => Some(InputInstruction::Jump(s)),
|
||||||
|
winit::event::VirtualKeyCode::Z => Some(InputInstruction::Zoom(s)),
|
||||||
|
winit::event::VirtualKeyCode::R => if s{Some(InputInstruction::Reset)}else{None},
|
||||||
|
_ => None,
|
||||||
|
}{
|
||||||
|
self.physics_thread.send(TimedInstruction{
|
||||||
|
time,
|
||||||
|
instruction:input_instruction,
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_=>(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
_=>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_event(&mut self, window: &winit::window::Window, event: winit::event::DeviceEvent) {
|
||||||
|
//there's no way this is the best way get a timestamp.
|
||||||
|
let time=integer::Time::from_nanos(self.start_time.elapsed().as_nanos() as i64);
|
||||||
|
match event {
|
||||||
winit::event::DeviceEvent::MouseMotion {
|
winit::event::DeviceEvent::MouseMotion {
|
||||||
delta,//these (f64,f64) are integers on my machine
|
delta,//these (f64,f64) are integers on my machine
|
||||||
} => {
|
} => {
|
||||||
@ -1063,7 +1238,7 @@ impl framework::Example for GlobalState {
|
|||||||
_spawner: &framework::Spawner,
|
_spawner: &framework::Spawner,
|
||||||
) {
|
) {
|
||||||
//ideally this would be scheduled to execute and finish right before the render.
|
//ideally this would be scheduled to execute and finish right before the render.
|
||||||
let time=self.start_time.elapsed().as_nanos() as i64;
|
let time=integer::Time::from_nanos(self.start_time.elapsed().as_nanos() as i64);
|
||||||
self.physics_thread.send(TimedInstruction{
|
self.physics_thread.send(TimedInstruction{
|
||||||
time,
|
time,
|
||||||
instruction:InputInstruction::Idle,
|
instruction:InputInstruction::Idle,
|
||||||
|
231
src/model.rs
231
src/model.rs
@ -1,12 +1,6 @@
|
|||||||
use bytemuck::{Pod, Zeroable};
|
use crate::integer::{Time,Planar64,Planar64Vec3,Planar64Affine3};
|
||||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
pub type TextureCoordinate=glam::Vec2;
|
||||||
#[repr(C)]
|
pub type Color4=glam::Vec4;
|
||||||
pub struct Vertex {
|
|
||||||
pub pos: [f32; 3],
|
|
||||||
pub tex: [f32; 2],
|
|
||||||
pub normal: [f32; 3],
|
|
||||||
pub color: [f32; 4],
|
|
||||||
}
|
|
||||||
#[derive(Clone,Hash,PartialEq,Eq)]
|
#[derive(Clone,Hash,PartialEq,Eq)]
|
||||||
pub struct IndexedVertex{
|
pub struct IndexedVertex{
|
||||||
pub pos:u32,
|
pub pos:u32,
|
||||||
@ -22,50 +16,25 @@ pub struct IndexedGroup{
|
|||||||
pub polys:Vec<IndexedPolygon>,
|
pub polys:Vec<IndexedPolygon>,
|
||||||
}
|
}
|
||||||
pub struct IndexedModel{
|
pub struct IndexedModel{
|
||||||
pub unique_pos:Vec<[f32; 3]>,
|
pub unique_pos:Vec<Planar64Vec3>,
|
||||||
pub unique_tex:Vec<[f32; 2]>,
|
pub unique_normal:Vec<Planar64Vec3>,
|
||||||
pub unique_normal:Vec<[f32; 3]>,
|
pub unique_tex:Vec<TextureCoordinate>,
|
||||||
pub unique_color:Vec<[f32; 4]>,
|
pub unique_color:Vec<Color4>,
|
||||||
pub unique_vertices:Vec<IndexedVertex>,
|
pub unique_vertices:Vec<IndexedVertex>,
|
||||||
pub groups: Vec<IndexedGroup>,
|
pub groups: Vec<IndexedGroup>,
|
||||||
pub instances:Vec<ModelInstance>,
|
pub instances:Vec<ModelInstance>,
|
||||||
}
|
}
|
||||||
pub struct IndexedGroupFixedTexture{
|
|
||||||
pub polys:Vec<IndexedPolygon>,
|
|
||||||
}
|
|
||||||
pub struct IndexedModelSingleTexture{
|
|
||||||
pub unique_pos:Vec<[f32; 3]>,
|
|
||||||
pub unique_tex:Vec<[f32; 2]>,
|
|
||||||
pub unique_normal:Vec<[f32; 3]>,
|
|
||||||
pub unique_color:Vec<[f32; 4]>,
|
|
||||||
pub unique_vertices:Vec<IndexedVertex>,
|
|
||||||
pub texture:Option<u32>,//RenderPattern? material/texture/shader/flat color
|
|
||||||
pub groups: Vec<IndexedGroupFixedTexture>,
|
|
||||||
pub instances:Vec<ModelGraphicsInstance>,
|
|
||||||
}
|
|
||||||
pub struct ModelSingleTexture{
|
|
||||||
pub instances: Vec<ModelGraphicsInstance>,
|
|
||||||
pub vertices: Vec<Vertex>,
|
|
||||||
pub entities: Vec<Vec<u16>>,
|
|
||||||
pub texture: Option<u32>,
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ModelGraphicsInstance{
|
|
||||||
pub transform:glam::Mat4,
|
|
||||||
pub normal_transform:glam::Mat3,
|
|
||||||
pub color:glam::Vec4,
|
|
||||||
}
|
|
||||||
pub struct ModelInstance{
|
pub struct ModelInstance{
|
||||||
//pub id:u64,//this does not actually help with map fixes resimulating bots, they must always be resimulated
|
//pub id:u64,//this does not actually help with map fixes resimulating bots, they must always be resimulated
|
||||||
pub transform:glam::Affine3A,
|
pub transform:Planar64Affine3,
|
||||||
pub color:glam::Vec4,//transparency is in here
|
pub color:Color4,//transparency is in here
|
||||||
pub attributes:CollisionAttributes,
|
pub attributes:CollisionAttributes,
|
||||||
pub temp_indexing:Vec<TempIndexedAttributes>,
|
pub temp_indexing:Vec<TempIndexedAttributes>,
|
||||||
}
|
}
|
||||||
impl std::default::Default for ModelInstance{
|
impl std::default::Default for ModelInstance{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self{
|
Self{
|
||||||
color:glam::Vec4::ONE,
|
color:Color4::ONE,
|
||||||
transform:Default::default(),
|
transform:Default::default(),
|
||||||
attributes:Default::default(),
|
attributes:Default::default(),
|
||||||
temp_indexing:Default::default(),
|
temp_indexing:Default::default(),
|
||||||
@ -77,76 +46,105 @@ pub struct IndexedModelInstances{
|
|||||||
pub models:Vec<IndexedModel>,
|
pub models:Vec<IndexedModel>,
|
||||||
//may make this into an object later.
|
//may make this into an object later.
|
||||||
pub modes:Vec<ModeDescription>,
|
pub modes:Vec<ModeDescription>,
|
||||||
pub spawn_point:glam::Vec3,
|
pub spawn_point:Planar64Vec3,
|
||||||
}
|
}
|
||||||
//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:u32,//start=model_id
|
pub start:usize,//start=model_id
|
||||||
pub spawns:Vec<u32>,//spawns[spawn_id]=model_id
|
pub spawns:Vec<usize>,//spawns[spawn_id]=model_id
|
||||||
pub ordered_checkpoints:Vec<u32>,//ordered_checkpoints[checkpoint_id]=model_id
|
pub ordered_checkpoints:Vec<usize>,//ordered_checkpoints[checkpoint_id]=model_id
|
||||||
pub unordered_checkpoints:Vec<u32>,//unordered_checkpoints[checkpoint_id]=model_id
|
pub unordered_checkpoints:Vec<usize>,//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<&u32>{
|
pub fn get_spawn_model_id(&self,stage_id:u32)->Option<&usize>{
|
||||||
if let Some(&spawn)=self.spawn_from_stage_id.get(&stage_id){
|
self.spawns.get(*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<&u32>{
|
pub fn get_ordered_checkpoint_model_id(&self,checkpoint_id:u32)->Option<&usize>{
|
||||||
if let Some(&checkpoint)=self.ordered_checkpoint_from_checkpoint_id.get(&checkpoint_id){
|
self.ordered_checkpoints.get(*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{
|
Start(TempAttrStart),
|
||||||
mode_id:u32,
|
Spawn(TempAttrSpawn),
|
||||||
},
|
OrderedCheckpoint(TempAttrOrderedCheckpoint),
|
||||||
Spawn{
|
UnorderedCheckpoint(TempAttrUnorderedCheckpoint),
|
||||||
mode_id:u32,
|
Wormhole(TempAttrWormhole),
|
||||||
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{
|
||||||
pub viscosity:i64,
|
pub viscosity:Planar64,
|
||||||
pub density:i64,
|
pub density:Planar64,
|
||||||
pub current:glam::Vec3,
|
pub current:Planar64Vec3,
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct IntersectingAccelerator{
|
|
||||||
pub acceleration:glam::Vec3
|
|
||||||
}
|
}
|
||||||
//All models can be given these attributes
|
//All models can be given these attributes
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GameMechanicJumpLimit{
|
pub struct GameMechanicAccelerator{
|
||||||
pub count:u32,
|
pub acceleration:Planar64Vec3
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GameMechanicBooster{
|
pub enum GameMechanicBooster{
|
||||||
pub velocity:glam::Vec3,
|
Affine(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
|
||||||
|
Energy{direction:Planar64Vec3,energy:Planar64},//increase energy in direction
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum TrajectoryChoice{
|
||||||
|
HighArcLongDuration,//underhand lob at target: less horizontal speed and more air time
|
||||||
|
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{
|
||||||
@ -161,10 +159,10 @@ pub struct GameMechanicZone{
|
|||||||
pub behaviour:ZoneBehaviour,
|
pub behaviour:ZoneBehaviour,
|
||||||
}
|
}
|
||||||
// enum TrapCondition{
|
// enum TrapCondition{
|
||||||
// FasterThan(i64),
|
// FasterThan(Planar64),
|
||||||
// SlowerThan(i64),
|
// SlowerThan(Planar64),
|
||||||
// InRange(i64,i64),
|
// InRange(Planar64,Planar64),
|
||||||
// OutsideRange(i64,i64),
|
// OutsideRange(Planar64,Planar64),
|
||||||
// }
|
// }
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum StageElementBehaviour{
|
pub enum StageElementBehaviour{
|
||||||
@ -173,6 +171,7 @@ 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)]
|
||||||
@ -183,28 +182,54 @@ pub struct GameMechanicStageElement{
|
|||||||
pub behaviour:StageElementBehaviour
|
pub behaviour:StageElementBehaviour
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GameMechanicWormhole{//(position,angles)*=origin.transform.inverse()*destination.transform
|
pub struct GameMechanicWormhole{
|
||||||
pub model_id:u32,
|
//destination does not need to be another wormhole
|
||||||
|
//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 jump_limit:Option<GameMechanicJumpLimit>,
|
|
||||||
pub booster:Option<GameMechanicBooster>,
|
|
||||||
pub zone:Option<GameMechanicZone>,
|
pub zone:Option<GameMechanicZone>,
|
||||||
pub stage_element:Option<GameMechanicStageElement>,
|
pub booster:Option<GameMechanicBooster>,
|
||||||
pub wormhole:Option<GameMechanicWormhole>,//stage_element and wormhole are in conflict
|
pub trajectory:Option<GameMechanicSetTrajectory>,
|
||||||
|
pub teleport_behaviour:Option<TeleportBehaviour>,
|
||||||
|
pub accelerator:Option<GameMechanicAccelerator>,
|
||||||
|
}
|
||||||
|
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 surf:Option<ContactingSurf>,
|
pub contact_behaviour:Option<ContactingBehaviour>,
|
||||||
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{
|
||||||
@ -227,7 +252,7 @@ impl std::default::Default for CollisionAttributes{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_indexed_model_list_from_obj(data:obj::ObjData,color:[f32;4]) -> Vec<IndexedModel>{
|
pub fn generate_indexed_model_list_from_obj(data:obj::ObjData,color:Color4)->Vec<IndexedModel>{
|
||||||
let mut unique_vertex_index = std::collections::HashMap::<obj::IndexTuple,u32>::new();
|
let mut unique_vertex_index = std::collections::HashMap::<obj::IndexTuple,u32>::new();
|
||||||
return data.objects.iter().map(|object|{
|
return data.objects.iter().map(|object|{
|
||||||
unique_vertex_index.clear();
|
unique_vertex_index.clear();
|
||||||
@ -257,9 +282,9 @@ pub fn generate_indexed_model_list_from_obj(data:obj::ObjData,color:[f32;4]) ->
|
|||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
IndexedModel{
|
IndexedModel{
|
||||||
unique_pos: data.position.clone(),
|
unique_pos: data.position.iter().map(|&v|Planar64Vec3::try_from(v).unwrap()).collect(),
|
||||||
unique_tex: data.texture.clone(),
|
unique_tex: data.texture.iter().map(|&v|TextureCoordinate::from_array(v)).collect(),
|
||||||
unique_normal: data.normal.clone(),
|
unique_normal: data.normal.iter().map(|&v|Planar64Vec3::try_from(v).unwrap()).collect(),
|
||||||
unique_color: vec![color],
|
unique_color: vec![color],
|
||||||
unique_vertices,
|
unique_vertices,
|
||||||
groups,
|
groups,
|
||||||
|
55
src/model_graphics.rs
Normal file
55
src/model_graphics.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use crate::model::{IndexedVertex,IndexedPolygon};
|
||||||
|
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct GraphicsVertex {
|
||||||
|
pub pos: [f32; 3],
|
||||||
|
pub tex: [f32; 2],
|
||||||
|
pub normal: [f32; 3],
|
||||||
|
pub color: [f32; 4],
|
||||||
|
}
|
||||||
|
pub struct IndexedGroupFixedTexture{
|
||||||
|
pub polys:Vec<IndexedPolygon>,
|
||||||
|
}
|
||||||
|
pub struct IndexedModelGraphicsSingleTexture{
|
||||||
|
pub unique_pos:Vec<[f32; 3]>,
|
||||||
|
pub unique_tex:Vec<[f32; 2]>,
|
||||||
|
pub unique_normal:Vec<[f32; 3]>,
|
||||||
|
pub unique_color:Vec<[f32; 4]>,
|
||||||
|
pub unique_vertices:Vec<IndexedVertex>,
|
||||||
|
pub texture:Option<u32>,//RenderPattern? material/texture/shader/flat color
|
||||||
|
pub groups: Vec<IndexedGroupFixedTexture>,
|
||||||
|
pub instances:Vec<ModelGraphicsInstance>,
|
||||||
|
}
|
||||||
|
pub struct ModelGraphicsSingleTexture{
|
||||||
|
pub instances: Vec<ModelGraphicsInstance>,
|
||||||
|
pub vertices: Vec<GraphicsVertex>,
|
||||||
|
pub entities: Vec<Vec<u16>>,
|
||||||
|
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)]
|
||||||
|
pub struct ModelGraphicsInstance{
|
||||||
|
pub transform:glam::Mat4,
|
||||||
|
pub normal_transform:glam::Mat3,
|
||||||
|
pub color:ModelGraphicsColor4,
|
||||||
|
}
|
1
src/model_physics.rs
Normal file
1
src/model_physics.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
//
|
1235
src/physics.rs
1235
src/physics.rs
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
|||||||
use crate::model::{IndexedModel, IndexedPolygon, IndexedGroup, IndexedVertex};
|
use crate::model::{Color4,TextureCoordinate,IndexedModel,IndexedPolygon,IndexedGroup,IndexedVertex};
|
||||||
|
use crate::integer::Planar64Vec3;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Primitives{
|
pub enum Primitives{
|
||||||
@ -17,24 +18,29 @@ pub enum CubeFace{
|
|||||||
Bottom,
|
Bottom,
|
||||||
Front,
|
Front,
|
||||||
}
|
}
|
||||||
const CUBE_DEFAULT_TEXTURE_COORDS:[[f32;2];4]=[[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]];
|
const CUBE_DEFAULT_TEXTURE_COORDS:[TextureCoordinate;4]=[
|
||||||
const CUBE_DEFAULT_VERTICES:[[f32;3];8]=[
|
TextureCoordinate::new(0.0,0.0),
|
||||||
[-1.,-1., 1.],//0 left bottom back
|
TextureCoordinate::new(1.0,0.0),
|
||||||
[ 1.,-1., 1.],//1 right bottom back
|
TextureCoordinate::new(1.0,1.0),
|
||||||
[ 1., 1., 1.],//2 right top back
|
TextureCoordinate::new(0.0,1.0),
|
||||||
[-1., 1., 1.],//3 left top back
|
|
||||||
[-1., 1.,-1.],//4 left top front
|
|
||||||
[ 1., 1.,-1.],//5 right top front
|
|
||||||
[ 1.,-1.,-1.],//6 right bottom front
|
|
||||||
[-1.,-1.,-1.],//7 left bottom front
|
|
||||||
];
|
];
|
||||||
const CUBE_DEFAULT_NORMALS:[[f32;3];6]=[
|
const CUBE_DEFAULT_VERTICES:[Planar64Vec3;8]=[
|
||||||
[ 1., 0., 0.],//CubeFace::Right
|
Planar64Vec3::int(-1,-1, 1),//0 left bottom back
|
||||||
[ 0., 1., 0.],//CubeFace::Top
|
Planar64Vec3::int( 1,-1, 1),//1 right bottom back
|
||||||
[ 0., 0., 1.],//CubeFace::Back
|
Planar64Vec3::int( 1, 1, 1),//2 right top back
|
||||||
[-1., 0., 0.],//CubeFace::Left
|
Planar64Vec3::int(-1, 1, 1),//3 left top back
|
||||||
[ 0.,-1., 0.],//CubeFace::Bottom
|
Planar64Vec3::int(-1, 1,-1),//4 left top front
|
||||||
[ 0., 0.,-1.],//CubeFace::Front
|
Planar64Vec3::int( 1, 1,-1),//5 right top front
|
||||||
|
Planar64Vec3::int( 1,-1,-1),//6 right bottom front
|
||||||
|
Planar64Vec3::int(-1,-1,-1),//7 left bottom front
|
||||||
|
];
|
||||||
|
const CUBE_DEFAULT_NORMALS:[Planar64Vec3;6]=[
|
||||||
|
Planar64Vec3::int( 1, 0, 0),//CubeFace::Right
|
||||||
|
Planar64Vec3::int( 0, 1, 0),//CubeFace::Top
|
||||||
|
Planar64Vec3::int( 0, 0, 1),//CubeFace::Back
|
||||||
|
Planar64Vec3::int(-1, 0, 0),//CubeFace::Left
|
||||||
|
Planar64Vec3::int( 0,-1, 0),//CubeFace::Bottom
|
||||||
|
Planar64Vec3::int( 0, 0,-1),//CubeFace::Front
|
||||||
];
|
];
|
||||||
const CUBE_DEFAULT_POLYS:[[[u32;3];4];6]=[
|
const CUBE_DEFAULT_POLYS:[[[u32;3];4];6]=[
|
||||||
// right (1, 0, 0)
|
// right (1, 0, 0)
|
||||||
@ -89,12 +95,12 @@ pub enum WedgeFace{
|
|||||||
Left,
|
Left,
|
||||||
Bottom,
|
Bottom,
|
||||||
}
|
}
|
||||||
const WEDGE_DEFAULT_NORMALS:[[f32;3];5]=[
|
const WEDGE_DEFAULT_NORMALS:[Planar64Vec3;5]=[
|
||||||
[ 1., 0., 0.],//Wedge::Right
|
Planar64Vec3::int( 1, 0, 0),//Wedge::Right
|
||||||
[ 0., 1.,-1.],//Wedge::TopFront
|
Planar64Vec3::int( 0, 1,-1),//Wedge::TopFront
|
||||||
[ 0., 0., 1.],//Wedge::Back
|
Planar64Vec3::int( 0, 0, 1),//Wedge::Back
|
||||||
[-1., 0., 0.],//Wedge::Left
|
Planar64Vec3::int(-1, 0, 0),//Wedge::Left
|
||||||
[ 0.,-1., 0.],//Wedge::Bottom
|
Planar64Vec3::int( 0,-1, 0),//Wedge::Bottom
|
||||||
];
|
];
|
||||||
/*
|
/*
|
||||||
local cornerWedgeVerticies = {
|
local cornerWedgeVerticies = {
|
||||||
@ -113,20 +119,18 @@ pub enum CornerWedgeFace{
|
|||||||
Bottom,
|
Bottom,
|
||||||
Front,
|
Front,
|
||||||
}
|
}
|
||||||
const CORNERWEDGE_DEFAULT_NORMALS:[[f32;3];5]=[
|
const CORNERWEDGE_DEFAULT_NORMALS:[Planar64Vec3;5]=[
|
||||||
[ 1., 0., 0.],//CornerWedge::Right
|
Planar64Vec3::int( 1, 0, 0),//CornerWedge::Right
|
||||||
[ 0., 1., 1.],//CornerWedge::BackTop
|
Planar64Vec3::int( 0, 1, 1),//CornerWedge::BackTop
|
||||||
[-1., 1., 0.],//CornerWedge::LeftTop
|
Planar64Vec3::int(-1, 1, 0),//CornerWedge::LeftTop
|
||||||
[ 0.,-1., 0.],//CornerWedge::Bottom
|
Planar64Vec3::int( 0,-1, 0),//CornerWedge::Bottom
|
||||||
[ 0., 0.,-1.],//CornerWedge::Front
|
Planar64Vec3::int( 0, 0,-1),//CornerWedge::Front
|
||||||
];
|
];
|
||||||
//HashMap fits this use case perfectly but feels like using a sledgehammer to drive a nail
|
//HashMap fits this use case perfectly but feels like using a sledgehammer to drive a nail
|
||||||
pub fn unit_sphere()->crate::model::IndexedModel{
|
pub fn unit_sphere()->crate::model::IndexedModel{
|
||||||
let mut indexed_model=crate::model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/suzanne.obj")[..]).unwrap(),*glam::Vec4::ONE.as_ref()).remove(0);
|
let mut indexed_model=crate::model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/suzanne.obj")[..]).unwrap(),Color4::ONE).remove(0);
|
||||||
for pos in indexed_model.unique_pos.iter_mut(){
|
for pos in indexed_model.unique_pos.iter_mut(){
|
||||||
pos[0]=pos[0]*0.5;
|
*pos=*pos/2;
|
||||||
pos[1]=pos[1]*0.5;
|
|
||||||
pos[2]=pos[2]*0.5;
|
|
||||||
}
|
}
|
||||||
indexed_model
|
indexed_model
|
||||||
}
|
}
|
||||||
@ -141,11 +145,11 @@ pub fn unit_cube()->crate::model::IndexedModel{
|
|||||||
t.insert(CubeFace::Front,FaceDescription::default());
|
t.insert(CubeFace::Front,FaceDescription::default());
|
||||||
generate_partial_unit_cube(t)
|
generate_partial_unit_cube(t)
|
||||||
}
|
}
|
||||||
const TEAPOT_TRANSFORM:glam::Mat3=glam::mat3(glam::vec3(0.0,0.1,0.0),glam::vec3(-0.1,0.0,0.0),glam::vec3(0.0,0.0,0.1));
|
const TEAPOT_TRANSFORM:crate::integer::Planar64Mat3=crate::integer::Planar64Mat3::int_from_cols_array([0,1,0, -1,0,0, 0,0,1]);
|
||||||
pub fn unit_cylinder()->crate::model::IndexedModel{
|
pub fn unit_cylinder()->crate::model::IndexedModel{
|
||||||
let mut indexed_model=crate::model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/teapot.obj")[..]).unwrap(),*glam::Vec4::ONE.as_ref()).remove(0);
|
let mut indexed_model=crate::model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/teapot.obj")[..]).unwrap(),Color4::ONE).remove(0);
|
||||||
for pos in indexed_model.unique_pos.iter_mut(){
|
for pos in indexed_model.unique_pos.iter_mut(){
|
||||||
[pos[0],pos[1],pos[2]]=*(TEAPOT_TRANSFORM*glam::Vec3::from_array(*pos)).as_ref();
|
*pos=TEAPOT_TRANSFORM*(*pos)/10;
|
||||||
}
|
}
|
||||||
indexed_model
|
indexed_model
|
||||||
}
|
}
|
||||||
@ -170,37 +174,37 @@ pub fn unit_cornerwedge()->crate::model::IndexedModel{
|
|||||||
generate_partial_unit_cornerwedge(t)
|
generate_partial_unit_cornerwedge(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FaceDescription{
|
pub struct FaceDescription{
|
||||||
pub texture:Option<u32>,
|
pub texture:Option<u32>,
|
||||||
pub transform:glam::Affine2,
|
pub transform:glam::Affine2,
|
||||||
pub color:glam::Vec4,
|
pub color:Color4,
|
||||||
}
|
}
|
||||||
impl std::default::Default for FaceDescription{
|
impl std::default::Default for FaceDescription{
|
||||||
fn default()->Self {
|
fn default()->Self {
|
||||||
Self{
|
Self{
|
||||||
texture:None,
|
texture:None,
|
||||||
transform:glam::Affine2::IDENTITY,
|
transform:glam::Affine2::IDENTITY,
|
||||||
color:glam::vec4(1.0,1.0,1.0,0.0),//zero alpha to hide the default texture
|
color:Color4::new(1.0,1.0,1.0,0.0),//zero alpha to hide the default texture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl FaceDescription{
|
impl FaceDescription{
|
||||||
pub fn new(texture:u32,transform:glam::Affine2,color:glam::Vec4)->Self{
|
pub fn new(texture:u32,transform:glam::Affine2,color:Color4)->Self{
|
||||||
Self{texture:Some(texture),transform,color}
|
Self{texture:Some(texture),transform,color}
|
||||||
}
|
}
|
||||||
pub fn from_texture(texture:u32)->Self{
|
pub fn from_texture(texture:u32)->Self{
|
||||||
Self{
|
Self{
|
||||||
texture:Some(texture),
|
texture:Some(texture),
|
||||||
transform:glam::Affine2::IDENTITY,
|
transform:glam::Affine2::IDENTITY,
|
||||||
color:glam::Vec4::ONE,
|
color:Color4::ONE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: it's probably better to use a shared vertex buffer between all primitives and use indexed rendering instead of generating a unique vertex buffer for each primitive.
|
//TODO: it's probably better to use a shared vertex buffer between all primitives and use indexed rendering instead of generating a unique vertex buffer for each primitive.
|
||||||
//implementation: put all roblox primitives into one model.groups <- this won't work but I forget why
|
//implementation: put all roblox primitives into one model.groups <- this won't work but I forget why
|
||||||
pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->crate::model::IndexedModel{
|
pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->crate::model::IndexedModel{
|
||||||
let mut generated_pos=Vec::<[f32;3]>::new();
|
let mut generated_pos=Vec::new();
|
||||||
let mut generated_tex=Vec::new();
|
let mut generated_tex=Vec::new();
|
||||||
let mut generated_normal=Vec::new();
|
let mut generated_normal=Vec::new();
|
||||||
let mut generated_color=Vec::new();
|
let mut generated_color=Vec::new();
|
||||||
@ -217,16 +221,16 @@ pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->crate:
|
|||||||
let transform_index=transforms.len();
|
let transform_index=transforms.len();
|
||||||
transforms.push(face_description.transform);
|
transforms.push(face_description.transform);
|
||||||
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
|
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
|
||||||
generated_tex.push(*face_description.transform.transform_point2(glam::Vec2::from_array(tex)).as_ref());
|
generated_tex.push(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.as_ref()){
|
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
|
||||||
let color_index=generated_color.len();
|
let color_index=generated_color.len();
|
||||||
generated_color.push(*face_description.color.as_ref());
|
generated_color.push(face_description.color);
|
||||||
color_index
|
color_index
|
||||||
} as u32;
|
} as u32;
|
||||||
let face_id=match face{
|
let face_id=match face{
|
||||||
@ -315,7 +319,7 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->crat
|
|||||||
[6,2,4],
|
[6,2,4],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
let mut generated_pos=Vec::<[f32;3]>::new();
|
let mut generated_pos=Vec::new();
|
||||||
let mut generated_tex=Vec::new();
|
let mut generated_tex=Vec::new();
|
||||||
let mut generated_normal=Vec::new();
|
let mut generated_normal=Vec::new();
|
||||||
let mut generated_color=Vec::new();
|
let mut generated_color=Vec::new();
|
||||||
@ -332,16 +336,16 @@ pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->crat
|
|||||||
let transform_index=transforms.len();
|
let transform_index=transforms.len();
|
||||||
transforms.push(face_description.transform);
|
transforms.push(face_description.transform);
|
||||||
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
|
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
|
||||||
generated_tex.push(*face_description.transform.transform_point2(glam::Vec2::from_array(tex)).as_ref());
|
generated_tex.push(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.as_ref()){
|
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
|
||||||
let color_index=generated_color.len();
|
let color_index=generated_color.len();
|
||||||
generated_color.push(*face_description.color.as_ref());
|
generated_color.push(face_description.color);
|
||||||
color_index
|
color_index
|
||||||
} as u32;
|
} as u32;
|
||||||
let face_id=match face{
|
let face_id=match face{
|
||||||
@ -427,7 +431,7 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
|
|||||||
[7,2,4],
|
[7,2,4],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
let mut generated_pos=Vec::<[f32;3]>::new();
|
let mut generated_pos=Vec::new();
|
||||||
let mut generated_tex=Vec::new();
|
let mut generated_tex=Vec::new();
|
||||||
let mut generated_normal=Vec::new();
|
let mut generated_normal=Vec::new();
|
||||||
let mut generated_color=Vec::new();
|
let mut generated_color=Vec::new();
|
||||||
@ -444,16 +448,16 @@ pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescri
|
|||||||
let transform_index=transforms.len();
|
let transform_index=transforms.len();
|
||||||
transforms.push(face_description.transform);
|
transforms.push(face_description.transform);
|
||||||
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
|
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
|
||||||
generated_tex.push(*face_description.transform.transform_point2(glam::Vec2::from_array(tex)).as_ref());
|
generated_tex.push(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.as_ref()){
|
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
|
||||||
let color_index=generated_color.len();
|
let color_index=generated_color.len();
|
||||||
generated_color.push(*face_description.color.as_ref());
|
generated_color.push(face_description.color);
|
||||||
color_index
|
color_index
|
||||||
} as u32;
|
} as u32;
|
||||||
let face_id=match face{
|
let face_id=match face{
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::integer::{Ratio64,Ratio64Vec2};
|
||||||
struct Ratio{
|
struct Ratio{
|
||||||
ratio:f64,
|
ratio:f64,
|
||||||
}
|
}
|
||||||
@ -7,23 +8,25 @@ enum DerivedFov{
|
|||||||
}
|
}
|
||||||
enum Fov{
|
enum Fov{
|
||||||
Exactly{x:f64,y:f64},
|
Exactly{x:f64,y:f64},
|
||||||
DeriveX{x:DerivedFov,y:f64},
|
SpecifyXDeriveY{x:f64,y:DerivedFov},
|
||||||
DeriveY{x:f64,y:DerivedFov},
|
SpecifyYDeriveX{x:DerivedFov,y:f64},
|
||||||
}
|
}
|
||||||
impl Default for Fov{
|
impl Default for Fov{
|
||||||
fn default() -> Self {
|
fn default()->Self{
|
||||||
Fov::DeriveX{x:DerivedFov::FromScreenAspect,y:1.0}
|
Fov::SpecifyYDeriveX{x:DerivedFov::FromScreenAspect,y:1.0}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
enum DerivedSensitivity{
|
||||||
|
FromRatio(Ratio64),
|
||||||
|
}
|
||||||
enum Sensitivity{
|
enum Sensitivity{
|
||||||
Exactly{x:f64,y:f64},
|
Exactly{x:Ratio64,y:Ratio64},
|
||||||
DeriveX{x:Ratio,y:f64},
|
SpecifyXDeriveY{x:Ratio64,y:DerivedSensitivity},
|
||||||
DeriveY{x:f64,y:Ratio},
|
SpecifyYDeriveX{x:DerivedSensitivity,y:Ratio64},
|
||||||
}
|
}
|
||||||
impl Default for Sensitivity{
|
impl Default for Sensitivity{
|
||||||
fn default() -> Self {
|
fn default()->Self{
|
||||||
Sensitivity::DeriveY{x:0.001,y:Ratio{ratio:1.0}}
|
Sensitivity::SpecifyXDeriveY{x:Ratio64::ONE*524288,y:DerivedSensitivity::FromRatio(Ratio64::ONE)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,21 +39,25 @@ impl UserSettings{
|
|||||||
pub fn calculate_fov(&self,zoom:f64,screen_size:&glam::UVec2)->glam::DVec2{
|
pub fn calculate_fov(&self,zoom:f64,screen_size:&glam::UVec2)->glam::DVec2{
|
||||||
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::DeriveX{x,y}=>match x{
|
Fov::SpecifyXDeriveY{x,y}=>match 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),
|
|
||||||
},
|
|
||||||
Fov::DeriveY{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{
|
||||||
|
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),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn calculate_sensitivity(&self)->glam::DVec2{
|
pub fn calculate_sensitivity(&self)->Ratio64Vec2{
|
||||||
match &self.sensitivity{
|
match &self.sensitivity{
|
||||||
&Sensitivity::Exactly{x,y}=>glam::dvec2(x,y),
|
Sensitivity::Exactly{x,y}=>Ratio64Vec2::new(x.clone(),y.clone()),
|
||||||
Sensitivity::DeriveX{x,y}=>glam::dvec2(y*x.ratio,*y),
|
Sensitivity::SpecifyXDeriveY{x,y}=>match y{
|
||||||
Sensitivity::DeriveY{x,y}=>glam::dvec2(*x,x*y.ratio),
|
DerivedSensitivity::FromRatio(ratio)=>Ratio64Vec2::new(x.clone(),x.mul_ref(ratio)),
|
||||||
|
}
|
||||||
|
Sensitivity::SpecifyYDeriveX{x,y}=>match x{
|
||||||
|
DerivedSensitivity::FromRatio(ratio)=>Ratio64Vec2::new(y.mul_ref(ratio),y.clone()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +78,7 @@ pub fn read_user_settings()->UserSettings{
|
|||||||
x:fov_x,
|
x:fov_x,
|
||||||
y:fov_y
|
y:fov_y
|
||||||
},
|
},
|
||||||
(Ok(Some(fov_x)),Ok(None))=>Fov::DeriveY{
|
(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))=cfg.getfloat("camera","fov_y_from_x_ratio"){
|
||||||
DerivedFov::FromAspect(Ratio{ratio:fov_y_from_x_ratio})
|
DerivedFov::FromAspect(Ratio{ratio:fov_y_from_x_ratio})
|
||||||
@ -79,7 +86,7 @@ pub fn read_user_settings()->UserSettings{
|
|||||||
DerivedFov::FromScreenAspect
|
DerivedFov::FromScreenAspect
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(Ok(None),Ok(Some(fov_y)))=>Fov::DeriveX{
|
(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))=cfg.getfloat("camera","fov_x_from_y_ratio"){
|
||||||
DerivedFov::FromAspect(Ratio{ratio:fov_x_from_y_ratio})
|
DerivedFov::FromAspect(Ratio{ratio:fov_x_from_y_ratio})
|
||||||
}else{
|
}else{
|
||||||
@ -94,20 +101,24 @@ pub fn read_user_settings()->UserSettings{
|
|||||||
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:sensitivity_x,
|
x:Ratio64::try_from(sensitivity_x).unwrap(),
|
||||||
y:sensitivity_y
|
y:Ratio64::try_from(sensitivity_y).unwrap(),
|
||||||
},
|
},
|
||||||
(Ok(Some(sensitivity_x)),Ok(None))=>Sensitivity::DeriveY{
|
(Ok(Some(sensitivity_x)),Ok(None))=>Sensitivity::SpecifyXDeriveY{
|
||||||
x:sensitivity_x,
|
x:Ratio64::try_from(sensitivity_x).unwrap(),
|
||||||
y:Ratio{
|
y:if let Ok(Some(sensitivity_y_from_x_ratio))=cfg.getfloat("camera","sensitivity_y_from_x_ratio"){
|
||||||
ratio:if let Ok(Some(sensitivity_y_from_x_ratio))=cfg.getfloat("camera","sensitivity_y_from_x_ratio"){sensitivity_y_from_x_ratio}else{1.0}
|
DerivedSensitivity::FromRatio(Ratio64::try_from(sensitivity_y_from_x_ratio).unwrap())
|
||||||
}
|
}else{
|
||||||
},
|
DerivedSensitivity::FromRatio(Ratio64::ONE)
|
||||||
(Ok(None),Ok(Some(sensitivity_y)))=>Sensitivity::DeriveX{
|
|
||||||
x:Ratio{
|
|
||||||
ratio:if let Ok(Some(sensitivity_x_from_y_ratio))=cfg.getfloat("camera","sensitivity_x_from_y_ratio"){sensitivity_x_from_y_ratio}else{1.0}
|
|
||||||
},
|
},
|
||||||
y:sensitivity_y,
|
},
|
||||||
|
(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"){
|
||||||
|
DerivedSensitivity::FromRatio(Ratio64::try_from(sensitivity_x_from_y_ratio).unwrap())
|
||||||
|
}else{
|
||||||
|
DerivedSensitivity::FromRatio(Ratio64::ONE)
|
||||||
|
},
|
||||||
|
y:Ratio64::try_from(sensitivity_y).unwrap(),
|
||||||
},
|
},
|
||||||
_=>{
|
_=>{
|
||||||
Sensitivity::default()
|
Sensitivity::default()
|
||||||
|
134
src/sniffer.rs
Normal file
134
src/sniffer.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
//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
|
||||||
|
}
|
@ -74,14 +74,14 @@ impl<Task,Value:Clone,F:FnMut(Task)->Value> CompatWorker<Task,Value,F> {
|
|||||||
fn test_worker() {
|
fn test_worker() {
|
||||||
println!("hiiiii");
|
println!("hiiiii");
|
||||||
// Create the worker thread
|
// Create the worker thread
|
||||||
let worker = Worker::new(crate::physics::Body::with_pva(glam::Vec3::ZERO,glam::Vec3::ZERO,glam::Vec3::ZERO),
|
let worker = Worker::new(crate::physics::Body::with_pva(crate::integer::Planar64Vec3::ZERO,crate::integer::Planar64Vec3::ZERO,crate::integer::Planar64Vec3::ZERO),
|
||||||
|_|crate::physics::Body::with_pva(glam::Vec3::ONE,glam::Vec3::ONE,glam::Vec3::ONE)
|
|_|crate::physics::Body::with_pva(crate::integer::Planar64Vec3::ONE,crate::integer::Planar64Vec3::ONE,crate::integer::Planar64Vec3::ONE)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send tasks to the worker
|
// Send tasks to the worker
|
||||||
for i in 0..5 {
|
for _ in 0..5 {
|
||||||
let task = crate::instruction::TimedInstruction{
|
let task = crate::instruction::TimedInstruction{
|
||||||
time:0,
|
time:crate::integer::Time::ZERO,
|
||||||
instruction:crate::physics::PhysicsInstruction::StrafeTick,
|
instruction:crate::physics::PhysicsInstruction::StrafeTick,
|
||||||
};
|
};
|
||||||
worker.send(task).unwrap();
|
worker.send(task).unwrap();
|
||||||
@ -95,12 +95,12 @@ fn test_worker() {
|
|||||||
|
|
||||||
// Send a new task
|
// Send a new task
|
||||||
let task = crate::instruction::TimedInstruction{
|
let task = crate::instruction::TimedInstruction{
|
||||||
time:0,
|
time:crate::integer::Time::ZERO,
|
||||||
instruction:crate::physics::PhysicsInstruction::StrafeTick,
|
instruction:crate::physics::PhysicsInstruction::StrafeTick,
|
||||||
};
|
};
|
||||||
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));
|
||||||
|
@ -1,26 +1,30 @@
|
|||||||
//find roots of polynomials
|
//find roots of polynomials
|
||||||
|
use crate::integer::Planar64;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zeroes2(a0:f32,a1:f32,a2:f32) -> Vec<f32>{
|
pub fn zeroes2(a0:Planar64,a1:Planar64,a2:Planar64) -> Vec<Planar64>{
|
||||||
if a2==0f32{
|
if a2==Planar64::ZERO{
|
||||||
return zeroes1(a0, a1);
|
return zeroes1(a0, a1);
|
||||||
}
|
}
|
||||||
let mut radicand=a1*a1-4f32*a2*a0;
|
let radicand=a1.get() as i128*a1.get() as i128-a2.get() as i128*a0.get() as i128*4;
|
||||||
if 0f32<radicand {
|
if 0<radicand {
|
||||||
radicand=radicand.sqrt();
|
//start with f64 sqrt
|
||||||
if 0f32<a2 {
|
let planar_radicand=Planar64::raw(unsafe{(radicand as f64).sqrt().to_int_unchecked()});
|
||||||
return vec![(-a1-radicand)/(2f32*a2),(-a1+radicand)/(2f32*a2)];
|
//TODO: one or two newtons
|
||||||
|
if Planar64::ZERO<a2 {
|
||||||
|
return vec![(-a1-planar_radicand)/(a2*2),(-a1+planar_radicand)/(a2*2)];
|
||||||
} else {
|
} else {
|
||||||
return vec![(-a1+radicand)/(2f32*a2),(-a1-radicand)/(2f32*a2)];
|
return vec![(-a1+planar_radicand)/(a2*2),(-a1-planar_radicand)/(a2*2)];
|
||||||
}
|
}
|
||||||
} else if radicand==0f32 {
|
} else if radicand==0 {
|
||||||
return vec![-a1/(2f32*a2)];
|
return vec![a1/(a2*-2)];
|
||||||
} else {
|
} else {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zeroes1(a0:f32,a1:f32) -> Vec<f32> {
|
pub fn zeroes1(a0:Planar64,a1:Planar64) -> Vec<Planar64> {
|
||||||
if a1==0f32{
|
if a1==Planar64::ZERO{
|
||||||
return vec![];
|
return vec![];
|
||||||
} else {
|
} else {
|
||||||
return vec![-a0/a1];
|
return vec![-a0/a1];
|
||||||
|
Reference in New Issue
Block a user