OpenRaider  0.1.4-dev
Open Source Tomb Raider Game Engine implementation
Camera.cpp
Go to the documentation of this file.
1 
9 #include <limits>
10 
11 #include "imgui/imgui.h"
12 
13 #include "global.h"
14 #include "RunTime.h"
15 #include "system/Shader.h"
16 #include "system/Sound.h"
17 #include "system/Window.h"
18 #include "Camera.h"
19 
20 #include <glm/gtc/epsilon.hpp>
21 #include <glm/gtc/matrix_transform.hpp>
22 #include <glm/gtc/quaternion.hpp>
23 #include <glm/gtx/quaternion.hpp>
24 
25 static bool equal(float a, float b) {
26  return glm::epsilonEqual(a, b, std::numeric_limits<float>::epsilon());
27 }
28 
29 static bool equal(glm::vec2 a, float b) {
30  return equal(a.x, b) && equal(a.y, b);
31 }
32 
33 static bool equal(glm::vec3 a, float b) {
34  return equal(a.x, b) && equal(a.y, b) && equal(a.z, b);
35 }
36 
37 // ----------------------------------------------------------------------------
38 
39 const static float fov = 45.0f;
40 const static float nearDist = 0.1f;
41 const static float farDist = 75000.0f;
42 const static float maxSpeed = 3072.0f;
43 const static float controllerDeadZone = 0.33f;
44 const static float controllerViewFactor = glm::pi<float>();
45 const static float rotationAngleClamp = glm::pi<float>() * 2.0f;
46 const static float rotationAngleVertMax = glm::pi<float>() / 2.0f;
47 const static float runFactor = 2.5f;
48 
49 const static glm::vec3 rightUnit(1.0f, 0.0f, 0.0f);
50 const static glm::vec3 upUnit(0.0f, 1.0f, 0.0f);
51 const static glm::vec3 dirUnit(0.0f, 0.0f, -1.0f);
52 
53 glm::vec3 Camera::pos(0.0f, 0.0f, 0.0f);
54 glm::vec2 Camera::rot(glm::pi<float>(), 0.0f);
55 glm::vec3 Camera::posSpeed(0.0f, 0.0f, 0.0f);
56 glm::vec2 Camera::rotSpeed(0.0f, 0.0f);
57 glm::mat4 Camera::projection(1.0f);
58 glm::mat4 Camera::view(1.0f);
59 float Camera::rotationDeltaX = 0.75f;
60 float Camera::rotationDeltaY = 0.75f;
61 bool Camera::updateViewFrustum = true;
62 bool Camera::dirty = true;
63 bool Camera::showOverlay = false;
64 bool Camera::movingFaster = false;
65 int Camera::room = -1;
66 
67 void Camera::reset() {
68  pos = glm::vec3(0.0f, 0.0f, 0.0f);
69  rot = glm::vec2(glm::pi<float>(), 0.0f);
70  posSpeed = glm::vec3(0.0f, 0.0f, 0.0f);
71  rotSpeed = glm::vec2(0.0f, 0.0f);
72  dirty = true;
73  projection = glm::mat4(1.0f);
74  view = glm::mat4(1.0f);
75  room = -1;
76 
78 }
79 
80 void Camera::setSize(glm::i32vec2 s) {
82  projection = glm::perspective(fov, float(s.x) / float(s.y), nearDist, farDist);
83 }
84 
85 void Camera::handleAction(ActionEvents action, bool isFinished) {
86  float factor = 1.0f;
87  if (isFinished)
88  factor = -1.0f;
89 
90  if (action == forwardAction) {
91  posSpeed += dirUnit * maxSpeed * factor;
92  } else if (action == backwardAction) {
93  posSpeed -= dirUnit * maxSpeed * factor;
94  } else if (action == leftAction) {
95  posSpeed += rightUnit * maxSpeed * factor;
96  } else if (action == rightAction) {
97  posSpeed -= rightUnit * maxSpeed * factor;
98  } else if (action == jumpAction) {
99  posSpeed += upUnit * maxSpeed * factor;
100  } else if (action == crouchAction) {
101  posSpeed -= upUnit * maxSpeed * factor;
102  } else if (action == walkAction) {
103  movingFaster = !isFinished;
104  } else {
105  return;
106  }
107 
108  dirty = true;
109 }
110 
111 void Camera::handleMouseMotion(int x, int y) {
112  if ((x != 0) || (y != 0))
113  dirty = true;
114 
115  while (x > 0) {
116  rot.x += rotationDeltaX;
117  x--;
118  }
119 
120  while (x < 0) {
121  rot.x -= rotationDeltaX;
122  x++;
123  }
124 
125  while (y > 0) {
126  if (rot.y > -rotationAngleVertMax) {
127  rot.y -= rotationDeltaY;
128  }
129  y--;
130  }
131 
132  while (y < 0) {
133  if (rot.y < rotationAngleVertMax) {
134  rot.y += rotationDeltaY;
135  }
136  y++;
137  }
138 }
139 
141  if (glm::epsilonEqual(value, 0.0f, controllerDeadZone))
142  value = 0.0f;
143 
144  if (axis == leftXAxis) {
145  posSpeed.x = -maxSpeed * value;
146  } else if (axis == leftYAxis) {
147  posSpeed.z = maxSpeed * value;
148  } else if (axis == rightXAxis) {
149  rotSpeed.x = controllerViewFactor * value;
150  } else if (axis == rightYAxis) {
151  rotSpeed.y = -controllerViewFactor * value;
152  } else {
153  return;
154  }
155 
156  dirty = true;
157 }
158 
160  if ((!dirty) && equal(posSpeed, 0.0f) && equal(rotSpeed, 0.0f))
161  return false;
162 
163  while (rot.x > rotationAngleClamp)
164  rot.x -= rotationAngleClamp;
165  while (rot.x < -rotationAngleClamp)
166  rot.x += rotationAngleClamp;
167  while (rot.y > rotationAngleClamp)
168  rot.y -= rotationAngleClamp;
169  while (rot.y < -rotationAngleClamp)
170  rot.y += rotationAngleClamp;
171 
172  float dT = RunTime::getLastFrameTime();
173  glm::vec2 newRot = rot + rotSpeed * dT;
174 
175  if ((newRot.y > -rotationAngleVertMax) && (newRot.y < rotationAngleVertMax))
176  rot = newRot;
177  else
178  rotSpeed = glm::vec2(0.0f, 0.0f);
179 
180  glm::quat quatY = glm::angleAxis(rot.x, glm::vec3(0.0f, 1.0f, 0.0f));
181  glm::quat quatX = glm::angleAxis(rot.y, glm::vec3(1.0f, 0.0f, 0.0f));
182  glm::quat quaternion = quatY * quatX;
183 
184  glm::vec3 clampedSpeed;
185  if (movingFaster) {
186  clampedSpeed = posSpeed * runFactor;
187  if (glm::length(clampedSpeed) > (maxSpeed * runFactor)) {
188  clampedSpeed = glm::normalize(clampedSpeed) * maxSpeed * runFactor;
189  }
190  } else {
191  clampedSpeed = posSpeed;
192  if (glm::length(clampedSpeed) > maxSpeed) {
193  clampedSpeed = glm::normalize(clampedSpeed) * maxSpeed;
194  }
195  }
196 
197  pos += quaternion * clampedSpeed * dT;
198 
199  glm::mat4 translate = glm::translate(glm::mat4(1.0f), pos);
200  glm::mat4 rotate = glm::toMat4(quaternion);
201  view = glm::inverse(translate * rotate);
202 
203  if (updateViewFrustum)
205 
206  glm::vec3 at(0.0f, 0.0f, -1.0f);
207  glm::vec3 up(0.0f, -1.0f, 0.0f);
208  Sound::listenAt(pos, quaternion * at, quaternion * up);
209 
210  dirty = false;
211  return updateViewFrustum;
212 }
213 
215  if (!showOverlay)
216  return;
217 
218  if (ImGui::Begin("Camera Look-At Overlay", &showOverlay, ImVec2(0, 0), -1.0f,
222  // TODO
223  }
224  ImGui::End();
225 }
226 
227 // ----------------------------------------------------------------------------
228 
229 class FrustumPlane {
230  public:
231  FrustumPlane() : normal(glm::vec3(0.0f, 0.0f, 0.0f)), d(0.0f) { }
232  void set(glm::vec3 v1, glm::vec3 v2, glm::vec3 v3) {
233  normal = glm::normalize(glm::cross(v3 - v2, v1 - v2));
234  d = -glm::dot(normal, v2);
235  }
236  float distance(glm::vec3 p) {
237  return d + glm::dot(normal, p);
238  }
239  private:
240  glm::vec3 normal;
241  float d;
242 };
243 
244 // ----------------------------------------------------------------------------
245 
246 #define NEAR 0
247 #define FAR 1
248 #define TOP 2
249 #define BOTTOM 3
250 #define LEFT 4
251 #define RIGHT 5
252 
253 #define NTL 0
254 #define NBL 1
255 #define NBR 2
256 #define NTR 3
257 #define FTL 4
258 #define FBL 5
259 #define FBR 6
260 #define FTR 7
261 
262 static FrustumPlane planes[6];
263 static glm::vec3 frustumColors[6] = {
264  glm::vec3(1.0f, 0.0f, 0.0f), // NEAR, red
265  glm::vec3(0.0f, 1.0f, 0.0f), // FAR, green
266  glm::vec3(0.0f, 0.0f, 1.0f), // TOP, blue
267  glm::vec3(1.0f, 1.0f, 0.0f), // BOTTOM, yellow
268  glm::vec3(0.0f, 1.0f, 1.0f), // LEFT, light-blue
269  glm::vec3(1.0f, 0.0f, 1.0f) // RIGHT, pink
270 };
271 static glm::vec3 frustumVertices[8];
272 
278 
280  glm::mat4 combo = projection * view;
281 
282  // Calculate frustum corners to display them
283  glm::mat4 inverse = glm::inverse(combo);
284  frustumVertices[NTL] = glm::vec3(1.0f, 1.0f, 0.0f);
285  frustumVertices[NTR] = glm::vec3(-1.0f, 1.0f, 0.0f);
286  frustumVertices[NBL] = glm::vec3(1.0f, -1.0f, 0.0f);
287  frustumVertices[NBR] = glm::vec3(-1.0f, -1.0f, 0.0f);
288  frustumVertices[FTL] = glm::vec3(1.0f, 1.0f, 1.0f);
289  frustumVertices[FTR] = glm::vec3(-1.0f, 1.0f, 1.0f);
290  frustumVertices[FBL] = glm::vec3(1.0f, -1.0f, 1.0f);
291  frustumVertices[FBR] = glm::vec3(-1.0f, -1.0f, 1.0f);
292  for (int i = 0; i < 8; i++) {
293  glm::vec4 t = inverse * glm::vec4(frustumVertices[i], 1.0f);
294  frustumVertices[i] = glm::vec3(t) / t.w;
295  frustumVertices[i].y *= -1.0f;
296  }
297 
298  // Set planes used for frustum culling
299  planes[TOP].set(frustumVertices[NTR], frustumVertices[NTL], frustumVertices[FTL]);
300  planes[BOTTOM].set(frustumVertices[NBL], frustumVertices[NBR], frustumVertices[FBR]);
301  planes[LEFT].set(frustumVertices[NTL], frustumVertices[NBL], frustumVertices[FBL]);
302  planes[RIGHT].set(frustumVertices[NBR], frustumVertices[NTR], frustumVertices[FBR]);
303  planes[NEAR].set(frustumVertices[NTL], frustumVertices[NTR], frustumVertices[NBR]);
304  planes[FAR].set(frustumVertices[FTR], frustumVertices[FTL], frustumVertices[FBL]);
305 
306  std::vector<glm::vec3> verts;
307 
308  // Near
309  verts.push_back(frustumVertices[NTL]);
310  verts.push_back(frustumVertices[NTR]);
311  verts.push_back(frustumVertices[NBR]);
312  verts.push_back(frustumVertices[NBL]);
313 
314  // Far
315  verts.push_back(frustumVertices[FTR]);
316  verts.push_back(frustumVertices[FTL]);
317  verts.push_back(frustumVertices[FBL]);
318  verts.push_back(frustumVertices[FBR]);
319 
320  // Top
321  verts.push_back(frustumVertices[NTR]);
322  verts.push_back(frustumVertices[NTL]);
323  verts.push_back(frustumVertices[FTL]);
324  verts.push_back(frustumVertices[FTR]);
325 
326  // Bottom
327  verts.push_back(frustumVertices[NBL]);
328  verts.push_back(frustumVertices[NBR]);
329  verts.push_back(frustumVertices[FBR]);
330  verts.push_back(frustumVertices[FBL]);
331 
332  // Left
333  verts.push_back(frustumVertices[NTL]);
334  verts.push_back(frustumVertices[NBL]);
335  verts.push_back(frustumVertices[FBL]);
336  verts.push_back(frustumVertices[FTL]);
337 
338  // Right
339  verts.push_back(frustumVertices[NBR]);
340  verts.push_back(frustumVertices[NTR]);
341  verts.push_back(frustumVertices[FTR]);
342  verts.push_back(frustumVertices[FBR]);
343 
344  vertexBuffer.bufferData(verts);
345 
346  verts.clear();
347  std::vector<glm::vec3> cols;
348 
349  verts.push_back(getPosition());
350  cols.push_back(glm::vec3(1.0f, 1.0f, 1.0f));
351 
352  vertexPointBuffer.bufferData(verts);
353  colorPointBuffer.bufferData(cols);
354 
355  if (colorBuffer.getSize() == 0) {
356  cols.clear();
357  for (int i = 0; i < 6; i++) {
358  for (int j = 0; j < 4; j++) {
359  cols.push_back(frustumColors[i]);
360  }
361  }
362  colorBuffer.bufferData(cols);
363  }
364 
365  if (indexBuffer.getSize() == 0) {
366  std::vector<unsigned short> inds;
367  for (int i = 0; i < 6; i++) {
368  inds.push_back(4 * i);
369  inds.push_back((4 * i) + 1);
370  inds.push_back((4 * i) + 2);
371  inds.push_back((4 * i) + 3);
372  inds.push_back((4 * i) + 2);
373  inds.push_back(4 * i);
374  }
375  indexBuffer.bufferData(inds);
376  }
377 }
378 
380  for (int i = 0; i < 6; i++) {
381  int out = 0, in = 0;
382  for (int c = 0; (c < 8) && ((in == 0) || (out == 0)); c++) {
383  if (planes[i].distance(b.getCorner(c)) < 0)
384  out++;
385  else
386  in++;
387  }
388 
389  if (in == 0)
390  return false;
391  }
392 
393  return true;
394 }
395 
396 void Camera::displayFrustum(glm::mat4 MVP) {
397  Shader::set2DState(true, false);
398  Shader::drawGL(vertexBuffer, colorBuffer, indexBuffer, MVP);
399  Shader::drawGL(vertexPointBuffer, colorPointBuffer, MVP, GL_POINTS);
400  Shader::set2DState(false, false);
401 }
402 
static const float controllerViewFactor
Definition: Camera.cpp:44
static bool boxInFrustum(BoundingBox b)
Definition: Camera.cpp:379
static ShaderBuffer vertexPointBuffer
Definition: Camera.cpp:276
static const float rotationAngleClamp
Definition: Camera.cpp:45
void bufferData(int elem, int size, void *data)
Definition: Shader.cpp:18
static float rotationDeltaY
Definition: Camera.h:62
static const float fov
Definition: Camera.cpp:39
static FrustumPlane planes[6]
Definition: Camera.cpp:262
static int room
Definition: Camera.h:64
static ShaderBuffer colorPointBuffer
Definition: Camera.cpp:277
static bool movingFaster
Definition: Camera.h:63
#define NBR
Definition: Camera.cpp:255
static glm::vec2 rot
Definition: Camera.h:57
static void displayFrustum(glm::mat4 MVP)
Definition: Camera.cpp:396
static glm::mat4 projection
Definition: Camera.h:60
OpenGL Shader Implementation.
#define FBL
Definition: Camera.cpp:258
static const float runFactor
Definition: Camera.cpp:47
static glm::vec2 rotSpeed
Definition: Camera.h:59
static void reset()
Definition: Camera.cpp:67
static glm::vec3 posSpeed
Definition: Camera.h:58
#define BOTTOM
Definition: Camera.cpp:249
static void displayUI()
Definition: Camera.cpp:214
glm::vec3 getCorner(int i)
Definition: RoomData.h:37
IMGUI_API void End()
Definition: imgui.cpp:3137
static void listenAt(glm::vec3 pos, glm::vec3 at, glm::vec3 up)
Definition: Sound.cpp:75
int getSize()
Definition: Shader.h:31
static glm::vec3 getPosition()
Definition: Camera.h:27
KeyboardButton
Definition: global.h:34
Included everywhere.
#define NBL
Definition: Camera.cpp:254
static const glm::vec3 dirUnit(0.0f, 0.0f,-1.0f)
static const glm::vec3 rightUnit(1.0f, 0.0f, 0.0f)
#define LEFT
Definition: Camera.cpp:250
static const float controllerDeadZone
Definition: Camera.cpp:43
static const glm::vec3 upUnit(0.0f, 1.0f, 0.0f)
static const float farDist
Definition: Camera.cpp:41
static void handleMouseMotion(int x, int y)
Definition: Camera.cpp:111
#define FBR
Definition: Camera.cpp:259
Definition: imgui.h:50
static void calculateFrustumPlanes()
Definition: Camera.cpp:279
Windowing Interface.
#define TOP
Definition: Camera.cpp:248
ActionEvents
Definition: global.h:15
static glm::mat4 view
Definition: Camera.h:61
static const float maxSpeed
Definition: Camera.cpp:42
static void drawGL(ShaderBuffer &vertices, ShaderBuffer &uvs, glm::vec4 color, unsigned int texture, TextureStorage store=TextureStorage::SYSTEM, unsigned int mode=GL_TRIANGLES, ShaderTexture *target=nullptr, Shader &shader=textShader)
Definition: Shader.cpp:278
static const float nearDist
Definition: Camera.cpp:40
static glm::vec3 pos
Definition: Camera.h:56
static bool showOverlay
Definition: Camera.h:63
#define NTL
Definition: Camera.cpp:253
static const float rotationAngleVertMax
Definition: Camera.cpp:46
static bool updateViewFrustum
Definition: Camera.h:63
Runtime Configuration Storage.
static ShaderBuffer vertexBuffer
Definition: Camera.cpp:273
static void handleControllerAxis(float value, KeyboardButton axis)
Definition: Camera.cpp:140
static ShaderBuffer colorBuffer
Definition: Camera.cpp:274
static void handleAction(ActionEvents action, bool isFinished)
Definition: Camera.cpp:85
static bool dirty
Definition: Camera.h:63
static ShaderBuffer indexBuffer
Definition: Camera.cpp:275
static glm::vec3 frustumVertices[8]
Definition: Camera.cpp:271
Camera, View Frustum.
#define NEAR
Definition: Camera.cpp:246
static bool equal(float a, float b)
Definition: Camera.cpp:25
#define RIGHT
Definition: Camera.cpp:251
static glm::vec3 frustumColors[6]
Definition: Camera.cpp:263
static float rotationDeltaX
Definition: Camera.h:62
#define FAR
Definition: Camera.cpp:247
#define FTL
Definition: Camera.cpp:257
static float getLastFrameTime()
Definition: RunTime.h:43
IMGUI_API bool Begin(const char *name="Debug", bool *p_opened=NULL, const ImVec2 &initial_size=ImVec2(0, 0), float bg_alpha=-1.0f, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:2735
static bool update()
Definition: Camera.cpp:159
static void set2DState(bool on, bool depth=true)
Definition: Shader.cpp:266
Sound Interface.
static void setSize(glm::i32vec2 s)
Definition: Camera.cpp:80
#define NTR
Definition: Camera.cpp:256
static glm::i32vec2 getSize()
Definition: Window.cpp:71
#define FTR
Definition: Camera.cpp:260