]> git.localhorst.tv Git - l2e.git/blob - src/app/Application.cpp
made application state changes yet a bit safer
[l2e.git] / src / app / Application.cpp
1 /*
2  * Application.cpp
3  *
4  *  Created on: Apr 8, 2012
5  *      Author: holy
6  */
7
8 #include "Application.h"
9
10 #include "State.h"
11
12 #include <cassert>
13
14 namespace app {
15
16 Application::Application(sdl::InitScreen *screen, State *initialState)
17 : screen(screen)
18 , states()
19 , last(SDL_GetTicks()) {
20         assert(screen && "cannot create application without screen");
21         assert(initialState && "cannot create application without initial state");
22         RealPushState(initialState);
23 }
24
25 Application::~Application() {
26         PopAllStates();
27 }
28
29
30 State *Application::CurrentState() {
31         return states.top();
32 }
33
34 void Application::UpdateState() {
35         while (!stateChanges.empty()) {
36                 switch (stateChanges.front().type) {
37                         case StateCommand::PUSH:
38                                 RealPushState(stateChanges.front().state);
39                                 break;
40                         case StateCommand::POP:
41                                 RealPopState();
42                                 break;
43                         case StateCommand::CHANGE:
44                                 RealChangeState(stateChanges.front().state);
45                                 break;
46                 }
47                 stateChanges.pop();
48         }
49 }
50
51 void Application::ChangeState(State *s) {
52         StateCommand cmd;
53         cmd.type = StateCommand::CHANGE;
54         cmd.state = s;
55         stateChanges.push(cmd);
56 }
57
58 void Application::PushState(State *s) {
59         StateCommand cmd;
60         cmd.type = StateCommand::PUSH;
61         cmd.state = s;
62         stateChanges.push(cmd);
63 }
64
65 void Application::PopState() {
66         StateCommand cmd;
67         cmd.type = StateCommand::POP;
68         cmd.state = 0;
69         stateChanges.push(cmd);
70 }
71
72 void Application::RealChangeState(State *s) {
73         if (!states.empty()) {
74                 states.top()->PauseState(*this, screen->Screen());
75                 states.top()->ExitState(*this, screen->Screen());
76                 states.pop();
77         }
78         states.push(s);
79         s->EnterState(*this, screen->Screen());
80         s->ResumeState(*this, screen->Screen());
81 }
82
83 void Application::RealPushState(State *s) {
84         if (!states.empty()) {
85                 states.top()->PauseState(*this, screen->Screen());
86         }
87         states.push(s);
88         s->EnterState(*this, screen->Screen());
89         s->ResumeState(*this, screen->Screen());
90 }
91
92 void Application::RealPopState() {
93         if (states.empty()) return;
94         states.top()->PauseState(*this, screen->Screen());
95         states.top()->ExitState(*this, screen->Screen());
96         delete states.top();
97         states.pop();
98         if (!states.empty()) {
99                 states.top()->ResumeState(*this, screen->Screen());
100         }
101 }
102
103 void Application::Quit() {
104         PopAllStates();
105 }
106
107 void Application::PopAllStates() {
108         while (!states.empty()) {
109                 RealPopState();
110         }
111 }
112
113
114 void Application::Run() {
115         while (CurrentState()) {
116                 Loop();
117         }
118 }
119
120 void Application::Loop() {
121         Uint32 now(SDL_GetTicks());
122         Uint32 deltaT(now - last);
123         if (deltaT > 34) deltaT = 34;
124
125         HandleEvents();
126         if (!StateChangePending()) {
127                 UpdateWorld(deltaT);
128                 Render();
129         }
130
131         last = now;
132         UpdateState();
133 }
134
135
136 void Application::HandleEvents() {
137         if (!CurrentState()) return;
138         input.ResetInteractiveState();
139         SDL_Event event;
140         while (SDL_PollEvent(&event)) {
141                 switch (event.type) {
142                         case SDL_QUIT:
143                                 PopAllStates();
144                                 break;
145                         case SDL_VIDEORESIZE:
146                                 screen->Resize(event.resize.w, event.resize.h);
147                                 CurrentState()->Resize(event.resize.w, event.resize.h);
148                                 break;
149                         case SDL_KEYDOWN:
150                         case SDL_KEYUP:
151                                 input.HandleKeyboardEvent(event.key);
152                                 break;
153                         default:
154                                 // skip event
155                                 break;
156                 }
157         }
158         CurrentState()->HandleInput(input);
159 }
160
161 void Application::UpdateWorld(Uint32 deltaT) {
162         if (!CurrentState()) return;
163         for (Uint32 i(0); i < deltaT; ++i) {
164                 CurrentState()->UpdateWorld(0.001f);
165         }
166 }
167
168 void Application::Render(void) {
169         if (!CurrentState()) return;
170         CurrentState()->Render(screen->Screen());
171         screen->Flip();
172 }
173
174 }