summaryrefslogtreecommitdiff
path: root/src/camera.rs
blob: 576f12c94e8343ed16529e9f8241b33a0f3733c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use glam::{IVec2, Vec2};

use crate::{
    config::CAMERA_MOVEMENT_SPEED,
    input::{Input, InputManager},
    sim::{entity::EntityId, sim_manager::SimManager},
};

#[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: Vec2,
    screen_size: IVec2,
}

impl Camera {
    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)
    }

    // (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, 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
    }

    pub fn to_uniform(&self) -> CameraUniform {
        CameraUniform {
            scale: self.scale().to_array(),
            centre: self.centre.to_array(),
        }
    }

    pub fn resize(&mut self, screen_size: IVec2) {
        self.screen_size = screen_size;
    }

    pub fn new(screen_size: IVec2) -> Self {
        Camera {
            zoom: 0.12,
            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 }
    }
}