tiny_game_framework/graphics/
camera.rs1use 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; pub 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 };
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 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 }