37033957472fe847bab02902e565abc713283af0
[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;
26 glm::vec3 camPos   = glm::vec3(0.0f, 0.0f,  -10.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 chestPos(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, "lightPos");
52         glUniform3fv(lightPosLoc, 1, glm::value_ptr(lightPos));
53 }
54
55 void drawLight(float d, glm::vec3 lightPos, glm::vec4 lightColor) {
56         glUseProgram(plainProgId);
57         glBindVertexArray(lightVao);
58         setProjectionAndViewUniforms(plainProgId);
59         glm::mat4 model = glm::translate(glm::mat4(1.f), lightPos);
60         model = glm::scale(model, glm::vec3(0.2));
61         GLuint modelLoc = glGetUniformLocation(plainProgId, "model");
62         glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
63
64         GLuint colorLoc = glGetUniformLocation(plainProgId, "color");
65         glm::vec4 color(lightColor);
66         glUniform4fv(colorLoc, 1, glm::value_ptr(color));
67                 
68         glDrawArrays(GL_TRIANGLES, 0, 36);
69 };
70
71 void drawPyramids(float d, glm::vec3 lightPos, glm::vec4 lightColor) {
72         glUseProgram(gradientProgId);
73         glBindVertexArray(pyramidVao);
74         setProjectionAndViewUniforms(gradientProgId);
75
76         setLightColorAndPos(gradientProgId, lightPos, lightColor);
77
78         GLuint viewPosLoc = glGetUniformLocation(gradientProgId, "viewPos");
79         glUniform3fv(viewPosLoc, 1, glm::value_ptr(camPos));
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, 0, cos(d) * 10);
160         glm::vec4 lightColor(1, 1, 1, 1);
161
162         glViewport(0, 0, WIDTH, HEIGHT);
163         /* drawPyramids(d, lightPos, lightColor); */
164         drawLight(d, lightPos, lightColor);
165
166         glUseProgram(solidProgId);
167         setProjectionAndViewUniforms(solidProgId);
168         setLightColorAndPos(solidProgId, lightPos, lightColor);
169         
170         GLuint colorLoc = glGetUniformLocation(solidProgId, "color");
171         glm::vec4 c(1);
172         glUniform4fv(colorLoc, 1, glm::value_ptr(c));
173
174         monkeyHead->getRoot()->model = glm::translate(glm::mat4(1), glm::vec3(2, 0, 0));
175         monkeyHead->draw();
176
177         Model::Node *top = chest->find("top");
178         top->model = glm::translate(glm::mat4(1), glm::vec3(0, 1, -1));
179         top->model = glm::rotate(top->model, sin(d / 2.5f) * 0.5f, glm::vec3(1, 0, 0));
180         top->model = glm::translate(top->model, glm::vec3(0, -1, 1));
181         
182         Model::Node *jewels = chest->find("jewels");
183         jewels->model = glm::scale(glm::mat4(1), glm::vec3((sin(d) + 1.2f) / 2.f));
184
185         Model::Node *lock = chest->find("lock");
186         lock->model = glm::translate(glm::mat4(1), glm::vec3(0.22610, 3.36478, -0.75649));
187         lock->model = glm::rotate(lock->model, (d / 2.5f), glm::vec3(0, 1, 0.4));
188         lock->model = glm::translate(lock->model, -glm::vec3(0.22610, 3.36478, -0.75649));
189
190         Model::Node *key = chest->find("key");
191         key->model = glm::translate(glm::mat4(1), glm::vec3(0, 0, sin(d)));
192         
193         chest->getRoot()->model = glm::translate(glm::mat4(1), chestPos);
194         chest->draw();
195         
196         /* drawTeapot(teapotCamera, false, d, lightPos, lightColor); */
197
198         /* glClear(GL_DEPTH_BUFFER_BIT); */
199
200         /* glViewport(0, 0, WIDTH / 4, HEIGHT / 4); */
201         /* drawTeapot(teapotOrtho, false, d, lightPos, lightColor); */
202
203         /* glViewport(WIDTH / 4, 0, WIDTH / 4, HEIGHT / 4); */
204         /* drawTeapot(teapotOrtho, true, d, lightPos, lightColor); */
205
206         /* glViewport(WIDTH / 4 * 2, 0, WIDTH / 4, HEIGHT / 4); */
207         /* drawTeapot(teapotPerspStatic, false, d, lightPos, lightColor); */
208
209         /* glViewport(WIDTH / 4 * 3, 0, WIDTH / 4, HEIGHT / 4); */
210         /* drawTeapot(teapotPerspAnimated, false, d, lightPos, lightColor); */
211
212
213         glutSwapBuffers();
214 }
215
216 void attachShader(GLuint progId, const char* filePath, GLenum type) {
217         GLuint shader = glCreateShader(type);
218
219         if (!shader) {
220                 fprintf(stderr, "error creating shader\n");
221                 exit(1);
222         }
223
224         ifstream file(filePath);
225         stringstream buffer;
226         buffer << file.rdbuf();
227         string str = buffer.str();
228         const char* contents = str.c_str();
229
230         glShaderSource(shader, 1, (const GLchar**)&contents, NULL);
231         glCompileShader(shader);
232         GLint success;
233         glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
234         if (!success) {
235                 GLchar log[1024];
236                 glGetShaderInfoLog(shader, 1024, NULL, log);
237                 fprintf(stderr, "error: %s\n", log);
238                 exit(1);
239         }
240         glAttachShader(progId, shader);
241 }
242
243 GLuint compileShaders(char* vertexShader, char* fragmentShader) {
244         GLuint progId = glCreateProgram();
245
246         attachShader(progId, vertexShader, GL_VERTEX_SHADER);
247         attachShader(progId, fragmentShader, GL_FRAGMENT_SHADER);
248
249         glLinkProgram(progId);
250         GLint success = 0;
251         glGetProgramiv(progId, GL_LINK_STATUS, &success);
252         if (!success) {
253                 GLchar log[1024];
254                 glGetProgramInfoLog(progId, sizeof(log), NULL, log);
255                 fprintf(stderr, "error linking: %s\n", log);
256                 exit(1);
257         }
258
259         return progId;
260 }
261
262 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
263
264 GLuint setupBuffers(glm::vec3* vertices, glm::vec3* normals, GLuint progId) {
265
266         GLfloat colors[] = {
267                 0, 1, 0, 1,
268                 1, 0, 0, 1,
269                 0, 0, 1, 1,
270
271                 0, 1, 0, 1,
272                 1, 0, 0, 1,
273                 0, 0, 1, 1,
274
275                 0, 1, 0, 1,
276                 1, 0, 0, 1,
277                 0, 0, 1, 1,
278
279                 0, 1, 0, 1,
280                 1, 0, 0, 1,
281                 0, 0, 1, 1,
282
283                 0, 1, 0, 1,
284                 1, 0, 0, 1,
285                 0, 0, 1, 1,
286                 
287                 0, 1, 0, 1,
288                 1, 0, 0, 1,
289                 0, 0, 1, 1
290         };
291
292         GLuint numVerts = 18;
293
294         GLuint vbo;
295         glGenBuffers(1, &vbo);
296
297         GLuint vao;
298         glGenVertexArrays(1, &vao);
299
300         GLuint posId = glGetAttribLocation(progId, "vPosition");
301         GLuint colorId = glGetAttribLocation(progId, "vColor");
302         GLuint normalLoc = glGetAttribLocation(progId, "vNormal");
303
304         GLuint vertsLen = numVerts * 3 * sizeof(GLfloat);
305         GLuint colorsLen = numVerts * 4 * sizeof(GLfloat);
306         GLuint normalLen = numVerts * 3 * sizeof(GLfloat);
307
308         glBindBuffer(GL_ARRAY_BUFFER, vbo);
309         glBufferData(GL_ARRAY_BUFFER, vertsLen + colorsLen + normalLen, NULL, GL_STATIC_DRAW);
310
311         glBufferSubData(GL_ARRAY_BUFFER, 0, vertsLen, glm::value_ptr(vertices[0]));
312         glBufferSubData(GL_ARRAY_BUFFER, vertsLen, colorsLen, colors);
313         glBufferSubData(GL_ARRAY_BUFFER, vertsLen + colorsLen, normalLen, glm::value_ptr(normals[0]));
314         
315         glBindVertexArray(vao);
316
317         glEnableVertexAttribArray(posId);
318         glVertexAttribPointer(posId, 3, GL_FLOAT, GL_FALSE, 0, 0);
319
320         glEnableVertexAttribArray(colorId);
321         glVertexAttribPointer(colorId, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(vertsLen));
322
323         glEnableVertexAttribArray(normalLoc);
324         glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(vertsLen + colorsLen));
325
326         return vao;
327 }
328
329 vector<glm::vec3> quadToTriangles(glm::vec3 *quads) {
330         vector<glm::vec3> triangles(6);
331         triangles[0] = quads[0];
332         triangles[1] = quads[1];
333         triangles[2] = quads[2];
334         triangles[3] = quads[2];
335         triangles[4] = quads[3];
336         triangles[5] = quads[0];
337         return triangles;
338 }
339
340 template <typename T>
341 void append(vector<T> &a, vector<T> &b) {
342         a.insert(a.end(), b.begin(), b.end());
343 };
344
345 void setupLightBuffers(GLuint progId) {
346         vector<glm::vec3> vertices;
347         glm::vec3 front[] = {
348                 glm::vec3(1, -1, -1),
349                 glm::vec3(-1, -1, -1),
350                 glm::vec3(-1, 1, -1),
351                 glm::vec3(1, 1, -1)
352         };
353         vector<glm::vec3> frontTriangles = quadToTriangles(front);
354         append(vertices, frontTriangles);
355
356         glm::vec3 back[] = {
357                 glm::vec3(1, 1, 1),
358                 glm::vec3(-1, 1, 1),
359                 glm::vec3(-1, -1, 1),
360                 glm::vec3(1, -1, 1)
361         };
362         vector<glm::vec3> backQuads = quadToTriangles(back);
363         append(vertices, backQuads);
364
365         glm::vec3 top[] = {
366                 glm::vec3(1, 1, -1),
367                 glm::vec3(-1, 1, -1),
368                 glm::vec3(-1, 1, 1),
369                 glm::vec3(1, 1, 1)
370         };
371         vector<glm::vec3> topTriangles = quadToTriangles(top);
372         append(vertices, topTriangles);
373
374         glm::vec3 bottom[] = {
375                 glm::vec3(1, -1, 1),
376                 glm::vec3(-1, -1, 1),
377                 glm::vec3(-1, -1, -1),
378                 glm::vec3(1, -1, -1)
379         };
380         vector<glm::vec3> bottomTriangles = quadToTriangles(bottom);
381         append(vertices, bottomTriangles);
382
383         glm::vec3 left[] = {
384                 glm::vec3(-1, 1, 1),
385                 glm::vec3(-1, 1, -1),
386                 glm::vec3(-1, -1, -1),
387                 glm::vec3(-1, -1, 1)
388         };
389         vector<glm::vec3> leftTriangles = quadToTriangles(left);
390         append(vertices, leftTriangles);
391
392         glm::vec3 right[] = {
393                 glm::vec3(1, 1, -1),
394                 glm::vec3(1, 1, 1),
395                 glm::vec3(1, -1, 1),
396                 glm::vec3(1, -1, -1)
397         };
398         vector<glm::vec3> rightTriangles = quadToTriangles(right);
399         append(vertices, rightTriangles);
400         GLuint verticesSize = 36 * 3 * sizeof(GLfloat);
401
402         glGenVertexArrays(1, &lightVao);
403         GLuint vbo;
404         glBindVertexArray(lightVao);
405         glGenBuffers(1, &vbo);
406         glBindBuffer(GL_ARRAY_BUFFER, vbo);
407         glBufferData(GL_ARRAY_BUFFER, verticesSize, NULL, GL_STATIC_DRAW);
408         glBufferSubData(GL_ARRAY_BUFFER, 0, verticesSize, glm::value_ptr(vertices[0]));
409         GLuint posLoc = glGetAttribLocation(progId, "vPosition");
410         glEnableVertexAttribArray(posLoc);
411         glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
412 }
413
414 void setupTeapotBuffers(GLuint progId) {
415         GLuint vbos[2];
416         glGenBuffers(2, vbos);
417         glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
418         glBufferData(GL_ARRAY_BUFFER, 3 * teapot_vertex_count * sizeof(float), teapot_vertex_points, GL_STATIC_DRAW);
419         glBindBuffer(GL_ARRAY_BUFFER, vbos[1]);
420         glBufferData(GL_ARRAY_BUFFER, 3 * teapot_vertex_count * sizeof(float), teapot_normals, GL_STATIC_DRAW);
421
422         glGenVertexArrays(1, &teapotVao);
423         glBindVertexArray(teapotVao);
424
425         GLuint posLoc = glGetAttribLocation(progId, "vPosition");
426         GLuint normalLoc = glGetAttribLocation(progId, "vNormal");
427
428         glEnableVertexAttribArray(posLoc);
429         glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
430         glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, NULL);
431         
432         glEnableVertexAttribArray(normalLoc);
433         glBindBuffer(GL_ARRAY_BUFFER, vbos[1]);
434         glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, 0, NULL);
435 }
436
437 void validateProgram(GLuint progId) {
438         glValidateProgram(progId);
439         
440         GLint success;
441         glGetProgramiv(progId, GL_VALIDATE_STATUS, &success);
442         if (!success) {
443                 GLchar log[1024];
444                 glGetProgramInfoLog(progId, sizeof(log), NULL, log);
445                 fprintf(stderr, "error: %s\n", log);
446                 exit(1);
447         }
448 }
449
450 void init() {
451         glm::vec3 vertices[18] = {
452                 glm::vec3(0.0f, 1.0f, 0.0f),
453                 glm::vec3(1.0f, -1.0f, -1.0f),
454                 glm::vec3(-1.0f, -1.0f, -1.0f),
455
456                 glm::vec3(0.0f, 1.0f, 0.0f),
457                 glm::vec3(-1.0f, -1.0f, 1.0f),
458                 glm::vec3(1.0f, -1.0f, 1.0f),
459
460                 glm::vec3(0.0f, 1.0f, 0.0f),
461                 glm::vec3(-1.0f, -1.0f, -1.0f),
462                 glm::vec3(-1.0f, -1.0f, 1.0f),
463
464                 glm::vec3(0.0f, 1.0f, 0.0f),
465                 glm::vec3(1.0f, -1.0f, 1.0f),
466                 glm::vec3(1.0f, -1.0f, -1.0f),
467
468                 glm::vec3(1, -1, 1),
469                 glm::vec3(-1, -1, 1),
470                 glm::vec3(-1, -1, -1),
471                 glm::vec3(-1, -1, -1),
472                 glm::vec3(1, -1, -1),
473                 glm::vec3(1, -1, 1)
474         };
475
476         // work out the normals
477         glm::vec3 normals[18];
478         for (int i = 0; i < 6; i++) {
479                 glm::vec3 a = vertices[i * 3];
480                 glm::vec3 b = vertices[i * 3 + 1];
481                 glm::vec3 c = vertices[i * 3 + 2];
482                 glm::vec3 u = glm::normalize(a - c);
483                 glm::vec3 v = glm::normalize(b - c);
484                 glm::vec3 norm = glm::normalize(glm::cross(v, u));
485                 for(int j = 0; j < 3; j++) {
486                         normals[i * 3 + j] = -glm::vec3(norm);
487                 }
488         }
489
490         gradientProgId = compileShaders((char*)"vertex.glsl", (char*)"gradientfrag.glsl");
491         glUseProgram(gradientProgId);
492         pyramidVao = setupBuffers(vertices, normals, gradientProgId);
493         validateProgram(gradientProgId);
494
495         plainProgId = compileShaders((char*)"plainvertex.glsl", (char*)"plainfrag.glsl");
496         glUseProgram(plainProgId);
497         setupLightBuffers(plainProgId);
498         validateProgram(plainProgId);
499
500         normalProgId = compileShaders((char*)"vertex.glsl", (char*)"normalfrag.glsl");
501         glUseProgram(normalProgId);
502         setupTeapotBuffers(normalProgId);
503         validateProgram(normalProgId);
504
505         solidProgId = compileShaders((char*)"vertex.glsl", (char*)"solidfrag.glsl");
506         glUseProgram(solidProgId);
507         validateProgram(solidProgId);
508
509         monkeyHead = new Model("monkeyhead_smooth.dae", solidProgId);
510         chest = new Model("chest.dae", solidProgId);
511
512         glEnable(GL_DEPTH_TEST); 
513         glEnable(GL_CULL_FACE); 
514 }
515
516 bool* keyStates = new bool[256];
517
518 void keyboard(unsigned char key, int x, int y) {
519         keyStates[key] = true;
520         if (key == 'z')
521                 doScale = !doScale;
522         if (key == 'x')
523                 doRotate = !doRotate;
524         if (key == 'c')
525                 doTranslate = !doTranslate;
526 }
527
528 void keyboardUp(unsigned char key, int x, int y) {
529         keyStates[key] = false;
530 }
531
532 void timer(int _) {
533         float xSpeed = 0.f, ySpeed = 0.f, zSpeed = 0.f;
534         if (keyStates['w'])
535                 zSpeed = 0.1f;
536         if (keyStates['s'])
537                 zSpeed = -0.1f;
538         if (keyStates['a'])
539                 xSpeed = 0.1f;
540         if (keyStates['d'])
541                 xSpeed = -0.1f;
542         if (keyStates['q'])
543                 ySpeed = 0.1f;
544         if (keyStates['e'])
545                 ySpeed = -0.1f;
546
547         if (keyStates['j']) chestPos.z += 0.1f;
548         if (keyStates['k']) chestPos.z -= 0.1f;
549         if (keyStates['h']) chestPos.x -= 0.1f;
550         if (keyStates['l']) chestPos.x += 0.1f;
551
552         camPos.x += xSpeed * sin(yaw) + zSpeed * cos(yaw);
553         camPos.y += ySpeed;
554         camPos.z += zSpeed * sin(yaw) - xSpeed * cos(yaw);
555         glutPostRedisplay();
556         glutTimerFunc(16, timer, 0);
557 }
558
559 int prevMouseX, prevMouseY;
560 bool firstMouse = true;
561
562 void motion(int x, int y) {
563         if (firstMouse) {
564                 prevMouseX = x;
565                 prevMouseY = y;
566                 firstMouse = false;
567         }
568         int dx = x - prevMouseX, dy = y - prevMouseY;
569
570         prevMouseX = x;
571         prevMouseY = y;
572
573         const float sensitivity = 0.005f;
574         yaw += dx * sensitivity;
575         pitch -= dy * sensitivity;
576
577         glm::vec3 front;
578         front.x = cos(pitch) * cos(yaw);
579         front.y = sin(pitch);
580         front.z = cos(pitch) * sin(yaw);
581         camFront = glm::normalize(front);
582
583         if (pitch < -1.57079632679 || pitch >= 1.57079632679) {
584                 camUp = glm::vec3(0, -1, 0);
585         } else {
586                 camUp = glm::vec3(0, 1, 0);
587         }
588 }
589
590 void mouse(int button, int state, int x, int y) {
591         if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
592                 firstMouse = true;
593 }
594
595 int main(int argc, char** argv) {
596         glutInit(&argc, argv);
597         glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGB|GLUT_3_2_CORE_PROFILE);
598         glutInitWindowSize(WIDTH, HEIGHT);
599         int win = glutCreateWindow("Hello Triangle");
600         glutDisplayFunc(display);
601
602         glewInit();
603         
604         init();
605
606         glutKeyboardFunc(keyboard);
607         glutKeyboardUpFunc(keyboardUp);
608         glutTimerFunc(16, timer, 0);
609         glutMotionFunc(motion);
610         glutMouseFunc(mouse);
611
612         glutMainLoop();
613
614         return 0;
615 }
616