changed src so the libpg headers are now used
[physics.git] / src / main.cpp
CommitLineData
e68f847b
PG
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
f32a9b7c
PG
18#include <pg/debug.h>
19
ad9f1fb6
PG
20#include <GL/gl.h>
21#include <GL/glu.h>
22#include <SDL/SDL.h>
23
7cbd4505 24#include "handleSignal.h"
f7b3b2eb 25
ad9f1fb6
PG
26#include "game.h"
27#include "ticks.h"
44b079f8
PG
28
29#include "graphics/graphics.h"
f7b3b2eb 30#include "input/inputManager.h"
b1d92c2f 31#include "config/config.h"
ad9f1fb6 32
ad9f1fb6 33/// ***** Private Method Headers *****
617dcc71 34
e2b1ddcd
PG
35static void mainInit();
36static void mainClean();
2a02c4bb 37
e2b1ddcd
PG
38static void updatesInit();
39static void updatesClean();
2a02c4bb 40
e2b1ddcd
PG
41static void drawInit();
42static void drawClean();
ad9f1fb6 43
e2b1ddcd 44static void run();
7cbd4505 45
e2b1ddcd 46static void updateFPSCounters();
ad9f1fb6 47
e2b1ddcd
PG
48static void handleInput();
49static void update(float);
50static void draw();
ad9f1fb6 51
e2b1ddcd
PG
52static int startUpdateThread(void*);
53static int startDrawThread(void*);
2a02c4bb 54
ad9f1fb6
PG
55/// ***** Private Variables *****
56
57// variable used to determine if it is time to shutdown
e2b1ddcd
PG
58static bool s_bIsRunning;
59
60// Minimum possible wait times by used library
61static const int s_iMinWaitMilli = 20;
62static const int s_iMinWaitMicro = s_iMinWaitMilli * 1000;
ad9f1fb6
PG
63
64/* Values for the main game loop
ce53f20f 65 *
e2b1ddcd
PG
66 * s_iTargetUPS := the amount of updates that is wanted in one second
67 * s_fAccUpdateWait := the accumulated wait time for the update sleeps
68 *
69 * s_iUPS := updates per second for the last second
70 * s_iFPS := frames per second for the last second
71 * s_iUpdateCount := counts this seconds updates
72 * s_iDrawCount := counts this seconds draws
73 * s_micLastSecond := stores the time of the last second, used for ups and fps
ad9f1fb6 74 */
e2b1ddcd
PG
75static int s_iTargetUPS = 100;
76static float s_fAccUpdateWait = 0;
ad9f1fb6 77
fa885913
PG
78static int s_iTargetFPS = 100;
79static float s_fAccDrawWait = 0;
80
e2b1ddcd
PG
81static int s_iUPS, s_iFPS;
82static int s_iUpdateCount, s_iDrawCount;
83static MICRO s_micLastSecond;
8baa4b2f 84
e2b1ddcd 85static const float s_fGameStep = 10;
ad9f1fb6 86
e2b1ddcd
PG
87static bool s_bUpdateInitialized = false;
88static bool s_bDrawInitialized = false;
d279b77b 89
617dcc71 90/// ***** MAIN Method *****
3c3c195d 91int main(int argc, char** args)
617dcc71 92{
2a02c4bb 93 mainInit();
617dcc71 94 run();
2a02c4bb 95 mainClean();
e2b1ddcd 96
617dcc71
PG
97 return 0;
98}
99
100/// ***** Initializers/Cleaners *****
101
2a02c4bb 102void mainInit()
ad9f1fb6 103{
7cbd4505
PG
104 installSignal();
105
2a02c4bb
PG
106 debug::init();
107}
2a02c4bb
PG
108void mainClean()
109{
110 debug::clean();
111}
112
113void updatesInit()
114{
e2b1ddcd 115 while(!s_bDrawInitialized)
2a02c4bb 116 SDL_Delay(100);
3c3c195d 117
68b2316d 118 game::init();
5f3520c8 119 DPF(0, "Game initialized");
3c3c195d 120
68b2316d 121 input::init();
5f3520c8 122 DPF(0, "Input initialized");
3c3c195d 123
b1d92c2f 124 cfg::init();
5f3520c8 125 DPF(0, "Configs initialized");
b1d92c2f 126
5f3520c8 127 DPF(0, "Initialization Complete");
2a02c4bb 128
e2b1ddcd 129 s_bUpdateInitialized = true;
ad9f1fb6 130}
2a02c4bb 131void updatesClean()
44b079f8 132{
2a02c4bb 133 DPF(0, "Update Thread Cleaning");
44b079f8 134
b1d92c2f
PG
135 cfg::clean();
136
68b2316d 137 input::clean();
617dcc71 138
68b2316d 139 game::clean();
2a02c4bb
PG
140}
141
142void drawInit()
143{
144 graphics::init();
145 DPF(0, "Graphics initialized");
146
e2b1ddcd 147 s_bDrawInitialized = true;
2a02c4bb 148
e2b1ddcd 149 while(!s_bUpdateInitialized)
2a02c4bb
PG
150 SDL_Delay(100);
151}
2a02c4bb
PG
152void drawClean()
153{
154 DPF(0, "Draw Thread Cleaning");
44b079f8 155
68b2316d 156 graphics::clean();
44b079f8
PG
157}
158
617dcc71
PG
159/// ***** Private Methods *****
160
ad9f1fb6
PG
161void run()
162{
e2b1ddcd 163 s_bIsRunning = true;
d279b77b 164
e2b1ddcd
PG
165 SDL_Thread* s_pUpdatesThread = SDL_CreateThread(startUpdateThread, NULL);
166 SDL_Thread* s_pDrawThread = SDL_CreateThread(startDrawThread, NULL);
d279b77b 167
e2b1ddcd
PG
168 SDL_WaitThread(s_pUpdatesThread, NULL);
169 SDL_WaitThread(s_pDrawThread, NULL);
ad9f1fb6
PG
170}
171
172void updateFPSCounters()
173{
174 // Check if a second has passed to recalculate UPS and FPS
e2b1ddcd 175 if (tickCountMicro() - s_micLastSecond >= 1000000)
ad9f1fb6 176 {
e2b1ddcd
PG
177 s_iUPS = s_iUpdateCount;
178 s_iFPS = s_iDrawCount;
ce53f20f
PG
179
180 // NOT thread safe, but they're estimates anyways
e2b1ddcd
PG
181 s_iUpdateCount -= s_iUPS;
182 s_iDrawCount -= s_iFPS;
ad9f1fb6 183
e2b1ddcd 184 s_micLastSecond = tickCountMicro();
44b079f8 185
c46074c1
PG
186 if(cfg::showFPS())
187 {
e2b1ddcd 188 cout << "fps:\t" << s_iFPS << endl;
c46074c1
PG
189 }
190 if(cfg::showUPS())
191 {
e2b1ddcd 192 cout << "ups:\t" << s_iUPS << endl;
c46074c1 193 }
ad9f1fb6
PG
194 }
195}
196
68b2316d 197void handleInput()
ad9f1fb6 198{
ce53f20f 199 input::update();
f7b3b2eb 200
2b8199e7 201 cfg::handleInput();
ce53f20f 202 game::handleInput();
ad9f1fb6 203
ce53f20f 204 if(cfg::endGame())
e2b1ddcd 205 s_bIsRunning = false;
ad9f1fb6
PG
206}
207
e2b1ddcd 208void update(float fTimeStep)
ad9f1fb6 209{
e2b1ddcd
PG
210 game::update(fTimeStep);
211 s_iUpdateCount++;
ad9f1fb6
PG
212}
213
214void draw()
215{
ce53f20f 216 game::draw();
d279b77b 217
4a0863f3
PG
218 SDL_PumpEvents(); // has to be on the Draw thread for the Windows API
219
ce53f20f
PG
220 SDL_GL_SwapBuffers();
221
222 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ad9f1fb6 223
e2b1ddcd 224 s_iDrawCount++;
ce53f20f 225}
d279b77b 226
ce53f20f
PG
227int startUpdateThread(void*)
228{
2a02c4bb
PG
229 updatesInit();
230
e2b1ddcd 231 s_micLastSecond = tickCountMicro();
8baa4b2f 232
e2b1ddcd 233 while(s_bIsRunning)
ce53f20f 234 {
8baa4b2f
PG
235 MICRO time = tickCountMicro();
236 handleInput();
e2b1ddcd 237 update(s_fGameStep);
8baa4b2f
PG
238
239 updateFPSCounters();
240 time = tickCountMicro() - time;
d279b77b 241
e2b1ddcd
PG
242 float wait = (1000000.0 / s_iTargetUPS - time);
243 s_fAccUpdateWait += 0 < wait ? wait : 0;
d279b77b 244
e2b1ddcd 245 if(s_iMinWaitMicro < s_fAccUpdateWait)
8baa4b2f 246 {
fa885913 247 int iWaits = (int)(s_fAccUpdateWait / s_iMinWaitMicro);
e2b1ddcd
PG
248 s_fAccUpdateWait -= iWaits * s_iMinWaitMicro;
249 SDL_Delay(iWaits * s_iMinWaitMilli);
8baa4b2f 250 }
ce53f20f 251 }
ad9f1fb6 252
2a02c4bb
PG
253 updatesClean();
254
ce53f20f
PG
255 return 0;
256}
ad9f1fb6 257
ce53f20f
PG
258int startDrawThread(void*)
259{
2a02c4bb
PG
260 drawInit();
261
e2b1ddcd 262 while(s_bIsRunning)
ce53f20f 263 {
fa885913
PG
264 MICRO time = tickCountMicro();
265 draw();
266 time = tickCountMicro() - time;
267
268 float wait = (1000000.0 / s_iTargetFPS - time);
269 s_fAccDrawWait += 0 < wait ? wait : 0;
270
271 if(s_iMinWaitMicro < s_fAccDrawWait)
272 {
273 int iWaits = (int)(s_fAccDrawWait / s_iMinWaitMicro);
274 s_fAccDrawWait -= iWaits * s_iMinWaitMicro;
275 SDL_Delay(iWaits * s_iMinWaitMilli);
276 }
ce53f20f 277 }
25d84412 278
2a02c4bb
PG
279 drawClean();
280
ce53f20f 281 return 0;
ad9f1fb6 282}