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