0efd7485d9486ad58dd76ff10f2143eb08dafff3
[physics.git] / src / main.cpp
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
34 void mainInit();
35 void mainClean();
36
37 void updatesInit();
38 void updatesClean();
39
40 void drawInit();
41 void drawClean();
42
43 void sighandler( int sig );
44
45 void run();
46 void clean();
47
48 void updateFPSCounters();
49
50 void handleInput();
51 void update(float);
52 void draw();
53
54 int startUpdateThread(void*);
55 int startDrawThread(void*);
56
57 /// ***** Private Variables *****
58
59 // variable used to determine if it is time to shutdown
60 bool is_Running;
61
62 /* Values for the main game loop
63  * target_UPS := the amount of updates that is wanted in one second
64  *
65  * ups := updates per second for the last second
66  * fps := frames per second for the last second
67  * update_Count := counts this seconds updates
68  * draw_Count  := counts this seconds draws
69  * last_Second := stores the time of the last second, used for ups and fps
70  */
71 int target_UPS = 100;
72 float update_Wait = 0;
73
74 int ups, fps;
75 int update_Count, draw_Count;
76 MICRO last_Second;
77
78 const int min_wait_milli = 20;
79 const int min_wait_micro = min_wait_milli * 1000;
80 const float game_step    = 10;
81
82 bool updateInitialized  = false;
83 bool drawInitialized    = false;
84
85 /// ***** MAIN Method *****
86 int main(int argc, char** args)
87 {
88     mainInit();
89     run();
90     mainClean();
91     return 0;
92 }
93
94 /// ***** Initializers/Cleaners *****
95
96 void mainInit()
97 {
98     installSignal();
99
100     debug::init();
101 }
102
103 void mainClean()
104 {
105     debug::clean();
106 }
107
108 void updatesInit()
109 {
110     while(!drawInitialized)
111         SDL_Delay(100);
112
113     game::init();
114     DPF(0, "Game initialized");
115
116     input::init();
117     DPF(0, "Input initialized");
118
119     cfg::init();
120     DPF(0, "Configs initialized");
121
122     DPF(0, "Initialization Complete");
123
124     updateInitialized = true;
125 }
126
127 void updatesClean()
128 {
129     DPF(0, "Update Thread Cleaning");
130
131     cfg::clean();
132
133     input::clean();
134
135     game::clean();
136 }
137
138 void drawInit()
139 {
140     graphics::init();
141     DPF(0, "Graphics initialized");
142
143     drawInitialized = true;
144
145     while(!updateInitialized)
146         SDL_Delay(100);
147 }
148
149 void drawClean()
150 {
151     DPF(0, "Draw Thread Cleaning");
152
153     graphics::clean();
154 }
155
156 /// ***** Private Methods *****
157 SDL_Thread* updatesThread   = NULL;
158 SDL_Thread* drawThread      = NULL;
159
160 void run()
161 {
162     is_Running = true;
163
164     updatesThread   = SDL_CreateThread(startUpdateThread,   NULL);
165     drawThread      = SDL_CreateThread(startDrawThread,     NULL);
166
167     SDL_WaitThread(updatesThread,   NULL);
168     SDL_WaitThread(drawThread,      NULL);
169 }
170
171 void updateFPSCounters()
172 {
173     // Check if a second has passed to recalculate UPS and FPS
174     if (tickCountMicro() - last_Second >= 1000000)
175     {
176         ups = update_Count;
177         fps = draw_Count;
178
179         // NOT thread safe, but they're estimates anyways
180         update_Count -= ups;
181         draw_Count -= fps;
182
183         last_Second = tickCountMicro();
184
185         if(cfg::showFPS())
186         {
187             cout << "fps:\t" << fps << endl;
188         }
189         if(cfg::showUPS())
190         {
191             cout << "ups:\t" << ups << endl;
192         }
193     }
194 }
195
196 void handleInput()
197 {
198     input::update();
199
200     game::handleInput();
201
202     if(cfg::endGame())
203         is_Running = false;
204 }
205
206 void update(float time_step)
207 {
208     game::update(time_step);
209     update_Count++;
210 }
211
212 void draw()
213 {
214     game::draw();
215
216     SDL_PumpEvents(); // has to be on the Draw thread for the Windows API
217
218     SDL_GL_SwapBuffers();
219
220     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
221
222     draw_Count++;
223 }
224
225 int startUpdateThread(void*)
226 {
227     updatesInit();
228
229     last_Second = tickCountMicro();
230
231     while(is_Running)
232     {
233         MICRO time = tickCountMicro();
234             handleInput();
235             update(game_step);
236
237             updateFPSCounters();
238         time = tickCountMicro() - time;
239
240         float wait = (1000000.0 / target_UPS - time);
241         update_Wait += 0 < wait ? wait : 0;
242
243         while(min_wait_micro < update_Wait)
244         {
245             update_Wait -= min_wait_micro;
246             SDL_Delay(min_wait_milli);
247         }
248     }
249
250     updatesClean();
251
252     return 0;
253 }
254
255 int startDrawThread(void*)
256 {
257     drawInit();
258
259     while(is_Running)
260     {
261         draw();
262     }
263
264     drawClean();
265
266     return 0;
267 }