refactored main
[physics.git] / src / main.cpp
... / ...
CommitLineData
1/*
2 * Copyright (C) 2008 Patrik Gornicz, Gornicz_P (at) hotmail (dot) com.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <GL/gl.h>
19#include <GL/glu.h>
20#include <SDL/SDL.h>
21
22#include "debug.h"
23#include "handleSignal.h"
24
25#include "game.h"
26#include "ticks.h"
27
28#include "graphics/graphics.h"
29#include "input/inputManager.h"
30#include "config/config.h"
31
32/// ***** Private Method Headers *****
33
34static void mainInit();
35static void mainClean();
36
37static void updatesInit();
38static void updatesClean();
39
40static void drawInit();
41static void drawClean();
42
43static void run();
44
45static void updateFPSCounters();
46
47static void handleInput();
48static void update(float);
49static void draw();
50
51static int startUpdateThread(void*);
52static int startDrawThread(void*);
53
54/// ***** Private Variables *****
55
56// variable used to determine if it is time to shutdown
57static bool s_bIsRunning;
58
59// Minimum possible wait times by used library
60static const int s_iMinWaitMilli = 20;
61static const int s_iMinWaitMicro = s_iMinWaitMilli * 1000;
62
63/* Values for the main game loop
64 *
65 * s_iTargetUPS := the amount of updates that is wanted in one second
66 * s_fAccUpdateWait := the accumulated wait time for the update sleeps
67 *
68 * s_iUPS := updates per second for the last second
69 * s_iFPS := frames per second for the last second
70 * s_iUpdateCount := counts this seconds updates
71 * s_iDrawCount := counts this seconds draws
72 * s_micLastSecond := stores the time of the last second, used for ups and fps
73 */
74static int s_iTargetUPS = 100;
75static float s_fAccUpdateWait = 0;
76
77static int s_iUPS, s_iFPS;
78static int s_iUpdateCount, s_iDrawCount;
79static MICRO s_micLastSecond;
80
81static const float s_fGameStep = 10;
82
83static bool s_bUpdateInitialized = false;
84static bool s_bDrawInitialized = false;
85
86/// ***** MAIN Method *****
87int main(int argc, char** args)
88{
89 mainInit();
90 run();
91 mainClean();
92
93 return 0;
94}
95
96/// ***** Initializers/Cleaners *****
97
98void mainInit()
99{
100 installSignal();
101
102 debug::init();
103}
104void mainClean()
105{
106 debug::clean();
107}
108
109void updatesInit()
110{
111 while(!s_bDrawInitialized)
112 SDL_Delay(100);
113
114 game::init();
115 DPF(0, "Game initialized");
116
117 input::init();
118 DPF(0, "Input initialized");
119
120 cfg::init();
121 DPF(0, "Configs initialized");
122
123 DPF(0, "Initialization Complete");
124
125 s_bUpdateInitialized = true;
126}
127void updatesClean()
128{
129 DPF(0, "Update Thread Cleaning");
130
131 cfg::clean();
132
133 input::clean();
134
135 game::clean();
136}
137
138void drawInit()
139{
140 graphics::init();
141 DPF(0, "Graphics initialized");
142
143 s_bDrawInitialized = true;
144
145 while(!s_bUpdateInitialized)
146 SDL_Delay(100);
147}
148void drawClean()
149{
150 DPF(0, "Draw Thread Cleaning");
151
152 graphics::clean();
153}
154
155/// ***** Private Methods *****
156
157void run()
158{
159 s_bIsRunning = true;
160
161 SDL_Thread* s_pUpdatesThread = SDL_CreateThread(startUpdateThread, NULL);
162 SDL_Thread* s_pDrawThread = SDL_CreateThread(startDrawThread, NULL);
163
164 SDL_WaitThread(s_pUpdatesThread, NULL);
165 SDL_WaitThread(s_pDrawThread, NULL);
166}
167
168void updateFPSCounters()
169{
170 // Check if a second has passed to recalculate UPS and FPS
171 if (tickCountMicro() - s_micLastSecond >= 1000000)
172 {
173 s_iUPS = s_iUpdateCount;
174 s_iFPS = s_iDrawCount;
175
176 // NOT thread safe, but they're estimates anyways
177 s_iUpdateCount -= s_iUPS;
178 s_iDrawCount -= s_iFPS;
179
180 s_micLastSecond = tickCountMicro();
181
182 if(cfg::showFPS())
183 {
184 cout << "fps:\t" << s_iFPS << endl;
185 }
186 if(cfg::showUPS())
187 {
188 cout << "ups:\t" << s_iUPS << endl;
189 }
190 }
191}
192
193void handleInput()
194{
195 input::update();
196
197 cfg::handleInput();
198 game::handleInput();
199
200 if(cfg::endGame())
201 s_bIsRunning = false;
202}
203
204void update(float fTimeStep)
205{
206 game::update(fTimeStep);
207 s_iUpdateCount++;
208}
209
210void draw()
211{
212 game::draw();
213
214 SDL_PumpEvents(); // has to be on the Draw thread for the Windows API
215
216 SDL_GL_SwapBuffers();
217
218 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
219
220 s_iDrawCount++;
221}
222
223int startUpdateThread(void*)
224{
225 updatesInit();
226
227 s_micLastSecond = tickCountMicro();
228
229 while(s_bIsRunning)
230 {
231 MICRO time = tickCountMicro();
232 handleInput();
233 update(s_fGameStep);
234
235 updateFPSCounters();
236 time = tickCountMicro() - time;
237
238 float wait = (1000000.0 / s_iTargetUPS - time);
239 s_fAccUpdateWait += 0 < wait ? wait : 0;
240
241 if(s_iMinWaitMicro < s_fAccUpdateWait)
242 {
243 int iWaits = s_fAccUpdateWait / s_iMinWaitMicro;
244 s_fAccUpdateWait -= iWaits * s_iMinWaitMicro;
245 SDL_Delay(iWaits * s_iMinWaitMilli);
246 }
247 }
248
249 updatesClean();
250
251 return 0;
252}
253
254int startDrawThread(void*)
255{
256 drawInit();
257
258 while(s_bIsRunning)
259 {
260 draw();
261 }
262
263 drawClean();
264
265 return 0;
266}