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