#include <SDL.h>
#include <unistd.h>
#include <stdio.h>
+#include <time.h>
#include "random.h"
#include "planet.h"
-static void fade_buf(SDL_Surface *screen, double amount)
+#define MAX_FPS 60
+
+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)
buf[i] = 0;
}
-static int poll_events(SDL_Surface **screen, struct camera *cam,
- double *time_scale, double time)
+/* Return time in microseconds */
+
+static unsigned long gettime(void)
+{
+ struct timespec tp;
+ unsigned long ret;
+ static unsigned long start;
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+
+ ret = tp.tv_sec * 1000 * 1000;
+ ret += tp.tv_nsec / 1000;
+
+ if (!start)
+ start = ret;
+
+ return ret - start;
+}
+
+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 SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
- printf("\nExiting. Good bye!\n");
- return 1;
+ goto quit;
case SDLK_LEFT:
cam->speed.x = -CAM_SPEED;
break;
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_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;
}
}
return 0;
+quit:
+ printf("\nExiting. Good bye!\n");
+ return 1;
}
static void loop(SDL_Surface *screen, int num_of_planets, double total_mass,
double range)
{
+ struct sim_status status;
struct planet *planet, *pl1, *pl2;
struct camera camera;
int planets;
- int old_ticks, ticks, framecount = 0, last_fps_time = 0;
- int last_framecount = 0;
- double time = 0, last_fps = 0, time_scale = 1;
+ 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, last_sps = 0;
+ double step_time = 0, true_time = 0;
init_camera(&camera);
+ status.cam = &camera;
+ status.time_scale = 1;
+ status.screen = screen;
+ status.tracers_enabled = 0;
+
planet = malloc(sizeof(*planet));
init_planet(planet);
create_planets(planet, num_of_planets, total_mass, range);
list_for_each_entry_from(pl2, &planet->list, list) {
struct planet *ptmp;
if (!gravitize_planets(pl1, pl2,
- time * time_scale))
+ step_time))
continue;
ptmp = list_to_planet(pl2->list.prev);
pl2 = ptmp;
}
- move_planet(pl1, time * time_scale);
+ move_planet(pl1, step_time);
}
+ move_camera(&camera, 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 * status.time_scale;
+ step_time = MIN(step_time, 0.02);
+ step_count++;
+
+ /*
+ * 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);
+ if (status.tracers_enabled &&
+ !camera.speed.x && !camera.speed.y &&
+ camera.zoom_rate == 1) {
+ fade_buf(screen, 10 * true_time);
+ } else {
+ clear_buf(screen);
+ }
list_for_each_entry(pl1, &planet->list, list) {
draw_planet(screen, pl1, &camera);
SDL_Flip(screen);
- move_camera(&camera, time);
-
- if (poll_events(&screen, &camera, &time_scale, time))
- return;
-
- old_ticks = ticks;
- ticks = SDL_GetTicks();
- time = (ticks - old_ticks) / 1000.0;
- time = MIN(time, 0.02);
-
- if (last_fps_time + 500 < ticks) {
+ if (last_fps_time + (500 * 1000) < ticks) {
last_framecount = framecount - last_framecount;
- last_fps = last_framecount * 1000 /
+ last_fps = last_framecount * 1000 * 1000 /
(float)(ticks - last_fps_time);
last_framecount = framecount;
+
+ last_step_count = step_count - last_step_count;
+ last_sps = last_step_count * 1000 * 1000 /
+ (float)(ticks - last_fps_time);
+ last_step_count = step_count;
+
last_fps_time = ticks;
}
- printf(" \rFrames/s: %.2f, Frame: %d, planets: %d"
- ", scale %.2f, zoom %.2f",
- last_fps, framecount++, planets, time_scale,
- camera.zoom);
+
+
+ printf(" \rFrames/s: %.2f, steps/s: %.2f, planets: %d"
+ ", scale %.2f, zoom %.2f, step %ld",
+ last_fps, last_sps, planets, status.time_scale,
+ camera.zoom, step_count);
+ fflush(stdout);
+
+
+ framecount++;
}
}