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