update thread setup with a good cap
[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 init();
35
36 void sighandler( int sig );
37
38 void run();
39 void clean();
40
41 void updateFPSCounters();
42
43 void handleInput();
44 void update(float);
45 void draw();
46
47 /// ***** Private Variables *****
48
49 // variable used to determine if it is time to shutdown
50 bool is_Running;
51
52 /* Values for the main game loop
53  * target_UPS := the amount of updates that is wanted in one second
54  *
55  * ups := updates per second for the last second
56  * fps := frames per second for the last second
57  * update_Count := counts this seconds updates
58  * draw_Count  := counts this seconds draws
59  * last_Second := stores the time of the last second, used for ups and fps
60  */
61 int target_UPS = 100;
62 float update_Wait = 0;
63
64 int ups, fps;
65 int update_Count, draw_Count;
66 MICRO last_Second;
67
68 const int min_wait_milli = 20;
69 const int min_wait_micro = min_wait_milli * 1000;
70 const float game_step    = 10;
71
72 int startUpdateThread(void*);
73 int startDrawThread(void*);
74
75 /// ***** MAIN Method *****
76 int main(int argc, char** args)
77 {
78     init();
79     run();
80     clean();
81     return 0;
82 }
83
84 /// ***** Initializers/Cleaners *****
85
86 void init()
87 {
88     installSignal();
89
90     graphics::init();
91     DPF(0, "Graphics initialized");
92
93     game::init();
94     DPF(0, "Game initialized");
95
96     input::init();
97     DPF(0, "Input initialized");
98
99     cfg::init();
100     DPF(0, "Configs initialized");
101
102     DPF(0, "Initialization Complete");
103 }
104
105 void clean()
106 {
107     DPF(0, "Cleaning up");
108
109     cfg::clean();
110
111     input::clean();
112
113     game::clean();
114
115     graphics::clean();
116 }
117
118 /// ***** Private Methods *****
119
120 void run()
121 {
122     is_Running = true;
123
124     SDL_Thread* updates = SDL_CreateThread(startUpdateThread, NULL);
125
126     // for some reason this needs to be on the main thread ...?
127     startDrawThread(NULL);
128
129     SDL_WaitThread(updates, NULL);
130 }
131
132 void updateFPSCounters()
133 {
134     // Check if a second has passed to recalculate UPS and FPS
135     if (tickCountMicro() - last_Second >= 1000000)
136     {
137         ups = update_Count;
138         fps = draw_Count;
139
140         // NOT thread safe, but they're estimates anyways
141         update_Count -= ups;
142         draw_Count -= fps;
143
144         last_Second = tickCountMicro();
145
146 #ifdef FPSUPS
147         cout << "ups:\t" << ups << endl;
148         cout << "fps:\t" << fps << endl;
149 #endif
150     }
151 }
152
153 void handleInput()
154 {
155     input::update();
156
157     game::handleInput();
158
159     if(cfg::endGame())
160         is_Running = false;
161 }
162
163 void update(float time_step)
164 {
165     game::update(time_step);
166     update_Count++;
167 }
168
169 void draw()
170 {
171     game::draw();
172
173     SDL_GL_SwapBuffers();
174
175     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
176
177     draw_Count++;
178 }
179
180 int startUpdateThread(void*)
181 {
182     last_Second = tickCountMicro();
183
184     while(is_Running)
185     {
186         MICRO time = tickCountMicro();
187             handleInput();
188             update(game_step);
189
190             updateFPSCounters();
191         time = tickCountMicro() - time;
192
193         float wait = (1000000.0 / target_UPS - time);
194         update_Wait += 0 < wait ? wait : 0;
195
196         while(min_wait_micro < update_Wait)
197         {
198             update_Wait -= min_wait_micro;
199             SDL_Delay(min_wait_milli);
200         }
201     }
202
203     return 0;
204 }
205
206 int startDrawThread(void*)
207 {
208     while(is_Running)
209     {
210         draw();
211     }
212
213     return 0;
214 }