]> git.itanic.dy.fi Git - sdl-planets/blob - main.c
Main loop: Suppress a compiler warning
[sdl-planets] / main.c
1 #include <SDL.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <time.h>
5
6 #include "random.h"
7 #include "planet.h"
8
9 #define MAX_FPS 60
10
11 static void fade_buf(SDL_Surface *screen, double amount)
12 {
13         int i;
14         unsigned char *buf = screen->pixels;
15
16         for (i = 0; i < screen->pitch * screen->h; i++)
17                 buf[i] = (buf[i] < amount) ? 0 : buf[i] - amount;
18 }
19
20 static void clear_buf(SDL_Surface *screen)
21 {
22         int i;
23         unsigned int *buf = screen->pixels;
24
25         for (i = 0; i < screen->pitch * screen->h / 4; i++)
26                 buf[i] = 0;
27 }
28
29 /* Return time in microseconds */
30
31 static unsigned long gettime(void)
32 {
33         struct timespec tp;
34         unsigned long ret;
35         static unsigned long start = 0;
36
37         clock_gettime(CLOCK_MONOTONIC, &tp);
38
39         ret = tp.tv_sec * 1000 * 1000;
40         ret += tp.tv_nsec / 1000;
41
42         if (!start)
43                 start = ret;
44
45         return ret - start;
46 }
47
48 struct sim_status {
49         SDL_Surface *screen;
50         struct camera *cam;
51         double time_scale;
52 };
53
54 static int poll_events(struct sim_status *status, double time)
55 {
56         static double time_scale_rate = 1;
57         SDL_Event event;
58         struct camera *cam = status->cam;
59
60         status->time_scale *= pow(time_scale_rate, time);
61
62         while (SDL_PollEvent(&event)) {
63                 switch (event.type) {
64                 case SDL_KEYDOWN:
65                         switch (event.key.keysym.sym) {
66                         case SDLK_ESCAPE:
67                                 goto quit;
68                         case SDLK_LEFT:
69                                 cam->speed.x = -CAM_SPEED;
70                                 break;
71                         case SDLK_RIGHT:
72                                 cam->speed.x = CAM_SPEED;
73                                 break;
74                         case SDLK_UP:
75                                 cam->speed.y = -CAM_SPEED;
76                                 break;
77                         case SDLK_DOWN:
78                                 cam->speed.y = CAM_SPEED;
79                                 break;
80                         case SDLK_PLUS:
81                         case SDLK_q:
82                                 cam->zoom_rate = CAM_ZOOM_RATE;
83                                 break;
84                         case SDLK_MINUS:
85                         case SDLK_w:
86                                 cam->zoom_rate = 1 / CAM_ZOOM_RATE;
87                                 break;
88                         case SDLK_s:
89                                 time_scale_rate = 1.5;
90                                 break;
91                         case SDLK_a:
92                                 time_scale_rate = 1 / 1.5;
93                                 break;
94                         default:
95                                 break;
96                         }
97                         break;
98                 case SDL_KEYUP:
99                         switch (event.key.keysym.sym) {
100                         case SDLK_LEFT:
101                                 cam->speed.x = 0;
102                                 break;
103                         case SDLK_RIGHT:
104                                 cam->speed.x = 0;
105                                 break;
106                         case SDLK_UP:
107                                 cam->speed.y = 0;
108                                 break;
109                         case SDLK_DOWN:
110                                 cam->speed.y = 0;
111                                 break;
112                         case SDLK_PLUS:
113                         case SDLK_q:
114                                 cam->zoom_rate = 1;
115                                 break;
116                         case SDLK_MINUS:
117                         case SDLK_w:
118                                 cam->zoom_rate = 1;
119                                 break;
120                         case SDLK_s:
121                                 time_scale_rate = 1;
122                                 break;
123                         case SDLK_a:
124                                 time_scale_rate = 1;
125                                 break;
126                         default:
127                                 break;
128                         }
129                         break;
130                 case SDL_VIDEORESIZE:
131                         status->screen = SDL_SetVideoMode(event.resize.w,
132                                                           event.resize.h,
133                                                           32,
134                                                           status->screen->flags);
135                         break;
136                 case SDL_QUIT:
137                         goto quit;
138                 }
139         }
140
141         return 0;
142 quit:
143         printf("\nExiting. Good bye!\n");
144         return 1;
145 }
146
147 static void loop(SDL_Surface *screen, int num_of_planets, double total_mass,
148                  double range)
149 {
150         struct sim_status status;
151         struct planet *planet, *pl1, *pl2;
152         struct camera camera;
153         int planets;
154         int framecount = 0, last_fps_time = 0;
155         int last_framecount = 0, last_step_count = 0;
156         unsigned long old_ticks, ticks = 0, last_frame_tick = 0;
157         unsigned long step_count = 0;
158         double last_fps = 0, last_sps = 0;
159         double step_time = 0, true_time = 0;
160
161         init_camera(&camera);
162
163         status.cam = &camera;
164         status.time_scale = 1;
165         status.screen = screen;
166
167         planet = malloc(sizeof(*planet));
168         init_planet(planet);
169         create_planets(planet, num_of_planets, total_mass, range);
170
171         ticks = SDL_GetTicks();
172         while (1) {
173                 planets = 0;
174
175                 list_for_each_entry(pl1, &planet->list, list) {
176                         pl2 = list_to_planet(pl1->list.next);
177                         list_for_each_entry_from(pl2, &planet->list, list) {
178                                 struct planet *ptmp;
179                                 if (!gravitize_planets(pl1, pl2,
180                                                        step_time))
181                                         continue;
182
183                                 ptmp = list_to_planet(pl2->list.prev);
184                                 merge_planets(pl1, pl2);
185                                 pl2 = ptmp;
186                         }
187
188                         move_planet(pl1, step_time);
189                 }
190
191                 move_camera(&camera, true_time);
192
193                 if (poll_events(&status, true_time))
194                         return;
195
196                 old_ticks = ticks;
197                 ticks = gettime();
198                 true_time = (ticks - old_ticks) / (1000.0 * 1000.0) ;
199                 step_time = true_time * status.time_scale;
200                 step_time = MIN(step_time, 0.02);
201                 step_count++;
202
203                 /*
204                  * Do not draw to the screen more often than MAS_FPS
205                  * per second
206                  */
207                 if (last_frame_tick + (1000 * 1000) / MAX_FPS > ticks)
208                         continue;
209
210                 last_frame_tick = ticks;
211
212                 SDL_LockSurface(screen);
213                 clear_buf(screen);
214
215                 list_for_each_entry(pl1, &planet->list, list) {
216                         draw_planet(screen, pl1, &camera);
217                         planets++;
218                 }
219
220                 SDL_UnlockSurface(screen);
221
222                 SDL_Flip(screen);
223
224                 if (last_fps_time + (500 * 1000) < ticks) {
225                         last_framecount = framecount - last_framecount;
226                         last_fps = last_framecount * 1000 * 1000 /
227                                 (float)(ticks - last_fps_time);
228                         last_framecount = framecount;
229
230                         last_step_count = step_count - last_step_count;
231                         last_sps = last_step_count * 1000 * 1000 /
232                                 (float)(ticks - last_fps_time);
233                         last_step_count = step_count;
234
235                         last_fps_time = ticks;
236                 }
237
238
239                 printf("  \rFrames/s: %.2f, steps/s: %.2f, planets: %d"
240                        ", scale %.2f, zoom %.2f, step %ld",
241                        last_fps, last_sps, planets, status.time_scale,
242                        camera.zoom, step_count);
243                 fflush(stdout);
244
245
246                 framecount++;
247         }
248 }
249
250 int main(int argc, char *argv[])
251 {
252         SDL_Surface *screen;
253         int flags = SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_RESIZABLE;
254         int planets = 100, xres = 800, yres = 600;
255         double total_mass = 50000;
256         double range = 500;
257
258         if (SDL_Init(SDL_INIT_VIDEO) != 0) {
259                 fprintf(stderr, "Unable to initialize SDL: %s\n",
260                         SDL_GetError());
261
262                 return 1;
263         }
264         atexit(SDL_Quit);
265
266         if (argc >= 2)
267                 planets = atoi(argv[1]);
268
269         if (argc >= 3)
270                 total_mass = atof(argv[2]);
271
272         if (argc >= 4)
273                 range = atof(argv[3]);
274
275         screen = SDL_SetVideoMode(xres, yres, 32, flags);
276         if (screen == NULL) {
277                 fprintf(stderr, "Unable to set video mode: %s\n",
278                         SDL_GetError());
279                 return 2;
280         }
281
282         SDL_WM_SetCaption(argv[0], NULL);
283
284         loop(screen, planets, total_mass, range);
285
286         return 0;
287 }
288