]> git.localhorst.tv Git - l2e.git/blob - src/app/Application.cpp
fixed popping all states on application exit
[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.empty() ? 0 : 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                 states.top()->PauseState(*this, screen->Screen());
110                 states.top()->ExitState(*this, screen->Screen());
111                 delete states.top();
112                 states.pop();
113         }
114 }
115
116
117 void Application::Run() {
118         while (CurrentState()) {
119                 Loop();
120         }
121 }
122
123 void Application::Loop() {
124         Uint32 now(SDL_GetTicks());
125         Uint32 deltaT(now - last);
126         GlobalTimers().Update(deltaT);
127         if (deltaT > 30) deltaT = 30;
128
129         if (CurrentState()) {
130                 CurrentState()->GraphicsTimers().Update(deltaT);
131         }
132         HandleEvents();
133         if (!StateChangePending()) {
134                 UpdateWorld(deltaT);
135                 Render();
136         }
137
138         last = now;
139         UpdateState();
140 }
141
142
143 void Application::HandleEvents() {
144         if (!CurrentState()) return;
145         input.ResetInteractiveState();
146         SDL_Event event;
147         while (SDL_PollEvent(&event)) {
148                 switch (event.type) {
149                         case SDL_QUIT:
150                                 PopAllStates();
151                                 break;
152                         case SDL_VIDEORESIZE:
153                                 screen->Resize(event.resize.w, event.resize.h);
154                                 CurrentState()->Resize(event.resize.w, event.resize.h);
155                                 break;
156                         case SDL_KEYDOWN:
157                         case SDL_KEYUP:
158                                 input.HandleKeyboardEvent(event.key);
159                                 break;
160                         default:
161                                 // skip event
162                                 break;
163                 }
164         }
165         if (CurrentState()) CurrentState()->HandleEvents(input);
166 }
167
168 void Application::UpdateWorld(Uint32 deltaT) {
169         if (!CurrentState()) return;
170         for (Uint32 i(0); i < deltaT; ++i) {
171                 CurrentState()->PhysicsTimers().Update(0.001f);
172                 CurrentState()->UpdateWorld(0.001f);
173         }
174 }
175
176 void Application::Render(void) {
177         if (!CurrentState()) return;
178         CurrentState()->Render(screen->Screen());
179         screen->Flip();
180 }
181
182 }