Tidy up
[opengl.git] / main.cpp
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <iostream>
4 #include <fstream>
5 #include <sstream>
6 #include <array>
7 #include <vector>
8 #ifdef __APPLE__
9 #include <GL/glew.h>
10 #else
11 #include <OpenGL/glew.h>
12 #endif
13 #include <GLUT/glut.h>
14 #include <glm/glm.hpp>
15 #include <glm/ext.hpp>
16 #include <glm/gtc/type_ptr.hpp>
17 #include "model.hpp"
18 #include "teapot.h"
19
20 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
21
22 using namespace std;
23
24 GLuint pyramidVao, lightVao, teapotVao;
25 GLuint gradientProgId, plainProgId, normalProgId, solidProgId, textureProgId;
26 glm::vec3 camPos   = glm::vec3(0.0f, 0.0f,  0.0f);
27 glm::vec3 camFront = glm::vec3(0.0f, 0.0f, 1.0f);
28 glm::vec3 camUp    = glm::vec3(0.0f, 1.0f,  0.0f);
29 float yaw = 1.57, pitch = 0;
30 bool doScale, doRotate, doTranslate;
31 Model *monkeyHead, *chest;
32 glm::vec3 lightPos(0);
33
34 const int WIDTH = 800, HEIGHT = 600;
35 const float ASPECT = (float)WIDTH / (float)HEIGHT;
36
37 void setProjectionAndViewUniforms(GLuint progId) {
38         GLuint projLoc = glGetUniformLocation(progId, "projection");
39         glm::mat4 proj = glm::perspective(glm::radians(45.f), ASPECT, 0.01f, 10000.f);
40         glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
41
42         GLuint viewLoc = glGetUniformLocation(progId, "view");
43         glm::mat4 view = glm::lookAt(camPos, camPos + camFront, camUp);
44         glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
45 }
46
47 void setLightColorAndPos(GLuint progId, glm::vec3 lightPos, glm::vec4 lightColor) {
48         GLuint lightColorLoc = glGetUniformLocation(progId, "lightColor");
49         glUniform4fv(lightColorLoc, 1, glm::value_ptr(lightColor));
50
51         GLuint lightPosLoc = glGetUniformLocation(progId, "vLightPos");
52         glUniform3fv(lightPosLoc, 1, glm::value_ptr(lightPos));
53
54         GLuint viewPosLoc = glGetUniformLocation(progId, "vViewPos");
55         glUniform3fv(viewPosLoc, 1, glm::value_ptr(camPos));
56 }
57
58 void drawLight(float d, glm::vec3 lightPos, glm::vec4 lightColor) {
59         glUseProgram(plainProgId);
60         glBindVertexArray(lightVao);
61         setProjectionAndViewUniforms(plainProgId);
62         glm::mat4 model = glm::translate(glm::mat4(1.f), lightPos);
63         model = glm::scale(model, glm::vec3(0.2));
64         GLuint modelLoc = glGetUniformLocation(plainProgId, "model");
65         glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
66
67         GLuint colorLoc = glGetUniformLocation(plainProgId, "color");
68         glm::vec4 color(lightColor);
69         glUniform4fv(colorLoc, 1, glm::value_ptr(color));
70                 
71         glDrawArrays(GL_TRIANGLES, 0, 36);
72 };
73
74 void drawPyramids(float d, glm::vec3 lightPos, glm::vec4 lightColor) {
75         glUseProgram(gradientProgId);
76         glBindVertexArray(pyramidVao);
77         setProjectionAndViewUniforms(gradientProgId);
78
79         setLightColorAndPos(gradientProgId, lightPos, lightColor);
80
81         GLuint modelId = glGetUniformLocation(gradientProgId, "model");
82
83         for (int i = 0; i < 10; i++) {
84
85                 glm::mat4 model = glm::mat4(1.f);
86
87                 model = glm::translate(model, glm::vec3(sin(i * 30) * 10, 0, i * 2 - 10));
88                 
89                 if (doRotate) {
90                         model = glm::rotate(model, d * glm::radians(30.f), glm::vec3(0.f, 1.f, 0.f));
91                         model = glm::rotate(model, d * glm::radians(20.f), glm::vec3(1.f, 0.f, 0.f));
92                 }
93                 
94                 if (doScale)
95                         model = glm::scale(model, glm::vec3(1.f, 0.7f + 0.7f * (1 + sin(d + (i + 3))), 1.f));
96
97                 if (doTranslate)
98                         model = glm::translate(model, glm::vec3(sin(d + (i + 1)), cos(d + (i + -3)), sin(d + (i + 4))));
99         
100
101                 glUniformMatrix4fv(modelId, 1, GL_FALSE, glm::value_ptr(model));
102                 
103                 glDrawArrays(GL_TRIANGLES, 0, 18);
104         }
105
106 };
107
108 enum TeapotProjection { teapotOrtho, teapotCamera, teapotPerspStatic, teapotPerspAnimated };
109
110 void drawTeapot(TeapotProjection proj, bool rotate, float d, glm::vec3 lightPos, glm::vec4 lightColor) {
111         glUseProgram(normalProgId);
112         
113         GLuint projLoc = glGetUniformLocation(normalProgId, "projection");
114         GLuint viewLoc = glGetUniformLocation(normalProgId, "view");
115         switch (proj) {
116         case teapotCamera:
117                 setProjectionAndViewUniforms(normalProgId);
118                 break;
119         case teapotOrtho:
120                 {
121                         glm::mat4 proj = glm::ortho(-5.f * ASPECT, 5.f * ASPECT, -5.f, 5.f, 0.01f, 1000.f);
122                         glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
123
124                         glm::vec3 camPos(-5, 5, -5), camFront = glm::vec3(0) - camPos;
125                         glm::mat4 view = glm::lookAt(camPos, camPos + camFront, camUp);
126                         glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
127                 }
128                 break;
129         case teapotPerspStatic:
130         case teapotPerspAnimated:
131                 {
132                         float fov = glm::radians(45.f);
133                         if (proj == teapotPerspAnimated)
134                                 fov += glm::radians(sin(d) * 30.f);
135                         glm::mat4 proj = glm::perspective(fov, ASPECT, 0.01f, 10000.f);
136                         glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
137
138                         glm::mat4 view = glm::lookAt(glm::vec3(0, 0, -10), glm::vec3(0), camUp);
139                         glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
140                 }
141                 break;
142         }
143         setLightColorAndPos(normalProgId, lightPos, lightColor);
144         glBindVertexArray(teapotVao);
145         GLuint modelId = glGetUniformLocation(normalProgId, "model");
146         glm::mat4 model(1);
147         model = glm::scale(model, glm::vec3(0.3));
148         if (rotate) model = glm::rotate(model, d, glm::vec3(0, 1, 0));
149         glUniformMatrix4fv(modelId, 1, GL_FALSE, glm::value_ptr(model));
150
151         glDrawArrays(GL_TRIANGLES, 0, teapot_vertex_count);
152 }
153
154 void display() {
155         glClearColor(0.5, 0.5, 0.5, 1);
156         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
157         float d = (float)glutGet(GLUT_ELAPSED_TIME) * 0.001f;
158
159         /* glm::vec3 lightPos = glm::vec3(sin(d / 10.f) * 10, 0, cos(d / 10.f) * 10); */
160         glm::vec3 lightPos = lightPos;
161         glm::vec4 lightColor(1, 1, 1, 1);
162
163         drawLight(d, lightPos, lightColor);
164
165         glUseProgram(textureProgId);
166         setProjectionAndViewUniforms(textureProgId);
167         setLightColorAndPos(textureProgId, lightPos, lightColor);
168
169         Model::Node *top = chest->find("top");
170         top->model = glm::translate(glm::mat4(1), glm::vec3(0, 1, -1));
171         top->model = glm::rotate(top->model, sin(d / 2.5f) * 0.5f, glm::vec3(1, 0, 0));
172         top->model = glm::translate(top->model, glm::vec3(0, -1, 1));
173         
174         /* Model::Node *jewels = chest->find("jewels"); */
175         /* jewels->model = glm::scale(glm::mat4(1), glm::vec3((sin(d) + 1.2f) / 2.f)); */
176
177         /* Model::Node *lock = chest->find("lock"); */
178         /* lock->model = glm::translate(glm::mat4(1), glm::vec3(0.22610, 3.36478, -0.75649)); */
179         /* lock->model = glm::rotate(lock->model, (d / 2.5f), glm::vec3(0, 1, 0.4)); */
180         /* lock->model = glm::translate(lock->model, -glm::vec3(0.22610, 3.36478, -0.75649)); */
181
182         /* Model::Node *key = chest->find("key"); */
183         /* key->model = glm::translate(glm::mat4(1), glm::vec3(0, 0, sin(d))); */
184         
185         /* chest->getRoot()->model = glm::translate(glm::mat4(1), lightPos); */
186         chest->draw();
187
188         glutSwapBuffers();
189 }
190
191 void attachShader(GLuint progId, const char* filePath, GLenum type) {
192         GLuint shader = glCreateShader(type);
193
194         if (!shader) {
195                 fprintf(stderr, "error creating shader\n");
196                 exit(1);
197         }
198
199         ifstream file(filePath);
200         stringstream buffer;
201         buffer << file.rdbuf();
202         string str = buffer.str();
203         const char* contents = str.c_str();
204
205         glShaderSource(shader, 1, (const GLchar**)&contents, NULL);
206         glCompileShader(shader);
207         GLint success;
208         glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
209         if (!success) {
210                 GLchar log[1024];
211                 glGetShaderInfoLog(shader, 1024, NULL, log);
212                 fprintf(stderr, "error: %s\n", log);
213                 exit(1);
214         }
215         glAttachShader(progId, shader);
216 }
217
218 GLuint compileShaders(char* vertexShader, char* fragmentShader) {
219         GLuint progId = glCreateProgram();
220
221         attachShader(progId, vertexShader, GL_VERTEX_SHADER);
222         attachShader(progId, fragmentShader, GL_FRAGMENT_SHADER);
223
224         glLinkProgram(progId);
225         GLint success = 0;
226         glGetProgramiv(progId, GL_LINK_STATUS, &success);
227         if (!success) {
228                 GLchar log[1024];
229                 glGetProgramInfoLog(progId, sizeof(log), NULL, log);
230                 fprintf(stderr, "error linking: %s\n", log);
231                 exit(1);
232         }
233
234         return progId;
235 }
236
237 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
238
239 GLuint setupBuffers(glm::vec3* vertices, glm::vec3* normals, GLuint progId) {
240
241         GLfloat colors[] = {
242                 0, 1, 0, 1,
243                 1, 0, 0, 1,
244                 0, 0, 1, 1,
245
246                 0, 1, 0, 1,
247                 1, 0, 0, 1,
248                 0, 0, 1, 1,
249
250                 0, 1, 0, 1,
251                 1, 0, 0, 1,
252                 0, 0, 1, 1,
253
254                 0, 1, 0, 1,
255                 1, 0, 0, 1,
256                 0, 0, 1, 1,
257
258                 0, 1, 0, 1,
259                 1, 0, 0, 1,
260                 0, 0, 1, 1,
261                 
262                 0, 1, 0, 1,
263                 1, 0, 0, 1,
264                 0, 0, 1, 1
265         };
266
267         GLuint numVerts = 18;
268
269         GLuint vbo;
270         glGenBuffers(1, &vbo);
271
272         GLuint vao;
273         glGenVertexArrays(1, &vao);
274
275         GLuint posId = glGetAttribLocation(progId, "vPosition");
276         GLuint colorId = glGetAttribLocation(progId, "vColor");
277         GLuint normalLoc = glGetAttribLocation(progId, "vNormal");
278
279         GLuint vertsLen = numVerts * 3 * sizeof(GLfloat);
280         GLuint colorsLen = numVerts * 4 * sizeof(GLfloat);
281         GLuint normalLen = numVerts * 3 * sizeof(GLfloat);
282
283         glBindBuffer(GL_ARRAY_BUFFER, vbo);
284         glBufferData(GL_ARRAY_BUFFER, vertsLen + colorsLen + normalLen, NULL, GL_STATIC_DRAW);
285
286         glBufferSubData(GL_ARRAY_BUFFER, 0, vertsLen, glm::value_ptr(vertices[0]));
287         glBufferSubData(GL_ARRAY_BUFFER, vertsLen, colorsLen, colors);
288         glBufferSubData(GL_ARRAY_BUFFER, vertsLen + colorsLen, normalLen, glm::value_ptr(normals[0]));
289         
290         glBindVertexArray(vao);
291
292         glEnableVertexAttribArray(posId);
293         glVertexAttribPointer(posId, 3, GL_FLOAT, GL_FALSE, 0, 0);
294
295         glEnableVertexAttribArray(colorId);
296         glVertexAttribPointer(colorId, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(vertsLen));
297
298         glEnableVertexAttribArray(normalLoc);
299         glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(vertsLen + colorsLen));
300
301         return vao;
302 }
303
304 vector<glm::vec3> quadToTriangles(glm::vec3 *quads) {
305         vector<glm::vec3> triangles(6);
306         triangles[0] = quads[0];
307         triangles[1] = quads[1];
308         triangles[2] = quads[2];
309         triangles[3] = quads[2];
310         triangles[4] = quads[3];
311         triangles[5] = quads[0];
312         return triangles;
313 }
314
315 template <typename T>
316 void append(vector<T> &a, vector<T> &b) {
317         a.insert(a.end(), b.begin(), b.end());
318 };
319
320 void setupLightBuffers(GLuint progId) {
321         vector<glm::vec3> vertices;
322         glm::vec3 front[] = {
323                 glm::vec3(1, -1, -1),
324                 glm::vec3(-1, -1, -1),
325                 glm::vec3(-1, 1, -1),
326                 glm::vec3(1, 1, -1)
327         };
328         vector<glm::vec3> frontTriangles = quadToTriangles(front);
329         append(vertices, frontTriangles);
330
331         glm::vec3 back[] = {
332                 glm::vec3(1, 1, 1),
333                 glm::vec3(-1, 1, 1),
334                 glm::vec3(-1, -1, 1),
335                 glm::vec3(1, -1, 1)
336         };
337         vector<glm::vec3> backQuads = quadToTriangles(back);
338         append(vertices, backQuads);
339
340         glm::vec3 top[] = {
341                 glm::vec3(1, 1, -1),
342                 glm::vec3(-1, 1, -1),
343                 glm::vec3(-1, 1, 1),
344                 glm::vec3(1, 1, 1)
345         };
346         vector<glm::vec3> topTriangles = quadToTriangles(top);
347         append(vertices, topTriangles);
348
349         glm::vec3 bottom[] = {
350                 glm::vec3(1, -1, 1),
351                 glm::vec3(-1, -1, 1),
352                 glm::vec3(-1, -1, -1),
353                 glm::vec3(1, -1, -1)
354         };
355         vector<glm::vec3> bottomTriangles = quadToTriangles(bottom);
356         append(vertices, bottomTriangles);
357
358         glm::vec3 left[] = {
359                 glm::vec3(-1, 1, 1),
360                 glm::vec3(-1, 1, -1),
361                 glm::vec3(-1, -1, -1),
362                 glm::vec3(-1, -1, 1)
363         };
364         vector<glm::vec3> leftTriangles = quadToTriangles(left);
365         append(vertices, leftTriangles);
366
367         glm::vec3 right[] = {
368                 glm::vec3(1, 1, -1),
369                 glm::vec3(1, 1, 1),
370                 glm::vec3(1, -1, 1),
371                 glm::vec3(1, -1, -1)
372         };
373         vector<glm::vec3> rightTriangles = quadToTriangles(right);
374         append(vertices, rightTriangles);
375         GLuint verticesSize = 36 * 3 * sizeof(GLfloat);
376
377         glGenVertexArrays(1, &lightVao);
378         GLuint vbo;
379         glBindVertexArray(lightVao);
380         glGenBuffers(1, &vbo);
381         glBindBuffer(GL_ARRAY_BUFFER, vbo);
382         glBufferData(GL_ARRAY_BUFFER, verticesSize, NULL, GL_STATIC_DRAW);
383         glBufferSubData(GL_ARRAY_BUFFER, 0, verticesSize, glm::value_ptr(vertices[0]));
384         GLuint posLoc = glGetAttribLocation(progId, "vPosition");
385         glEnableVertexAttribArray(posLoc);
386         glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
387 }
388
389 void setupTeapotBuffers(GLuint progId) {
390         GLuint vbos[2];
391         glGenBuffers(2, vbos);
392         glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
393         glBufferData(GL_ARRAY_BUFFER, 3 * teapot_vertex_count * sizeof(float), teapot_vertex_points, GL_STATIC_DRAW);
394         glBindBuffer(GL_ARRAY_BUFFER, vbos[1]);
395         glBufferData(GL_ARRAY_BUFFER, 3 * teapot_vertex_count * sizeof(float), teapot_normals, GL_STATIC_DRAW);
396
397         glGenVertexArrays(1, &teapotVao);
398         glBindVertexArray(teapotVao);
399
400         GLuint posLoc = glGetAttribLocation(progId, "vPosition");
401         GLuint normalLoc = glGetAttribLocation(progId, "vNormal");
402
403         glEnableVertexAttribArray(posLoc);
404         glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
405         glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, NULL);
406         
407         glEnableVertexAttribArray(normalLoc);
408         glBindBuffer(GL_ARRAY_BUFFER, vbos[1]);
409         glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, 0, NULL);
410 }
411
412 void validateProgram(GLuint progId) {
413         glValidateProgram(progId);
414         
415         GLint success;
416         glGetProgramiv(progId, GL_VALIDATE_STATUS, &success);
417         if (!success) {
418                 GLchar log[1024];
419                 glGetProgramInfoLog(progId, sizeof(log), NULL, log);
420                 fprintf(stderr, "error: %s\n", log);
421                 exit(1);
422         }
423 }
424
425 void init() {
426         glm::vec3 vertices[18] = {
427                 glm::vec3(0.0f, 1.0f, 0.0f),
428                 glm::vec3(1.0f, -1.0f, -1.0f),
429                 glm::vec3(-1.0f, -1.0f, -1.0f),
430
431                 glm::vec3(0.0f, 1.0f, 0.0f),
432                 glm::vec3(-1.0f, -1.0f, 1.0f),
433                 glm::vec3(1.0f, -1.0f, 1.0f),
434
435                 glm::vec3(0.0f, 1.0f, 0.0f),
436                 glm::vec3(-1.0f, -1.0f, -1.0f),
437                 glm::vec3(-1.0f, -1.0f, 1.0f),
438
439                 glm::vec3(0.0f, 1.0f, 0.0f),
440                 glm::vec3(1.0f, -1.0f, 1.0f),
441                 glm::vec3(1.0f, -1.0f, -1.0f),
442
443                 glm::vec3(1, -1, 1),
444                 glm::vec3(-1, -1, 1),
445                 glm::vec3(-1, -1, -1),
446                 glm::vec3(-1, -1, -1),
447                 glm::vec3(1, -1, -1),
448                 glm::vec3(1, -1, 1)
449         };
450
451         // work out the normals
452         glm::vec3 normals[18];
453         for (int i = 0; i < 6; i++) {
454                 glm::vec3 a = vertices[i * 3];
455                 glm::vec3 b = vertices[i * 3 + 1];
456                 glm::vec3 c = vertices[i * 3 + 2];
457                 glm::vec3 u = glm::normalize(a - c);
458                 glm::vec3 v = glm::normalize(b - c);
459                 glm::vec3 norm = glm::normalize(glm::cross(v, u));
460                 for(int j = 0; j < 3; j++) {
461                         normals[i * 3 + j] = -glm::vec3(norm);
462                 }
463         }
464
465         gradientProgId = compileShaders((char*)"vertex.glsl", (char*)"gradientfrag.glsl");
466         glUseProgram(gradientProgId);
467         pyramidVao = setupBuffers(vertices, normals, gradientProgId);
468         validateProgram(gradientProgId);
469
470         plainProgId = compileShaders((char*)"plainvertex.glsl", (char*)"plainfrag.glsl");
471         glUseProgram(plainProgId);
472         setupLightBuffers(plainProgId);
473         validateProgram(plainProgId);
474
475         normalProgId = compileShaders((char*)"vertex.glsl", (char*)"normalfrag.glsl");
476         glUseProgram(normalProgId);
477         setupTeapotBuffers(normalProgId);
478         validateProgram(normalProgId);
479
480         solidProgId = compileShaders((char*)"vertex.glsl", (char*)"solidfrag.glsl");
481         glUseProgram(solidProgId);
482         validateProgram(solidProgId);
483
484         textureProgId = compileShaders((char*)"texturevertex.glsl", (char*)"texturefrag.glsl");
485         glUseProgram(textureProgId);
486         validateProgram(textureProgId);
487
488         monkeyHead = new Model("monkeyhead_smooth.dae", solidProgId);
489         chest = new Model("chest.dae", textureProgId);
490
491         glEnable(GL_DEPTH_TEST); 
492         glEnable(GL_CULL_FACE); 
493 }
494
495 bool* keyStates = new bool[256];
496
497 void keyboard(unsigned char key, int x, int y) {
498         keyStates[key] = true;
499         if (key == 'z')
500                 doScale = !doScale;
501         if (key == 'x')
502                 doRotate = !doRotate;
503         if (key == 'c')
504                 doTranslate = !doTranslate;
505 }
506
507 void keyboardUp(unsigned char key, int x, int y) {
508         keyStates[key] = false;
509 }
510
511 void timer(int _) {
512         float xSpeed = 0.f, ySpeed = 0.f, zSpeed = 0.f;
513         if (keyStates['w'])
514                 zSpeed = 0.1f;
515         if (keyStates['s'])
516                 zSpeed = -0.1f;
517         if (keyStates['a'])
518                 xSpeed = 0.1f;
519         if (keyStates['d'])
520                 xSpeed = -0.1f;
521         if (keyStates['q'])
522                 ySpeed = 0.1f;
523         if (keyStates['e'])
524                 ySpeed = -0.1f;
525
526         if (keyStates['j']) lightPos.z += 0.1f;
527         if (keyStates['k']) lightPos.z -= 0.1f;
528         if (keyStates['h']) lightPos.x -= 0.1f;
529         if (keyStates['l']) lightPos.x += 0.1f;
530         if (keyStates['m']) lightPos.y -= 0.1f;
531         if (keyStates['n']) lightPos.y += 0.1f;
532
533         camPos.x += xSpeed * sin(yaw) + zSpeed * cos(yaw);
534         camPos.y += ySpeed;
535         camPos.z += zSpeed * sin(yaw) - xSpeed * cos(yaw);
536         glutPostRedisplay();
537         glutTimerFunc(16, timer, 0);
538 }
539
540 int prevMouseX, prevMouseY;
541 bool firstMouse = true;
542
543 void motion(int x, int y) {
544         if (firstMouse) {
545                 prevMouseX = x;
546                 prevMouseY = y;
547                 firstMouse = false;
548         }
549         int dx = x - prevMouseX, dy = y - prevMouseY;
550
551         prevMouseX = x;
552         prevMouseY = y;
553
554         const float sensitivity = 0.005f;
555         yaw += dx * sensitivity;
556         pitch -= dy * sensitivity;
557
558         glm::vec3 front;
559         front.x = cos(pitch) * cos(yaw);
560         front.y = sin(pitch);
561         front.z = cos(pitch) * sin(yaw);
562         camFront = glm::normalize(front);
563
564         if (pitch < -1.57079632679 || pitch >= 1.57079632679) {
565                 camUp = glm::vec3(0, -1, 0);
566         } else {
567                 camUp = glm::vec3(0, 1, 0);
568         }
569 }
570
571 void mouse(int button, int state, int x, int y) {
572         if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
573                 firstMouse = true;
574 }
575
576 int main(int argc, char** argv) {
577         glutInit(&argc, argv);
578         glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGB|GLUT_3_2_CORE_PROFILE);
579         glutInitWindowSize(WIDTH, HEIGHT);
580         int win = glutCreateWindow("Hello Triangle");
581         glutDisplayFunc(display);
582
583         glewInit();
584         
585         init();
586
587         glutKeyboardFunc(keyboard);
588         glutKeyboardUpFunc(keyboardUp);
589         glutTimerFunc(16, timer, 0);
590         glutMotionFunc(motion);
591         glutMouseFunc(mouse);
592
593         glutMainLoop();
594
595         return 0;
596 }
597