12 static void fade_buf(SDL_Surface *screen, double fade)
15 unsigned int *buf = screen->pixels;
18 static double threshold;
28 for (i = 0; i < screen->pitch * screen->h / sizeof(*buf); i++) {
31 b = (unsigned char *)&buf[i];
32 *b = *b >= amount ? (*b - amount) : *b;
34 *b = *b >= amount ? (*b - amount) : *b;
36 *b = *b >= amount ? (*b - amount) : *b;
40 static void clear_buf(SDL_Surface *screen)
43 unsigned int *buf = screen->pixels;
45 for (i = 0; i < screen->pitch * screen->h / 4; i++)
49 /* Return time in microseconds */
51 static unsigned long gettime(void)
55 static unsigned long start;
57 clock_gettime(CLOCK_MONOTONIC, &tp);
59 ret = tp.tv_sec * 1000 * 1000;
60 ret += tp.tv_nsec / 1000;
75 static int poll_events(struct sim_status *status, double time)
77 static double time_scale_rate = 1;
79 struct camera *cam = status->cam;
81 status->time_scale *= pow(time_scale_rate, time);
83 while (SDL_PollEvent(&event)) {
86 switch (event.key.keysym.sym) {
90 cam->speed.x = -CAM_SPEED;
93 cam->speed.x = CAM_SPEED;
96 cam->speed.y = -CAM_SPEED;
99 cam->speed.y = CAM_SPEED;
103 cam->zoom_rate = CAM_ZOOM_RATE;
107 cam->zoom_rate = 1 / CAM_ZOOM_RATE;
110 time_scale_rate = 1.5;
113 time_scale_rate = 1 / 1.5;
116 status->time_scale = 1;
119 status->time_scale = 10;
122 status->time_scale = 20;
125 status->time_scale = 30;
128 status->time_scale = 0;
131 status->tracers_enabled =
132 !status->tracers_enabled;
138 switch (event.key.keysym.sym) {
169 case SDL_VIDEORESIZE:
171 SDL_SetVideoMode(event.resize.w,
174 status->screen->flags);
183 printf("\nExiting. Good bye!\n");
187 static void loop(SDL_Surface *screen, int num_of_planets, double total_mass,
190 struct sim_status status;
191 struct planet *planet, *pl1, *pl2, *planet_root;
192 struct camera camera;
193 struct planet_search_iterator itr;
197 int framecount = 0, last_fps_time = 0;
198 int last_framecount = 0, last_step_count = 0;
199 unsigned long old_ticks, ticks = 0, last_frame_tick = 0;
200 unsigned long step_count = 0;
201 double last_fps = 0, last_sps = 0, fade_amount;
202 double step_time = 0, true_time = 0;
205 init_camera(&camera);
207 status.cam = &camera;
208 status.time_scale = 1;
209 status.screen = screen;
210 status.tracers_enabled = 0;
214 itr.qt_iterator.direction = planet_search_rectangular;
215 itr.qt_iterator.callback = planet_draw_iterator;
217 planet_root = planet = malloc(sizeof(*planet));
219 create_planets(planet, num_of_planets, total_mass, range);
221 ticks = SDL_GetTicks();
227 gravitize_planet_tree(planet_root, step_time);
228 planets = propagate_tree_movement(planet_root);
230 planet_root = prune_planet_tree(planet_root);
232 list_for_each_entry(pl1, &planet_root->list, list) {
233 planet_root = move_planet(pl1, step_time);
236 move_camera(&camera, true_time);
238 if (poll_events(&status, true_time))
243 true_time = (ticks - old_ticks) / (1000.0 * 1000.0) ;
244 step_time = true_time * status.time_scale;
245 step_time = MIN(step_time, 0.02);
249 * Do not draw to the screen more often than MAX_FPS
252 if (last_frame_tick + (1000 * 1000) / MAX_FPS > ticks)
255 SDL_LockSurface(screen);
257 if (status.tracers_enabled &&
258 !camera.speed.x && !camera.speed.y &&
259 camera.zoom_rate == 1) {
260 fade_amount = (ticks - last_frame_tick) /
261 (1000 * 1000.0) * 20;
262 fade_buf(screen, fade_amount);
267 itr.limit[0] = camera.pos;
268 vect.x = screen->w / 2;
269 vect.y = screen->h / 2;
270 vector_scale(&vect, 1 / camera.zoom, &vect);
271 vector_add(&itr.limit[0], &vect, &itr.limit[1]);
272 vector_sub(&itr.limit[0], &vect, &itr.limit[0]);
274 itr.qt_iterator.head = &planet_root->tree;
276 visible_planets = walk_quadtree(&itr.qt_iterator);
278 SDL_UnlockSurface(screen);
282 last_frame_tick = ticks;
284 if (last_fps_time + (500 * 1000) < ticks) {
285 last_framecount = framecount - last_framecount;
286 last_fps = last_framecount * 1000 * 1000 /
287 (float)(ticks - last_fps_time);
288 last_framecount = framecount;
290 last_step_count = step_count - last_step_count;
291 last_sps = last_step_count * 1000 * 1000 /
292 (float)(ticks - last_fps_time);
293 last_step_count = step_count;
295 last_fps_time = ticks;
298 printf(" \rfps: %.2f, steps/s: %.2f, planets: %d"
299 ", scale %.2f, zoom %.2f, step %ld, visible %d,"
300 " depth %ld, area: %.f, g: %.f %.f",
301 last_fps, last_sps, planets, status.time_scale,
302 camera.zoom, step_count, visible_planets,
303 planet_root->tree.depth,
304 planet_root->tree_area,
305 gravitations / (float) planets,
306 optimizations / (float) planets);
314 int main(int argc, char *argv[])
317 int flags = SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_RESIZABLE;
318 int planets = 100, xres = 800, yres = 600;
319 double total_mass = 50000;
322 static struct option long_options[] = {
323 { .val = 'x', .name = "xres", .has_arg = 1, },
324 { .val = 'y', .name = "yres", .has_arg = 1, },
325 { .val = 'p', .name = "planets", .has_arg = 1 },
326 { .val = 'm', .name = "total-mass", .has_arg = 1 },
327 { .val = 'r', .name = "range", .has_arg = 1 },
330 char short_options[] = "x:y:p:m:r:";
332 if (SDL_Init(SDL_INIT_VIDEO) != 0) {
333 fprintf(stderr, "Unable to initialize SDL: %s\n",
341 c = getopt_long(argc, argv, short_options, long_options,
347 printf("%c: %s\n", c, optarg);
359 planets = atoi(optarg);
363 range = atoi(optarg);
368 screen = SDL_SetVideoMode(xres, yres, 32, flags);
369 if (screen == NULL) {
370 fprintf(stderr, "Unable to set video mode: %s\n",
375 SDL_WM_SetCaption(argv[0], NULL);
377 loop(screen, planets, total_mass, range);