Add belly to triangle
[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
18 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
19
20 using namespace std;
21
22 GLuint pyramidVao, lightVao;
23 GLuint gradientProgId, solidProgId;
24 glm::vec3 camPos   = glm::vec3(0.0f, 0.0f,  -5.0f);
25 glm::vec3 camFront = glm::vec3(0.0f, 0.0f, 1.0f);
26 glm::vec3 camUp    = glm::vec3(0.0f, 1.0f,  0.0f);
27 float yaw = 1.57, pitch = 0;
28 bool doScale, doRotate, doTranslate;
29
30 void setProjectionAndViewUniforms(GLuint progId) {
31         GLuint projId = glGetUniformLocation(progId, "projection");
32         glm::mat4 proj = glm::perspective(glm::radians(45.f), 1.33f, 0.01f, 10000.f);
33         glUniformMatrix4fv(projId, 1, GL_FALSE, glm::value_ptr(proj));
34
35         GLuint viewId = glGetUniformLocation(progId, "view");
36         glm::mat4 view = glm::lookAt(camPos, camPos + camFront, camUp);
37         glUniformMatrix4fv(viewId, 1, GL_FALSE, glm::value_ptr(view));
38 }
39
40 void drawLight(float d, glm::vec3 lightPos) {
41         glUseProgram(solidProgId);
42         glBindVertexArray(lightVao);
43         setProjectionAndViewUniforms(solidProgId);
44         glm::mat4 model = glm::translate(glm::mat4(1.f), lightPos);
45         model = glm::scale(model, glm::vec3(0.2));
46         GLuint modelId = glGetUniformLocation(solidProgId, "model");
47         glUniformMatrix4fv(modelId, 1, GL_FALSE, glm::value_ptr(model));
48
49         GLuint colorLoc = glGetUniformLocation(solidProgId, "color");
50         glm::vec3 color = glm::vec3(1, 1, 1);
51         glUniform3fv(colorLoc, 1, glm::value_ptr(color));
52                 
53         glDrawArrays(GL_TRIANGLES, 0, 36);
54 };
55
56 void drawPyramids(float d, glm::vec3 lightPos) {
57         glUseProgram(gradientProgId);
58         glBindVertexArray(pyramidVao);
59         setProjectionAndViewUniforms(gradientProgId);
60
61         GLuint lightPosLoc = glGetUniformLocation(gradientProgId, "lightPos");
62         glUniform3fv(lightPosLoc, 1, glm::value_ptr(lightPos));
63         
64         GLuint viewPosLoc = glGetUniformLocation(gradientProgId, "viewPos");
65         glUniform3fv(viewPosLoc, 1, glm::value_ptr(camPos));
66
67         GLuint modelId = glGetUniformLocation(gradientProgId, "model");
68
69         for (int i = 0; i < 10; i++) {
70
71                 glm::mat4 model = glm::mat4(1.f);
72
73                 model = glm::translate(model, glm::vec3(sin(i * 30) * 10, 0, i * 2 - 10));
74                 
75                 if (doRotate) {
76                         model = glm::rotate(model, d * glm::radians(30.f), glm::vec3(0.f, 1.f, 0.f));
77                         model = glm::rotate(model, d * glm::radians(20.f), glm::vec3(1.f, 0.f, 0.f));
78                 }
79                 
80                 if (doScale)
81                         model = glm::scale(model, glm::vec3(1.f, 0.7f + 0.7f * (1 + sin(d + (i + 3))), 1.f));
82
83                 if (doTranslate)
84                         model = glm::translate(model, glm::vec3(sin(d + (i + 1)), cos(d + (i + -3)), sin(d + (i + 4))));
85         
86
87                 glUniformMatrix4fv(modelId, 1, GL_FALSE, glm::value_ptr(model));
88                 
89                 glDrawArrays(GL_TRIANGLES, 0, 18);
90         }
91
92 };
93
94 void display() {
95         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
96         float d = (float)glutGet(GLUT_ELAPSED_TIME) * 0.001f;
97
98         glm::vec3 lightPos = glm::vec3(sin(d) * 10, 0, cos(d) * 10);
99
100         drawPyramids(d, lightPos);
101         drawLight(d, lightPos);
102
103         glutSwapBuffers();
104 }
105
106 void attachShader(GLuint progId, const char* filePath, GLenum type) {
107         GLuint shader = glCreateShader(type);
108
109         if (!shader) {
110                 fprintf(stderr, "error creating shader\n");
111                 exit(1);
112         }
113
114         ifstream file(filePath);
115         stringstream buffer;
116         buffer << file.rdbuf();
117         string str = buffer.str();
118         const char* contents = str.c_str();
119
120         glShaderSource(shader, 1, (const GLchar**)&contents, NULL);
121         glCompileShader(shader);
122         GLint success;
123         glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
124         if (!success) {
125                 GLchar log[1024];
126                 glGetShaderInfoLog(shader, 1024, NULL, log);
127                 fprintf(stderr, "error: %s\n", log);
128                 exit(1);
129         }
130         glAttachShader(progId, shader);
131 }
132
133 GLuint compileShaders(char* vertexShader, char* fragmentShader) {
134         GLuint progId = glCreateProgram();
135
136         attachShader(progId, vertexShader, GL_VERTEX_SHADER);
137         attachShader(progId, fragmentShader, GL_FRAGMENT_SHADER);
138
139         glLinkProgram(progId);
140         GLint success = 0;
141         glGetProgramiv(progId, GL_LINK_STATUS, &success);
142         if (!success) {
143                 GLchar log[1024];
144                 glGetProgramInfoLog(progId, sizeof(log), NULL, log);
145                 fprintf(stderr, "error linking: %s\n", log);
146                 exit(1);
147         }
148
149         return progId;
150 }
151
152 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
153
154 GLuint setupBuffers(glm::vec3* vertices, glm::vec3* normals, GLuint progId) {
155
156         GLfloat colors[] = {
157                 0, 1, 0, 1,
158                 1, 0, 0, 1,
159                 0, 0, 1, 1,
160
161                 0, 1, 0, 1,
162                 1, 0, 0, 1,
163                 0, 0, 1, 1,
164
165                 0, 1, 0, 1,
166                 1, 0, 0, 1,
167                 0, 0, 1, 1,
168
169                 0, 1, 0, 1,
170                 1, 0, 0, 1,
171                 0, 0, 1, 1,
172
173                 0, 1, 0, 1,
174                 1, 0, 0, 1,
175                 0, 0, 1, 1,
176                 
177                 0, 1, 0, 1,
178                 1, 0, 0, 1,
179                 0, 0, 1, 1
180         };
181
182         GLuint numVerts = 18;
183
184         GLuint vbo;
185         glGenBuffers(1, &vbo);
186
187         GLuint vao;
188         glGenVertexArrays(1, &vao);
189
190         GLuint posId = glGetAttribLocation(progId, "vPosition");
191         GLuint colorId = glGetAttribLocation(progId, "vColor");
192         GLuint normalLoc = glGetAttribLocation(progId, "vNormal");
193
194         GLuint vertsLen = numVerts * 3 * sizeof(GLfloat);
195         GLuint colorsLen = numVerts * 4 * sizeof(GLfloat);
196         GLuint normalLen = numVerts * 3 * sizeof(GLfloat);
197
198         glBindBuffer(GL_ARRAY_BUFFER, vbo);
199         glBufferData(GL_ARRAY_BUFFER, vertsLen + colorsLen + normalLen, NULL, GL_STATIC_DRAW);
200
201         glBufferSubData(GL_ARRAY_BUFFER, 0, vertsLen, glm::value_ptr(vertices[0]));
202         glBufferSubData(GL_ARRAY_BUFFER, vertsLen, colorsLen, colors);
203         glBufferSubData(GL_ARRAY_BUFFER, vertsLen + colorsLen, normalLen, glm::value_ptr(normals[0]));
204         
205         glBindVertexArray(vao);
206
207         glEnableVertexAttribArray(posId);
208         glVertexAttribPointer(posId, 3, GL_FLOAT, GL_FALSE, 0, 0);
209
210         glEnableVertexAttribArray(colorId);
211         glVertexAttribPointer(colorId, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(vertsLen));
212
213         glEnableVertexAttribArray(normalLoc);
214         glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(vertsLen + colorsLen));
215
216         return vao;
217 }
218
219 vector<glm::vec3> quadToTriangles(glm::vec3 *quads) {
220         vector<glm::vec3> triangles(6);
221         triangles[0] = quads[0];
222         triangles[1] = quads[1];
223         triangles[2] = quads[2];
224         triangles[3] = quads[2];
225         triangles[4] = quads[3];
226         triangles[5] = quads[0];
227         return triangles;
228 }
229
230 template <typename T>
231 void append(vector<T> &a, vector<T> &b) {
232         a.insert(a.end(), b.begin(), b.end());
233 };
234
235 void setupLightBuffers(GLuint progId) {
236         vector<glm::vec3> vertices;
237         glm::vec3 front[] = {
238                 glm::vec3(1, -1, -1),
239                 glm::vec3(-1, -1, -1),
240                 glm::vec3(-1, 1, -1),
241                 glm::vec3(1, 1, -1)
242         };
243         vector<glm::vec3> frontTriangles = quadToTriangles(front);
244         append(vertices, frontTriangles);
245
246         glm::vec3 back[] = {
247                 glm::vec3(1, 1, 1),
248                 glm::vec3(-1, 1, 1),
249                 glm::vec3(-1, -1, 1),
250                 glm::vec3(1, -1, 1)
251         };
252         vector<glm::vec3> backQuads = quadToTriangles(back);
253         append(vertices, backQuads);
254
255         glm::vec3 top[] = {
256                 glm::vec3(1, 1, -1),
257                 glm::vec3(-1, 1, -1),
258                 glm::vec3(-1, 1, 1),
259                 glm::vec3(1, 1, 1)
260         };
261         vector<glm::vec3> topTriangles = quadToTriangles(top);
262         append(vertices, topTriangles);
263
264         glm::vec3 bottom[] = {
265                 glm::vec3(1, -1, 1),
266                 glm::vec3(-1, -1, 1),
267                 glm::vec3(-1, -1, -1),
268                 glm::vec3(1, -1, -1)
269         };
270         vector<glm::vec3> bottomTriangles = quadToTriangles(bottom);
271         append(vertices, bottomTriangles);
272
273         glm::vec3 left[] = {
274                 glm::vec3(-1, 1, 1),
275                 glm::vec3(-1, 1, -1),
276                 glm::vec3(-1, -1, -1),
277                 glm::vec3(-1, -1, 1)
278         };
279         vector<glm::vec3> leftTriangles = quadToTriangles(left);
280         append(vertices, leftTriangles);
281
282         glm::vec3 right[] = {
283                 glm::vec3(1, 1, -1),
284                 glm::vec3(1, 1, 1),
285                 glm::vec3(1, -1, 1),
286                 glm::vec3(1, -1, -1)
287         };
288         vector<glm::vec3> rightTriangles = quadToTriangles(right);
289         append(vertices, rightTriangles);
290         GLuint verticesSize = 36 * 3 * sizeof(GLfloat);
291
292         glGenVertexArrays(1, &lightVao);
293         GLuint vbo;
294         glBindVertexArray(lightVao);
295         glGenBuffers(1, &vbo);
296         glBindBuffer(GL_ARRAY_BUFFER, vbo);
297         glBufferData(GL_ARRAY_BUFFER, verticesSize, NULL, GL_STATIC_DRAW);
298         glBufferSubData(GL_ARRAY_BUFFER, 0, verticesSize, glm::value_ptr(vertices[0]));
299         GLuint posLoc = glGetAttribLocation(progId, "vPosition");
300         glEnableVertexAttribArray(posLoc);
301         glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
302 }
303
304 void validateProgram(GLuint progId) {
305         glValidateProgram(progId);
306         
307         GLint success;
308         glGetProgramiv(progId, GL_VALIDATE_STATUS, &success);
309         if (!success) {
310                 GLchar log[1024];
311                 glGetProgramInfoLog(progId, sizeof(log), NULL, log);
312                 fprintf(stderr, "error: %s\n", log);
313                 exit(1);
314         }
315 }
316
317 void init() {
318         glm::vec3 vertices[18] = {
319                 glm::vec3(0.0f, 1.0f, 0.0f),
320                 glm::vec3(1.0f, -1.0f, -1.0f),
321                 glm::vec3(-1.0f, -1.0f, -1.0f),
322
323                 glm::vec3(0.0f, 1.0f, 0.0f),
324                 glm::vec3(-1.0f, -1.0f, 1.0f),
325                 glm::vec3(1.0f, -1.0f, 1.0f),
326
327                 glm::vec3(0.0f, 1.0f, 0.0f),
328                 glm::vec3(-1.0f, -1.0f, -1.0f),
329                 glm::vec3(-1.0f, -1.0f, 1.0f),
330
331                 glm::vec3(0.0f, 1.0f, 0.0f),
332                 glm::vec3(1.0f, -1.0f, 1.0f),
333                 glm::vec3(1.0f, -1.0f, -1.0f),
334
335                 glm::vec3(1, -1, 1),
336                 glm::vec3(-1, -1, 1),
337                 glm::vec3(-1, -1, -1),
338                 glm::vec3(-1, -1, -1),
339                 glm::vec3(1, -1, -1),
340                 glm::vec3(1, -1, 1)
341         };
342
343         // work out the normals
344         glm::vec3 normals[18];
345         for (int i = 0; i < 6; i++) {
346                 glm::vec3 a = vertices[i * 3];
347                 glm::vec3 b = vertices[i * 3 + 1];
348                 glm::vec3 c = vertices[i * 3 + 2];
349                 glm::vec3 u = glm::normalize(a - c);
350                 glm::vec3 v = glm::normalize(b - c);
351                 glm::vec3 norm = glm::normalize(glm::cross(v, u));
352                 for(int j = 0; j < 3; j++) {
353                         normals[i * 3 + j] = glm::vec3(norm);
354                 }
355         }
356
357         gradientProgId = compileShaders((char*)"vertex.glsl", (char*)"fragment.glsl");
358         glUseProgram(gradientProgId);
359         pyramidVao = setupBuffers(vertices, normals, gradientProgId);
360         validateProgram(gradientProgId);
361
362         solidProgId = compileShaders((char*)"solidvertex.glsl", (char*)"solidfrag.glsl");
363         glUseProgram(solidProgId);
364         setupLightBuffers(solidProgId);
365         validateProgram(solidProgId);
366
367         glEnable(GL_DEPTH_TEST); 
368         glEnable(GL_CULL_FACE); 
369 }
370
371 bool* keyStates = new bool[256];
372
373 void keyboard(unsigned char key, int x, int y) {
374         keyStates[key] = true;
375         if (key == 'z')
376                 doScale = !doScale;
377         if (key == 'x')
378                 doRotate = !doRotate;
379         if (key == 'c')
380                 doTranslate = !doTranslate;
381 }
382
383 void keyboardUp(unsigned char key, int x, int y) {
384         keyStates[key] = false;
385 }
386
387 void timer(int _) {
388         float xSpeed = 0.f, ySpeed = 0.f, zSpeed = 0.f;
389         if (keyStates['w'])
390                 zSpeed = 0.1f;
391         if (keyStates['s'])
392                 zSpeed = -0.1f;
393         if (keyStates['a'])
394                 xSpeed = 0.1f;
395         if (keyStates['d'])
396                 xSpeed = -0.1f;
397         if (keyStates['q'])
398                 ySpeed = 0.1f;
399         if (keyStates['e'])
400                 ySpeed = -0.1f;
401
402         camPos.x += xSpeed * sin(yaw) + zSpeed * cos(yaw);
403         camPos.y += ySpeed;
404         camPos.z += zSpeed * sin(yaw) - xSpeed * cos(yaw);
405         glutPostRedisplay();
406         glutTimerFunc(16, timer, 0);
407 }
408
409 int prevMouseX, prevMouseY;
410 bool firstMouse = true;
411
412 void motion(int x, int y) {
413         if (firstMouse) {
414                 prevMouseX = x;
415                 prevMouseY = y;
416                 firstMouse = false;
417         }
418         int dx = x - prevMouseX, dy = y - prevMouseY;
419
420         prevMouseX = x;
421         prevMouseY = y;
422
423         const float sensitivity = 0.005f;
424         yaw += dx * sensitivity;
425         pitch -= dy * sensitivity;
426
427         glm::vec3 front;
428         front.x = cos(pitch) * cos(yaw);
429         front.y = sin(pitch);
430         front.z = cos(pitch) * sin(yaw);
431         camFront = glm::normalize(front);
432 }
433
434 void mouse(int button, int state, int x, int y) {
435         if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
436                 firstMouse = true;
437 }
438
439 int main(int argc, char** argv) {
440         glutInit(&argc, argv);
441         glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGB|GLUT_3_2_CORE_PROFILE);
442         glutInitWindowSize(800, 600);
443         int win = glutCreateWindow("Hello Triangle");
444         glutDisplayFunc(display);
445
446         glewInit();
447         
448         init();
449
450         glutKeyboardFunc(keyboard);
451         glutKeyboardUpFunc(keyboardUp);
452         glutTimerFunc(16, timer, 0);
453         glutMotionFunc(motion);
454         glutMouseFunc(mouse);
455
456         glutMainLoop();
457
458         return 0;
459 }
460