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