1 /* $Id: tenm_timer.c,v 1.65 2009/11/10 18:09:57 oohara Exp $ */
2
3 #include <stdio.h>
4 /* exit */
5 #include <stdlib.h>
6 #include <SDL.h>
7
8 #include "tenm_sdl_init.h"
9
10 #include "tenm_timer.h"
11
12 /* The problem of SDL timer is that its granularity is 10 ms, that is,
13 * if the machine doesn't have a good hardware clock, whenever SDL_Delay()
14 * returns, (SDL_GetTicks() % 10) is always same. In this case,
15 * a simple SDL_Delay(delay - (now - past)) is not enough.
16 */
17
18 static Uint32 tick = 0;
19 static Uint32 tick_master = 0;
20 static int number_wait = 0;
21 static int clock_granularity = 0;
22
23 /* return 0 on success, 1 on error */
24 int
tenm_timer_init(int num_wait)25 tenm_timer_init(int num_wait)
26 {
27 int i;
28 int t;
29 Uint32 tick_begin;
30
31 /* sanity check */
32 if (num_wait <= 0)
33 {
34 fprintf(stderr, "tenm_timer_init: strange num_wait (%d)\n", num_wait);
35 return 1;
36 }
37
38 if (tenm_sdl_init(SDL_INIT_TIMER) != 0)
39 {
40 fprintf(stderr, "tenm_timer_init: cannot initialize SDL timer\n");
41 return 1;
42 }
43
44 number_wait = num_wait;
45 /* jump to another 10 ms */
46 SDL_Delay(10);
47
48 /* clock accuracy tests */
49 tick_begin = SDL_GetTicks();
50 for (i = 0; i < 10; i++)
51 SDL_Delay(1);
52 t = SDL_GetTicks() - tick_begin;
53 if (t > 0)
54 t = t / 10 + 1;
55 if (t < 1)
56 t = 1;
57 clock_granularity = t;
58
59 tenm_timer_reset();
60 return 0;
61 }
62
63 void
tenm_timer_reset(void)64 tenm_timer_reset(void)
65 {
66 tick_master = SDL_GetTicks();
67 tick = tick_master;
68 }
69
70 /* return 0 on success, 1 on error */
71 int
tenm_wait_next_frame(void)72 tenm_wait_next_frame(void)
73 {
74 Uint32 tick_now;
75
76 tick_now = SDL_GetTicks();
77 if (tick_now < tick)
78 {
79 fprintf(stderr, "tenm_wait_next_frame: SDL_GetTicks ticks backward!\n");
80 return 1;
81 }
82
83 /* yes, this is stupid, but it offers maximum accuracy */
84 if (clock_granularity> 0)
85 {
86 while (tick_now + clock_granularity < tick + number_wait * 10)
87 {
88 SDL_Delay(1);
89 tick_now = SDL_GetTicks();
90 }
91 }
92 while (tick_now < tick + number_wait * 10)
93 tick_now = SDL_GetTicks();
94
95 tick = SDL_GetTicks();
96
97 return 0;
98 }
99
100 /* return average number of frames per second since tenm_timer_init() or
101 * tenm_timer_reset() is called
102 * return -1.0 on error */
103 double
tenm_calculate_fps(int frame_passed)104 tenm_calculate_fps(int frame_passed)
105 {
106 Uint32 time_passed;
107
108 /* sanity check */
109 if (frame_passed < 0)
110 {
111 fprintf(stderr, "tenm_calculate_fps: "
112 "negative frame_passed\n");
113 return -1.0;
114 }
115
116 time_passed = SDL_GetTicks();
117 if (time_passed < tick_master)
118 {
119 fprintf(stderr, "tenm_calculate_fps: "
120 "SDL_GetTicks ticks backward!\n");
121 return -1.0;
122 }
123 if (time_passed == tick_master)
124 {
125 fprintf(stderr, "tenm_calculate_fps: "
126 "no time passed\n");
127 return -1.0;
128 }
129
130 time_passed -= tick_master;
131 return 1000.0 * ((double) frame_passed) / ((double) time_passed);
132 }
133