]> git.localhorst.tv Git - l2e.git/blob - src/app/Application.cpp
90ed2882e2e75b013f1246aae873c29897a2bf81
[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 , inStateChage(false) {
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.empty() ? 0 : states.top();
32 }
33
34 void Application::UpdateState() {
35         inStateChage = true;
36         while (!stateChanges.empty()) {
37                 switch (stateChanges.front().type) {
38                         case StateCommand::PUSH:
39                                 RealPushState(stateChanges.front().state);
40                                 break;
41                         case StateCommand::POP:
42                                 RealPopState();
43                                 break;
44                         case StateCommand::CHANGE:
45                                 RealChangeState(stateChanges.front().state);
46                                 break;
47                 }
48                 stateChanges.pop();
49         }
50         inStateChage = false;
51 }
52
53 void Application::ChangeState(State *s) {
54         if (inStateChage) {
55                 RealChangeState(s);
56         } else {
57                 StateCommand cmd;
58                 cmd.type = StateCommand::CHANGE;
59                 cmd.state = s;
60                 stateChanges.push(cmd);
61         }
62 }
63
64 void Application::PushState(State *s) {
65         if (inStateChage) {
66                 RealPushState(s);
67         } else {
68                 StateCommand cmd;
69                 cmd.type = StateCommand::PUSH;
70                 cmd.state = s;
71                 stateChanges.push(cmd);
72         }
73 }
74
75 void Application::PopState() {
76         if (inStateChage) {
77                 RealPopState();
78         } else {
79                 StateCommand cmd;
80                 cmd.type = StateCommand::POP;
81                 cmd.state = 0;
82                 stateChanges.push(cmd);
83         }
84 }
85
86 void Application::RealChangeState(State *s) {
87         if (!states.empty()) {
88                 states.top()->PauseState(screen.Screen());
89                 states.top()->ExitState(*this, screen.Screen());
90                 states.pop();
91         }
92         states.push(s);
93         s->EnterState(*this, screen.Screen());
94         s->ResumeState(screen.Screen());
95 }
96
97 void Application::RealPushState(State *s) {
98         if (!states.empty()) {
99                 states.top()->PauseState(screen.Screen());
100         }
101         states.push(s);
102         s->EnterState(*this, screen.Screen());
103         s->ResumeState(screen.Screen());
104 }
105
106 void Application::RealPopState() {
107         if (states.empty()) return;
108         states.top()->PauseState(screen.Screen());
109         states.top()->ExitState(*this, screen.Screen());
110         delete states.top();
111         states.pop();
112         if (!states.empty()) {
113                 states.top()->ResumeState(screen.Screen());
114         }
115 }
116
117 void Application::Quit() {
118         PopAllStates();
119 }
120
121 void Application::PopAllStates() {
122         while (!states.empty()) {
123                 states.top()->PauseState(screen.Screen());
124                 states.top()->ExitState(*this, screen.Screen());
125                 delete states.top();
126                 states.pop();
127         }
128 }
129
130
131 void Application::Run() {
132         while (CurrentState()) {
133                 Loop();
134         }
135 }
136
137 void Application::Loop() {
138         Uint32 now(SDL_GetTicks());
139         Uint32 deltaT(now - last);
140         GlobalTimers().Update(deltaT);
141         if (deltaT > 30) deltaT = 30;
142
143         if (CurrentState()) {
144                 CurrentState()->GraphicsTimers().Update(deltaT);
145         }
146         HandleEvents();
147         if (!StateChangePending()) {
148                 UpdateWorld(deltaT);
149                 Render();
150         }
151
152         last = now;
153         UpdateState();
154 }
155
156
157 void Application::HandleEvents() {
158         if (!CurrentState()) return;
159         input.ResetInteractiveState();
160         SDL_Event event;
161         while (SDL_PollEvent(&event)) {
162                 switch (event.type) {
163                         case SDL_QUIT:
164                                 PopAllStates();
165                                 break;
166                         case SDL_VIDEORESIZE:
167                                 screen.Resize(event.resize.w, event.resize.h);
168                                 CurrentState()->Resize(event.resize.w, event.resize.h);
169                                 break;
170                         case SDL_KEYDOWN:
171                         case SDL_KEYUP:
172                                 input.HandleKeyboardEvent(event.key);
173                                 break;
174                         default:
175                                 // skip event
176                                 break;
177                 }
178         }
179         if (CurrentState()) CurrentState()->HandleEvents(input);
180 }
181
182 void Application::UpdateWorld(Uint32 deltaT) {
183         if (!CurrentState()) return;
184         for (Uint32 i(0); i < deltaT && !StateChangePending(); ++i) {
185                 CurrentState()->PhysicsTimers().Update(0.001f);
186                 CurrentState()->UpdateWorld(0.001f);
187         }
188 }
189
190 void Application::Render(void) {
191         if (!CurrentState()) return;
192         CurrentState()->Render(screen.Screen());
193         screen.Flip();
194 }
195
196 }