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