]> git.localhorst.tv Git - blank.git/blob - src/app/app.cpp
collect timing information
[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_sdl()
31 , init_img()
32 , init_ttf()
33 , init_gl(config.doublebuf, config.multisampling)
34 , window()
35 , ctx(window.CreateContext())
36 , init_glew()
37 , assets(get_asset_path())
38 , counter()
39 , chunk_prog()
40 , entity_prog()
41 , sprite_prog()
42 , cam()
43 , world(config.world)
44 , interface(config.interface, assets, world)
45 , test_controller(MakeTestEntity(world))
46 , running(false) {
47         if (config.vsync) {
48                 GLContext::EnableVSync();
49         }
50
51         glClearColor(0.0, 0.0, 0.0, 1.0);
52 }
53
54 Entity &Application::MakeTestEntity(World &world) {
55         Entity &e = world.AddEntity();
56         e.Name("test");
57         e.Position({ 0.0f, 0.0f, 0.0f });
58         e.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
59         e.WorldCollidable(true);
60         e.SetShape(world.BlockTypes()[1].shape, { 1.0f, 1.0f, 0.0f });
61         e.AngularVelocity(glm::quat(glm::vec3{ 0.00001f, 0.000006f, 0.000013f }));
62         return e;
63 }
64
65
66 void Application::RunN(size_t n) {
67         Uint32 last = SDL_GetTicks();
68         for (size_t i = 0; i < n; ++i) {
69                 Uint32 now = SDL_GetTicks();
70                 int delta = now - last;
71                 Loop(delta);
72                 last = now;
73         }
74 }
75
76 void Application::RunT(size_t t) {
77         Uint32 last = SDL_GetTicks();
78         Uint32 finish = last + t;
79         while (last < finish) {
80                 Uint32 now = SDL_GetTicks();
81                 int delta = now - last;
82                 Loop(delta);
83                 last = now;
84         }
85 }
86
87 void Application::RunS(size_t n, size_t t) {
88         for (size_t i = 0; i < n; ++i) {
89                 Loop(t);
90         }
91 }
92
93
94 void Application::Run() {
95         running = true;
96         Uint32 last = SDL_GetTicks();
97         window.GrabMouse();
98         while (running) {
99                 Uint32 now = SDL_GetTicks();
100                 int delta = now - last;
101                 Loop(delta);
102                 last = now;
103         }
104 }
105
106 void Application::Loop(int dt) {
107         counter.EnterFrame();
108         HandleEvents();
109         Update(dt);
110         Render();
111         counter.ExitFrame();
112 }
113
114
115 void Application::HandleEvents() {
116         counter.EnterHandle();
117         SDL_Event event;
118         while (SDL_PollEvent(&event)) {
119                 switch (event.type) {
120                         case SDL_KEYDOWN:
121                                 interface.HandlePress(event.key);
122                                 break;
123                         case SDL_KEYUP:
124                                 interface.HandleRelease(event.key);
125                                 break;
126                         case SDL_MOUSEBUTTONDOWN:
127                                 interface.HandlePress(event.button);
128                                 break;
129                         case SDL_MOUSEBUTTONUP:
130                                 interface.HandleRelease(event.button);
131                                 break;
132                         case SDL_MOUSEMOTION:
133                                 interface.Handle(event.motion);
134                                 break;
135                         case SDL_MOUSEWHEEL:
136                                 interface.Handle(event.wheel);
137                                 break;
138                         case SDL_QUIT:
139                                 running = false;
140                                 break;
141                         case SDL_WINDOWEVENT:
142                                 Handle(event.window);
143                                 break;
144                         default:
145                                 break;
146                 }
147         }
148         counter.ExitHandle();
149 }
150
151 void Application::Handle(const SDL_WindowEvent &event) {
152         switch (event.event) {
153                 case SDL_WINDOWEVENT_FOCUS_GAINED:
154                         window.GrabMouse();
155                         break;
156                 case SDL_WINDOWEVENT_FOCUS_LOST:
157                         window.ReleaseMouse();
158                         break;
159                 case SDL_WINDOWEVENT_RESIZED:
160                         cam.Viewport(event.data1, event.data2);
161                         interface.Handle(event);
162                         break;
163                 default:
164                         interface.Handle(event);
165                         break;
166         }
167 }
168
169 void Application::Update(int dt) {
170         counter.EnterUpdate();
171         interface.Update(dt);
172         test_controller.Update(dt);
173         world.Update(dt);
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         GLContext::Clear();
181         counter.EnterRender();
182
183         chunk_prog.SetProjection(cam.Projection());
184         entity_prog.SetProjection(cam.Projection());
185
186         world.Render(chunk_prog, entity_prog);
187
188         interface.Render(entity_prog, sprite_prog);
189
190         counter.ExitRender();
191         window.Flip();
192 }
193
194
195 Assets::Assets(const string &base)
196 : fonts(base + "fonts/") {
197
198 }
199
200 Font Assets::LoadFont(const string &name, int size) const {
201         string full = fonts + name + ".ttf";
202         return Font(full.c_str(), size);
203 }
204
205
206 void FrameCounter::EnterFrame() noexcept {
207         last_enter = SDL_GetTicks();
208         last_tick = last_enter;
209 }
210
211 void FrameCounter::EnterHandle() noexcept {
212         Tick();
213 }
214
215 void FrameCounter::ExitHandle() noexcept {
216         running.handle += Tick();
217 }
218
219 void FrameCounter::EnterUpdate() noexcept {
220         Tick();
221 }
222
223 void FrameCounter::ExitUpdate() noexcept {
224         running.update += Tick();
225 }
226
227 void FrameCounter::EnterRender() noexcept {
228         Tick();
229 }
230
231 void FrameCounter::ExitRender() noexcept {
232         running.render += Tick();
233 }
234
235 void FrameCounter::ExitFrame() noexcept {
236         Uint32 now = SDL_GetTicks();
237         running.total += now - last_enter;
238         ++cur_frame;
239         if (cur_frame >= NUM_FRAMES) {
240                 avg.handle = running.handle * factor;
241                 avg.update = running.update * factor;
242                 avg.render = running.render * factor;
243                 avg.total = running.total * factor;
244                 running = Frame<int>{};
245                 cur_frame = 0;
246                 changed = true;
247         } else {
248                 changed = false;
249         }
250 }
251
252 int FrameCounter::Tick() noexcept {
253         Uint32 now = SDL_GetTicks();
254         int delta = now - last_tick;
255         last_tick = now;
256         return delta;
257 }
258
259 void FrameCounter::Print(std::ostream &out) const {
260         out << "frame:     " << AvgFrame() << std::endl;
261         out << "  handle:  " << AvgHandle() << std::endl;
262         out << "  update:  " << AvgUpdate() << std::endl;
263         out << "  render:  " << AvgRender() << std::endl;
264         out << "  running: " << AvgRunning() << std::endl;
265         out << "  waiting: " << AvgWaiting() << std::endl;
266         out << std::endl;
267 }
268
269 }