rayzor

view src/main.cc @ 18:859ccadca671

portability fixes
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 14 Apr 2014 18:35:37 +0300
parents 79609d482762
children 252999cd1a3f
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <errno.h>
6 #include <float.h>
7 #include <direct.h>
8 #include "inttypes.h"
9 #include "gfx.h"
10 #include "keyb.h"
11 #include "mouse.h"
12 #include "logger.h"
13 #include "scene.h"
14 #include "rayzor.h"
15 #include "screen.h"
16 #include "modeller.h"
17 #include "renderer.h"
18 #include "scrman.h"
19 #include "timer.h"
21 #ifdef __DOS__
22 #undef USE_ASM_SWAPBUF
23 #endif
25 #ifdef USE_ASM_SWAPBUF
26 // defined in swapbuf.asm
27 extern "C" void swap_buffers_asm(void *dest, void *src, int xsz, int ysz, int bpp);
28 #endif
30 static bool init();
31 static void cleanup();
32 static void display();
33 static void swap_buffers();
34 static void draw_cursor(uint32_t *buf, int mx, int my);
35 static void screenshot();
36 static void handle_keyboard();
37 static void handle_mouse();
38 static bool parse_args(int argc, char **argv);
39 static void sig(int s);
41 uint32_t *fb_pixels;
42 int fb_width = 640;
43 int fb_height = 480;
44 int fb_bpp = 32;
45 Scene *scene;
47 static bool novideo;
48 static void *fb;
49 static int rbits, gbits, bbits;
50 static int rshift, gshift, bshift;
51 static unsigned int rmask, gmask, bmask;
53 static bool use_asm_swap = true;
54 static bool use_mouse;
55 static int mouse_x, mouse_y;
56 static bool quit;
57 static bool cap_shot;
59 int main(int argc, char **argv)
60 {
61 unsigned long start_msec, msec;
62 unsigned long nframes = 0;
64 if(!parse_args(argc, argv)) {
65 return 1;
66 }
67 if(!init()) {
68 return 1;
69 }
71 start_msec = get_msec();
73 // main loop
74 for(;;) {
75 handle_keyboard();
76 handle_mouse();
77 if(quit) break;
79 display();
80 ++nframes;
82 if(novideo) break;
83 }
85 msec = get_msec() - start_msec;
87 cleanup();
89 printf("Average framerate: %g\n", (float)nframes / ((float)msec / 1000.0f));
90 printf("Thank you for using Rayzor!\n");
91 return 0;
92 }
94 void quit_app()
95 {
96 quit = true;
97 }
99 static bool init()
100 {
101 signal(SIGINT, sig);
102 signal(SIGSEGV, sig);
103 signal(SIGILL, sig);
104 signal(SIGFPE, sig);
106 #ifdef __WATCOM__
107 // mask all fpe except invalid op
108 _control87(~_EM_INVALID, _MCW_EM);
109 #endif
111 init_timer(128);
113 if(!novideo) {
114 if(kb_init(32) == -1) {
115 fprintf(stderr, "failed to initialize keyboard driver\n");
116 return false;
117 }
119 if(!(fb = set_video_mode(fb_width, fb_height, fb_bpp))) {
120 set_text_mode();
121 fprintf(stderr, "failed to set video mode: %dx%d %dbpp\n", fb_width, fb_height, fb_bpp);
122 return false;
123 }
124 fb_bpp = get_color_depth();
125 get_color_bits(&rbits, &gbits, &bbits);
126 get_color_shift(&rshift, &gshift, &bshift);
127 get_color_mask(&rmask, &gmask, &bmask);
129 printlog("video resolution: %dx%d\n", fb_width, fb_height);
130 printlog("bpp: %d (%d %d %d)\n", fb_bpp, rbits, gbits, bbits);
131 printlog("shift: %d %d %d\n", rshift, gshift, bshift);
132 printlog("mask: %x %x %x\n", rmask, gmask, bmask);
134 if(have_mouse()) {
135 use_mouse = true;
136 set_mouse_limits(0, 0, fb_width - 1, fb_height - 1);
137 }
138 } else {
139 logger_output(stdout);
140 printlog("novideo (debug) mode\n");
141 fb_bpp = 24;
142 rbits = gbits = bbits = 8;
143 }
145 fb_pixels = new uint32_t[fb_width * fb_height * 4];
146 if(!fb_pixels) {
147 return false;
148 }
150 scene = new Scene;
152 Sphere *sph = new Sphere;
153 sph->mtl.diffuse = Vector3(1.0, 0.3, 0.1);
154 sph->mtl.roughness = 0.4;
155 scene->add(sph);
157 Box *box = new Box;
158 box->mtl.diffuse = Vector3(0.1, 0.4, 1.0);
159 box->mtl.roughness = 0.9;
160 box->set_position(Vector3(0, -1.1, 0));
161 box->set_scaling(Vector3(4, 0.1, 4));
162 scene->add(box);
164 Light *lt = new Light;
165 lt->set_intensity(0.8);
166 lt->set_position(Vector3(-10, 10, 10));
167 scene->add(lt);
169 Modeller *modeller = new Modeller;
170 if(!modeller->init()) {
171 return false;
172 }
173 add_screen(modeller);
175 Renderer *renderer = new Renderer;
176 if(!renderer->init()) {
177 return false;
178 }
179 add_screen(renderer);
181 activate_screen(modeller); // start the modeller screen
182 return true;
183 }
185 static void cleanup()
186 {
187 delete scene;
188 delete [] fb_pixels;
190 destroy_screens();
192 if(!novideo) {
193 set_text_mode();
194 kb_shutdown();
195 }
196 }
198 static void display()
199 {
200 Screen *scr = active_screen();
201 if(scr) {
202 scr->update();
203 scr->draw();
204 }
206 // draw the mouse cursor
207 if(use_mouse) {
208 draw_cursor(fb_pixels, mouse_x, mouse_y);
209 }
211 if(cap_shot) {
212 screenshot();
213 cap_shot = false;
214 }
216 if(!novideo) {
217 wait_vsync();
218 #ifdef USE_ASM_SWAPBUF
219 swap_buffers_asm(fb, fb_pixels, fb_width, fb_height, fb_bpp);
220 #else
221 swap_buffers();
222 #endif
223 }
224 }
226 #define PACK_RGB(r, g, b) \
227 ((((r) << rshift) & rmask) | \
228 (((g) << gshift) & gmask) | \
229 (((b) << bshift) & bmask))
231 #define UNPACK_RED(c) (((c) >> 16) & 0xff)
232 #define UNPACK_GREEN(c) (((c) >> 8) & 0xff)
233 #define UNPACK_BLUE(c) ((c) & 0xff)
235 static void swap_buffers()
236 {
237 uint32_t *src = fb_pixels;
238 int num_pixels = fb_width * fb_height;
240 switch(fb_bpp) {
241 case 32:
242 memcpy(fb, fb_pixels, num_pixels * 4);
243 break;
245 case 24:
246 {
247 unsigned char *dest = (unsigned char*)fb;
248 for(int i=0; i<num_pixels-1; i++) {
249 *((uint32_t*)dest) = *src++;
250 dest += 3;
251 }
252 *dest++ = UNPACK_RED(*src);
253 *dest++ = UNPACK_GREEN(*src);
254 *dest++ = UNPACK_BLUE(*src);
255 }
256 break;
258 case 16:
259 {
260 uint16_t *dest = (uint16_t*)fb;
261 for(int i=0; i<num_pixels; i++) {
262 uint32_t c = *src++;
263 unsigned char r = UNPACK_RED(c);
264 unsigned char g = UNPACK_GREEN(c);
265 unsigned char b = UNPACK_BLUE(c);
267 *dest++ = (((r) << 8) & 0xf800) |
268 (((g) << 3) & 0x7e0) |
269 (((b) >> 3) & 0x1f);
270 }
271 }
272 break;
274 default:
275 break;
276 }
277 }
279 static void draw_cursor(uint32_t *buf, int mx, int my)
280 {
281 uint32_t *cptr = buf + my * fb_width + mx;
282 int i, cw[2] = {4, 4}, ch[2] = {4, 4};
284 if(mx < cw[0]) cw[0] = mx;
285 if(my < ch[0]) ch[0] = my;
286 if(fb_width - mx < cw[1]) cw[1] = fb_width - mx - 1;
287 if(fb_height - my < ch[1]) ch[1] = fb_height - my - 1;
289 for(i=1; i<cw[0]; i++) {
290 int idx = -i;
291 cptr[idx] = 0xffffff;
292 }
293 for(i=1; i<cw[1]; i++) {
294 int idx = i;
295 cptr[idx] = 0xffffff;
296 }
297 for(i=1; i<ch[0]; i++) {
298 int idx = -i * fb_width;
299 cptr[idx] = 0xffffff;
300 }
301 for(i=1; i<ch[1]; i++) {
302 int idx = i * fb_width;
303 cptr[idx] = 0xffffff;
304 }
305 }
307 #define PPM_COMMENT "screenshot saved by the rayzor modeller/renderer"
308 static void screenshot()
309 {
310 static int shotidx = -1;
311 FILE *fp;
312 char fname[PATH_MAX];
314 if(shotidx == -1) {
315 DIR *dir;
316 struct dirent *dent;
318 shotidx = 0;
319 if((dir = opendir("."))) {
320 while((dent = readdir(dir))) {
321 int i, num;
322 for(i=0; dent->d_name[i]; i++) {
323 fname[i] = tolower(dent->d_name[i]);
324 }
325 fname[i] = 0;
327 if(sscanf(fname, "shot%d.ppm", &num) == 1 && num > shotidx) {
328 shotidx = num;
329 }
330 }
331 closedir(dir);
332 }
333 }
335 sprintf(fname, "shot%04d.ppm", ++shotidx);
336 if(!(fp = fopen(fname, "wb"))) {
337 printlog("failed to save screenshot %s: %s\n", fname, strerror(errno));
338 return;
339 }
341 fprintf(fp, "P6\n# " PPM_COMMENT "\n%d %d\n255\n", fb_width, fb_height);
342 for(int i=0; i<fb_width * fb_height; i++) {
343 uint32_t c = fb_pixels[i];
344 fputc(UNPACK_RED(c), fp);
345 fputc(UNPACK_GREEN(c), fp);
346 fputc(UNPACK_BLUE(c), fp);
347 }
349 fclose(fp);
350 }
352 static void handle_keyboard()
353 {
354 int key;
355 Screen *scr = active_screen();
357 if(novideo) return;
359 while((key = kb_getkey()) != -1) {
360 switch(key) {
361 case '`':
362 use_asm_swap = !use_asm_swap;
363 break;
365 case 'q':
366 case 'x':
367 if(kb_isdown(KB_ALT)) {
368 quit_app();
369 }
370 break;
372 case KB_F12:
373 cap_shot = true;
374 break;
376 default:
377 break;
378 }
379 scr->handle_keyboard(key, true); // TODO also generate release events...
380 }
381 }
383 static void handle_mouse()
384 {
385 static int prev_mx, prev_my, prev_bnmask, bndiff;
386 int mx, my, bnmask;
387 Screen *scr = active_screen();
389 if(!use_mouse || novideo) return;
391 bnmask = read_mouse(&mx, &my);
392 if(scr && (bndiff = bnmask ^ prev_bnmask)) {
393 for(int i=0; i<8; i++) {
394 int bit = 1 << i;
395 if(bndiff & bit) {
396 scr->handle_mbutton(i, bnmask & bit, mx, my);
397 }
398 }
399 }
400 prev_bnmask = bnmask;
402 if(scr && (mx != prev_mx || my != prev_my)) {
403 scr->handle_mmotion(mx, my);
404 }
405 prev_mx = mx;
406 prev_my = my;
408 mouse_x = mx;
409 mouse_y = my;
410 }
413 static struct {
414 int opt;
415 const char *lopt;
416 const char *desc;
417 } options[] = {
418 {'s', "size", "resolution <xres>x<yres>[:bpp]"},
419 {'n', "novid", "don't switch video mode (for debugging)"},
420 {'h', "help", "print usage information and exit"},
421 {-1, 0, 0}
422 };
424 static void print_usage(const char *argv0)
425 {
426 printf("%s usage\n", argv0);
427 for(int i=0; options[i].opt != -1; i++) {
428 printf(" -%c, -%s: %s\n", options[i].opt, options[i].lopt, options[i].desc);
429 }
430 exit(0);
431 }
433 static bool parse_args(int argc, char **argv)
434 {
435 for(int i=1; i<argc; i++) {
436 if(argv[i][0] == '-') {
437 int opt = -1;
439 for(int j=0; options[j].opt != -1; j++) {
440 if(argv[i][2] == 0) {
441 if(argv[i][1] == options[j].opt) {
442 opt = options[j].opt;
443 break;
444 }
445 } else {
446 if(strcmp(argv[i] + 1, options[j].lopt) == 0) {
447 opt = options[j].opt;
448 break;
449 }
450 }
451 }
453 switch(opt) {
454 case 's':
455 if(sscanf(argv[++i], "%dx%d:%d", &fb_width, &fb_height, &fb_bpp) < 2) {
456 fprintf(stderr, "%s must be followed by a resolution: WxH\n", argv[i - 1]);
457 return false;
458 }
459 break;
461 case 'n':
462 novideo = true;
463 break;
465 case 'h':
466 print_usage(argv[0]); // doesn't return
467 break;
469 default:
470 fprintf(stderr, "unknown option: %s\n", argv[i]);
471 return false;
472 }
473 } else {
474 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
475 return false;
476 }
477 }
478 return true;
479 }
481 static void sig(int s)
482 {
483 cleanup();
484 fprintf(stderr, "signal caught: %d\n", s);
486 #ifdef __WATCOM__
487 if(s == SIGFPE) {
488 unsigned int st = _status87();
489 fprintf(stderr, "fpu status: %x\n", st);
490 }
491 #endif
493 exit(1);
494 }