#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)
{
struct timespec tp;
unsigned long ret;
- static unsigned long start = 0;
+ static unsigned long start;
clock_gettime(CLOCK_MONOTONIC, &tp);
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) {
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;
}
}
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;
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);
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 /
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);
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",
}
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) {