implement PhysicsCamera
This commit is contained in:
parent
3ff73ed0bc
commit
9a12265881
131
src/integer.rs
131
src/integer.rs
@ -20,6 +20,47 @@ impl Time{
|
||||
//should I have checked subtraction? force all time variables to be positive?
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Hash)]
|
||||
pub struct Ratio64{
|
||||
num:i64,
|
||||
den:std::num::NonZeroU64,
|
||||
}
|
||||
impl Ratio64{
|
||||
pub const ONE:Self=Ratio64{num:1,den:unsafe{std::num::NonZeroU64::new_unchecked(1)}};
|
||||
pub fn mul_ratio(self,rhs:i64)->Self{
|
||||
Self{
|
||||
num:self.num*rhs,
|
||||
den:self.den
|
||||
}
|
||||
}
|
||||
pub fn mul_int(self,rhs:i64)->i64{
|
||||
rhs*self.num/self.den.get() as i64
|
||||
}
|
||||
pub fn rhs_div_int(self,rhs:i64)->i64{
|
||||
rhs*self.den.get() as i64/self.num
|
||||
}
|
||||
}
|
||||
#[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};
|
||||
pub fn mul_ratio(self,rhs:i64)->Self{
|
||||
Self{
|
||||
x:self.x.mul_ratio(rhs),
|
||||
y:self.y.mul_ratio(rhs),
|
||||
}
|
||||
}
|
||||
pub fn mul_int(self,rhs:glam::I64Vec2)->glam::I64Vec2{
|
||||
glam::i64vec2(
|
||||
self.x.mul_int(rhs.x),
|
||||
self.y.mul_int(rhs.y),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
///[-1.0,1.0] = [-2^30,2^30]
|
||||
pub struct Unit32(i32);
|
||||
impl Unit32{
|
||||
@ -30,17 +71,83 @@ impl Unit32{
|
||||
}
|
||||
|
||||
///[-pi,pi) = [-2^31,2^31-1]
|
||||
#[derive(Clone,Copy,Hash)]
|
||||
pub struct Angle32(i32);
|
||||
impl Angle32{
|
||||
pub const FRAC_PI_2:Self=Self(2<<31);
|
||||
pub const PI:Self=Self(-2<<32);
|
||||
#[inline]
|
||||
pub fn wrap_from_i64(theta:i64)->Self{
|
||||
//TODO: make this good
|
||||
Self((theta.wrapping_add(2<<31).rem_euclid(2<<32)-(2<<31)) as i32)
|
||||
}
|
||||
#[inline]
|
||||
pub fn clamp_from_i64(theta:i64)->Self{
|
||||
//TODO: make this good
|
||||
Self(theta.clamp(i32::MIN as i64,i32::MAX as i64) as i32)
|
||||
}
|
||||
#[inline]
|
||||
pub fn get(&self)->i32{
|
||||
self.0
|
||||
}
|
||||
/// Note that theta_min can be larger than theta_max and it will clamp the other way
|
||||
#[inline]
|
||||
pub fn clamp(&self,theta_min:Self,theta_max:Self)->Self{
|
||||
//TODO: make this good
|
||||
theta_min+Self::wrap_from_i64((self.0.wrapping_sub(theta_min.0) as i64).rem_euclid(2<<32).clamp(0,(theta_max.0.wrapping_sub(theta_min.0) as i64).rem_euclid(2<<32)))
|
||||
}
|
||||
#[inline]
|
||||
pub fn cos(&self)->Unit32{
|
||||
//TODO: fix this rounding towards 0
|
||||
Unit32(unsafe{((self.0 as f64*(std::f64::consts::PI/((2<<31) as f64))).cos()*((2<<30) as f64)).to_int_unchecked()})
|
||||
}
|
||||
#[inline]
|
||||
pub fn sin(&self)->Unit32{
|
||||
//TODO: fix this rounding towards 0
|
||||
Unit32(unsafe{((self.0 as f64*(std::f64::consts::PI/((2<<31) as f64))).sin()*((2<<30) as f64)).to_int_unchecked()})
|
||||
}
|
||||
}
|
||||
impl Into<f32> for Angle32{
|
||||
fn into(self)->f32{
|
||||
//TODO: make this good
|
||||
(self.0 as f64/-(i32::MIN as f64)*std::f64::consts::PI) 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))
|
||||
}
|
||||
}
|
||||
///[-pi,pi) = [-2^31,2^31-1]
|
||||
pub struct Angle32Vec2(glam::IVec2);
|
||||
impl Angle32Vec2{
|
||||
@ -153,6 +260,30 @@ pub struct Planar64Mat3{
|
||||
z_axis:Planar64Vec3,
|
||||
}
|
||||
|
||||
impl Planar64Mat3{
|
||||
#[inline]
|
||||
pub fn from_cols(x_axis:Planar64Vec3,y_axis:Planar64Vec3,z_axis:Planar64Vec3)->Self{
|
||||
Self{
|
||||
x_axis,
|
||||
y_axis,
|
||||
z_axis,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_rotation_y(angle:Angle32)->Self{
|
||||
let theta=angle.0 as f64*(std::f64::consts::PI/((2<<31) as f64));
|
||||
let (s,c)=theta.sin_cos();
|
||||
let (c,s)=(c*((2<<32) as f64),s*((2<<32) as f64));
|
||||
//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)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
///[-1.0,1.0] = [-2^32,2^32]
|
||||
#[derive(Clone,Copy)]
|
||||
pub struct Planar64Affine3{
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{instruction::{InstructionEmitter, InstructionConsumer, TimedInstruction}, zeroes::zeroes2};
|
||||
|
||||
use crate::integer::{Planar64,Planar64Vec3,Angle32Vec2};
|
||||
use crate::integer::{Planar64,Planar64Vec3,Planar64Mat3,Angle32,Angle32Vec2,Ratio64Vec2};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PhysicsInstruction {
|
||||
@ -153,41 +153,57 @@ impl WalkState {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PhysicsCamera {
|
||||
offset: Planar64Vec3,
|
||||
angles: glam::DVec2,//YAW AND THEN PITCH
|
||||
//punch: Planar64Vec3,
|
||||
//punch_velocity: Planar64Vec3,
|
||||
sensitivity: glam::DVec2,
|
||||
mouse:MouseState,
|
||||
sensitivity:Ratio64Vec2,//dots to Angle32 ratios
|
||||
mouse:MouseState,//last seen absolute mouse pos
|
||||
clamped_mouse_pos:glam::IVec2,//angles are calculated from this cumulative value
|
||||
angle_pitch_lower_limit:Angle32,
|
||||
angle_pitch_upper_limit:Angle32,
|
||||
//angle limits could be an enum + struct that defines whether it's limited and selects clamp or wrap depending
|
||||
// enum AngleLimit{
|
||||
// Unlimited,
|
||||
// Limited(Angle32,Angle32),
|
||||
// }
|
||||
//pitch_limit:AngleLimit,
|
||||
//yaw_limit:AngleLimit,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mat3_from_rotation_y_f64(angle: f64) -> glam::Mat3 {
|
||||
let (sina, cosa) = angle.sin_cos();
|
||||
glam::Mat3::from_cols(
|
||||
Planar64Vec3::new(cosa as f32, 0.0, -sina as f32),
|
||||
Planar64Vec3::Y,
|
||||
Planar64Vec3::new(sina as f32, 0.0, cosa as f32),
|
||||
)
|
||||
}
|
||||
impl PhysicsCamera {
|
||||
pub fn from_offset(offset:Planar64Vec3) -> Self {
|
||||
Self{
|
||||
offset,
|
||||
angles: glam::DVec2::ZERO,
|
||||
sensitivity: glam::dvec2(1.0/1024.0,1.0/1024.0),
|
||||
sensitivity:Ratio64Vec2::ONE.mul_ratio(200_000),
|
||||
mouse:MouseState{pos:glam::IVec2::ZERO,time:-1},//escape initialization hell divide by zero
|
||||
clamped_mouse_pos:glam::IVec2::ZERO,
|
||||
angle_pitch_lower_limit:-Angle32::FRAC_PI_2,
|
||||
angle_pitch_upper_limit:Angle32::FRAC_PI_2,
|
||||
}
|
||||
}
|
||||
pub fn simulate_move_angles(&self, mouse_pos: glam::IVec2) -> glam::DVec2 {
|
||||
let mut a=self.angles-self.sensitivity*(mouse_pos-self.mouse.pos).as_dvec2();
|
||||
a.y=a.y.clamp(-std::f64::consts::FRAC_PI_2, std::f64::consts::FRAC_PI_2);
|
||||
return a
|
||||
pub fn move_mouse(&mut self,mouse_pos:glam::IVec2){
|
||||
let mut unclamped_mouse_pos=self.clamped_mouse_pos+mouse_pos-self.mouse.pos;
|
||||
unclamped_mouse_pos.y=unclamped_mouse_pos.y.clamp(
|
||||
self.sensitivity.x.rhs_div_int(self.angle_pitch_lower_limit.get() as i64) as i32,
|
||||
self.sensitivity.y.rhs_div_int(self.angle_pitch_upper_limit.get() as i64) as i32,
|
||||
);
|
||||
self.clamped_mouse_pos=unclamped_mouse_pos;
|
||||
}
|
||||
fn simulate_move_rotation_y(&self, mouse_pos_x: i32) -> glam::Mat3 {
|
||||
mat3_from_rotation_y_f64(self.angles.x-self.sensitivity.x*((mouse_pos_x-self.mouse.pos.x) as f64))
|
||||
pub fn simulate_move_angles(&self,mouse_pos:glam::IVec2)->glam::Vec2 {
|
||||
let a=self.sensitivity.mul_int((mouse_pos-self.mouse.pos+self.clamped_mouse_pos).as_i64vec2());
|
||||
let ax=Angle32::wrap_from_i64(a.x);
|
||||
let ay=Angle32::clamp_from_i64(a.y)
|
||||
//clamp to actual vertical cam limit
|
||||
.clamp(self.angle_pitch_lower_limit,self.angle_pitch_upper_limit);
|
||||
return glam::vec2(ax.into(),ay.into());
|
||||
}
|
||||
fn simulate_move_rotation_y(&self,mouse_pos_x:i32)->Planar64Mat3{
|
||||
let ax=self.sensitivity.x.mul_int((mouse_pos_x-self.mouse.pos.x+self.clamped_mouse_pos.x) as i64);
|
||||
Planar64Mat3::from_rotation_y(Angle32::wrap_from_i64(ax))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1227,11 +1243,11 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
|
||||
let mut refresh_walk_target_velocity=true;
|
||||
match input_instruction{
|
||||
PhysicsInputInstruction::SetNextMouse(m) => {
|
||||
self.camera.angles=self.camera.simulate_move_angles(self.next_mouse.pos);
|
||||
self.camera.move_mouse(self.next_mouse.pos);
|
||||
(self.camera.mouse,self.next_mouse)=(self.next_mouse.clone(),m);
|
||||
},
|
||||
PhysicsInputInstruction::ReplaceMouse(m0,m1) => {
|
||||
self.camera.angles=self.camera.simulate_move_angles(m0.pos);
|
||||
self.camera.move_mouse(m0.pos);
|
||||
(self.camera.mouse,self.next_mouse)=(m0,m1);
|
||||
},
|
||||
PhysicsInputInstruction::SetMoveForward(s) => self.set_control(StyleModifiers::CONTROL_MOVEFORWARD,s),
|
||||
|
Loading…
Reference in New Issue
Block a user