chaos_framework/graphics/
camera.rs1use glam::{vec3, Mat4, Vec2, Vec3, Vec4};
2use glfw::{self, Key};
3use crate::{cstr, graphics::shader::Shader, EventLoop};
4use std::ffi::CString;
5
6const UP: Vec3 = Vec3::Y;
7const SENSITIVITY: f32 = 0.1; #[derive(Clone, Copy, Debug)]
10pub enum ProjectionType {
11 Perspective,
12 Orthographic,
13 Isometric,
14 Oblique,
15}
16
17#[derive(Debug, Clone, Copy)]
18pub struct Camera {
19 pub proj: Mat4,
20 pub view: Mat4,
21
22 projection_type: ProjectionType,
23
24 pub pos: Vec3,
25 _target: Vec3,
26 direction: Vec3,
27 pub right: Vec3,
28 pub front: Vec3,
29 pub up: Vec3,
30
31 pub pitch: f32,
32 pub yaw: f32,
33
34 pub speed: f32,
35
36 pub dt: f32,
37 last_frame: f32,
38
39 first_mouse: bool,
40 last_x: f32,
41 last_y: f32,
42}
43
44impl Camera {
45 pub fn new() -> Self {
46 let (pitch, yaw): (f32, f32) = (0.0, -90.0);
47 let pos = vec3(0.0, 0.0, 3.0);
48 let target = vec3(0.0, 0.0, -1.0);
49 let mut direction = (pos - target).normalize();
50 direction.x = yaw.to_radians().cos() * pitch.to_radians().cos();
51 direction.y = pitch.to_radians().sin();
52 direction.z = yaw.to_radians().sin() * pitch.to_radians().cos();
53
54 let right = UP.cross(direction).normalize();
55 let up = direction.cross(right);
56 let front = direction.normalize();
57
58 let view = Mat4::look_at_rh(pos, pos + front, up);
59
60 Self {
61 proj: Mat4::perspective_rh_gl(70.0f32.to_radians(), 1.0, 0.1, 100000.0),
62 view,
63
64 pos,
65 _target: target,
66 direction,
67 right,
68 front,
69 up,
70
71 speed: 1.0,
72
73 pitch,
74 yaw,
75
76 dt: 0.0,
77 last_frame: 0.0,
78
79 projection_type: ProjectionType::Perspective,
80
81 first_mouse: true,
82 last_x: 400.0,
83 last_y: 400.0,
84 }
85 }
86
87 pub fn update(&mut self, y: Vec3, el: &EventLoop) {
88 self.pos = y;
89
90 self.view = Mat4::look_at_rh(
91 self.pos,
92 self.pos + self.front,
93 self.up,
94 );
95
96 let (w, h) = el.window.get_framebuffer_size();
97
98 match self.projection_type {
99 ProjectionType::Orthographic => {
100 let ar = w as f32 / h as f32;
101
102 self.proj = Mat4::orthographic_rh(-ar, ar, -1.0, 1.0, -100.0, 100.0);
103 }
104
105 ProjectionType::Perspective => {
106 self.proj = Mat4::perspective_rh_gl(70.0f32.to_radians(), w as f32 / h as f32, 0.0001, 1000.0);
107 }
108
109 ProjectionType::Isometric => {
110 let rotate_y = Mat4::from_rotation_y(45.0_f32.to_radians());
111 let rotate_x = Mat4::from_rotation_x(35.064_f32.to_radians());
112 self.proj = rotate_x * rotate_y;
113 }
114
115 ProjectionType::Oblique => {
116 let scale = 0.5;
117 let angle = 45.0;
118
119 let angle_rad = f32::to_radians(angle);
120 let mut mat = Mat4::IDENTITY;
121 *mat.col_mut(2) = Vec4::new(scale * angle_rad.cos(), scale * angle_rad.sin(), 1.0, 0.0);
122
123 self.proj = mat;
124 }
125 }
126 }
127
128 pub fn input(
129 &mut self,
130 el: &EventLoop,
131 ) {
132 let mut speed = self.speed;
133 let curr_frame = el.window.glfw.get_time() as f32;
134 self.dt = curr_frame - self.last_frame;
135 self.last_frame = curr_frame;
136
137 if el.is_key_down(Key::LeftShift) {
138 speed *= 20.0;
139 }
140
141 if el.is_key_down(Key::RightShift) {
142 speed *= 20.0;
143 }
144
145 if el.is_key_down(Key::W) {
146 self.pos += speed * self.dt * self.front;
147 }
148 if el.is_key_down(Key::S) {
149 self.pos -= speed * self.dt * self.front;
150 }
151 if el.is_key_down(Key::Space) {
152 self.pos += speed * self.dt * self.up;
153 }
154 if el.is_key_down(Key::LeftControl) {
155 self.pos -= speed * self.dt * self.up;
156 }
157 if el.is_key_down(Key::A) {
158 self.pos -= speed * self.dt * self.front.cross(self.up).normalize();
159 }
160 if el.is_key_down(Key::D) {
161 self.pos += speed * self.dt * self.front.cross(self.up).normalize();
162 }
163 }
164
165 pub fn mouse_callback(
166 &mut self,
167 pos: Vec2,
168 window: &glfw::Window,
169 ) {
170 let xpos = pos.x;
171 let ypos = pos.y;
172
173 if window.get_cursor_mode() != glfw::CursorMode::Disabled {
174 self.first_mouse = true;
175 };
177 if self.first_mouse {
178 self.last_x = xpos;
179 self.last_y = ypos;
180 self.first_mouse = false;
181 }
182
183 let mut xoffs = xpos - self.last_x;
184 let mut yoffs = self.last_y - ypos;
185
186 self.last_x = xpos;
187 self.last_y = ypos;
188
189 xoffs *= SENSITIVITY;
190 yoffs *= -SENSITIVITY;
191
192 self.yaw += xoffs;
193 self.pitch += yoffs;
194
195 self.direction.x = self.yaw.to_radians().cos() * self.pitch.to_radians().cos();
196 self.direction.y = self.pitch.to_radians().sin();
197 self.direction.z = self.yaw.to_radians().sin() * self.pitch.to_radians().cos();
198
199 self.front = self.direction.normalize();
200 }
201
202 pub unsafe fn send_uniforms(&self, shader: &Shader) {
204 shader.uniform_mat4fv(
205 cstr!("view"),
206 &self.view.to_cols_array(),
207 );
208
209 shader.uniform_mat4fv(
210 cstr!("proj"),
211 &self.proj.to_cols_array(),
212 );
213 }
214
215 pub fn set_projection(
216 &mut self,
217 projection_type: ProjectionType,
218 ) {
219 match projection_type {
220 ProjectionType::Perspective => {
221 self.projection_type = ProjectionType::Perspective;
222 },
223 ProjectionType::Orthographic => {
224 self.projection_type = ProjectionType::Orthographic;
225 },
226 ProjectionType::Isometric => {
227 self.projection_type = ProjectionType::Isometric;
228 },
229 ProjectionType::Oblique => {
230 self.projection_type = ProjectionType::Oblique;
231 }
232 }
233 }
234
235 }