Skybox
[opengl.git] / main.cpp
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <iostream>
4 #include <array>
5 #include <vector>
6 #ifdef __APPLE__
7 #include <GL/glew.h>
8 #else
9 #include <OpenGL/glew.h>
10 #endif
11 #include <GLUT/glut.h>
12 #include "shapes.hpp"
13 #include <glm/glm.hpp>
14 #include <glm/ext.hpp>
15 #include <glm/gtc/type_ptr.hpp>
16 #include "model.hpp"
17 #include "program.hpp"
18 #include "skybox.hpp"
19
20 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
21
22 using namespace std;
23
24 GLuint lightVao;
25
26 Program *textureProg, *plainProg;
27 Skybox *skybox;
28                           
29 glm::vec3 camPos   = glm::vec3(0.0f, 0.0f,  0.0f);
30 glm::vec3 camFront = glm::vec3(0.0f, 0.0f, 1.0f);
31 glm::vec3 camUp    = glm::vec3(0.0f, 1.0f,  0.0f);
32 float yaw = 1.57, pitch = 0;
33 bool doScale, doRotate, doTranslate;
34 Model *chest;
35 glm::vec3 lightPos(0);
36
37 const int WIDTH = 800, HEIGHT = 600;
38 const float ASPECT = (float)WIDTH / (float)HEIGHT;
39
40 glm::mat4 projMat() {
41         return glm::perspective(glm::radians(45.f), ASPECT, 0.01f, 10000.f);
42 }
43
44 glm::mat4 viewMat() {
45         return glm::lookAt(camPos, camPos + camFront, camUp);
46 }
47
48 void setProjectionAndViewUniforms(GLuint progId) {
49         GLuint projLoc = glGetUniformLocation(progId, "projection");
50         glm::mat4 proj = projMat();
51         glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
52
53         GLuint viewLoc = glGetUniformLocation(progId, "view");
54         glm::mat4 view = viewMat();
55         glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
56 }
57
58 void setLightColorAndPos(GLuint progId, glm::vec3 lightPos, glm::vec4 lightColor) {
59         GLuint lightColorLoc = glGetUniformLocation(progId, "lightColor");
60         glUniform4fv(lightColorLoc, 1, glm::value_ptr(lightColor));
61
62         GLuint lightPosLoc = glGetUniformLocation(progId, "vLightPos");
63         glUniform3fv(lightPosLoc, 1, glm::value_ptr(lightPos));
64
65         GLuint viewPosLoc = glGetUniformLocation(progId, "vViewPos");
66         glUniform3fv(viewPosLoc, 1, glm::value_ptr(camPos));
67 }
68
69 void drawLight(float d, glm::vec3 lightPos, glm::vec4 lightColor) {
70         glUseProgram(plainProg->progId);
71         glBindVertexArray(lightVao);
72         setProjectionAndViewUniforms(plainProg->progId);
73         glm::mat4 model = glm::translate(glm::mat4(1.f), lightPos);
74         model = glm::scale(model, glm::vec3(0.2));
75         GLuint modelLoc = glGetUniformLocation(plainProg->progId, "model");
76         glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
77
78         GLuint colorLoc = glGetUniformLocation(plainProg->progId, "color");
79         glm::vec4 color(lightColor);
80         glUniform4fv(colorLoc, 1, glm::value_ptr(color));
81                 
82         glDrawArrays(GL_TRIANGLES, 0, 36);
83 }
84
85
86 void display() {
87         glClearColor(0.5, 0.5, 0.5, 1);
88         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
89         float d = (float)glutGet(GLUT_ELAPSED_TIME) * 0.001f;
90
91         skybox->draw(projMat(), viewMat());
92
93         glm::vec4 lightColor(1, 1, 1, 1);
94
95         drawLight(d, lightPos, lightColor);
96
97         glUseProgram(textureProg->progId);
98         setProjectionAndViewUniforms(textureProg->progId);
99         setLightColorAndPos(textureProg->progId, lightPos, lightColor);
100
101         Model::Node *top = chest->find("top");
102         top->model = glm::translate(glm::mat4(1), glm::vec3(0, 1, -1));
103         top->model = glm::rotate(top->model, sin(d / 2.5f) * 0.5f, glm::vec3(1, 0, 0));
104         top->model = glm::translate(top->model, glm::vec3(0, -1, 1));
105         
106         /* Model::Node *jewels = chest->find("jewels"); */
107         /* jewels->model = glm::scale(glm::mat4(1), glm::vec3((sin(d) + 1.2f) / 2.f)); */
108
109         /* Model::Node *lock = chest->find("lock"); */
110         /* lock->model = glm::translate(glm::mat4(1), glm::vec3(0.22610, 3.36478, -0.75649)); */
111         /* lock->model = glm::rotate(lock->model, (d / 2.5f), glm::vec3(0, 1, 0.4)); */
112         /* lock->model = glm::translate(lock->model, -glm::vec3(0.22610, 3.36478, -0.75649)); */
113
114         /* Model::Node *key = chest->find("key"); */
115         /* key->model = glm::translate(glm::mat4(1), glm::vec3(0, 0, sin(d))); */
116         
117         /* chest->getRoot()->model = glm::translate(glm::mat4(1), lightPos); */
118         chest->draw();
119
120         glutSwapBuffers();
121 }
122
123 void setupLightBuffers(GLuint progId) {
124         auto vertices = cube();
125         GLuint verticesSize = 36 * 3 * sizeof(GLfloat);
126
127         glGenVertexArrays(1, &lightVao);
128         GLuint vbo;
129         glBindVertexArray(lightVao);
130         glGenBuffers(1, &vbo);
131         glBindBuffer(GL_ARRAY_BUFFER, vbo);
132         glBufferData(GL_ARRAY_BUFFER, verticesSize, NULL, GL_STATIC_DRAW);
133         glBufferSubData(GL_ARRAY_BUFFER, 0, verticesSize, glm::value_ptr(vertices[0]));
134         GLuint posLoc = glGetAttribLocation(progId, "vPosition");
135         glEnableVertexAttribArray(posLoc);
136         glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
137 }
138
139 void validateProgram(GLuint progId) {
140         glValidateProgram(progId);
141         
142         GLint success;
143         glGetProgramiv(progId, GL_VALIDATE_STATUS, &success);
144         if (!success) {
145                 GLchar log[1024];
146                 glGetProgramInfoLog(progId, sizeof(log), NULL, log);
147                 fprintf(stderr, "error: %s\n", log);
148                 exit(1);
149         }
150 }
151
152 void init() {
153         plainProg = new Program("plainvertex.glsl", "plainfrag.glsl");
154         glUseProgram(plainProg->progId);
155         setupLightBuffers(plainProg->progId);
156         validateProgram(plainProg->progId);
157
158         textureProg = new Program("texturevertex.glsl", "texturefrag.glsl");
159         glUseProgram(textureProg->progId);
160
161         chest = new Model("models/chest.dae", *textureProg);
162
163         std::vector<std::string> faces = {
164                 "models/skybox/right.jpg",
165                 "models/skybox/left.jpg",
166                 "models/skybox/top.jpg",
167                 "models/skybox/bottom.jpg",
168                 "models/skybox/front.jpg",
169                 "models/skybox/back.jpg"
170         };
171         skybox = new Skybox(faces);
172
173         glEnable(GL_DEPTH_TEST); 
174         glEnable(GL_CULL_FACE); 
175 }
176
177 bool* keyStates = new bool[256];
178
179 void keyboard(unsigned char key, int x, int y) {
180         keyStates[key] = true;
181         if (key == 'z')
182                 doScale = !doScale;
183         if (key == 'x')
184                 doRotate = !doRotate;
185         if (key == 'c')
186                 doTranslate = !doTranslate;
187 }
188
189 void keyboardUp(unsigned char key, int x, int y) {
190         keyStates[key] = false;
191 }
192
193 void timer(int _) {
194         float xSpeed = 0.f, ySpeed = 0.f, zSpeed = 0.f;
195         if (keyStates['w'])
196                 zSpeed = 0.1f;
197         if (keyStates['s'])
198                 zSpeed = -0.1f;
199         if (keyStates['a'])
200                 xSpeed = 0.1f;
201         if (keyStates['d'])
202                 xSpeed = -0.1f;
203         if (keyStates['q'])
204                 ySpeed = 0.1f;
205         if (keyStates['e'])
206                 ySpeed = -0.1f;
207
208         if (keyStates['j']) lightPos.z += 0.1f;
209         if (keyStates['k']) lightPos.z -= 0.1f;
210         if (keyStates['h']) lightPos.x -= 0.1f;
211         if (keyStates['l']) lightPos.x += 0.1f;
212         if (keyStates['m']) lightPos.y -= 0.1f;
213         if (keyStates['n']) lightPos.y += 0.1f;
214
215         camPos.x += xSpeed * sin(yaw) + zSpeed * cos(yaw);
216         camPos.y += ySpeed;
217         camPos.z += zSpeed * sin(yaw) - xSpeed * cos(yaw);
218         glutPostRedisplay();
219         glutTimerFunc(16, timer, 0);
220 }
221
222 int prevMouseX, prevMouseY;
223 bool firstMouse = true;
224
225 void motion(int x, int y) {
226         if (firstMouse) {
227                 prevMouseX = x;
228                 prevMouseY = y;
229                 firstMouse = false;
230         }
231         int dx = x - prevMouseX, dy = y - prevMouseY;
232
233         prevMouseX = x;
234         prevMouseY = y;
235
236         const float sensitivity = 0.005f;
237         yaw += dx * sensitivity;
238         pitch -= dy * sensitivity;
239
240         glm::vec3 front;
241         front.x = cos(pitch) * cos(yaw);
242         front.y = sin(pitch);
243         front.z = cos(pitch) * sin(yaw);
244         camFront = glm::normalize(front);
245
246         if (pitch < -1.57079632679 || pitch >= 1.57079632679) {
247                 camUp = glm::vec3(0, -1, 0);
248         } else {
249                 camUp = glm::vec3(0, 1, 0);
250         }
251 }
252
253 void mouse(int button, int state, int x, int y) {
254         if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
255                 firstMouse = true;
256 }
257
258 int main(int argc, char** argv) {
259         glutInit(&argc, argv);
260         glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGB|GLUT_3_2_CORE_PROFILE);
261         glutInitWindowSize(WIDTH, HEIGHT);
262         int win = glutCreateWindow("Hello Triangle");
263         glutDisplayFunc(display);
264
265         glewInit();
266         
267         init();
268
269         glutKeyboardFunc(keyboard);
270         glutKeyboardUpFunc(keyboardUp);
271         glutTimerFunc(16, timer, 0);
272         glutMotionFunc(motion);
273         glutMouseFunc(mouse);
274
275         glutMainLoop();
276
277         return 0;
278 }
279