]> git.localhorst.tv Git - blank.git/blob - src/app/app.cpp
reorganize basic rendering functionality
[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                         interface.Resize(viewport);
149                         break;
150                 default:
151                         break;
152         }
153 }
154
155 void Application::Update(int dt) {
156         counter.EnterUpdate();
157         interface.Update(dt);
158         test_controller.Update(dt);
159         world.Update(dt);
160         counter.ExitUpdate();
161 }
162
163 void Application::Render() {
164         // gl implementation may (and will probably) delay vsync blocking until
165         // the first write after flipping, which is this clear call
166         viewport.Clear();
167         counter.EnterRender();
168
169         world.Render(viewport);
170         interface.Render(viewport);
171
172         counter.ExitRender();
173         init.window.Flip();
174 }
175
176
177 Assets::Assets(const string &base)
178 : fonts(base + "fonts/") {
179
180 }
181
182 Font Assets::LoadFont(const string &name, int size) const {
183         string full = fonts + name + ".ttf";
184         return Font(full.c_str(), size);
185 }
186
187
188 void FrameCounter::EnterFrame() noexcept {
189         last_enter = SDL_GetTicks();
190         last_tick = last_enter;
191 }
192
193 void FrameCounter::EnterHandle() noexcept {
194         Tick();
195 }
196
197 void FrameCounter::ExitHandle() noexcept {
198         running.handle += Tick();
199 }
200
201 void FrameCounter::EnterUpdate() noexcept {
202         Tick();
203 }
204
205 void FrameCounter::ExitUpdate() noexcept {
206         running.update += Tick();
207 }
208
209 void FrameCounter::EnterRender() noexcept {
210         Tick();
211 }
212
213 void FrameCounter::ExitRender() noexcept {
214         running.render += Tick();
215 }
216
217 void FrameCounter::ExitFrame() noexcept {
218         Uint32 now = SDL_GetTicks();
219         running.total += now - last_enter;
220         ++cur_frame;
221         if (cur_frame >= NUM_FRAMES) {
222                 avg.handle = running.handle * factor;
223                 avg.update = running.update * factor;
224                 avg.render = running.render * factor;
225                 avg.total = running.total * factor;
226                 running = Frame<int>{};
227                 cur_frame = 0;
228                 changed = true;
229         } else {
230                 changed = false;
231         }
232 }
233
234 int FrameCounter::Tick() noexcept {
235         Uint32 now = SDL_GetTicks();
236         int delta = now - last_tick;
237         last_tick = now;
238         return delta;
239 }
240
241 void FrameCounter::Print(std::ostream &out) const {
242         out << "frame:     " << AvgFrame() << std::endl;
243         out << "  handle:  " << AvgHandle() << std::endl;
244         out << "  update:  " << AvgUpdate() << std::endl;
245         out << "  render:  " << AvgRender() << std::endl;
246         out << "  running: " << AvgRunning() << std::endl;
247         out << "  waiting: " << AvgWaiting() << std::endl;
248         out << std::endl;
249 }
250
251 }