]> git.localhorst.tv Git - blank.git/blob - src/app.cpp
5a5d6fba176376ab1052cec778afe9dd90c242e2
[blank.git] / src / app.cpp
1 #include "app.hpp"
2
3 #include "geometry.hpp"
4
5 #include <iostream>
6 #include <stdexcept>
7
8
9 namespace blank {
10
11 Application::Application()
12 : init_sdl()
13 , init_img()
14 , init_gl()
15 , window()
16 , ctx(window.CreateContext())
17 , init_glew()
18 , program()
19 , move_velocity(0.003f)
20 , pitch_sensitivity(-0.0025f)
21 , yaw_sensitivity(-0.001f)
22 , blockType()
23 , cam()
24 , chunk()
25 , outline()
26 , outline_visible(false)
27 , outline_transform(1.0f)
28 , light_position(17.0f, 17.0f, 17.0f)
29 , light_color(1.0f, 1.0f, 1.0f)
30 , light_power(250.0f)
31 , m_handle(0)
32 , v_handle(0)
33 , mv_handle(0)
34 , mvp_handle(0)
35 , light_position_handle(0)
36 , light_color_handle(0)
37 , light_power_handle(0)
38 , running(false)
39 , front(false)
40 , back(false)
41 , left(false)
42 , right(false)
43 , up(false)
44 , down(false) {
45         GLContext::EnableVSync();
46         GLContext::EnableDepthTest();
47         GLContext::EnableBackfaceCulling();
48         program.LoadShader(
49                 GL_VERTEX_SHADER,
50                 "#version 330 core\n"
51                 "layout(location = 0) in vec3 vtx_position;\n"
52                 "layout(location = 1) in vec3 vtx_color;\n"
53                 "layout(location = 2) in vec3 vtx_normal;\n"
54                 "uniform mat4 M;\n"
55                 "uniform mat4 V;\n"
56                 "uniform mat4 MVP;\n"
57                 "uniform vec3 light_position;\n"
58                 "out vec3 frag_color;\n"
59                 "out vec3 vtx_world;\n"
60                 "out vec3 normal;\n"
61                 "out vec3 eye;\n"
62                 "out vec3 light_direction;\n"
63                 "void main() {\n"
64                         "vec4 v = vec4(vtx_position, 1);\n"
65                         "gl_Position = MVP * v;\n"
66                         "vtx_world = (M * v).xyz;\n"
67                         "vec3 vtx_camera = (V * M * v).xyz;\n"
68                         "eye = vec3(0, 0, 0) - vtx_camera;\n"
69                         "vec3 light_camera = (V * v).xyz;\n"
70                         "light_direction = light_position + eye;\n"
71                         "normal = (V * M * vec4(vtx_normal, 0)).xyz;\n"
72                         "frag_color = vtx_color;\n"
73                 "}\n"
74         );
75         program.LoadShader(
76                 GL_FRAGMENT_SHADER,
77                 "#version 330 core\n"
78                 "in vec3 frag_color;\n"
79                 "in vec3 vtx_world;\n"
80                 "in vec3 normal;\n"
81                 "in vec3 eye;\n"
82                 "in vec3 light_direction;\n"
83                 "uniform mat4 MV;\n"
84                 "uniform vec3 light_position;\n"
85                 "uniform vec3 light_color;\n"
86                 "uniform float light_power;\n"
87                 "out vec3 color;\n"
88                 "void main() {\n"
89                         "vec3 ambient = vec3(0.1, 0.1, 0.1) * frag_color;\n"
90                         "vec3 specular = vec3(0.3, 0.3, 0.3);\n"
91                         "float distance = length(light_position - vtx_world);\n"
92                         "vec3 n = normalize(normal);\n"
93                         "vec3 l = normalize(light_direction);\n"
94                         "float cos_theta = clamp(dot(n, l), 0, 1);\n"
95                         "vec3 E = normalize(eye);\n"
96                         "vec3 R = reflect(-l, n);\n"
97                         "float cos_alpha = clamp(dot(E, R), 0, 1);\n"
98                         "color = ambient"
99                                 " + frag_color * light_color * light_power * cos_theta / (distance * distance)"
100                                 " + specular * light_color * light_power * pow(cos_alpha, 5) / (distance * distance);\n"
101                 "}\n"
102         );
103         program.Link();
104         if (!program.Linked()) {
105                 program.Log(std::cerr);
106                 throw std::runtime_error("link program");
107         }
108
109         GLuint VertexArrayID;
110         glGenVertexArrays(1, &VertexArrayID);
111         glBindVertexArray(VertexArrayID);
112
113         cam.Position(glm::vec3(0, 4, 4));
114
115         blockType.Add(BlockType(true, glm::vec3(1, 1, 1)));
116         blockType.Add(BlockType(true, glm::vec3(1, 0, 0)));
117         blockType.Add(BlockType(true, glm::vec3(0, 1, 0)));
118         blockType.Add(BlockType(true, glm::vec3(0, 0, 1)));
119
120         chunk.BlockAt(glm::vec3(0, 0, 0)) = Block(blockType[4]);
121         chunk.BlockAt(glm::vec3(0, 0, 1)) = Block(blockType[1]);
122         chunk.BlockAt(glm::vec3(1, 0, 0)) = Block(blockType[2]);
123         chunk.BlockAt(glm::vec3(1, 0, 1)) = Block(blockType[3]);
124         chunk.BlockAt(glm::vec3(2, 0, 0)) = Block(blockType[4]);
125         chunk.BlockAt(glm::vec3(2, 0, 1)) = Block(blockType[1]);
126         chunk.BlockAt(glm::vec3(3, 0, 0)) = Block(blockType[2]);
127         chunk.BlockAt(glm::vec3(3, 0, 1)) = Block(blockType[3]);
128         chunk.BlockAt(glm::vec3(2, 0, 2)) = Block(blockType[4]);
129         chunk.BlockAt(glm::vec3(2, 0, 3)) = Block(blockType[1]);
130         chunk.BlockAt(glm::vec3(3, 0, 2)) = Block(blockType[2]);
131         chunk.BlockAt(glm::vec3(3, 0, 3)) = Block(blockType[3]);
132         chunk.BlockAt(glm::vec3(1, 1, 0)) = Block(blockType[1]);
133         chunk.BlockAt(glm::vec3(1, 1, 1)) = Block(blockType[4]);
134         chunk.BlockAt(glm::vec3(2, 1, 1)) = Block(blockType[3]);
135         chunk.BlockAt(glm::vec3(2, 2, 1)) = Block(blockType[2]);
136         chunk.Invalidate();
137
138         outline.vertices = std::vector<glm::vec3>({
139                 { 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f },
140                 { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 0.0f },
141                 { 1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f },
142                 { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 0.0f },
143                 { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f },
144                 { 1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 1.0f },
145                 { 1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f },
146                 { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 1.0f },
147                 { 0.0f, 0.0f, 1.0f }, { 1.0f, 0.0f, 1.0f },
148                 { 1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f },
149                 { 1.0f, 1.0f, 1.0f }, { 0.0f, 1.0f, 1.0f },
150                 { 0.0f, 1.0f, 1.0f }, { 0.0f, 0.0f, 1.0f },
151         });
152         outline.colors.resize(24, { -1, -1, -1 });
153         outline.Invalidate();
154
155         m_handle = program.UniformLocation("M");
156         v_handle = program.UniformLocation("V");
157         mv_handle = program.UniformLocation("MV");
158         mvp_handle = program.UniformLocation("MVP");
159         light_position_handle = program.UniformLocation("light_position");
160         light_color_handle = program.UniformLocation("light_color");
161         light_power_handle = program.UniformLocation("light_power");
162
163         glClearColor(0.0, 0.0, 0.0, 1.0);
164 }
165
166
167 void Application::Run() {
168         running = true;
169         Uint32 last = SDL_GetTicks();
170         window.GrabMouse();
171         while (running) {
172                 Uint32 now = SDL_GetTicks();
173                 int delta = now - last;
174                 Loop(delta);
175                 last = now;
176         }
177 }
178
179 void Application::Loop(int dt) {
180         HandleEvents();
181         Update(dt);
182         Render();
183 }
184
185
186 void Application::HandleEvents() {
187         SDL_Event event;
188         while (SDL_PollEvent(&event)) {
189                 switch (event.type) {
190                         case SDL_KEYDOWN:
191                         case SDL_KEYUP:
192                                 switch (event.key.keysym.sym) {
193                                         case SDLK_w:
194                                                 front = event.key.state == SDL_PRESSED;
195                                                 break;
196                                         case SDLK_s:
197                                                 back = event.key.state == SDL_PRESSED;
198                                                 break;
199                                         case SDLK_a:
200                                                 left = event.key.state == SDL_PRESSED;
201                                                 break;
202                                         case SDLK_d:
203                                                 right = event.key.state == SDL_PRESSED;
204                                                 break;
205                                         case SDLK_q:
206                                                 up = event.key.state == SDL_PRESSED;
207                                                 break;
208                                         case SDLK_e:
209                                                 down = event.key.state == SDL_PRESSED;
210                                                 break;
211                                 }
212                                 break;
213                         case SDL_MOUSEMOTION:
214                                 cam.RotateYaw(event.motion.xrel * yaw_sensitivity);
215                                 cam.RotatePitch(event.motion.yrel * pitch_sensitivity);
216                                 break;
217                         case SDL_QUIT:
218                                 running = false;
219                                 break;
220                         case SDL_WINDOWEVENT:
221                                 switch (event.window.event) {
222                                         case SDL_WINDOWEVENT_RESIZED:
223                                                 cam.Viewport(event.window.data1, event.window.data2);
224                                                 break;
225                                         default:
226                                                 break;
227                                 }
228                                 break;
229                         default:
230                                 break;
231                 }
232         }
233 }
234
235 void Application::Update(int dt) {
236         glm::vec3 vel;
237         if (right && !left) {
238                 vel.x = move_velocity;
239         } else if (left && !right) {
240                 vel.x = -move_velocity;
241         }
242         if (up && !down) {
243                 vel.y = move_velocity;
244         } else if (down && !up) {
245                 vel.y = -move_velocity;
246         }
247         if (back && !front) {
248                 vel.z = move_velocity;
249         } else if (front && !back) {
250                 vel.z = -move_velocity;
251         }
252         cam.OrientationVelocity(vel);
253
254         cam.Update(dt);
255
256         Ray aim = cam.Aim();
257         int blkid;
258         float dist;
259         if (chunk.Intersection(aim, glm::mat4(1.0f), &blkid, &dist)) {
260                 glm::vec3 pos = Chunk::ToCoords(blkid);
261                 outline_visible = true;
262                 outline_transform = glm::translate(glm::mat4(1.0f), pos);
263         } else {
264                 outline_visible = false;
265         }
266 }
267
268 void Application::Render() {
269         GLContext::Clear();
270
271         program.Use();
272
273         glm::mat4 m(1.0f);
274         glm::mat4 mv(cam.View() * m);
275         glm::mat4 mvp(cam.MakeMVP(m));
276         glUniformMatrix4fv(m_handle, 1, GL_FALSE, &m[0][0]);
277         glUniformMatrix4fv(v_handle, 1, GL_FALSE, &cam.View()[0][0]);
278         glUniformMatrix4fv(mv_handle, 1, GL_FALSE, &mv[0][0]);
279         glUniformMatrix4fv(mvp_handle, 1, GL_FALSE, &mvp[0][0]);
280         glUniform3f(light_position_handle, light_position.x, light_position.y, light_position.z);
281         glUniform3f(light_color_handle, light_color.x, light_color.y, light_color.z);
282         glUniform1f(light_power_handle, light_power);
283
284         chunk.Draw();
285         if (outline_visible) {
286                 mv = cam.View() * outline_transform;
287                 mvp = cam.MakeMVP(outline_transform);
288                 glUniformMatrix4fv(m_handle, 1, GL_FALSE, &m[0][0]);
289                 glUniformMatrix4fv(mv_handle, 1, GL_FALSE, &mv[0][0]);
290                 glUniformMatrix4fv(mvp_handle, 1, GL_FALSE, &mvp[0][0]);
291                 outline.Draw();
292         }
293
294         window.Flip();
295 }
296
297 }