-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathControllerInterface.h
More file actions
364 lines (300 loc) · 10 KB
/
ControllerInterface.h
File metadata and controls
364 lines (300 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
#pragma once
#define _USE_MATH_DEFINES
#include <cmath>
#include <chrono>
#include <climits>
#include <GL/glut.h>
#include "Player.h"
#include "WorldObject.h"
#include "Shape.h"
#include "Sphere.h"
#include "Rectangle.h"
#include "FileManager.h"
#include "Cuboid.h"
#include "LightSource.h"
#include "ScreenLogger.h"
#include "materials.h"
#include "globals.h"
class ControllerInterface
{
private:
// Utility object that renders log strings on the screen.
inline static ScreenLogger& logger = ScreenLogger::getInstance();
// The user-controlled player object.
inline static engine::Player& player = engine::Player::getInstance();
// Utility object for path and file management.
// - @see ControllerInterface::movePlayer()
inline static const FileManager& fileManager = FileManager::getInstance();
// Boolean array with with each cell corresponding to a distinct ASCII character.
// Indicates whether the corresponding key is pressed or not in real time.
// - @see ControllerInterface::movePlayer()
inline static bool keystates[UCHAR_MAX+1] = {false};
// [ESSENTIAL] Ensures the game's hardware independency and stable performance.
inline static double deltaTime = 0.0;
// Examplary objects.
// - @see engine::Shape class.
inline static engine::Rectangle ground = engine::Rectangle(100.0f, 100.0f);
inline static engine::Cuboid cuboid_object = engine::Cuboid(8.0f, 8.0f, 8.0f);
inline static engine::Sphere sphere_object = engine::Sphere(10.0f);
inline static engine::Sphere ball = engine::Sphere(0.5f);
// Light emitting object (experimental).
// - @see engine::LightSource class.
inline static engine::LightSource lamp = engine::LightSource(GL_LIGHT0);
public:
// Interface is not meant to generate instances.
ControllerInterface() = delete;
ControllerInterface(const ControllerInterface&) = delete;
// Prerenders physical objects' attributes, collision boxes, etc.
static void initializeWorld()
{
ground
.materialv(GL_AMBIENT, materials::ground_amb)
.materialv(GL_SPECULAR, materials::ground_spec)
.materialv(GL_DIFFUSE, materials::ground_diff)
.resolution(20)
.createCollisionBox(0.0f, 0.0f, 0.0f);
cuboid_object
.resolution(10)
.material(materials::jade);
cuboid_object.createCollisionBox(20.0f, 20.0f, 20.0f);
cuboid_object.createCollisionBox(-20.0f, 20.0f, -20.0f);
sphere_object
.resolution(6)
.material(materials::pearl);
ball.material(materials::pearl);
player.createCollisionBox(0.0f, 0.0f, 0.0f);
}
// Handles the player's WASD movement.
static void movePlayer(void)
{
double delta_move = player.move_speed * deltaTime;
if constexpr (LOG_CAMERA_MOVEMENT)
logger.logMessage(
"Camera Position: (%.3lf, %.3lf, %.3lf)",
player.cam_pos[0], player.cam_pos[1], player.cam_pos[2]
);
if (keystates['w'])
{
player.cam_pos[0] += player.torso_dir[0] * delta_move;
player.cam_pos[2] += player.torso_dir[2] * delta_move;
if constexpr (LOG_CAMERA_MOVEMENT)
logger.logMessage("Forward movement");
}
if (keystates['a'])
{
player.cam_pos[0] += player.left_dir[0] * delta_move;
player.cam_pos[2] += player.left_dir[2] * delta_move;
if constexpr (LOG_CAMERA_MOVEMENT)
logger.logMessage("Left movement");
}
if (keystates['s'])
{
player.cam_pos[0] -= player.torso_dir[0] * delta_move;
player.cam_pos[2] -= player.torso_dir[2] * delta_move;
if constexpr (LOG_CAMERA_MOVEMENT)
logger.logMessage("Backwards movement");
}
if (keystates['d'])
{
player.cam_pos[0] -= player.left_dir[0] * delta_move;
player.cam_pos[2] -= player.left_dir[2] * delta_move;
if constexpr (LOG_CAMERA_MOVEMENT)
logger.logMessage("Right movement");
}
if (keystates[' '])
{
player.cam_pos[1] += delta_move;
}
if (keystates['x'])
{
player.cam_pos[1] -= delta_move;
}
// Performs collision detection with the new player position.
if (collisionCheck(player, ground) || collisionCheck(player, cuboid_object))
{
if constexpr (LOG_COLLISIONS)
logger.logWarning("WARNING: Collision Detected");
}
}
// Collision detection between physical objects.
static bool collisionCheck(const engine::WorldObject& one, const engine::WorldObject& two)
{
bool collisionX;
bool collisionY;
bool collisionZ;
for (auto bb_one : one.getCollisionList())
{
for (auto bb_two : two.getCollisionList())
{
collisionX = (bb_one->x2 >= bb_two->x1) && (bb_two->x2 >= bb_one->x1);
collisionY = (bb_one->y2 >= bb_two->y1) && (bb_two->y2 >= bb_one->y1);
collisionZ = (bb_one->z2 >= bb_two->z1) && (bb_two->z2 >= bb_one->z1);
if (collisionX && collisionY && collisionZ) {
return true;
}
}
}
return false;
}
// Freeglut's callback function namespace.
class Callback
{
public:
Callback() = delete;
Callback(const Callback&) = delete;
public:
// [ESSENTIAL] Display callback function.
static void display(void)
{
constexpr float light_radius = 15.0f;
static vector3f light_pos = { light_radius, 10.0f, 0.0f };
static float light_angle = 0.0f;
static auto beginTime = std::chrono::high_resolution_clock::now();
static auto currentTime = std::chrono::high_resolution_clock::now();
static auto oldTime = std::chrono::high_resolution_clock::now();
static std::chrono::duration<double> totalProgramRuntime;
static std::chrono::duration<double> dt;
static const double aspect_ratio = (double)windowWidth / windowHeight;
currentTime = std::chrono::high_resolution_clock::now();
dt = currentTime - oldTime;
deltaTime = dt.count();
// Escape Button
if (keystates[27]) {
exit(EXIT_SUCCESS);
}
light_angle = light_angle + 2.0f * (float)deltaTime;
if (light_angle > 2.0 * M_PI)
light_angle = 0.0f;
light_pos[0] = light_radius * cos(light_angle);
light_pos[2] = light_radius * sin(light_angle);
if constexpr (LOG_ELAPSED_FRAME_TIME)
totalProgramRuntime = currentTime - beginTime;
if constexpr (LOG_ELAPSED_FRAME_TIME)
logger.logMessage("Elapsed Time: %.3lfs", totalProgramRuntime.count());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0, aspect_ratio, 0.1, 150.0);
//glOrtho(-60.0, 60.0, -60.0, 60.0, -300.0, 300.0);
movePlayer();
gluLookAt(
player.cam_pos[0], player.cam_pos[1], player.cam_pos[2],
player.cam_pos[0] + player.cam_dir[0], player.cam_pos[1] + player.cam_dir[1], player.cam_pos[2] + player.cam_dir[2],
0.0, 1.0, 0.0
);
player.updateCollisionBox();
if (LOG_COLLISIONS)
{
player.showCollisionBox();
ground.showCollisionBox();
cuboid_object.showCollisionBox();
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
ground.spawn(0.0f, 0.0f, 0.0f);
cuboid_object
.spawn(20.0f, 20.0f, 20.0f)
.spawn(-20.0f, 20.0f, -20.0f);
sphere_object
.spawn(-20.0f, 30.0f, 0.0f);
ball
.spawn(1.0f, 1.0f, 1.0f)
.spawn(3.0f, 1.0f, 7.0f)
.spawn(8.0f, 1.0f, -6.0f)
.spawn(10.0f, 1.0f, -12.0f)
.spawn(9.0f, 1.0f, 15.0f);
lamp
.emission(materials::lamp_emsn)
.materialv(GL_DIFFUSE, materials::lamp_diff)
.lightv(GL_SPECULAR, materials::light_spec)
.lightv(GL_DIFFUSE, materials::light_diff)
.spawn(light_pos);
if constexpr (LOG_FPS)
logger.logFPS(1.0 / deltaTime);
if constexpr (LOG_SOUNDS)
logger.logMessage((sound_on ? "Playing Music: lake_wind_ambience.wav" : "Music Disabled"));
logger.flushLogBuffer();
oldTime = currentTime;
glutSwapBuffers();
}
// Keyboard listener (a)
static void keyboardDown(unsigned char key, int x, int y)
{
if (isalpha(key))
key = tolower(key);
keystates[key] = true;
glutPostRedisplay();
}
// Keyboard listener (b)
static void keyboardUp(unsigned char key, int x, int y)
{
if (isalpha(key))
key = tolower(key);
keystates[key] = false;
glutPostRedisplay();
}
// Camera rotation
static void passiveMotion(int x, int y)
{
using engine::sgn;
constexpr static double step = 0.1745;
static double horizontal_angle = -M_PI_2;
static double vertical_angle = 0;
int x_prev = windowCenter[0];
int y_prev = windowCenter[1];
// Camera's rotation speed is proportionate to mouse speed.
int dx = x_prev - x;
int dy = y_prev - y;
double delta_step = step * deltaTime;
horizontal_angle += dx * delta_step;
// Angle reset prevents overflow and precision errors.
if (horizontal_angle < -M_PI) {
horizontal_angle += 2 * M_PI;
}
else if (horizontal_angle > M_PI) {
horizontal_angle -= 2 * M_PI;
}
if (sgn(dy) != sgn(vertical_angle) || abs(vertical_angle) < M_PI_2 - 0.2 * step) {
vertical_angle += dy * delta_step;
}
// Vertical camera bounds.
if (abs(vertical_angle) > M_PI_2) {
vertical_angle = sgn(vertical_angle) * M_PI_2;
}
double sin_vert = sin(vertical_angle);
double sin_horz = sin(horizontal_angle);
double cos_vert = cos(vertical_angle);
double cos_horz = cos(horizontal_angle);
// Camera direction, defined by the unary sphere.
player.cam_dir[0] = cos_vert * sin_horz;
player.cam_dir[1] = sin_vert;
player.cam_dir[2] = cos_vert * cos_horz;
// Player's relative frontward orientation, defined by the unary circle on the XZ plane.
player.torso_dir[0] = sin_horz;
player.torso_dir[2] = cos_horz;
// Player's reelative leftward orientation; perpendicular to its frontward orientation.
player.left_dir[0] = cos_horz;
player.left_dir[2] = -sin_horz;
if constexpr (LOG_TORSO_ORIENTATION)
{
logger.logMessage("Body Orientation:");
logger.logMessage(
"> Torso: (%.3lf, %.3lf, %.3lf)",
player.torso_dir[0], player.torso_dir[1], player.torso_dir[2]
);
logger.logMessage(
"> Left: (%.3lf, %.3lf, %.3lf)",
player.left_dir[0], player.left_dir[1], player.left_dir[2]
);
}
if constexpr (LOG_CAMERA_ROTATATION)
logger.logMessage(
"Camera Orientation: (%.3lf, %.3lf, %.3lf)",
player.cam_dir[0], player.cam_dir[1], player.cam_dir[2]
);
// Returns mouse to the center of the window.
glutWarpPointer(windowCenter[0], windowCenter[1]);
glutPostRedisplay();
}
};
};