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