diff options
| author | Kai Stevenson <kai@kaistevenson.com> | 2026-09-02 22:55:09 -0700 |
|---|---|---|
| committer | Kai Stevenson <kai@kaistevenson.com> | 2026-09-02 22:55:09 -0700 |
| commit | 8c2acf066fc9767a7011db056248ea657392f390 (patch) | |
| tree | b226b3c60cc0944752b299b277afe084bd260576 /src/camera.rs | |
| parent | 51ecf9530dae94341e2ba96453a4bf7e376ad33b (diff) | |
refactor camera
Diffstat (limited to 'src/camera.rs')
| -rw-r--r-- | src/camera.rs | 153 |
1 files changed, 98 insertions, 55 deletions
diff --git a/src/camera.rs b/src/camera.rs index 3de7ba7..576f12c 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,6 +1,9 @@ +use glam::{IVec2, Vec2}; + use crate::{ config::CAMERA_MOVEMENT_SPEED, input::{Input, InputManager}, + sim::{entity::EntityId, sim_manager::SimManager}, }; #[repr(C)] @@ -12,82 +15,122 @@ pub struct CameraUniform { pub struct Camera { pub zoom: f32, - pub centre: (f32, f32), - screen_size: (i32, i32), + pub centre: Vec2, + screen_size: IVec2, } 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) + fn scale(&self) -> Vec2 { + let half = self.zoom * self.screen_size.as_vec2() / 2.0; + Vec2::new(1.0 / half.x, -1.0 / half.y) } - pub fn handle_camera_input(&mut self, input_manager: &InputManager, delta_time: f32) { - // wasd movement - let x: f32 = if input_manager.held(Input::CameraLeft) { - -1.0 - } else if input_manager.held(Input::CameraRight) { - 1.0 - } else { - 0.0 - }; - let y: f32 = if input_manager.held(Input::CameraDown) { - 1.0 - } else if input_manager.held(Input::CameraUp) { - -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; + // (lower, upper) + pub fn viewport_bounds_world(&self) -> (Vec2, Vec2) { + let lower = self.screen_position_to_world(Vec2::ZERO); + let upper = self.screen_position_to_world(self.screen_size.as_vec2()); + (lower, upper) } - 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; + pub fn screen_position_to_world(&self, pos: Vec2) -> Vec2 { + let scale = self.scale(); + let ndc = pos / self.screen_size.as_vec2() * 2.0 - 1.0; + let world = Vec2::new( + ndc.x / scale.x + self.centre.x, + ndc.y / -scale.y + self.centre.y, + ); - (world_x, world_y) + world } 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], + scale: self.scale().to_array(), + centre: self.centre.to_array(), } } - pub fn resize(&mut self, screen_size: (i32, i32)) { + pub fn resize(&mut self, screen_size: IVec2) { self.screen_size = screen_size; } - pub fn new(screen_size: (i32, i32)) -> Self { + pub fn new(screen_size: IVec2) -> Self { Camera { zoom: 0.12, - centre: (0.0, 0.0), + centre: Vec2::ZERO, screen_size, } } } + +pub enum CameraControllerMode { + Free, + TrackEntity(EntityId), +} + +pub struct CameraController { + camera: Camera, + mode: CameraControllerMode, +} + +impl CameraController { + pub fn track_entity(&mut self, entity_id: EntityId) { + self.mode = CameraControllerMode::TrackEntity(entity_id); + } + + pub fn free_camera(&mut self) { + self.mode = CameraControllerMode::Free; + } + + pub fn camera(&self) -> &Camera { + &self.camera + } + + pub fn camera_mut(&mut self) -> &mut Camera { + &mut self.camera + } + + pub fn update(&mut self, input_manager: &InputManager, sim: &SimManager, delta_time: f32) { + match self.mode { + CameraControllerMode::Free => { + let x: f32 = if input_manager.held(Input::CameraLeft) { + -1.0 + } else if input_manager.held(Input::CameraRight) { + 1.0 + } else { + 0.0 + }; + let y: f32 = if input_manager.held(Input::CameraDown) { + 1.0 + } else if input_manager.held(Input::CameraUp) { + -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.camera.zoom * CAMERA_MOVEMENT_SPEED * delta_time; + let adjusted_y = + y / magnitude * self.camera.zoom * CAMERA_MOVEMENT_SPEED * delta_time; + + self.camera.centre += Vec2::new(adjusted_x, adjusted_y); + } + CameraControllerMode::TrackEntity(entity_id) => { + if let Some(entity) = sim.entities.get(&entity_id) { + let (position, _) = entity.data._transform(&sim.rb_manager).unwrap(); + self.camera.centre = position; + } + } + } + } + + pub fn new(screen_size: IVec2, mode: CameraControllerMode) -> Self { + let camera = Camera::new(screen_size); + CameraController { camera, mode } + } +} |
