TazGraph Project v0.1.0
Loading...
Searching...
No Matches
PerspectiveCamera.h
1#pragma once
2#include <SDL2/SDL.h>
3#include "ICamera.h"
4
5enum class ViewMode {
6 Y_UP,
7 Z_UP
8};
9
10
12public:
13 glm::vec3 eyePos{ 0,0,0 };
14 glm::vec3 aimPos{ 0,0,0 };
15 glm::vec3 upDir{0,-1,0};
16 float zFar = 1000000.0f;
17
18 ViewMode currentViewMode = ViewMode::Y_UP;
19
20 PerspectiveCamera() : _position(0.0f, 0.0f),
21 _cameraMatrix(1.0f), //I
22 _projectionMatrix(1.0f), //I
23 _viewMatrix(1.0f),
24 _scale(1.0f),
25 _cameraChange(true),
26 _screenWidth(800),
27 _screenHeight(640)
28 {
29 eyePos = glm::vec3(0.f, 0.f, -770.0f);
30 aimPos = glm::vec3(0.f, 0.f, 0.f);
31 }
32
33 PerspectiveCamera(glm::vec3 eye_pos, glm::vec3 aim_pos) : PerspectiveCamera()
34 {
35 eyePos = eye_pos;
36 aimPos = aim_pos;
37 }
38
40 {
41
42 }
43
44 void init() override {
45 _projectionMatrix = glm::perspective(glm::radians(45.0f), (float)_screenWidth / (float)_screenHeight, 0.1f, zFar); //left, right, top, bottom
46 updateCameraOrientation();
47
48 _cameraMatrix = glm::mat4(1.0f);
49
50 glm::vec3 scale(_scale, _scale, 1.0f);
51 _cameraMatrix = glm::scale(_cameraMatrix, scale);
52
53
54 glm::vec3 translate(-_position.x, -_position.y, 0.0f);
55 _cameraMatrix = glm::translate(_cameraMatrix, translate); //if glm ortho = -1,1,-1,1 then 1 horizontal with -400,-320 to bottom-left
56
57 _cameraMatrix = _projectionMatrix * _viewMatrix * _cameraMatrix;
58
59 }
60
61 void update() override {
62 if (_cameraChange) {
63 updateCameraOrientation();
64
65 _cameraMatrix = glm::mat4(1.0f);
66
67
68 glm::vec3 translate(-_position.x, -_position.y, 0.0f);
69 _cameraMatrix = glm::translate(_cameraMatrix, translate); //if glm ortho = -1,1,-1,1 then 1 horizontal with -400,-320 to bottom-left
70
71 glm::vec3 scale(_scale, _scale, 1.0f);
72 _cameraMatrix = glm::scale(_cameraMatrix, scale);
73
74
75 _cameraMatrix = _projectionMatrix * _viewMatrix * _cameraMatrix;
76
77 }
78
79 }
80
81 void updateCameraOrientation() {
82 if (currentViewMode == ViewMode::Y_UP) {
83 upDir = glm::vec3(0.0f, -1.0f, 0.0f);
84
85 setOrientation(
86 eyePos, aimPos, upDir
87 );
88 }
89 else {
90 upDir = glm::vec3(0.0f, 0.0f, -1.0f);
91
92 setOrientation(
93 eyePos, aimPos, upDir
94 );
95 }
96 }
97
98 void setOrientation(glm::vec3 eye, glm::vec3 target, glm::vec3 up) {
99 _viewMatrix = glm::lookAt(eye, target, up);
100 }
101
102 glm::vec2 convertScreenToWorld(glm::vec2 screenCoords) const override {
103 SDL_FRect cameraRect = getCameraRect();
104
105 glm::vec2 worldCoords;
106
107 worldCoords = screenCoords;
108 worldCoords /= _scale;
109
110 worldCoords.x = worldCoords.x + cameraRect.x;
111 worldCoords.y = worldCoords.y + cameraRect.y;
112
113
114 return worldCoords;
115 }
116
117 //setters
118 void setPosition(const glm::vec3 newPosition) override {
119 eyePos = newPosition;
120 _cameraChange = true;
121 }
122
123 void setPosition_X(const float newPosition) override {
124 eyePos.x = newPosition;
125 _cameraChange = true;
126 }
127
128 void setPosition_Y(const float newPosition) override {
129 eyePos.y = newPosition;
130 _cameraChange = true;
131 }
132
133 void setPosition_Z(const float newPosition) override {
134 eyePos.z = newPosition;
135 _cameraChange = true;
136 }
137
138 void movePosition_Hor(const float step) {
139 glm::vec3 direction = glm::normalize(aimPos - eyePos); // Get movement direction
140
141 // Calculate the right vector (perpendicular to direction and up)
142 glm::vec3 right = glm::normalize(glm::cross(direction, upDir));
143
144 // Move the camera horizontally along the right vector
145 eyePos += right * step;
146 aimPos += right * step;
147 _cameraChange = true;
148 }
149 void movePosition_Vert(const float step) {
150 glm::vec3 direction = glm::normalize(aimPos - eyePos); // Get movement direction
151
152 // Move the camera horizontally along the right vector
153 eyePos += upDir * step;
154 aimPos += upDir * step;
155 _cameraChange = true;
156 }
157
158 void movePosition_Forward(const float step) {
159 glm::vec3 direction = glm::normalize(aimPos - eyePos);
160 eyePos += direction * step;
161 aimPos += direction * step;
162 _cameraChange = true;
163 }
164
165 void setAimPos(const glm::vec3 newAimPos) {
166 aimPos = newAimPos;
167 _cameraChange = true;
168 }
169
170 void moveAimPos(glm::vec3 startingAimPos, const glm::vec2 distance) {
171 aimPos = startingAimPos;
172 const float sensitivity = 0.0001f;
173
174 float yaw = distance.x * sensitivity;
175 float pitch = distance.y * sensitivity;
176
177 glm::vec3 direction = glm::normalize(aimPos - eyePos);
178
179 direction = glm::rotate(direction, yaw, upDir);
180
181 glm::vec3 right = glm::normalize(glm::cross(direction, upDir));
182
183 direction = glm::rotate(direction, pitch, right);
184
185 // Update the aimPos based on the new direction
186 aimPos = eyePos + direction;
187 _cameraChange = true;
188 }
189
190 glm::vec3 getEulerAnglesFromDirection(glm::vec3 direction) {
191 float yaw = glm::atan(direction.x, direction.z);
192 float pitch = glm::asin(-direction.y);
193 float roll = 0.0f;
194
195 return glm::vec3(glm::degrees(pitch), glm::degrees(yaw), glm::degrees(roll));
196 }
197
198
199 float getZFar() {
200 return zFar;
201 }
202
203 glm::vec3 getAimPos() {
204 return aimPos;
205 }
206
207 void setScale(float newScale) override {
208 _scale = newScale;
209 _cameraChange = true;
210 }
211
212 //getters
213 glm::vec3 getPosition() const override {
214 return eyePos;
215 }
216
217 float getScale() const override {
218 return _scale;
219 }
220
221 glm::mat4 getCameraMatrix() const override {
222 return _cameraMatrix;
223 }
224
225 glm::ivec2 getCameraDimensions() const override {
226 glm::vec2 cameraDimensions = { _screenWidth, _screenHeight };
227 return cameraDimensions;
228 }
229
230 SDL_FRect getCameraRect() const override {
231 float cameraWidth = getCameraDimensions().x / getScale();
232 float cameraHeight = getCameraDimensions().y / getScale();
233
234 float cameraX = _position.x - cameraWidth / 2.0f ;
235 float cameraY = _position.y - cameraHeight / 2.0f ;
236
237 SDL_FRect cameraRect = { cameraX , cameraY , cameraWidth, cameraHeight };
238 return cameraRect;
239 }
240
241 void setCameraMatrix(glm::mat4 newMatrix) {
242 _cameraChange = true;
243 }
244 void resetCameraPosition() {
245
246 _position = glm::vec2(0.0f,0.0f);
247 _scale = 1.0f;
248
249 eyePos = glm::vec3(0.f, 0.f, -770.0f);
250 aimPos = glm::vec3( 0,0,0 );
251
252 currentViewMode = ViewMode::Y_UP;
253 upDir = glm::vec3( 0,-1,0 );
254
255 init();
256
257 _cameraChange = true;
258 }
259 float getMinScale() {
260 return _minScale;
261 }
262
263 float getMaxScale() {
264 return _maxScale;
265 }
266
267
268 bool isPointInCameraView(const glm::vec4 point, float margin)
269 {
270 glm::mat4 vpMatrix = _cameraMatrix;
271
272 glm::vec4 clipSpacePos = vpMatrix * point;
273
274 if (clipSpacePos.w != 0.0f) {
275 clipSpacePos.x /= clipSpacePos.w;
276 clipSpacePos.y /= clipSpacePos.w;
277 clipSpacePos.z /= clipSpacePos.w;
278 }
279
280 // 0.2f is the margin
281 if (clipSpacePos.x < -1.0f - margin || clipSpacePos.x > 1.0f + margin) return false;
282 if (clipSpacePos.y < -1.0f - margin || clipSpacePos.y > 1.0f + margin) return false;
283 if (clipSpacePos.z < -margin || clipSpacePos.z > 1.0f + margin) return false;
284
285 return true;
286 }
287
288 bool hasChanged() override {
289 return _cameraChange;
290 }
291
292 void makeCameraDirty() override {
293 _cameraChange = true;
294 }
295
296 void refreshCamera() override {
297 _cameraChange = false;
298 }
299
300 // Function to cast a ray from screen coordinates into world space
301 glm::vec3 castRayAt(const glm::vec2& screenPos) {
302 // Convert screen position to normalized device coordinates (NDC)
303 float x = (2.0f * screenPos.x) / _screenWidth - 1.0f;
304 float y = 1.0f - (2.0f * screenPos.y) / _screenHeight;
305 glm::vec4 clipCoords = glm::vec4(x, y, -1.0f, 1.0f);
306
307 // Convert to eye space
308 glm::vec4 eyeCoords = glm::inverse(_projectionMatrix) * clipCoords;
309 eyeCoords = glm::vec4(eyeCoords.x, eyeCoords.y, -1.0f, 0.0f);
310
311 // Convert to world space
312 glm::vec3 worldRay = glm::vec3(glm::inverse(_viewMatrix) * eyeCoords);
313 worldRay = glm::normalize(worldRay);
314
315 return worldRay;
316 }
317 glm::vec3 getPointOnRayAtZ(const glm::vec3& rayOrigin, const glm::vec3& rayDirection, float desiredZ) {
318 // Check if the ray is parallel to the z-plane (no intersection)
319 if (rayDirection.z == 0.0f) {
320 // Ray is parallel to the plane, no intersection
321 return glm::vec3(std::numeric_limits<float>::infinity()); // Return invalid point
322 }
323
324 // Calculate t for the desired z value
325 float t = (desiredZ - rayOrigin.z) / rayDirection.z;
326
327 // Calculate the point on the ray
328 glm::vec3 pointOnRay = rayOrigin + t * rayDirection;
329
330 return pointOnRay;
331 }
332
333 glm::mat4 getViewMatrix() {
334 return _viewMatrix;
335 }
336
337 glm::mat4 getProjMatrix() {
338 return _viewMatrix;
339 }
340
341private:
342 int _screenWidth, _screenHeight;
343 float _minScale = 0.1f, _maxScale = 5.0f;
344 float _scale; // decreases when zoom-out
345 bool _cameraChange;
346
347 glm::vec2 _position;
348 glm::mat4 _projectionMatrix; // changed once in init
349 glm::mat4 _viewMatrix;
350 glm::mat4 _cameraMatrix;
351};
Definition ICamera.h:9
Definition PerspectiveCamera.h:11