summaryrefslogtreecommitdiff
path: root/src/camera.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/camera.rs')
-rw-r--r--src/camera.rs153
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 }
+ }
+}