use crate::{Input, config::CAMERA_MOVEMENT_SPEED}; #[repr(C)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct CameraUniform { pub scale: [f32; 2], pub centre: [f32; 2], } pub struct Camera { pub zoom: f32, pub centre: (f32, f32), screen_size: (i32, i32), } impl Camera { fn scale(&self) -> (f32, f32) { let half_w = self.zoom * self.screen_size.0 as f32 / 2.0; let half_h = self.zoom * self.screen_size.1 as f32 / 2.0; (1.0 / half_w, -1.0 / half_h) } // xl, xu, yl, yu pub fn viewport_bounds_world(&self) -> (f32, f32, f32, f32) { let (xl, yl) = self.screen_position_to_world(0.0, 0.0); let (xu, yu) = self.screen_position_to_world(self.screen_size.0 as f32, self.screen_size.1 as f32); (xl, xu, yl, yu) } pub fn handle_camera_input(&mut self, input: &Input, delta_time: f32) { // wasd movement let x: f32 = if input.is_left_pressed { -1.0 } else if input.is_right_pressed { 1.0 } else { 0.0 }; let y: f32 = if input.is_down_pressed { 1.0 } else if input.is_up_pressed { -1.0 } else { 0.0 }; if x == 0.0 && y == 0.0 { return; } let magnitude = (x.powi(2) + y.powi(2)).sqrt(); let adjusted_x = x / magnitude * self.zoom * CAMERA_MOVEMENT_SPEED * delta_time; let adjusted_y = y / magnitude * self.zoom * CAMERA_MOVEMENT_SPEED * delta_time; self.centre.0 += adjusted_x; self.centre.1 += adjusted_y; } pub fn screen_position_to_world(&self, x: f32, y: f32) -> (f32, f32) { let (scale_x, scale_y) = self.scale(); let ndc_x = x / self.screen_size.0 as f32 * 2.0 - 1.0; let world_x = ndc_x / scale_x + self.centre.0; let ndc_y = y / self.screen_size.1 as f32 * 2.0 - 1.0; let world_y = ndc_y / -scale_y + self.centre.1; (world_x, world_y) } pub fn to_uniform(&self) -> CameraUniform { let (scale_x, scale_y) = self.scale(); CameraUniform { scale: [scale_x, scale_y], centre: [self.centre.0, self.centre.1], } } pub fn resize(&mut self, screen_size: (i32, i32)) { self.screen_size = screen_size; } pub fn new(screen_size: (i32, i32)) -> Self { Camera { zoom: 0.2, centre: (0.0, 0.0), screen_size, } } }