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