From 7f7b0d92e61ee4a746260d1dba5bf6d2688f5358 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 11 Oct 2023 23:34:32 -0700 Subject: [PATCH] implement settings --- src/integer.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++++ src/settings.rs | 77 ++++++++++++++++++++++++++++--------------------- 2 files changed, 119 insertions(+), 33 deletions(-) diff --git a/src/integer.rs b/src/integer.rs index 7a82656..391ca7c 100644 --- a/src/integer.rs +++ b/src/integer.rs @@ -57,7 +57,17 @@ pub struct Ratio64{ den:std::num::NonZeroU64, } impl Ratio64{ + pub const ZERO:Self=Ratio64{num:0,den:unsafe{std::num::NonZeroU64::new_unchecked(1)}}; pub const ONE:Self=Ratio64{num:1,den:unsafe{std::num::NonZeroU64::new_unchecked(1)}}; + pub fn new(num:i64,den:u64)->Option{ + match std::num::NonZeroU64::new(den){ + Some(den)=>{ + //TODO: gcd + Some(Self{num,den}) + }, + None=>None, + } + } pub fn mul_int(self,rhs:i64)->i64{ rhs*self.num/self.den.get() as i64 } @@ -65,6 +75,68 @@ impl Ratio64{ rhs*self.den.get() as i64/self.num } } +//from num_traits crate +#[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)] +enum Ratio64TryFromFloat64Error{ + Nan, + Infinite, + Subnormal, + HighlyNegativeExponent(i16), + HighlyPositiveExponent(i16), +} +impl TryFrom for Ratio64{ + type Error=Ratio64TryFromFloat64Error; + fn try_from(value:f64)->Result{ + 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=>{ + let (m,e,s)=integer_decode_f64(value); + if e< -127{ + //bye bye + Err(Self::Error::HighlyNegativeExponent(e)) + }else if e< -63{ + //TODO + Err(Self::Error::HighlyNegativeExponent(e)) + }else if e<0{ + Ok(Ratio64::new((m as i64)*(s as i64),1<<-e).unwrap()) + }else if e<62-52{ + Ok(Ratio64::new((m as i64)*(s as i64)*(1< for Ratio64{ + type Output=Ratio64; + #[inline] + fn mul(self,rhs:Ratio64)->Self::Output{ + let (num,den)=(self.num*rhs.num,self.den.get()*rhs.den.get()); + //TODO: gcd + Self{ + num, + den:unsafe{std::num::NonZeroU64::new_unchecked(den)}, + } + } +} impl std::ops::Mul for Ratio64{ type Output=Ratio64; #[inline] @@ -92,6 +164,9 @@ pub struct Ratio64Vec2{ } impl Ratio64Vec2{ pub const ONE:Self=Self{x:Ratio64::ONE,y:Ratio64::ONE}; + pub fn new(x:Ratio64,y:Ratio64)->Self{ + Self{x,y} + } pub fn mul_int(self,rhs:glam::I64Vec2)->glam::I64Vec2{ glam::i64vec2( self.x.mul_int(rhs.x), diff --git a/src/settings.rs b/src/settings.rs index 2e27e87..415abc3 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,3 +1,4 @@ +use crate::integer::{Ratio64,Ratio64Vec2}; struct Ratio{ ratio:f64, } @@ -7,23 +8,25 @@ enum DerivedFov{ } enum Fov{ Exactly{x:f64,y:f64}, - DeriveX{x:DerivedFov,y:f64}, - DeriveY{x:f64,y:DerivedFov}, + SpecifyXDeriveY{x:f64,y:DerivedFov}, + SpecifyYDeriveX{x:DerivedFov,y:f64}, } impl Default for Fov{ - fn default() -> Self { - Fov::DeriveX{x:DerivedFov::FromScreenAspect,y:1.0} + fn default()->Self{ + Fov::SpecifyYDeriveX{x:DerivedFov::FromScreenAspect,y:1.0} } } - +enum DerivedSensitivity{ + FromRatio(Ratio64), +} enum Sensitivity{ - Exactly{x:f64,y:f64}, - DeriveX{x:Ratio,y:f64}, - DeriveY{x:f64,y:Ratio}, + Exactly{x:Ratio64,y:Ratio64}, + SpecifyXDeriveY{x:Ratio64,y:DerivedSensitivity}, + SpecifyYDeriveX{x:DerivedSensitivity,y:Ratio64}, } impl Default for Sensitivity{ - fn default() -> Self { - Sensitivity::DeriveY{x:0.001,y:Ratio{ratio:1.0}} + fn default()->Self{ + Sensitivity::SpecifyXDeriveY{x:Ratio64::ONE/1000,y:DerivedSensitivity::FromRatio(Ratio64::ONE)} } } @@ -36,21 +39,25 @@ impl UserSettings{ pub fn calculate_fov(&self,zoom:f64,screen_size:&glam::UVec2)->glam::DVec2{ zoom*match &self.fov{ &Fov::Exactly{x,y}=>glam::dvec2(x,y), - Fov::DeriveX{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), - }, - Fov::DeriveY{x,y}=>match y{ + Fov::SpecifyXDeriveY{x,y}=>match y{ DerivedFov::FromScreenAspect=>glam::dvec2(*x,x*(screen_size.y as f64/screen_size.x as f64)), DerivedFov::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{ - &Sensitivity::Exactly{x,y}=>glam::dvec2(x,y), - Sensitivity::DeriveX{x,y}=>glam::dvec2(y*x.ratio,*y), - Sensitivity::DeriveY{x,y}=>glam::dvec2(*x,x*y.ratio), + &Sensitivity::Exactly{x,y}=>Ratio64Vec2::new(x,y), + Sensitivity::SpecifyXDeriveY{x,y}=>match y{ + &DerivedSensitivity::FromRatio(ratio)=>Ratio64Vec2::new(*x,*x*ratio), + } + Sensitivity::SpecifyYDeriveX{x,y}=>match x{ + &DerivedSensitivity::FromRatio(ratio)=>Ratio64Vec2::new(*y*ratio,*y), + } } } } @@ -71,7 +78,7 @@ pub fn read_user_settings()->UserSettings{ x:fov_x, y:fov_y }, - (Ok(Some(fov_x)),Ok(None))=>Fov::DeriveY{ + (Ok(Some(fov_x)),Ok(None))=>Fov::SpecifyXDeriveY{ x:fov_x, 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}) @@ -79,7 +86,7 @@ pub fn read_user_settings()->UserSettings{ 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"){ DerivedFov::FromAspect(Ratio{ratio:fov_x_from_y_ratio}) }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 sensitivity=match(cfg_sensitivity_x,cfg_sensitivity_y){ (Ok(Some(sensitivity_x)),Ok(Some(sensitivity_y)))=>Sensitivity::Exactly { - x:sensitivity_x, - y:sensitivity_y + x:Ratio64::try_from(sensitivity_x).unwrap(), + y:Ratio64::try_from(sensitivity_y).unwrap(), }, - (Ok(Some(sensitivity_x)),Ok(None))=>Sensitivity::DeriveY{ - x:sensitivity_x, - y: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} - } - }, - (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} + (Ok(Some(sensitivity_x)),Ok(None))=>Sensitivity::SpecifyXDeriveY{ + x:Ratio64::try_from(sensitivity_x).unwrap(), + y:if let Ok(Some(sensitivity_y_from_x_ratio))=cfg.getfloat("camera","sensitivity_y_from_x_ratio"){ + DerivedSensitivity::FromRatio(Ratio64::try_from(sensitivity_y_from_x_ratio).unwrap()) + }else{ + DerivedSensitivity::FromRatio(Ratio64::ONE) }, - 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()