]> git.itanic.dy.fi Git - sdl-planets/blobdiff - main.c
planet.c: Use the quadtree_move function from quadtree lib
[sdl-planets] / main.c
diff --git a/main.c b/main.c
index bfdd295459548a0c0400533f8dbf5a2ffc49ebe0..b42f2345d5404ae0e54cc579d6ae4bc39a006f6c 100644 (file)
--- a/main.c
+++ b/main.c
@@ -2,19 +2,39 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <time.h>
+#include <getopt.h>
 
 #include "random.h"
 #include "planet.h"
 
 #define MAX_FPS 60
 
-static void fade_buf(SDL_Surface *screen, double amount)
+static void fade_buf(SDL_Surface *screen, double fade)
 {
        int i;
-       unsigned char *buf = screen->pixels;
+       unsigned int *buf = screen->pixels;
+       unsigned char *b;
+       unsigned char amount;
+       static double threshold;
+       threshold += fade;
+
+       if (threshold > 1) {
+               amount = threshold;
+               threshold -= amount;
+       } else {
+               return;
+       }
 
-       for (i = 0; i < screen->pitch * screen->h; i++)
-               buf[i] = (buf[i] < amount) ? 0 : buf[i] - amount;
+       for (i = 0; i < screen->pitch * screen->h / sizeof(*buf); i++) {
+               if (!buf[i])
+                       continue;
+               b = (unsigned char *)&buf[i];
+               *b = *b >= amount ? (*b - amount) : *b;
+               b++;
+               *b = *b >= amount ? (*b - amount) : *b;
+               b++;
+               *b = *b >= amount ? (*b - amount) : *b;
+       }
 }
 
 static void clear_buf(SDL_Surface *screen)
@@ -32,7 +52,7 @@ static unsigned long gettime(void)
 {
        struct timespec tp;
        unsigned long ret;
-       static unsigned long start = 0;
+       static unsigned long start;
 
        clock_gettime(CLOCK_MONOTONIC, &tp);
 
@@ -45,13 +65,20 @@ static unsigned long gettime(void)
        return ret - start;
 }
 
-static int poll_events(SDL_Surface **screen, struct camera *cam,
-                      double *time_scale, double time)
+struct sim_status {
+       SDL_Surface *screen;
+       struct camera *cam;
+       double time_scale;
+       int tracers_enabled;
+};
+
+static int poll_events(struct sim_status *status, double time)
 {
        static double time_scale_rate = 1;
        SDL_Event event;
+       struct camera *cam = status->cam;
 
-       *time_scale *= pow(time_scale_rate, time);
+       status->time_scale *= pow(time_scale_rate, time);
 
        while (SDL_PollEvent(&event)) {
                switch (event.type) {
@@ -85,6 +112,24 @@ static int poll_events(SDL_Surface **screen, struct camera *cam,
                        case SDLK_a:
                                time_scale_rate = 1 / 1.5;
                                break;
+                       case SDLK_1:
+                               status->time_scale = 1;
+                               break;
+                       case SDLK_2:
+                               status->time_scale = 10;
+                               break;
+                       case SDLK_3:
+                               status->time_scale = 20;
+                               break;
+                       case SDLK_4:
+                               status->time_scale = 30;
+                               break;
+                       case SDLK_0:
+                               status->time_scale = 0;
+                               break;
+                       case SDLK_t:
+                               status->tracers_enabled =
+                                       !status->tracers_enabled;
                        default:
                                break;
                        }
@@ -122,10 +167,11 @@ static int poll_events(SDL_Surface **screen, struct camera *cam,
                        }
                        break;
                case SDL_VIDEORESIZE:
-                       *screen = SDL_SetVideoMode(event.resize.w,
-                                                  event.resize.h,
-                                                  32,
-                                                  screen[0]->flags);
+                       status->screen =
+                               SDL_SetVideoMode(event.resize.w,
+                                                event.resize.h,
+                                                32,
+                                                status->screen->flags);
                        break;
                case SDL_QUIT:
                        goto quit;
@@ -141,18 +187,33 @@ quit:
 static void loop(SDL_Surface *screen, int num_of_planets, double total_mass,
                 double range)
 {
-       struct planet *planet, *pl1, *pl2;
+       struct sim_status status;
+       struct planet *planet, *pl1, *pl2, *planet_root;
        struct camera camera;
+       struct planet_search_iterator itr;
+       struct vector vect;
+
        int planets;
        int framecount = 0, last_fps_time = 0;
        int last_framecount = 0, last_step_count = 0;
        unsigned long old_ticks, ticks = 0, last_frame_tick = 0;
        unsigned long step_count = 0;
-       double last_fps = 0, time_scale = 1, last_sps = 0;
+       double last_fps = 0, last_sps = 0, fade_amount;
        double step_time = 0, true_time = 0;
+       int visible_planets;
 
        init_camera(&camera);
 
+       status.cam = &camera;
+       status.time_scale = 1;
+       status.screen = screen;
+       status.tracers_enabled = 0;
+
+       itr.screen = screen;
+       itr.cam = &camera;
+       itr.qt_iterator.direction = planet_search_rectangular;
+       itr.qt_iterator.callback = planet_draw_iterator;
+
        planet = malloc(sizeof(*planet));
        init_planet(planet);
        create_planets(planet, num_of_planets, total_mass, range);
@@ -161,55 +222,73 @@ static void loop(SDL_Surface *screen, int num_of_planets, double total_mass,
        while (1) {
                planets = 0;
 
-               list_for_each_entry(pl1, &planet->list, list) {
-                       pl2 = list_to_planet(pl1->list.next);
-                       list_for_each_entry_from(pl2, &planet->list, list) {
-                               struct planet *ptmp;
-                               if (!gravitize_planets(pl1, pl2,
-                                                      step_time))
-                                       continue;
-
-                               ptmp = list_to_planet(pl2->list.prev);
-                               merge_planets(pl1, pl2);
-                               pl2 = ptmp;
+               if (status.time_scale > 0) {
+                       list_for_each_entry(pl1, &planet->list, list) {
+                               pl2 = list_to_planet(pl1->list.next);
+                               list_for_each_entry_from(pl2, &planet->list,
+                                                        list) {
+                                       struct planet *ptmp;
+                                       if (!gravitize_planets(pl1, pl2,
+                                                              step_time))
+                                               continue;
+
+                                       ptmp = list_to_planet(pl2->list.prev);
+                                       merge_planets(pl1, pl2);
+                                       pl2 = ptmp;
+                               }
+
+                               planet_root = move_planet(pl1, step_time);
+                               planets++;
                        }
-
-                       move_planet(pl1, step_time);
                }
-
                move_camera(&camera, true_time);
 
-               if (poll_events(&screen, &camera, &time_scale, true_time))
+               if (poll_events(&status, true_time))
                        return;
 
                old_ticks = ticks;
                ticks = gettime();
                true_time = (ticks - old_ticks) / (1000.0 * 1000.0) ;
-               step_time = true_time * time_scale;
+               step_time = true_time * status.time_scale;
                step_time = MIN(step_time, 0.02);
                step_count++;
 
                /*
-                * Do not draw to the screen more often than MAS_FPS
+                * Do not draw to the screen more often than MAX_FPS
                 * per second
                 */
                if (last_frame_tick + (1000 * 1000) / MAX_FPS > ticks)
                        continue;
 
-               last_frame_tick = ticks;
-
                SDL_LockSurface(screen);
-               clear_buf(screen);
 
-               list_for_each_entry(pl1, &planet->list, list) {
-                       draw_planet(screen, pl1, &camera);
-                       planets++;
+               if (status.tracers_enabled &&
+                   !camera.speed.x && !camera.speed.y &&
+                   camera.zoom_rate == 1) {
+                       fade_amount = (ticks - last_frame_tick) /
+                               (1000 * 1000.0) * 20;
+                       fade_buf(screen, fade_amount);
+               } else {
+                       clear_buf(screen);
                }
 
+               itr.limit[0] = camera.pos;
+               vect.x = screen->w / 2;
+               vect.y = screen->h / 2;
+               vector_scale(&vect, 1 / camera.zoom, &vect);
+               vector_add(&itr.limit[0], &vect, &itr.limit[1]);
+               vector_sub(&itr.limit[0], &vect, &itr.limit[0]);
+
+               itr.qt_iterator.head = &planet_root->tree;
+
+               visible_planets = walk_quadtree(&itr.qt_iterator);
+
                SDL_UnlockSurface(screen);
 
                SDL_Flip(screen);
 
+               last_frame_tick = ticks;
+
                if (last_fps_time + (500 * 1000) < ticks) {
                        last_framecount = framecount - last_framecount;
                        last_fps = last_framecount * 1000 * 1000 /
@@ -224,11 +303,12 @@ static void loop(SDL_Surface *screen, int num_of_planets, double total_mass,
                        last_fps_time = ticks;
                }
 
-
-               printf("  \rFrames/s: %.2f, steps/s: %.2f, planets: %d"
-                      ", scale %.2f, zoom %.2f, step %d",
-                      last_fps, last_sps, planets, time_scale,
-                      camera.zoom, step_count);
+               printf("  \rfps: %.2f, steps/s: %.2f, planets: %d"
+                      ", scale %.2f, zoom %.2f, step %ld, visible %d,"
+                      " depth %ld, c:%ld",
+                      last_fps, last_sps, planets, status.time_scale,
+                      camera.zoom, step_count, visible_planets,
+                      planet_root->tree.depth, planet_root->tree.children);
                fflush(stdout);
 
 
@@ -243,6 +323,16 @@ int main(int argc, char *argv[])
        int planets = 100, xres = 800, yres = 600;
        double total_mass = 50000;
        double range = 500;
+       int optind = 0, c;
+       static struct option long_options[] = {
+               { .val = 'x', .name = "xres", .has_arg = 1, },
+               { .val = 'y', .name = "yres", .has_arg = 1, },
+               { .val = 'p', .name = "planets", .has_arg = 1 },
+               { .val = 'm', .name = "total-mass", .has_arg = 1 },
+               { .val = 'r', .name = "range", .has_arg = 1 },
+               {},
+       };
+       char short_options[] = "x:y:p:m:r:";
 
        if (SDL_Init(SDL_INIT_VIDEO) != 0) {
                fprintf(stderr, "Unable to initialize SDL: %s\n",
@@ -252,14 +342,33 @@ int main(int argc, char *argv[])
        }
        atexit(SDL_Quit);
 
-       if (argc >= 2)
-               planets = atoi(argv[1]);
+       while (1) {
+               c = getopt_long(argc, argv, short_options, long_options,
+                               &optind);
+
+               if (c == -1)
+                       break;
+
+               printf("%c: %s\n", c, optarg);
 
-       if (argc >= 3)
-               total_mass = atof(argv[2]);
+               switch (c) {
+               case 'x':
+                       xres = atoi(optarg);
+                       break;
 
-       if (argc >= 4)
-               range = atof(argv[3]);
+               case 'y':
+                       yres = atoi(optarg);
+                       break;
+
+               case 'p':
+                       planets = atoi(optarg);
+                       break;
+
+               case 'r':
+                       range = atoi(optarg);
+                       break;
+               }
+       }
 
        screen = SDL_SetVideoMode(xres, yres, 32, flags);
        if (screen == NULL) {