game/src/camera.rs

115 lines
3.1 KiB
Rust
Raw Normal View History

2023-05-22 16:18:35 +00:00
use cgmath::{Vector3, Point3, InnerSpace, Deg, Rad, Matrix4};
use crate::{input::Input, player::Player};
2023-05-13 09:41:36 +00:00
#[derive(Debug)]
pub struct Camera {
pub position: Option<Point3<f32>>,
pub target: Option<Point3<f32>>,
2023-05-22 16:18:35 +00:00
2023-05-15 08:28:40 +00:00
pub rot_y: Deg<f32>,
2023-05-13 09:41:36 +00:00
aspect: f32,
2023-05-15 08:28:40 +00:00
fovy: Deg<f32>,
2023-05-13 09:41:36 +00:00
znear: f32,
zfar: f32,
}
2023-05-22 16:18:35 +00:00
fn pitch_clamp(pitch: f32) -> Deg<f32> {
const PITCH_LIM: f32 = 90.0 - (0.0001 * 10.0);
2023-05-22 16:18:35 +00:00
return Deg(pitch.clamp(-PITCH_LIM, PITCH_LIM));
}
2023-05-13 09:41:36 +00:00
impl Camera {
pub fn new(
2023-05-13 09:41:36 +00:00
dimensions: winit::dpi::PhysicalSize<u32>,
2023-05-22 16:18:35 +00:00
rot_y: Deg<f32>,
2023-05-13 09:41:36 +00:00
) -> Self {
2023-05-16 10:07:08 +00:00
return Self {
position: None,
target: None,
2023-05-22 16:18:35 +00:00
rot_y: pitch_clamp(rot_y.0),
2023-05-13 09:41:36 +00:00
aspect: dimensions.width as f32 / dimensions.height as f32,
2023-05-22 16:18:35 +00:00
fovy: Deg(40.0),
2023-05-13 09:41:36 +00:00
znear: 0.1,
zfar: 100.0,
2023-05-16 10:07:08 +00:00
};
2023-05-13 09:41:36 +00:00
}
pub fn reconfigure(&mut self, dimensions: winit::dpi::PhysicalSize<u32>) {
self.aspect = dimensions.width as f32 / dimensions.height as f32;
2023-05-16 10:07:08 +00:00
return;
2023-05-13 09:41:36 +00:00
}
2023-05-22 16:18:35 +00:00
pub fn update_pos(&mut self, player: &Player) {
let mut target = player.position + (player.forward_right().1 * (0.1 /* player half width */ + 0.05 /* additional offset */));
target.y += 0.25; // player half height
2023-05-22 16:18:35 +00:00
let (sin_yaw, cos_yaw) = Rad::from(player.rot_x).0.sin_cos();
let (sin_pitch, cos_pitch) = Rad::from(self.rot_y).0.sin_cos();
let v = Vector3::new(
cos_pitch * cos_yaw,
sin_pitch,
cos_pitch * sin_yaw
).normalize();
2023-05-15 08:19:56 +00:00
self.position = Some(target - v);
self.target = Some(target);
2023-05-16 10:07:08 +00:00
return;
2023-05-15 13:45:55 +00:00
}
2023-05-13 09:41:36 +00:00
pub fn update_rot(&mut self, input: &Input, sf: f32) {
2023-05-16 09:58:36 +00:00
// doesn't need dt because the input is not continuous.
2023-05-22 16:18:35 +00:00
let (_, dy) = input.mouse_moved;
2023-05-13 09:41:36 +00:00
2023-05-22 16:18:35 +00:00
self.rot_y = pitch_clamp(self.rot_y.0 + ((-dy / input.dots_per_deg) * sf));
2023-05-16 10:07:08 +00:00
return;
2023-05-13 09:41:36 +00:00
}
}
pub struct CameraUniform {
buffer: wgpu::Buffer,
}
impl<'a> CameraUniform {
const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.0, 0.0, 0.5, 1.0,
);
const SIZE: usize = std::mem::size_of::<[[f32; 4]; 4]>();
pub fn new(device: &wgpu::Device) -> Self {
2023-05-16 10:07:08 +00:00
return Self {
2023-05-13 09:41:36 +00:00
buffer: device.create_buffer(
&(wgpu::BufferDescriptor {
label: Some("Camera Buffer"),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
size: Self::SIZE as u64,
mapped_at_creation: false,
})
),
2023-05-16 10:07:08 +00:00
};
2023-05-13 09:41:36 +00:00
}
pub fn set_view_projection_matrix(&self, queue: &wgpu::Queue, camera: &Camera) {
2023-05-22 16:18:35 +00:00
/*let (sin_yaw, cos_yaw) = Rad::from(camera.rot.x).0.sin_cos();
let (sin_pitch, cos_pitch) = Rad::from(camera.rot.y).0.sin_cos();
2023-05-13 09:41:36 +00:00
let target = Vector3::new(
cos_pitch * cos_yaw,
sin_pitch,
cos_pitch * sin_yaw
2023-05-22 16:18:35 +00:00
).normalize();*/
2023-05-13 09:41:36 +00:00
let view = Matrix4::look_to_rh(camera.position.unwrap(), camera.target.unwrap() - camera.position.unwrap(), Vector3::unit_y());
2023-05-13 09:41:36 +00:00
let proj = cgmath::perspective(camera.fovy, camera.aspect, camera.znear, camera.zfar);
let transformed_proj: [[f32; 4]; 4] = (Self::OPENGL_TO_WGPU_MATRIX * proj * view).into();
queue.write_buffer(&(self.buffer), 0, bytemuck::cast_slice(&(transformed_proj)));
2023-05-16 10:07:08 +00:00
return;
2023-05-13 09:41:36 +00:00
}
pub fn as_entire_binding(&self) -> wgpu::BindingResource {
2023-05-16 10:07:08 +00:00
return self.buffer.as_entire_binding();
2023-05-13 09:41:36 +00:00
}
}