rayzor
view src/main.cc @ 16:4d87b0aafbb0
forgot to add the redblack tree
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 13 Apr 2014 09:54:51 +0300 |
parents | d94a69933a71 |
children | 79609d482762 |
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <errno.h>
6 #include <direct.h>
7 #include "inttypes.h"
8 #include "gfx.h"
9 #include "keyb.h"
10 #include "mouse.h"
11 #include "logger.h"
12 #include "scene.h"
13 #include "rayzor.h"
14 #include "screen.h"
15 #include "modeller.h"
16 #include "renderer.h"
17 #include "scrman.h"
18 #include "timer.h"
20 #ifdef __DOS__
21 #undef USE_ASM_SWAPBUF
22 #endif
24 #ifdef USE_ASM_SWAPBUF
25 // defined in swapbuf.asm
26 extern "C" void swap_buffers_asm(void *dest, void *src, int xsz, int ysz, int bpp);
27 #endif
29 static bool init();
30 static void cleanup();
31 static void display();
32 static void swap_buffers();
33 static void draw_cursor(uint32_t *buf, int mx, int my);
34 static void screenshot();
35 static void handle_keyboard();
36 static void handle_mouse();
37 static bool parse_args(int argc, char **argv);
38 static void sig(int s);
40 uint32_t *fb_pixels;
41 int fb_width = 640;
42 int fb_height = 480;
43 int fb_bpp = 32;
44 Scene *scene;
46 static bool novideo;
47 static void *fb;
48 static int rbits, gbits, bbits;
49 static int rshift, gshift, bshift;
50 static unsigned int rmask, gmask, bmask;
52 static bool use_asm_swap = true;
53 static bool use_mouse;
54 static int mouse_x, mouse_y;
55 static bool quit;
56 static bool cap_shot;
58 int main(int argc, char **argv)
59 {
60 unsigned long start_msec, msec;
61 unsigned long nframes = 0;
63 if(!parse_args(argc, argv)) {
64 return 1;
65 }
66 if(!init()) {
67 return 1;
68 }
70 start_msec = get_msec();
72 // main loop
73 for(;;) {
74 handle_keyboard();
75 handle_mouse();
76 if(quit) break;
78 display();
79 ++nframes;
81 if(novideo) break;
82 }
84 msec = get_msec() - start_msec;
86 cleanup();
88 printf("Average framerate: %g\n", (float)nframes / ((float)msec / 1000.0f));
89 printf("Thank you for using Rayzor!\n");
90 return 0;
91 }
93 void quit_app()
94 {
95 quit = true;
96 }
98 static bool init()
99 {
100 signal(SIGINT, sig);
101 signal(SIGSEGV, sig);
102 signal(SIGILL, sig);
103 signal(SIGFPE, sig);
105 init_timer(128);
107 if(!novideo) {
108 if(kb_init(32) == -1) {
109 fprintf(stderr, "failed to initialize keyboard driver\n");
110 return false;
111 }
113 if(!(fb = set_video_mode(fb_width, fb_height, fb_bpp))) {
114 set_text_mode();
115 fprintf(stderr, "failed to set video mode: %dx%d %dbpp\n", fb_width, fb_height, fb_bpp);
116 return false;
117 }
118 fb_bpp = get_color_depth();
119 get_color_bits(&rbits, &gbits, &bbits);
120 get_color_shift(&rshift, &gshift, &bshift);
121 get_color_mask(&rmask, &gmask, &bmask);
123 printlog("video resolution: %dx%d\n", fb_width, fb_height);
124 printlog("bpp: %d (%d %d %d)\n", fb_bpp, rbits, gbits, bbits);
125 printlog("shift: %d %d %d\n", rshift, gshift, bshift);
126 printlog("mask: %x %x %x\n", rmask, gmask, bmask);
128 if(have_mouse()) {
129 use_mouse = true;
130 set_mouse_limits(0, 0, fb_width - 1, fb_height - 1);
131 }
132 } else {
133 logger_output(stdout);
134 printlog("novideo (debug) mode\n");
135 fb_bpp = 24;
136 rbits = gbits = bbits = 8;
137 }
139 fb_pixels = new uint32_t[fb_width * fb_height * 4];
140 if(!fb_pixels) {
141 return false;
142 }
144 scene = new Scene;
146 Sphere *sph = new Sphere;
147 scene->add(sph);
149 Box *box = new Box;
150 scene->add(box);
151 box->set_scaling(Vector3(2, 0.25, 2));
153 Modeller *modeller = new Modeller;
154 if(!modeller->init()) {
155 return false;
156 }
157 add_screen(modeller);
159 Renderer *renderer = new Renderer;
160 if(!renderer->init()) {
161 return false;
162 }
163 add_screen(renderer);
165 activate_screen(modeller); // start the modeller screen
166 return true;
167 }
169 static void cleanup()
170 {
171 delete scene;
172 delete [] fb_pixels;
174 destroy_screens();
176 if(!novideo) {
177 set_text_mode();
178 kb_shutdown();
179 }
180 }
182 static void display()
183 {
184 Screen *scr = active_screen();
185 if(scr) {
186 scr->update();
187 scr->draw();
188 }
190 // draw the mouse cursor
191 if(use_mouse) {
192 draw_cursor(fb_pixels, mouse_x, mouse_y);
193 }
195 if(cap_shot) {
196 screenshot();
197 cap_shot = false;
198 }
200 if(!novideo) {
201 wait_vsync();
202 #ifdef USE_ASM_SWAPBUF
203 swap_buffers_asm(fb, fb_pixels, fb_width, fb_height, fb_bpp);
204 #else
205 swap_buffers();
206 #endif
207 }
208 }
210 #define PACK_RGB(r, g, b) \
211 ((((r) << rshift) & rmask) | \
212 (((g) << gshift) & gmask) | \
213 (((b) << bshift) & bmask))
215 #define UNPACK_RED(c) (((c) >> 16) & 0xff)
216 #define UNPACK_GREEN(c) (((c) >> 8) & 0xff)
217 #define UNPACK_BLUE(c) ((c) & 0xff)
219 static void swap_buffers()
220 {
221 uint32_t *src = fb_pixels;
222 int num_pixels = fb_width * fb_height;
224 switch(fb_bpp) {
225 case 32:
226 memcpy(fb, fb_pixels, num_pixels * 4);
227 break;
229 case 24:
230 {
231 unsigned char *dest = (unsigned char*)fb;
232 for(int i=0; i<num_pixels-1; i++) {
233 *((uint32_t*)dest) = *src++;
234 dest += 3;
235 }
236 *dest++ = UNPACK_RED(*src);
237 *dest++ = UNPACK_GREEN(*src);
238 *dest++ = UNPACK_BLUE(*src);
239 }
240 break;
242 case 16:
243 {
244 uint16_t *dest = (uint16_t*)fb;
245 for(int i=0; i<num_pixels; i++) {
246 uint32_t c = *src++;
247 unsigned char r = UNPACK_RED(c);
248 unsigned char g = UNPACK_GREEN(c);
249 unsigned char b = UNPACK_BLUE(c);
251 *dest++ = (((r) << 8) & 0xf800) |
252 (((g) << 3) & 0x7e0) |
253 (((b) >> 3) & 0x1f);
254 }
255 }
256 break;
258 default:
259 break;
260 }
261 }
263 static void draw_cursor(uint32_t *buf, int mx, int my)
264 {
265 uint32_t *cptr = buf + my * fb_width + mx;
266 int i, cw[2] = {4, 4}, ch[2] = {4, 4};
268 if(mx < cw[0]) cw[0] = mx;
269 if(my < ch[0]) ch[0] = my;
270 if(fb_width - mx < cw[1]) cw[1] = fb_width - mx - 1;
271 if(fb_height - my < ch[1]) ch[1] = fb_height - my - 1;
273 for(i=1; i<cw[0]; i++) {
274 int idx = -i;
275 cptr[idx] = 0xffffff;
276 }
277 for(i=1; i<cw[1]; i++) {
278 int idx = i;
279 cptr[idx] = 0xffffff;
280 }
281 for(i=1; i<ch[0]; i++) {
282 int idx = -i * fb_width;
283 cptr[idx] = 0xffffff;
284 }
285 for(i=1; i<ch[1]; i++) {
286 int idx = i * fb_width;
287 cptr[idx] = 0xffffff;
288 }
289 }
291 #define PPM_COMMENT "screenshot saved by the rayzor modeller/renderer"
292 static void screenshot()
293 {
294 static int shotidx = -1;
295 FILE *fp;
296 char fname[PATH_MAX];
298 if(shotidx == -1) {
299 DIR *dir;
300 struct dirent *dent;
302 shotidx = 0;
303 if((dir = opendir("."))) {
304 while((dent = readdir(dir))) {
305 int i, num;
306 for(i=0; dent->d_name[i]; i++) {
307 fname[i] = tolower(dent->d_name[i]);
308 }
309 fname[i] = 0;
311 if(sscanf(fname, "shot%d.ppm", &num) == 1 && num > shotidx) {
312 shotidx = num;
313 }
314 }
315 closedir(dir);
316 }
317 }
319 sprintf(fname, "shot%04d.ppm", ++shotidx);
320 if(!(fp = fopen(fname, "wb"))) {
321 printlog("failed to save screenshot %s: %s\n", fname, strerror(errno));
322 return;
323 }
325 fprintf(fp, "P6\n" PPM_COMMENT "\n%d %d\n255\n", fb_width, fb_height);
326 for(int i=0; i<fb_width * fb_height; i++) {
327 uint32_t c = fb_pixels[i];
328 fputc(UNPACK_RED(c), fp);
329 fputc(UNPACK_GREEN(c), fp);
330 fputc(UNPACK_BLUE(c), fp);
331 }
333 fclose(fp);
334 }
336 static void handle_keyboard()
337 {
338 int key;
339 Screen *scr = active_screen();
341 if(novideo) return;
343 while((key = kb_getkey()) != -1) {
344 switch(key) {
345 case '`':
346 use_asm_swap = !use_asm_swap;
347 break;
349 case 'q':
350 case 'x':
351 if(kb_isdown(KB_ALT)) {
352 quit_app();
353 }
354 break;
356 case KB_SYSRQ:
357 case KB_F12:
358 cap_shot = true;
359 break;
361 default:
362 break;
363 }
364 scr->handle_keyboard(key, true); // TODO also generate release events...
365 }
366 }
368 static void handle_mouse()
369 {
370 static int prev_mx, prev_my, prev_bnmask, bndiff;
371 int mx, my, bnmask;
372 Screen *scr = active_screen();
374 if(!use_mouse || novideo) return;
376 bnmask = read_mouse(&mx, &my);
377 if(scr && (bndiff = bnmask ^ prev_bnmask)) {
378 for(int i=0; i<8; i++) {
379 int bit = 1 << i;
380 if(bndiff & bit) {
381 scr->handle_mbutton(i, bnmask & bit, mx, my);
382 }
383 }
384 }
385 prev_bnmask = bnmask;
387 if(scr && (mx != prev_mx || my != prev_my)) {
388 scr->handle_mmotion(mx, my);
389 }
390 prev_mx = mx;
391 prev_my = my;
393 mouse_x = mx;
394 mouse_y = my;
395 }
398 static struct {
399 int opt;
400 const char *lopt;
401 const char *desc;
402 } options[] = {
403 {'s', "size", "resolution <xres>x<yres>[:bpp]"},
404 {'n', "novid", "don't switch video mode (for debugging)"},
405 {'h', "help", "print usage information and exit"},
406 {-1, 0, 0}
407 };
409 static void print_usage(const char *argv0)
410 {
411 printf("%s usage\n", argv0);
412 for(int i=0; options[i].opt != -1; i++) {
413 printf(" -%c, -%s: %s\n", options[i].opt, options[i].lopt, options[i].desc);
414 }
415 exit(0);
416 }
418 static bool parse_args(int argc, char **argv)
419 {
420 for(int i=1; i<argc; i++) {
421 if(argv[i][0] == '-') {
422 int opt = -1;
424 for(int j=0; options[j].opt != -1; j++) {
425 if(argv[i][2] == 0) {
426 if(argv[i][1] == options[j].opt) {
427 opt = options[j].opt;
428 break;
429 }
430 } else {
431 if(strcmp(argv[i] + 1, options[j].lopt) == 0) {
432 opt = options[j].opt;
433 break;
434 }
435 }
436 }
438 switch(opt) {
439 case 's':
440 if(sscanf(argv[++i], "%dx%d:%d", &fb_width, &fb_height, &fb_bpp) < 2) {
441 fprintf(stderr, "%s must be followed by a resolution: WxH\n", argv[i - 1]);
442 return false;
443 }
444 break;
446 case 'n':
447 novideo = true;
448 break;
450 case 'h':
451 print_usage(argv[0]); // doesn't return
452 break;
454 default:
455 fprintf(stderr, "unknown option: %s\n", argv[i]);
456 return false;
457 }
458 } else {
459 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
460 return false;
461 }
462 }
463 return true;
464 }
466 static void sig(int s)
467 {
468 cleanup();
469 fprintf(stderr, "signal caught: %d\n", s);
470 exit(1);
471 }