]> git.localhorst.tv Git - blank.git/blob - src/app/app.cpp
move init out of Application class
[blank.git] / src / app / app.cpp
1 #include "Application.hpp"
2 #include "Assets.hpp"
3 #include "FrameCounter.hpp"
4
5 #include "init.hpp"
6 #include "../audio/Sound.hpp"
7 #include "../graphics/Font.hpp"
8 #include "../world/BlockType.hpp"
9 #include "../world/Entity.hpp"
10
11 #include <iostream>
12 #include <stdexcept>
13
14 using std::string;
15
16
17 namespace {
18
19 string get_asset_path() {
20         char *base = SDL_GetBasePath();
21         string assets(base);
22         assets += "assets/";
23         SDL_free(base);
24         return assets;
25 }
26
27 }
28
29 namespace blank {
30
31 Application::Application(Window &win, const Config &config)
32 : window(win)
33 , viewport()
34 , assets(get_asset_path())
35 , audio()
36 , counter()
37 , world(config.world)
38 , interface(config.interface, assets, audio, counter, world)
39 , test_controller(MakeTestEntity(world))
40 , running(false) {
41         viewport.VSync(config.vsync);
42 }
43
44 Application::~Application() {
45         audio.StopAll();
46 }
47
48 Entity &Application::MakeTestEntity(World &world) {
49         Entity &e = world.AddEntity();
50         e.Name("test");
51         e.Position({ 0.0f, 0.0f, 0.0f });
52         e.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
53         e.WorldCollidable(true);
54         e.SetShape(world.BlockTypes()[1].shape, { 1.0f, 1.0f, 0.0f });
55         e.AngularVelocity(glm::quat(glm::vec3{ 0.00001f, 0.000006f, 0.000013f }));
56         return e;
57 }
58
59
60 void Application::RunN(size_t n) {
61         Uint32 last = SDL_GetTicks();
62         for (size_t i = 0; i < n; ++i) {
63                 Uint32 now = SDL_GetTicks();
64                 int delta = now - last;
65                 Loop(delta);
66                 last = now;
67         }
68 }
69
70 void Application::RunT(size_t t) {
71         Uint32 last = SDL_GetTicks();
72         Uint32 finish = last + t;
73         while (last < finish) {
74                 Uint32 now = SDL_GetTicks();
75                 int delta = now - last;
76                 Loop(delta);
77                 last = now;
78         }
79 }
80
81 void Application::RunS(size_t n, size_t t) {
82         for (size_t i = 0; i < n; ++i) {
83                 Loop(t);
84         }
85 }
86
87
88 void Application::Run() {
89         running = true;
90         Uint32 last = SDL_GetTicks();
91         window.GrabMouse();
92         while (running) {
93                 Uint32 now = SDL_GetTicks();
94                 int delta = now - last;
95                 Loop(delta);
96                 last = now;
97         }
98 }
99
100 void Application::Loop(int dt) {
101         counter.EnterFrame();
102         HandleEvents();
103         Update(dt);
104         Render();
105         counter.ExitFrame();
106 }
107
108
109 void Application::HandleEvents() {
110         counter.EnterHandle();
111         SDL_Event event;
112         while (SDL_PollEvent(&event)) {
113                 switch (event.type) {
114                         case SDL_KEYDOWN:
115                                 interface.HandlePress(event.key);
116                                 break;
117                         case SDL_KEYUP:
118                                 interface.HandleRelease(event.key);
119                                 break;
120                         case SDL_MOUSEBUTTONDOWN:
121                                 interface.HandlePress(event.button);
122                                 break;
123                         case SDL_MOUSEBUTTONUP:
124                                 interface.HandleRelease(event.button);
125                                 break;
126                         case SDL_MOUSEMOTION:
127                                 interface.Handle(event.motion);
128                                 break;
129                         case SDL_MOUSEWHEEL:
130                                 interface.Handle(event.wheel);
131                                 break;
132                         case SDL_QUIT:
133                                 running = false;
134                                 break;
135                         case SDL_WINDOWEVENT:
136                                 Handle(event.window);
137                                 break;
138                         default:
139                                 break;
140                 }
141         }
142         counter.ExitHandle();
143 }
144
145 void Application::Handle(const SDL_WindowEvent &event) {
146         switch (event.event) {
147                 case SDL_WINDOWEVENT_FOCUS_GAINED:
148                         window.GrabMouse();
149                         break;
150                 case SDL_WINDOWEVENT_FOCUS_LOST:
151                         window.ReleaseMouse();
152                         break;
153                 case SDL_WINDOWEVENT_RESIZED:
154                         viewport.Resize(event.data1, event.data2);
155                         break;
156                 default:
157                         break;
158         }
159 }
160
161 void Application::Update(int dt) {
162         counter.EnterUpdate();
163         interface.Update(dt);
164         test_controller.Update(dt);
165         world.Update(dt);
166
167         glm::mat4 trans = world.Player().Transform(Chunk::Pos(0, 0, 0));
168         glm::vec3 dir(trans * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));
169         glm::vec3 up(trans * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f));
170         audio.Position(world.Player().Position());
171         audio.Velocity(world.Player().Velocity());
172         audio.Orientation(dir, up);
173
174         counter.ExitUpdate();
175 }
176
177 void Application::Render() {
178         // gl implementation may (and will probably) delay vsync blocking until
179         // the first write after flipping, which is this clear call
180         viewport.Clear();
181         counter.EnterRender();
182
183         world.Render(viewport);
184         interface.Render(viewport);
185
186         counter.ExitRender();
187         window.Flip();
188 }
189
190
191 Assets::Assets(const string &base)
192 : fonts(base + "fonts/")
193 , sounds(base + "sounds/") {
194
195 }
196
197 Font Assets::LoadFont(const string &name, int size) const {
198         string full = fonts + name + ".ttf";
199         return Font(full.c_str(), size);
200 }
201
202 Sound Assets::LoadSound(const string &name) const {
203         string full = sounds + name + ".wav";
204         return Sound(full.c_str());
205 }
206
207
208 void FrameCounter::EnterFrame() noexcept {
209         last_enter = SDL_GetTicks();
210         last_tick = last_enter;
211 }
212
213 void FrameCounter::EnterHandle() noexcept {
214         Tick();
215 }
216
217 void FrameCounter::ExitHandle() noexcept {
218         current.handle = Tick();
219 }
220
221 void FrameCounter::EnterUpdate() noexcept {
222         Tick();
223 }
224
225 void FrameCounter::ExitUpdate() noexcept {
226         current.update = Tick();
227 }
228
229 void FrameCounter::EnterRender() noexcept {
230         Tick();
231 }
232
233 void FrameCounter::ExitRender() noexcept {
234         current.render = Tick();
235 }
236
237 void FrameCounter::ExitFrame() noexcept {
238         Uint32 now = SDL_GetTicks();
239         current.total = now - last_enter;
240         current.running = current.handle + current.update + current.render;
241         current.waiting = current.total - current.running;
242         Accumulate();
243
244         ++cur_frame;
245         if (cur_frame >= NUM_FRAMES) {
246                 Push();
247                 cur_frame = 0;
248                 changed = true;
249         } else {
250                 changed = false;
251         }
252 }
253
254 int FrameCounter::Tick() noexcept {
255         Uint32 now = SDL_GetTicks();
256         int delta = now - last_tick;
257         last_tick = now;
258         return delta;
259 }
260
261 void FrameCounter::Accumulate() noexcept {
262         sum.handle += current.handle;
263         sum.update += current.update;
264         sum.render += current.render;
265         sum.running += current.running;
266         sum.waiting += current.waiting;
267         sum.total += current.total;
268
269         max.handle = std::max(current.handle, max.handle);
270         max.update = std::max(current.update, max.update);
271         max.render = std::max(current.render, max.render);
272         max.running = std::max(current.running, max.running);
273         max.waiting = std::max(current.waiting, max.waiting);
274         max.total = std::max(current.total, max.total);
275
276         current = Frame<int>();
277 }
278
279 void FrameCounter::Push() noexcept {
280         peak = max;
281         avg.handle = sum.handle * factor;
282         avg.update = sum.update * factor;
283         avg.render = sum.render * factor;
284         avg.running = sum.running * factor;
285         avg.waiting = sum.waiting * factor;
286         avg.total = sum.total * factor;
287
288         sum = Frame<int>();
289         max = Frame<int>();
290 }
291
292 }