215 lines
6.4 KiB
Rust
215 lines
6.4 KiB
Rust
pub struct CameraState {
|
|
aspect_ratio: f32,
|
|
position: (f32, f32, f32),
|
|
direction: (f32, f32, f32),
|
|
|
|
moving_up: bool,
|
|
moving_left: bool,
|
|
moving_down: bool,
|
|
moving_right: bool,
|
|
moving_forward: bool,
|
|
moving_backward: bool,
|
|
rotate_left: bool,
|
|
rotate_right: bool,
|
|
}
|
|
|
|
const SPEED: f32 = 10.0; //1.0;
|
|
|
|
impl CameraState {
|
|
pub fn new() -> CameraState {
|
|
CameraState {
|
|
aspect_ratio: 1_920.0 / 1_080.0,
|
|
// The second coordinate is for the altitude.
|
|
position: (3_646.41, 12.3622, 13_113.7),
|
|
direction: (0.0, 0.0, -1.0),
|
|
moving_up: false,
|
|
moving_left: false,
|
|
moving_down: false,
|
|
moving_right: false,
|
|
moving_forward: false,
|
|
moving_backward: false,
|
|
rotate_left: false,
|
|
rotate_right: false,
|
|
}
|
|
}
|
|
|
|
pub fn get_perspective(&self) -> [[f32; 4]; 4] {
|
|
let fov: f32 = std::f32::consts::PI / 2.0;
|
|
let zfar = 53_209.0;
|
|
let znear = 0.01;
|
|
|
|
let f = 1.0 / (fov / 2.0).tan();
|
|
|
|
// note: remember that this is column-major, so the lines of code are actually columns
|
|
[
|
|
[f / self.aspect_ratio, 0.0, 0.0, 0.0],
|
|
[0.0, f, 0.0, 0.0],
|
|
[0.0, 0.0, (zfar + znear) / (zfar - znear), 1.0],
|
|
[0.0, 0.0, -(2.0 * zfar * znear) / (zfar - znear), 0.0],
|
|
]
|
|
}
|
|
|
|
pub fn get_view(&self) -> [[f32; 4]; 4] {
|
|
let f = {
|
|
let f = self.direction;
|
|
let len = f.0 * f.0 + f.1 * f.1 + f.2 * f.2;
|
|
let len = len.sqrt();
|
|
(f.0 / len, f.1 / len, f.2 / len)
|
|
};
|
|
|
|
let up = (0.0, 1.0, 0.0);
|
|
|
|
let s = (
|
|
f.1 * up.2 - f.2 * up.1,
|
|
f.2 * up.0 - f.0 * up.2,
|
|
f.0 * up.1 - f.1 * up.0,
|
|
);
|
|
|
|
let s_norm = {
|
|
let len = s.0 * s.0 + s.1 * s.1 + s.2 * s.2;
|
|
let len = len.sqrt();
|
|
(s.0 / len, s.1 / len, s.2 / len)
|
|
};
|
|
|
|
let u = (
|
|
s_norm.1 * f.2 - s_norm.2 * f.1,
|
|
s_norm.2 * f.0 - s_norm.0 * f.2,
|
|
s_norm.0 * f.1 - s_norm.1 * f.0,
|
|
);
|
|
|
|
let p = (
|
|
-self.position.0 * s.0 - self.position.1 * s.1 - self.position.2 * s.2,
|
|
-self.position.0 * u.0 - self.position.1 * u.1 - self.position.2 * u.2,
|
|
-self.position.0 * f.0 - self.position.1 * f.1 - self.position.2 * f.2,
|
|
);
|
|
|
|
// note: remember that this is column-major, so the lines of code are actually columns
|
|
[
|
|
[s_norm.0, u.0, f.0, 0.0],
|
|
[s_norm.1, u.1, f.1, 0.0],
|
|
[s_norm.2, u.2, f.2, 0.0],
|
|
[p.0, p.1, p.2, 1.0],
|
|
]
|
|
}
|
|
|
|
pub fn update(&mut self) {
|
|
let f = {
|
|
let f = self.direction;
|
|
let len = f.0 * f.0 + f.1 * f.1 + f.2 * f.2;
|
|
let len = len.sqrt();
|
|
(f.0 / len, f.1 / len, f.2 / len)
|
|
};
|
|
|
|
let up = (0.0, 1.0, 0.0);
|
|
|
|
let s = (
|
|
f.1 * up.2 - f.2 * up.1,
|
|
f.2 * up.0 - f.0 * up.2,
|
|
f.0 * up.1 - f.1 * up.0,
|
|
);
|
|
|
|
let s = {
|
|
let len = s.0 * s.0 + s.1 * s.1 + s.2 * s.2;
|
|
let len = len.sqrt();
|
|
(s.0 / len, s.1 / len, s.2 / len)
|
|
};
|
|
|
|
let u = (
|
|
s.1 * f.2 - s.2 * f.1,
|
|
s.2 * f.0 - s.0 * f.2,
|
|
s.0 * f.1 - s.1 * f.0,
|
|
);
|
|
|
|
if self.moving_up {
|
|
self.position.0 += u.0 * SPEED;
|
|
self.position.1 += u.1 * SPEED;
|
|
self.position.2 += u.2 * SPEED;
|
|
}
|
|
|
|
if self.moving_left {
|
|
self.position.0 -= s.0 * SPEED;
|
|
self.position.1 -= s.1 * SPEED;
|
|
self.position.2 -= s.2 * SPEED;
|
|
}
|
|
|
|
if self.moving_down {
|
|
self.position.0 -= u.0 * SPEED;
|
|
self.position.1 -= u.1 * SPEED;
|
|
self.position.2 -= u.2 * SPEED;
|
|
}
|
|
|
|
if self.moving_right {
|
|
self.position.0 += s.0 * SPEED;
|
|
self.position.1 += s.1 * SPEED;
|
|
self.position.2 += s.2 * SPEED;
|
|
}
|
|
|
|
if self.moving_forward {
|
|
self.position.0 += f.0 * SPEED;
|
|
self.position.1 += f.1 * SPEED;
|
|
self.position.2 += f.2 * SPEED;
|
|
}
|
|
|
|
if self.moving_backward {
|
|
self.position.0 -= f.0 * SPEED;
|
|
self.position.1 -= f.1 * SPEED;
|
|
self.position.2 -= f.2 * SPEED;
|
|
}
|
|
|
|
if self.rotate_left {
|
|
let theta: f32 = -0.1;
|
|
|
|
let a_x = self.direction.0;
|
|
let a_y = self.direction.2;
|
|
|
|
let cos_theta = theta.cos();
|
|
let sin_theta = theta.sin();
|
|
|
|
self.direction.0 = cos_theta * a_x - sin_theta * a_y;
|
|
self.direction.2 = sin_theta * a_x + cos_theta * a_y;
|
|
}
|
|
|
|
if self.rotate_right {
|
|
let theta: f32 = 0.1;
|
|
|
|
let a_x = self.direction.0;
|
|
let a_y = self.direction.2;
|
|
|
|
let cos_theta = theta.cos();
|
|
let sin_theta = theta.sin();
|
|
|
|
self.direction.0 = cos_theta * a_x - sin_theta * a_y;
|
|
self.direction.2 = sin_theta * a_x + cos_theta * a_y;
|
|
}
|
|
|
|
if self.rotate_left || self.rotate_right {
|
|
let norm = (self.direction.0.powi(2) + self.direction.2.powi(2)).sqrt();
|
|
self.direction.0 /= norm;
|
|
self.direction.1 /= norm;
|
|
}
|
|
}
|
|
|
|
pub fn process_input(&mut self, event: &glutin::event::WindowEvent<'_>) {
|
|
let input = match *event {
|
|
glutin::event::WindowEvent::KeyboardInput { input, .. } => input,
|
|
_ => return,
|
|
};
|
|
let pressed = input.state == glutin::event::ElementState::Pressed;
|
|
let key = match input.virtual_keycode {
|
|
Some(key) => key,
|
|
None => return,
|
|
};
|
|
match key {
|
|
glutin::event::VirtualKeyCode::Up => self.moving_up = pressed,
|
|
glutin::event::VirtualKeyCode::Down => self.moving_down = pressed,
|
|
glutin::event::VirtualKeyCode::Q => self.moving_left = pressed,
|
|
glutin::event::VirtualKeyCode::D => self.moving_right = pressed,
|
|
glutin::event::VirtualKeyCode::Z => self.moving_forward = pressed,
|
|
glutin::event::VirtualKeyCode::S => self.moving_backward = pressed,
|
|
glutin::event::VirtualKeyCode::A => self.rotate_left = pressed,
|
|
glutin::event::VirtualKeyCode::E => self.rotate_right = pressed,
|
|
_ => (),
|
|
};
|
|
}
|
|
}
|