You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
5.7 KiB
191 lines
5.7 KiB
use std::f32::consts::{FRAC_PI_2, PI};
|
|
use std::time::{Duration, Instant};
|
|
|
|
use cgmath::{Decomposed, InnerSpace, Matrix4, Point3, Rad, Vector3};
|
|
use winit_24::dpi::{LogicalPosition, PhysicalPosition};
|
|
use winit_24::event::{ElementState, MouseScrollDelta, VirtualKeyCode};
|
|
use crate::render::OPENGL_TO_WGPU_MATRIX;
|
|
use imgui::Condition;
|
|
use imgui::*;
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
pub struct Camera {
|
|
pub position: Point3<f32>,
|
|
pub yaw: Rad<f32>,
|
|
pub pitch: Rad<f32>,
|
|
}
|
|
|
|
impl Camera {
|
|
pub fn new<V: Into<Point3<f32>>, Y: Into<Rad<f32>>, P: Into<Rad<f32>>>(
|
|
position: V,
|
|
yaw: Y,
|
|
pitch: P,
|
|
) -> Self {
|
|
Self {
|
|
position: position.into(),
|
|
yaw: yaw.into(),
|
|
pitch: pitch.into(),
|
|
}
|
|
}
|
|
|
|
pub fn calc_matrix(&self, projection: cgmath::Matrix4<f32>) -> Matrix4<f32> {
|
|
|
|
let view_vector = Point3::new(
|
|
(1.0 * self.pitch.0.sin() * self.yaw.0.sin()),
|
|
(1.0 * self.pitch.0.cos()),
|
|
(1.0 * self.pitch.0.sin() * self.yaw.0.cos()),
|
|
);
|
|
|
|
let mx_view = Matrix4::look_at(
|
|
self.position,
|
|
Point3::new(
|
|
view_vector.x + self.position.x,
|
|
view_vector.y + self.position.y,
|
|
view_vector.z + self.position.z,
|
|
),
|
|
Vector3::unit_y(),
|
|
);
|
|
// I don't know how this works, but it limits pitching to like
|
|
// 70 degrees. Lame
|
|
// let mx_view = Matrix4::look_at_dir(
|
|
// self.position,
|
|
// Vector3::new(
|
|
// self.yaw.0.cos(),
|
|
// self.pitch.0.sin(),
|
|
// self.yaw.0.sin(),
|
|
// ).normalize(),
|
|
// Vector3::unit_y(),
|
|
// );
|
|
let mx_correction = OPENGL_TO_WGPU_MATRIX;
|
|
mx_correction * projection * mx_view
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct CameraController {
|
|
amount_left: f32,
|
|
amount_right: f32,
|
|
amount_forward: f32,
|
|
amount_backward: f32,
|
|
amount_up: f32,
|
|
amount_down: f32,
|
|
rotate_horizontal: f32,
|
|
rotate_vertical: f32,
|
|
scroll: f32,
|
|
speed: f32,
|
|
sensitivity: f32,
|
|
active: bool,
|
|
}
|
|
|
|
impl CameraController {
|
|
pub fn new(speed: f32, sensitivity: f32) -> Self {
|
|
Self {
|
|
amount_left: 0.0,
|
|
amount_right: 0.0,
|
|
amount_forward: 0.0,
|
|
amount_backward: 0.0,
|
|
amount_up: 0.0,
|
|
amount_down: 0.0,
|
|
rotate_horizontal: 0.0,
|
|
rotate_vertical: 0.0,
|
|
scroll: 0.0,
|
|
speed,
|
|
sensitivity,
|
|
active: true
|
|
}
|
|
}
|
|
|
|
pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool {
|
|
let amount = if state == ElementState::Pressed {
|
|
1.0
|
|
} else {
|
|
0.0
|
|
};
|
|
let active = match key {
|
|
VirtualKeyCode::P => {
|
|
if state == ElementState::Pressed {
|
|
self.active = !self.active;
|
|
}
|
|
self.active
|
|
},
|
|
_ => {self.active}
|
|
};
|
|
if active {
|
|
match key {
|
|
VirtualKeyCode::W | VirtualKeyCode::Up => {
|
|
self.amount_forward = amount;
|
|
true
|
|
}
|
|
VirtualKeyCode::S | VirtualKeyCode::Down => {
|
|
self.amount_backward = amount;
|
|
true
|
|
}
|
|
VirtualKeyCode::A | VirtualKeyCode::Left => {
|
|
self.amount_left = amount;
|
|
true
|
|
}
|
|
VirtualKeyCode::D | VirtualKeyCode::Right => {
|
|
self.amount_right = amount;
|
|
true
|
|
}
|
|
VirtualKeyCode::Space => {
|
|
self.amount_up = amount;
|
|
true
|
|
}
|
|
VirtualKeyCode::LShift => {
|
|
self.amount_down = amount;
|
|
true
|
|
}
|
|
_ => false,
|
|
}
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
pub fn process_mouse(&mut self, mouse_dx: f64, mouse_dy: f64) {
|
|
if self.active {
|
|
self.rotate_horizontal = -mouse_dx as f32;
|
|
self.rotate_vertical = mouse_dy as f32;
|
|
}
|
|
}
|
|
|
|
pub fn update_camera(&mut self, camera: &mut Camera, dt: f32) {
|
|
|
|
// Move forward/backward and left/right
|
|
let view_vector = Vector3::new(
|
|
(1.0 * camera.pitch.0.sin() * camera.yaw.0.sin()),
|
|
(1.0 * camera.pitch.0.cos()),
|
|
(1.0 * camera.pitch.0.sin() * camera.yaw.0.cos()),
|
|
);
|
|
|
|
// Offset the yaw 90 degrees and set the pitch to level for our
|
|
// right / left hand translation vectors
|
|
let offset = camera.yaw.0 + PI/2.0;
|
|
let pitch = PI/2.0;
|
|
let left_vector = Vector3::new(
|
|
(1.0 * pitch.sin() * offset.sin()),
|
|
(1.0 * pitch.cos()),
|
|
(1.0 * pitch.sin() * offset.cos()),
|
|
);
|
|
|
|
camera.position += view_vector * (self.amount_forward - self.amount_backward) * self.speed * dt;
|
|
camera.position += left_vector * (self.amount_left - self.amount_right) * self.speed * dt;
|
|
camera.position.y += (self.amount_up - self.amount_down) * self.speed * dt;
|
|
|
|
// Rotate
|
|
camera.yaw += Rad(self.rotate_horizontal) * self.sensitivity * dt;
|
|
camera.pitch += Rad(self.rotate_vertical) * self.sensitivity * dt;
|
|
|
|
self.rotate_horizontal = 0.0;
|
|
self.rotate_vertical = 0.0;
|
|
|
|
// Keep the camera's angle from going too high/low.
|
|
if camera.pitch < -Rad(0.001) {
|
|
camera.pitch = -Rad(0.001);
|
|
} else if camera.pitch > Rad(PI - 0.001) {
|
|
camera.pitch = Rad(PI - 0.001);
|
|
}
|
|
}
|
|
}
|