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