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