tiny_game_framework/graphics/
camera.rs

1use glfw::{self, Action, Key};
2use crate::{cstr, graphics::shader::Shader};
3use crate::glam::{vec3, Vec3, Mat4};
4use std::ffi::CString;
5
6const UP: Vec3 = Vec3::Y;
7const SENSITIVITY: f32 = 0.1; // todo: make this editable
8
9pub enum ProjectionType {
10    Perspective,
11    Orthographic,
12}
13
14#[derive(Debug, Clone, Copy)]
15pub struct Camera {
16    pub proj: Mat4,
17    pub view: Mat4,
18
19    pub pos: Vec3,
20    target: Vec3,
21    direction: Vec3,
22    pub right: Vec3,
23    pub front: Vec3,
24    pub up: Vec3,
25
26    pub pitch: f32,
27    pub yaw: f32,
28
29    pub speed: f32,
30
31    pub dt: f32,
32    last_frame: f32,
33
34    first_mouse: bool,
35    last_x: f32,
36    last_y: f32,
37}
38
39impl Camera {
40    pub fn new() -> Self {
41        let (pitch, yaw): (f32, f32) = (0.0, -90.0);
42        let pos = vec3(0.0, 0.0, 3.0);
43        let target = vec3(0.0, 0.0, -1.0);
44        let mut direction = (pos - target).normalize();
45        direction.x = yaw.to_radians().cos() * pitch.to_radians().cos();
46        direction.y = pitch.to_radians().sin();
47        direction.z = yaw.to_radians().sin() * pitch.to_radians().cos();
48        
49        let right = UP.cross(direction).normalize();
50        let up = direction.cross(right);
51        let front = direction.normalize();
52
53        let view = Mat4::look_at_rh(pos, pos + front, up);
54
55        Self {
56            proj: Mat4::perspective_rh_gl(70.0f32.to_radians(), 1.0, 0.1, 100000.0),
57            view,
58
59            pos,
60            target,
61            direction,
62            right,
63            front,
64            up,
65
66            speed: 1.0,
67
68            pitch,
69            yaw,
70
71            dt: 0.0,
72            last_frame: 0.0,
73
74            first_mouse: true,
75            last_x: 400.0,
76            last_y: 400.0,
77        }
78    }
79
80    pub fn update(&mut self, y: Vec3) {
81        self.pos = y;
82        
83        self.view = Mat4::look_at_rh(
84            self.pos,
85            self.pos + self.front,
86            self.up,
87        );
88    }
89
90    pub fn input(
91        &mut self,
92        window: &glfw::Window, 
93        glfw: &glfw::Glfw,
94    ) {
95        let mut speed = self.speed;
96        let curr_frame = glfw.get_time() as f32;
97        self.dt = curr_frame - self.last_frame;
98        self.last_frame = curr_frame;
99
100        if window.get_key(Key::LeftShift) == Action::Press {
101            speed *= 20.0;
102        }
103        
104        if window.get_key(Key::RightShift) == Action::Press {
105            speed *= 20.0;
106        }
107
108        if window.get_key(Key::W) == Action::Press {
109            self.pos += speed * self.dt * self.front; 
110        }
111        if window.get_key(Key::S) == Action::Press {
112            self.pos -= speed * self.dt * self.front; 
113        }
114        if window.get_key(Key::Space) == Action::Press {
115            self.pos += speed * self.dt * self.up;
116        }
117        if window.get_key(Key::LeftControl) == Action::Press {
118            self.pos -= speed * self.dt * self.up;
119        }
120        if window.get_key(Key::A) == Action::Press {
121            self.pos -= speed * self.dt * self.front.cross(self.up).normalize(); 
122        }
123        if window.get_key(Key::D) == Action::Press {
124            self.pos += speed * self.dt * self.front.cross(self.up).normalize(); 
125        }
126
127        let (w, h) = window.get_framebuffer_size();
128        self.proj = Mat4::perspective_rh_gl(70.0f32.to_radians(), w as f32 / h as f32, 0.0001, 1000.0);
129    }
130
131    pub fn mouse_callback(
132        &mut self, 
133        xpos: f32, 
134        ypos: f32,
135        window: &glfw::Window,
136    ) {
137        if window.get_cursor_mode() != glfw::CursorMode::Disabled {
138            self.first_mouse = true;
139            // return 
140        };
141        if self.first_mouse { 
142            self.last_x = xpos;
143            self.last_y = ypos;
144            self.first_mouse = false;
145        }
146
147        let mut xoffs = xpos - self.last_x;
148        let mut yoffs = self.last_y - ypos;
149
150        self.last_x = xpos;
151        self.last_y = ypos;
152
153        xoffs *= SENSITIVITY;
154        yoffs *= -SENSITIVITY;
155
156        self.yaw += xoffs;
157        self.pitch += yoffs;
158
159        self.direction.x = self.yaw.to_radians().cos() * self.pitch.to_radians().cos();
160        self.direction.y = self.pitch.to_radians().sin();
161        self.direction.z = self.yaw.to_radians().sin() * self.pitch.to_radians().cos();
162
163        self.front = self.direction.normalize();
164    }
165
166    // RENDERING //
167    pub unsafe fn send_uniforms(&self, shader: &Shader) {
168        shader.uniform_mat4fv(
169            cstr!("view"),
170            &self.view.to_cols_array(),
171        );
172
173        shader.uniform_mat4fv(
174            cstr!("proj"),
175            &self.proj.to_cols_array(),
176        );
177    }
178
179    pub fn set_projection(
180        &mut self, 
181        projection_type: ProjectionType,
182    ) {
183        match projection_type {
184            ProjectionType::Perspective => {
185                self.proj = Mat4::perspective_rh_gl(70.0f32.to_radians(), 1.0, 0.1, 10000.0);
186            },
187            ProjectionType::Orthographic => {
188                self.proj = Mat4::orthographic_rh(-1.0, 1.0, -1.0, 1.0, -100.0, 100.0);
189            }
190        }
191    }
192 
193 }