]> icculus.org git repositories - taylor/freespace2.git/blob - src/io/timer.cpp
clean up process_debug_keys() a bit for FS1
[taylor/freespace2.git] / src / io / timer.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Io/Timer.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Include file for timer stuff
16  *
17  * $Log$
18  * Revision 1.7  2002/06/09 04:41:22  relnev
19  * added copyright header
20  *
21  * Revision 1.6  2002/06/05 08:05:29  relnev
22  * stub/warning removal.
23  *
24  * reworked the sound code.
25  *
26  * Revision 1.5  2002/05/29 21:38:20  relnev
27  * fixed?
28  *
29  * Revision 1.4  2002/05/28 21:36:10  relnev
30  * some more timer junk.
31  *
32  * tried to fix software mode.
33  *
34  * Revision 1.3  2002/05/28 17:26:57  theoddone33
35  * Fill in some timer and palette setting stubs.  Still no display
36  *
37  * Revision 1.2  2002/05/07 03:16:46  theoddone33
38  * The Great Newline Fix
39  *
40  * Revision 1.1.1.1  2002/05/03 03:28:09  root
41  * Initial import.
42  *
43  * 
44  * 4     5/26/99 3:19p Dave
45  * Fixed release build errors.
46  * 
47  * 3     5/17/99 6:03p Dave
48  * Added new timing code. Put in code to allow camera speed zooming.
49  * 
50  * 2     10/07/98 10:53a Dave
51  * Initial checkin.
52  * 
53  * 1     10/07/98 10:49a Dave
54  * 
55  * 14    4/13/98 10:16a John
56  * Switched gettime back to timer_get_milliseconds, which is now thread
57  * safe.
58  * 
59  * 13    4/13/98 10:11a John
60  * Made timer functions thread safe.  Made timer_init be called in all
61  * projects.
62  * 
63  * 12    4/13/98 8:09a John
64  * Made timer_get functions thread safe.
65  * 
66  * 11    12/02/97 3:56p John
67  * fixed a bug with timestamp_until, created one with it rolling over.
68  * 
69  * 10    9/11/97 7:12p Hoffoss
70  * Added more functionality to training sexp handling code.
71  * 
72  * 9     8/29/97 4:49p Allender
73  * added mprintf to check for wrap problems with timestamp ticker
74  * 
75  * 8     8/28/97 1:38p Allender
76  * from John:  changes to timer func to detect early rollever
77  * 
78  * 7     7/29/97 5:30p Lawrance
79  * move gettime() from keyboard module to timer module
80  * 
81  * 6     7/16/97 4:42p Mike
82  * Make afterburner shake viewer, not ship.
83  * Shake for limited time.
84  * Add timestamp_until() function to timer library.
85  * 
86  * 5     2/17/97 5:18p John
87  * Added a bunch of RCS headers to a bunch of old files that don't have
88  * them.
89  *
90  * $NoKeywords: $
91  */
92
93
94 #include        "limits.h"
95 #include "pstypes.h"
96 #include "timer.h"
97 #include "2d.h"
98 #include "alphacolors.h"
99
100 #ifndef NDEBUG
101         #define USE_TIMING
102 #endif
103
104 static int Timer_inited = 0;
105
106 void timer_close()
107 {
108         if ( Timer_inited )     {
109                 Timer_inited = 0;
110         }
111 }
112
113 void timer_init()
114 {
115         if ( !Timer_inited )    {
116                 SDL_InitSubSystem(SDL_INIT_TIMER);
117
118                 SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1");
119
120                 Timer_inited = 1;
121
122                 atexit(timer_close);
123         }
124 }
125
126
127 fix timer_get_fixed_seconds()
128 {
129         Sint64 a = SDL_GetTicks();
130         
131         a *= 65536;
132         return (fix)(a / 1000);
133 }
134
135 fix timer_get_fixed_secondsX()
136 {
137         return timer_get_fixed_seconds();
138 }
139
140 fix timer_get_approx_seconds()
141 {
142         return timer_get_fixed_seconds();
143 }
144
145 int timer_get_seconds()
146 {
147         return SDL_GetTicks() / 1000;
148 }
149
150 int timer_get_milliseconds()
151 {
152         return SDL_GetTicks();
153 }
154
155 int timer_get_microseconds()
156 {
157         return SDL_GetTicks() * 1000;
158 }
159
160 // 0 means invalid,
161 // 1 means always return true
162 // 2 and above actually check the time
163 int timestamp_ticker = 2;
164
165 void timestamp_reset()
166 {
167         timestamp_ticker = 2;
168 }
169
170 // Restrict all time values between 0 and MAX_TIME
171 // so we don't have to use UINTs to calculate rollover.
172 // For debugging & testing, you could set this to 
173 // something like 1 minute (6000).
174 #define MAX_TIME (INT_MAX/2)
175
176 void timestamp_inc(float frametime)
177 {
178         timestamp_ticker += (int)(frametime*TIMESTAMP_FREQUENCY);
179
180         if ( timestamp_ticker > MAX_TIME )      {
181                 timestamp_ticker = 2;           // Roll!
182         }
183
184         if (timestamp_ticker < 2 ) {
185                 mprintf(("Whoa!!!  timestamp_ticker < 2 -- resetting to 2!!!\n"));
186                 timestamp_ticker = 2;
187         }
188 }
189
190 int timestamp(int delta_ms )
191 {
192         int t2;
193         if (delta_ms < 0 ) return 0;
194         if (delta_ms == 0 ) return 1;
195         t2 = timestamp_ticker + delta_ms;
196         if ( t2 > MAX_TIME )    {
197                 // wrap!!!
198                 t2 = delta_ms - (MAX_TIME-timestamp_ticker);
199         }
200         if (t2 < 2 ) t2 = 2;    // hack??
201         return t2;
202 }
203
204 //      Returns milliseconds until timestamp will elapse.
205 //      Negative value gives milliseconds ago that timestamp elapsed.
206 int timestamp_until(int stamp)
207 {
208         // JAS: FIX
209         // HACK!! This doesn't handle rollover!
210         // (Will it ever happen?)
211         
212         return stamp - timestamp_ticker;
213
214 /*
215         uint    delta;
216
217         delta = stamp - timestamp_ticker;
218         
219
220         if (delta > UINT_MAX/2)
221                 delta = UINT_MAX - delta + 1;
222         else if (delta < - ( (int) (UINT_MAX/2)))
223                 delta = UINT_MAX + delta + 1;
224
225         return delta;
226 */
227 }
228
229 // alternate timestamp functions.  The way these work is you call xtimestamp() to get the
230 // current counter value, and then call
231 int timestamp()
232 {
233         return timestamp_ticker;
234 }
235
236 int timestamp_has_time_elapsed(int stamp, int time)
237 {
238         int t;
239
240         if (time <= 0)
241                 return 1;
242
243         t = stamp + time;
244         if (t <= timestamp_ticker)
245                 return 1;  // if we are unlucky enough to have it wrap on us, this will assume time has elapsed.
246
247         return 0;
248 }
249
250 // timing functions -------------------------------------------------------------------------------
251
252 #define MAX_TIMING_EVENTS               15
253
254 // timing struct
255 #ifdef USE_TIMING
256
257 typedef struct timing {
258         char name[64];
259         int microseconds_total;
260         int start;
261         int ref_count;
262 } timing;
263
264 timing Timing_frame;
265 timing Timing_events[MAX_TIMING_EVENTS];
266 int Timing_event_count = 0;
267
268 #endif
269
270 // lookup a timing event
271 int timing_event_lookup(char *event_name)
272 {
273 #ifndef USE_TIMING
274         return -1;
275 #else
276         int idx;
277
278         // sanity
279         if(event_name == NULL){
280                 return -1;
281         }
282
283         // look through all events
284         for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
285                 if(!SDL_strcasecmp(Timing_events[idx].name, event_name)){
286                         return idx;
287                 }
288         }
289
290         return -1;
291 #endif
292 }
293
294 // start timing frame stuff
295 void timing_frame_start()
296 {
297 #ifndef USE_TIMING
298         return;
299 #else
300         int idx;
301
302         // restart the frame
303         Timing_event_count = 0;
304         Timing_frame.start = timer_get_microseconds();
305         for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
306                 Timing_events[idx].microseconds_total = 0;
307                 SDL_strlcpy(Timing_events[idx].name, "", SDL_arraysize(Timing_events[0].name));
308                 Timing_events[idx].ref_count = 0;
309         }
310 #endif
311 }
312
313 // done timing the frame
314 void timing_frame_stop()
315 {
316 #ifndef USE_TIMING
317         return;
318 #else   
319         int stop_time;
320
321         // stop time
322         stop_time = timer_get_microseconds();
323
324         // calc times
325         Timing_frame.microseconds_total = stop_time - Timing_frame.start;       
326 #endif
327 }
328
329 // get the total frame time in microseconds
330 int timing_frame_total()
331 {
332 #ifndef USE_TIMING
333         return 0;
334 #else
335         return Timing_frame.microseconds_total;
336 #endif
337 }
338
339 // time an individual event
340 void timing_event_start(char *event_name)
341 {
342 #ifndef USE_TIMING
343         return;
344 #else
345         int event;
346
347         // sanity
348         if(event_name == NULL){
349                 return;
350         }
351
352         // try and find the event
353         event = timing_event_lookup(event_name);
354
355         // if we already have one
356         if(event != -1){
357                 SDL_assert(Timing_events[event].ref_count == 0);
358                 Timing_events[event].start = timer_get_microseconds();
359                 Timing_events[event].ref_count++;
360         }
361         // if we need to add a new one
362         else {
363                 if(Timing_event_count < MAX_TIMING_EVENTS){
364                         SDL_strlcpy(Timing_events[Timing_event_count].name, event_name, SDL_arraysize(Timing_events[0].name));
365                         Timing_events[Timing_event_count].start = timer_get_microseconds();
366                         Timing_events[Timing_event_count++].ref_count++;
367                 }
368         }
369 #endif
370 }
371
372 // stop timing an event
373 void timing_event_stop(char *event_name)
374 {
375 #ifndef USE_TIMING
376         return;
377 #else
378         int event;
379
380         // sanity
381         if(event_name == NULL){
382                 return;
383         }
384
385         // try and find the event
386         event = timing_event_lookup(event_name);
387
388         // if we already have one
389         if(event != -1){
390                 SDL_assert(Timing_events[event].ref_count == 1);
391                 Timing_events[event].microseconds_total += timer_get_microseconds() - Timing_events[event].start;
392                 Timing_events[event].ref_count--;
393         }
394 #endif
395 }
396
397 // get the total time for an event in microseconds
398 int timing_event_total(char *event_name)
399 {
400 #ifndef USE_TIMING
401         return -1;
402 #else
403         int event;
404
405         // sanity
406         if(event_name == NULL){
407                 return -1;
408         }
409
410         // try and find the event
411         event = timing_event_lookup(event_name);
412         if(event == -1){
413                 return -1;
414         }
415         
416         return Timing_events[event].microseconds_total;
417 #endif
418 }
419
420 // get the percentage of total frametime for the event (0.0 to 1.0)
421 float timing_event_pct(char *event_name)
422 {
423 #ifndef USE_TIMING
424         return 0.0f;
425 #else
426         int event;
427
428         // sanity
429         if(event_name == NULL){
430                 return -1.0f;
431         }
432
433         // try and find the event
434         event = timing_event_lookup(event_name);
435         if(event == -1){
436                 return -1.0f;
437         }
438
439         return (float)((double)Timing_events[event].microseconds_total / (double)Timing_frame.microseconds_total);
440 #endif
441 }
442
443 // display timing 
444 void timing_display(int x, int y)
445 {
446 #ifndef USE_TIMING
447         return;
448 #else
449         int idx;
450
451         gr_set_color_fast(&Color_bright_blue);
452
453         // total time
454         gr_printf(x, y, "Total time %f\n", (float)timing_frame_total() / 1000000.0f);
455         y += 10;
456
457         // each event percentage
458         for(idx=0; idx<Timing_event_count; idx++){
459                 gr_printf(x, y, "%s : %f\n", Timing_events[idx].name, timing_event_pct(Timing_events[idx].name));
460                 y += 10;
461         }
462 #endif
463 }