]> git.localhorst.tv Git - blank.git/blob - src/app.cpp
orientable blocks
[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 , cam()
20 , hud()
21 , world()
22 , controller(world.Player())
23 , outline()
24 , outline_visible(false)
25 , outline_transform(1.0f)
26 , running(false)
27 , place(false)
28 , remove(false)
29 , pick(false)
30 , remove_id(0)
31 , place_id(1) {
32         GLContext::EnableVSync();
33
34         hud.Viewport(960, 600);
35         hud.Display(*world.BlockTypes()[place_id]);
36
37         glClearColor(0.0, 0.0, 0.0, 1.0);
38 }
39
40
41 void Application::RunN(size_t n) {
42         Uint32 last = SDL_GetTicks();
43         for (size_t i = 0; i < n; ++i) {
44                 Uint32 now = SDL_GetTicks();
45                 int delta = now - last;
46                 Loop(delta);
47                 last = now;
48         }
49 }
50
51 void Application::RunT(size_t t) {
52         Uint32 last = SDL_GetTicks();
53         Uint32 finish = last + t;
54         while (last < finish) {
55                 Uint32 now = SDL_GetTicks();
56                 int delta = now - last;
57                 Loop(delta);
58                 last = now;
59         }
60 }
61
62 void Application::RunS(size_t n, size_t t) {
63         for (size_t i = 0; i < n; ++i) {
64                 Loop(t);
65         }
66 }
67
68
69 void Application::Run() {
70         running = true;
71         Uint32 last = SDL_GetTicks();
72         window.GrabMouse();
73         while (running) {
74                 Uint32 now = SDL_GetTicks();
75                 int delta = now - last;
76                 Loop(delta);
77                 last = now;
78         }
79 }
80
81 void Application::Loop(int dt) {
82         HandleEvents();
83         Update(dt);
84         Render();
85 }
86
87
88 void Application::HandleEvents() {
89         SDL_Event event;
90         while (SDL_PollEvent(&event)) {
91                 switch (event.type) {
92                         case SDL_KEYDOWN:
93                         case SDL_KEYUP:
94                                 controller.HandleKeyboard(event.key);
95                                 break;
96                         case SDL_MOUSEBUTTONDOWN:
97                                 if (event.button.button == 1) {
98                                         // left
99                                         remove = true;
100                                 } else if (event.button.button == 2) {
101                                         // middle
102                                         pick = true;
103                                 } else if (event.button.button == 3) {
104                                         // right
105                                         place = true;
106                                 }
107                                 break;
108                         case SDL_MOUSEMOTION:
109                                 controller.HandleMouse(event.motion);
110                                 break;
111                         case SDL_QUIT:
112                                 running = false;
113                                 break;
114                         case SDL_WINDOWEVENT:
115                                 switch (event.window.event) {
116                                         case SDL_WINDOWEVENT_RESIZED:
117                                                 cam.Viewport(event.window.data1, event.window.data2);
118                                                 hud.Viewport(event.window.data1, event.window.data2);
119                                                 break;
120                                         default:
121                                                 break;
122                                 }
123                                 break;
124                         default:
125                                 break;
126                 }
127         }
128 }
129
130 void Application::Update(int dt) {
131         controller.Update(dt);
132         world.Update(dt);
133
134         Ray aim = controller.Aim();
135         Chunk *chunk;
136         int blkid;
137         float dist;
138         glm::vec3 normal;
139         if (world.Intersection(aim, glm::mat4(1.0f), &chunk, &blkid, &dist, &normal)) {
140                 outline_visible = true;
141                 outline.Clear();
142                 chunk->Type(chunk->BlockAt(blkid)).FillOutlineModel(outline);
143                 outline_transform = glm::scale(glm::mat4(1.0f), glm::vec3(1.0002f));
144                 outline_transform = chunk->Transform(world.Player().ChunkCoords());
145                 outline_transform *= chunk->ToTransform(blkid);
146         } else {
147                 outline_visible = false;
148         }
149
150         if (pick) {
151                 if (chunk) {
152                         place_id = chunk->BlockAt(blkid).type;
153                         hud.Display(*world.BlockTypes()[place_id]);
154                 }
155                 pick = false;
156         }
157         if (remove) {
158                 if (chunk) {
159                         chunk->BlockAt(blkid).type = remove_id;
160                         chunk->Invalidate();
161                 }
162                 remove = false;
163         }
164         if (place) {
165                 if (chunk) {
166                         Chunk *mod_chunk = chunk;
167                         glm::vec3 next_pos = Chunk::ToCoords(blkid) + normal;
168                         if (!Chunk::InBounds(next_pos)) {
169                                 mod_chunk = &world.Next(*chunk, normal);
170                                 next_pos -= normal * glm::vec3(Chunk::Extent());
171                         }
172                         mod_chunk->BlockAt(next_pos).type = place_id;
173                         mod_chunk->Invalidate();
174                 }
175                 place = false;
176         }
177 }
178
179 void Application::Render() {
180         GLContext::Clear();
181
182         program.Activate();
183
184         program.SetProjection(cam.Projection());
185         world.Render(program);
186
187         if (outline_visible) {
188                 program.SetM(outline_transform);
189                 outline.Draw();
190         }
191
192         hud.Render(program);
193
194         window.Flip();
195 }
196
197 }