1 #include "Application.hpp"
3 #include "Environment.hpp"
4 #include "FrameCounter.hpp"
6 #include "StateControl.hpp"
9 #include "../audio/Sound.hpp"
10 #include "../graphics/ArrayTexture.hpp"
11 #include "../graphics/Font.hpp"
12 #include "../graphics/Texture.hpp"
13 #include "../world/BlockType.hpp"
14 #include "../world/Entity.hpp"
18 #include <SDL_image.h>
25 Application::Application(Environment &e)
31 Application::~Application() {
36 void Application::RunN(size_t n) {
37 Uint32 last = SDL_GetTicks();
38 for (size_t i = 0; HasState() && i < n; ++i) {
39 Uint32 now = SDL_GetTicks();
40 int delta = now - last;
46 void Application::RunT(size_t t) {
47 Uint32 last = SDL_GetTicks();
48 Uint32 finish = last + t;
49 while (HasState() && last < finish) {
50 Uint32 now = SDL_GetTicks();
51 int delta = now - last;
57 void Application::RunS(size_t n, size_t t) {
58 for (size_t i = 0; HasState() && i < n; ++i) {
64 void Application::Run() {
65 Uint32 last = SDL_GetTicks();
66 env.window.GrabMouse();
68 Uint32 now = SDL_GetTicks();
69 int delta = now - last;
75 void Application::Loop(int dt) {
76 env.counter.EnterFrame();
78 if (!HasState()) return;
80 env.state.Commit(*this);
81 if (!HasState()) return;
83 env.counter.ExitFrame();
87 void Application::HandleEvents() {
88 env.counter.EnterHandle();
90 while (HasState() && SDL_PollEvent(&event)) {
92 env.state.Commit(*this);
94 env.counter.ExitHandle();
97 void Application::Handle(const SDL_Event &event) {
102 case SDL_WINDOWEVENT:
103 Handle(event.window);
106 GetState().Handle(event);
111 void Application::Handle(const SDL_WindowEvent &event) {
112 switch (event.event) {
113 case SDL_WINDOWEVENT_FOCUS_GAINED:
114 env.window.GrabMouse();
116 case SDL_WINDOWEVENT_FOCUS_LOST:
117 env.window.ReleaseMouse();
119 case SDL_WINDOWEVENT_RESIZED:
120 env.viewport.Resize(event.data1, event.data2);
127 void Application::Update(int dt) {
128 env.counter.EnterUpdate();
130 GetState().Update(dt);
132 env.counter.ExitUpdate();
135 void Application::Render() {
136 // gl implementation may (and will probably) delay vsync blocking until
137 // the first write after flipping, which is this clear call
138 env.viewport.Clear();
139 env.counter.EnterRender();
142 GetState().Render(env.viewport);
145 env.counter.ExitRender();
150 void Application::PushState(State *s) {
154 State *Application::PopState() {
155 State *s = states.top();
160 State *Application::SwitchState(State *s_new) {
161 State *s_old = states.top();
162 states.top() = s_new;
166 State &Application::GetState() {
167 return *states.top();
170 bool Application::HasState() const noexcept {
171 return !states.empty();
175 void StateControl::Commit(Application &app) {
176 while (!cue.empty()) {
181 app.PushState(m.state);
184 app.SwitchState(m.state);
190 while (app.HasState()) {
199 Assets::Assets(const string &base)
200 : fonts(base + "fonts/")
201 , sounds(base + "sounds/")
202 , textures(base + "textures/") {
206 Font Assets::LoadFont(const string &name, int size) const {
207 string full = fonts + name + ".ttf";
208 return Font(full.c_str(), size);
211 Sound Assets::LoadSound(const string &name) const {
212 string full = sounds + name + ".wav";
213 return Sound(full.c_str());
216 Texture Assets::LoadTexture(const string &name) const {
217 string full = textures + name + ".png";
219 SDL_Surface *srf = IMG_Load(full.c_str());
221 throw SDLError("IMG_Load");
225 SDL_FreeSurface(srf);
229 void Assets::LoadTexture(const string &name, ArrayTexture &tex, int layer) const {
230 string full = textures + name + ".png";
231 SDL_Surface *srf = IMG_Load(full.c_str());
233 throw SDLError("IMG_Load");
237 tex.Data(layer, *srf);
239 SDL_FreeSurface(srf);
242 SDL_FreeSurface(srf);
246 void FrameCounter::EnterFrame() noexcept {
247 last_enter = SDL_GetTicks();
248 last_tick = last_enter;
251 void FrameCounter::EnterHandle() noexcept {
255 void FrameCounter::ExitHandle() noexcept {
256 current.handle = Tick();
259 void FrameCounter::EnterUpdate() noexcept {
263 void FrameCounter::ExitUpdate() noexcept {
264 current.update = Tick();
267 void FrameCounter::EnterRender() noexcept {
271 void FrameCounter::ExitRender() noexcept {
272 current.render = Tick();
275 void FrameCounter::ExitFrame() noexcept {
276 Uint32 now = SDL_GetTicks();
277 current.total = now - last_enter;
278 current.running = current.handle + current.update + current.render;
279 current.waiting = current.total - current.running;
283 if (cur_frame >= NUM_FRAMES) {
292 int FrameCounter::Tick() noexcept {
293 Uint32 now = SDL_GetTicks();
294 int delta = now - last_tick;
299 void FrameCounter::Accumulate() noexcept {
300 sum.handle += current.handle;
301 sum.update += current.update;
302 sum.render += current.render;
303 sum.running += current.running;
304 sum.waiting += current.waiting;
305 sum.total += current.total;
307 max.handle = std::max(current.handle, max.handle);
308 max.update = std::max(current.update, max.update);
309 max.render = std::max(current.render, max.render);
310 max.running = std::max(current.running, max.running);
311 max.waiting = std::max(current.waiting, max.waiting);
312 max.total = std::max(current.total, max.total);
314 current = Frame<int>();
317 void FrameCounter::Push() noexcept {
319 avg.handle = sum.handle * factor;
320 avg.update = sum.update * factor;
321 avg.render = sum.render * factor;
322 avg.running = sum.running * factor;
323 avg.waiting = sum.waiting * factor;
324 avg.total = sum.total * factor;