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