]> git.localhorst.tv Git - blank.git/blob - src/app.cpp
8c0793dfc123b4ab0f14bafd806aafc8c118f09e
[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 , cam()
23 , hud()
24 , world()
25 , outline()
26 , outline_visible(false)
27 , outline_transform(1.0f)
28 , running(false)
29 , front(false)
30 , back(false)
31 , left(false)
32 , right(false)
33 , up(false)
34 , down(false)
35 , place(false)
36 , remove(false)
37 , pick(false)
38 , remove_id(0)
39 , place_id(1) {
40         GLContext::EnableVSync();
41
42         GLuint VertexArrayID;
43         glGenVertexArrays(1, &VertexArrayID);
44         glBindVertexArray(VertexArrayID);
45
46         world.Generate();
47
48         cam.Position(glm::vec3(0, 4, 4));
49         hud.Viewport(960, 600);
50         hud.Display(*world.BlockTypes()[place_id]);
51
52         glClearColor(0.0, 0.0, 0.0, 1.0);
53 }
54
55
56 void Application::Run() {
57         running = true;
58         Uint32 last = SDL_GetTicks();
59         window.GrabMouse();
60         while (running) {
61                 Uint32 now = SDL_GetTicks();
62                 int delta = now - last;
63                 Loop(delta);
64                 last = now;
65         }
66 }
67
68 void Application::Loop(int dt) {
69         HandleEvents();
70         Update(dt);
71         Render();
72 }
73
74
75 void Application::HandleEvents() {
76         SDL_Event event;
77         while (SDL_PollEvent(&event)) {
78                 switch (event.type) {
79                         case SDL_KEYDOWN:
80                         case SDL_KEYUP:
81                                 switch (event.key.keysym.sym) {
82                                         case SDLK_w:
83                                                 front = event.key.state == SDL_PRESSED;
84                                                 break;
85                                         case SDLK_s:
86                                                 back = event.key.state == SDL_PRESSED;
87                                                 break;
88                                         case SDLK_a:
89                                                 left = event.key.state == SDL_PRESSED;
90                                                 break;
91                                         case SDLK_d:
92                                                 right = event.key.state == SDL_PRESSED;
93                                                 break;
94                                         case SDLK_q:
95                                         case SDLK_SPACE:
96                                                 up = event.key.state == SDL_PRESSED;
97                                                 break;
98                                         case SDLK_e:
99                                         case SDLK_LSHIFT:
100                                                 down = event.key.state == SDL_PRESSED;
101                                                 break;
102                                 }
103                                 break;
104                         case SDL_MOUSEBUTTONDOWN:
105                                 if (event.button.button == 1) {
106                                         // left
107                                         remove = true;
108                                 } else if (event.button.button == 2) {
109                                         // middle
110                                         pick = true;
111                                 } else if (event.button.button == 3) {
112                                         // right
113                                         place = true;
114                                 }
115                                 break;
116                         case SDL_MOUSEMOTION:
117                                 cam.RotateYaw(event.motion.xrel * yaw_sensitivity);
118                                 cam.RotatePitch(event.motion.yrel * pitch_sensitivity);
119                                 break;
120                         case SDL_QUIT:
121                                 running = false;
122                                 break;
123                         case SDL_WINDOWEVENT:
124                                 switch (event.window.event) {
125                                         case SDL_WINDOWEVENT_RESIZED:
126                                                 cam.Viewport(event.window.data1, event.window.data2);
127                                                 hud.Viewport(event.window.data1, event.window.data2);
128                                                 break;
129                                         default:
130                                                 break;
131                                 }
132                                 break;
133                         default:
134                                 break;
135                 }
136         }
137 }
138
139 void Application::Update(int dt) {
140         glm::vec3 vel;
141         if (right && !left) {
142                 vel.x = move_velocity;
143         } else if (left && !right) {
144                 vel.x = -move_velocity;
145         }
146         if (up && !down) {
147                 vel.y = move_velocity;
148         } else if (down && !up) {
149                 vel.y = -move_velocity;
150         }
151         if (back && !front) {
152                 vel.z = move_velocity;
153         } else if (front && !back) {
154                 vel.z = -move_velocity;
155         }
156         cam.OrientationVelocity(vel);
157
158         cam.Update(dt);
159
160         Ray aim = cam.Aim();
161         Chunk *chunk;
162         int blkid;
163         float dist;
164         glm::vec3 normal;
165         if (world.Intersection(aim, glm::mat4(1.0f), &chunk, &blkid, &dist, &normal)) {
166                 glm::vec3 pos = Chunk::ToCoords(blkid);
167                 outline_visible = true;
168                 outline.Clear();
169                 chunk->BlockAt(blkid).type->FillOutlineModel(outline);
170                 outline_transform = glm::translate(chunk->Transform(), pos);
171                 outline_transform = glm::scale(outline_transform, glm::vec3(1.0001f));
172         } else {
173                 outline_visible = false;
174         }
175
176         if (pick) {
177                 if (chunk) {
178                         place_id = chunk->BlockAt(blkid).type->id;
179                         hud.Display(*world.BlockTypes()[place_id]);
180                 }
181                 pick = false;
182         }
183         if (remove) {
184                 if (chunk) {
185                         chunk->BlockAt(blkid).type = world.BlockTypes()[remove_id];
186                         chunk->Invalidate();
187                 }
188                 remove = false;
189         }
190         if (place) {
191                 if (chunk) {
192                         Chunk *mod_chunk = chunk;
193                         glm::vec3 next_pos = Chunk::ToCoords(blkid) + normal;
194                         if (!Chunk::InBounds(next_pos)) {
195                                 mod_chunk = &world.Next(*chunk, normal);
196                                 next_pos -= normal * Chunk::Extent();
197                         }
198                         mod_chunk->BlockAt(next_pos).type = world.BlockTypes()[place_id];
199                         mod_chunk->Invalidate();
200                 }
201                 place = false;
202         }
203 }
204
205 void Application::Render() {
206         GLContext::Clear();
207
208         program.Activate();
209
210         program.SetLightDirection({ -1.0f, -3.0f, -2.0f });
211         program.SetVP(cam.View(), cam.Projection());
212
213         for (Chunk &chunk : world.LoadedChunks()) {
214                 program.SetM(chunk.Transform());
215                 chunk.Draw();
216         }
217
218         if (outline_visible) {
219                 program.SetM(outline_transform);
220                 outline.Draw();
221         }
222
223         hud.Render(program);
224
225         window.Flip();
226 }
227
228 }