rayzor

annotate src/main.cc @ 12:d94a69933a71

lots of stuff, can't remember
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 12 Apr 2014 23:28:24 +0300
parents fe94d9e986ae
children a9a948809c6f
rev   line source
nuclear@1 1 #include <stdio.h>
nuclear@1 2 #include <stdlib.h>
nuclear@1 3 #include <string.h>
nuclear@7 4 #include <signal.h>
nuclear@1 5 #include "inttypes.h"
nuclear@1 6 #include "gfx.h"
nuclear@1 7 #include "keyb.h"
nuclear@1 8 #include "mouse.h"
nuclear@1 9 #include "logger.h"
nuclear@6 10 #include "scene.h"
nuclear@9 11 #include "rayzor.h"
nuclear@9 12 #include "screen.h"
nuclear@9 13 #include "modeller.h"
nuclear@9 14 #include "renderer.h"
nuclear@9 15 #include "scrman.h"
nuclear@10 16 #include "timer.h"
nuclear@10 17
nuclear@10 18 #ifdef __DOS__
nuclear@10 19 #undef USE_ASM_SWAPBUF
nuclear@10 20 #endif
nuclear@10 21
nuclear@10 22 #ifdef USE_ASM_SWAPBUF
nuclear@10 23 // defined in swapbuf.asm
nuclear@10 24 extern "C" void swap_buffers_asm(void *dest, void *src, int xsz, int ysz, int bpp);
nuclear@10 25 #endif
nuclear@1 26
nuclear@6 27 static bool init();
nuclear@6 28 static void cleanup();
nuclear@1 29 static void display();
nuclear@1 30 static void swap_buffers();
nuclear@9 31 static void draw_cursor(uint32_t *buf, int mx, int my);
nuclear@1 32 static void handle_keyboard();
nuclear@1 33 static void handle_mouse();
nuclear@1 34 static bool parse_args(int argc, char **argv);
nuclear@7 35 static void sig(int s);
nuclear@1 36
nuclear@9 37 uint32_t *fb_pixels;
nuclear@9 38 int fb_width = 640;
nuclear@9 39 int fb_height = 480;
nuclear@9 40 int fb_bpp = 32;
nuclear@9 41 Scene *scene;
nuclear@9 42
nuclear@6 43 static bool novideo;
nuclear@9 44 static void *fb;
nuclear@1 45 static int rbits, gbits, bbits;
nuclear@1 46 static int rshift, gshift, bshift;
nuclear@1 47 static unsigned int rmask, gmask, bmask;
nuclear@1 48
nuclear@10 49 static bool use_asm_swap = true;
nuclear@7 50 static bool use_mouse;
nuclear@9 51 static int mouse_x, mouse_y;
nuclear@1 52 static bool quit;
nuclear@1 53
nuclear@1 54 int main(int argc, char **argv)
nuclear@1 55 {
nuclear@10 56 unsigned long start_msec, msec;
nuclear@10 57 unsigned long nframes = 0;
nuclear@10 58
nuclear@1 59 if(!parse_args(argc, argv)) {
nuclear@1 60 return 1;
nuclear@1 61 }
nuclear@6 62 if(!init()) {
nuclear@1 63 return 1;
nuclear@1 64 }
nuclear@1 65
nuclear@10 66 start_msec = get_msec();
nuclear@10 67
nuclear@1 68 // main loop
nuclear@1 69 for(;;) {
nuclear@1 70 handle_keyboard();
nuclear@1 71 handle_mouse();
nuclear@1 72 if(quit) break;
nuclear@1 73
nuclear@1 74 display();
nuclear@10 75 ++nframes;
nuclear@6 76
nuclear@6 77 if(novideo) break;
nuclear@1 78 }
nuclear@1 79
nuclear@10 80 msec = get_msec() - start_msec;
nuclear@10 81
nuclear@6 82 cleanup();
nuclear@10 83
nuclear@10 84 printf("Average framerate: %g\n", (float)nframes / ((float)msec / 1000.0f));
nuclear@1 85 printf("Thank you for using Rayzor!\n");
nuclear@1 86 return 0;
nuclear@1 87 }
nuclear@1 88
nuclear@9 89 void quit_app()
nuclear@9 90 {
nuclear@9 91 quit = true;
nuclear@9 92 }
nuclear@9 93
nuclear@6 94 static bool init()
nuclear@6 95 {
nuclear@7 96 signal(SIGINT, sig);
nuclear@7 97 signal(SIGSEGV, sig);
nuclear@7 98 signal(SIGILL, sig);
nuclear@7 99 signal(SIGFPE, sig);
nuclear@7 100
nuclear@10 101 init_timer(128);
nuclear@10 102
nuclear@6 103 if(!novideo) {
nuclear@6 104 if(kb_init(32) == -1) {
nuclear@6 105 fprintf(stderr, "failed to initialize keyboard driver\n");
nuclear@6 106 return false;
nuclear@6 107 }
nuclear@6 108
nuclear@9 109 if(!(fb = set_video_mode(fb_width, fb_height, fb_bpp))) {
nuclear@6 110 set_text_mode();
nuclear@9 111 fprintf(stderr, "failed to set video mode: %dx%d %dbpp\n", fb_width, fb_height, fb_bpp);
nuclear@6 112 return false;
nuclear@6 113 }
nuclear@9 114 fb_bpp = get_color_depth();
nuclear@6 115 get_color_bits(&rbits, &gbits, &bbits);
nuclear@6 116 get_color_shift(&rshift, &gshift, &bshift);
nuclear@6 117 get_color_mask(&rmask, &gmask, &bmask);
nuclear@6 118
nuclear@10 119 printlog("video resolution: %dx%d\n", fb_width, fb_height);
nuclear@9 120 printlog("bpp: %d (%d %d %d)\n", fb_bpp, rbits, gbits, bbits);
nuclear@6 121 printlog("shift: %d %d %d\n", rshift, gshift, bshift);
nuclear@6 122 printlog("mask: %x %x %x\n", rmask, gmask, bmask);
nuclear@7 123
nuclear@7 124 if(have_mouse()) {
nuclear@7 125 use_mouse = true;
nuclear@9 126 set_mouse_limits(0, 0, fb_width - 1, fb_height - 1);
nuclear@7 127 }
nuclear@6 128 } else {
nuclear@6 129 logger_output(stdout);
nuclear@6 130 printlog("novideo (debug) mode\n");
nuclear@10 131 fb_bpp = 24;
nuclear@6 132 rbits = gbits = bbits = 8;
nuclear@6 133 }
nuclear@6 134
nuclear@9 135 fb_pixels = new uint32_t[fb_width * fb_height * 4];
nuclear@9 136 if(!fb_pixels) {
nuclear@6 137 return false;
nuclear@6 138 }
nuclear@6 139
nuclear@9 140 scene = new Scene;
nuclear@6 141
nuclear@6 142 Sphere *sph = new Sphere;
nuclear@12 143 scene->add(sph);
nuclear@12 144
nuclear@12 145 Box *box = new Box;
nuclear@12 146 scene->add(box);
nuclear@12 147 box->set_scaling(Vector3(2, 0.25, 2));
nuclear@6 148
nuclear@9 149 Modeller *modeller = new Modeller;
nuclear@9 150 if(!modeller->init()) {
nuclear@9 151 return false;
nuclear@9 152 }
nuclear@9 153 add_screen(modeller);
nuclear@9 154
nuclear@9 155 Renderer *renderer = new Renderer;
nuclear@9 156 if(!renderer->init()) {
nuclear@9 157 return false;
nuclear@9 158 }
nuclear@9 159 add_screen(renderer);
nuclear@9 160
nuclear@9 161 activate_screen(modeller); // start the modeller screen
nuclear@6 162 return true;
nuclear@6 163 }
nuclear@6 164
nuclear@6 165 static void cleanup()
nuclear@6 166 {
nuclear@9 167 delete scene;
nuclear@9 168 delete [] fb_pixels;
nuclear@6 169
nuclear@9 170 destroy_screens();
nuclear@6 171
nuclear@6 172 if(!novideo) {
nuclear@6 173 set_text_mode();
nuclear@6 174 kb_shutdown();
nuclear@6 175 }
nuclear@6 176 }
nuclear@6 177
nuclear@1 178 static void display()
nuclear@1 179 {
nuclear@9 180 Screen *scr = active_screen();
nuclear@9 181 if(scr) {
nuclear@9 182 scr->update();
nuclear@9 183 scr->draw();
nuclear@9 184 }
nuclear@6 185
nuclear@7 186 // draw the mouse cursor
nuclear@7 187 if(use_mouse) {
nuclear@9 188 draw_cursor(fb_pixels, mouse_x, mouse_y);
nuclear@7 189 }
nuclear@7 190
nuclear@6 191 if(!novideo) {
nuclear@10 192 wait_vsync();
nuclear@10 193 #ifdef USE_ASM_SWAPBUF
nuclear@10 194 swap_buffers_asm(fb, fb_pixels, fb_width, fb_height, fb_bpp);
nuclear@10 195 #else
nuclear@6 196 swap_buffers();
nuclear@10 197 #endif
nuclear@1 198 }
nuclear@1 199 }
nuclear@1 200
nuclear@1 201 #define PACK_RGB(r, g, b) \
nuclear@1 202 ((((r) << rshift) & rmask) | \
nuclear@1 203 (((g) << gshift) & gmask) | \
nuclear@1 204 (((b) << bshift) & bmask))
nuclear@1 205
nuclear@11 206 #define UNPACK_RED(c) (((c) >> 16) & 0xff)
nuclear@9 207 #define UNPACK_GREEN(c) (((c) >> 8) & 0xff)
nuclear@11 208 #define UNPACK_BLUE(c) ((c) & 0xff)
nuclear@9 209
nuclear@1 210 static void swap_buffers()
nuclear@1 211 {
nuclear@9 212 uint32_t *src = fb_pixels;
nuclear@9 213 int num_pixels = fb_width * fb_height;
nuclear@1 214
nuclear@9 215 switch(fb_bpp) {
nuclear@1 216 case 32:
nuclear@9 217 memcpy(fb, fb_pixels, num_pixels * 4);
nuclear@1 218 break;
nuclear@1 219
nuclear@1 220 case 24:
nuclear@9 221 {
nuclear@9 222 unsigned char *dest = (unsigned char*)fb;
nuclear@10 223 for(int i=0; i<num_pixels-1; i++) {
nuclear@10 224 *((uint32_t*)dest) = *src++;
nuclear@10 225 dest += 3;
nuclear@9 226 }
nuclear@10 227 *dest++ = UNPACK_RED(*src);
nuclear@10 228 *dest++ = UNPACK_GREEN(*src);
nuclear@10 229 *dest++ = UNPACK_BLUE(*src);
nuclear@9 230 }
nuclear@1 231 break;
nuclear@1 232
nuclear@1 233 case 16:
nuclear@1 234 {
nuclear@1 235 uint16_t *dest = (uint16_t*)fb;
nuclear@1 236 for(int i=0; i<num_pixels; i++) {
nuclear@9 237 uint32_t c = *src++;
nuclear@9 238 unsigned char r = UNPACK_RED(c);
nuclear@9 239 unsigned char g = UNPACK_GREEN(c);
nuclear@9 240 unsigned char b = UNPACK_BLUE(c);
nuclear@9 241
nuclear@11 242 *dest++ = (((r) << 8) & 0xf800) |
nuclear@11 243 (((g) << 3) & 0x7e0) |
nuclear@11 244 (((b) >> 3) & 0x1f);
nuclear@1 245 }
nuclear@1 246 }
nuclear@1 247 break;
nuclear@1 248
nuclear@1 249 default:
nuclear@1 250 break;
nuclear@1 251 }
nuclear@1 252 }
nuclear@1 253
nuclear@9 254 static void draw_cursor(uint32_t *buf, int mx, int my)
nuclear@7 255 {
nuclear@9 256 uint32_t *cptr = buf + my * fb_width + mx;
nuclear@7 257 int i, cw[2] = {4, 4}, ch[2] = {4, 4};
nuclear@7 258
nuclear@7 259 if(mx < cw[0]) cw[0] = mx;
nuclear@7 260 if(my < ch[0]) ch[0] = my;
nuclear@9 261 if(fb_width - mx < cw[1]) cw[1] = fb_width - mx - 1;
nuclear@9 262 if(fb_height - my < ch[1]) ch[1] = fb_height - my - 1;
nuclear@7 263
nuclear@7 264 for(i=1; i<cw[0]; i++) {
nuclear@9 265 int idx = -i;
nuclear@9 266 cptr[idx] = 0xffffff;
nuclear@7 267 }
nuclear@7 268 for(i=1; i<cw[1]; i++) {
nuclear@9 269 int idx = i;
nuclear@9 270 cptr[idx] = 0xffffff;
nuclear@7 271 }
nuclear@7 272 for(i=1; i<ch[0]; i++) {
nuclear@9 273 int idx = -i * fb_width;
nuclear@9 274 cptr[idx] = 0xffffff;
nuclear@7 275 }
nuclear@7 276 for(i=1; i<ch[1]; i++) {
nuclear@9 277 int idx = i * fb_width;
nuclear@9 278 cptr[idx] = 0xffffff;
nuclear@7 279 }
nuclear@7 280 }
nuclear@7 281
nuclear@1 282 static void handle_keyboard()
nuclear@1 283 {
nuclear@5 284 int key;
nuclear@9 285 Screen *scr = active_screen();
nuclear@1 286
nuclear@6 287 if(novideo) return;
nuclear@6 288
nuclear@5 289 while((key = kb_getkey()) != -1) {
nuclear@10 290 switch(key) {
nuclear@10 291 case '`':
nuclear@10 292 use_asm_swap = !use_asm_swap;
nuclear@10 293 break;
nuclear@10 294
nuclear@12 295 case 'q':
nuclear@12 296 case 'x':
nuclear@12 297 if(kb_isdown(KB_ALT)) {
nuclear@12 298 quit_app();
nuclear@12 299 }
nuclear@12 300 break;
nuclear@12 301
nuclear@10 302 default:
nuclear@10 303 break;
nuclear@10 304 }
nuclear@9 305 scr->handle_keyboard(key, true); // TODO also generate release events...
nuclear@1 306 }
nuclear@1 307 }
nuclear@1 308
nuclear@1 309 static void handle_mouse()
nuclear@1 310 {
nuclear@9 311 static int prev_mx, prev_my, prev_bnmask, bndiff;
nuclear@9 312 int mx, my, bnmask;
nuclear@9 313 Screen *scr = active_screen();
nuclear@7 314
nuclear@7 315 if(!use_mouse || novideo) return;
nuclear@7 316
nuclear@7 317 bnmask = read_mouse(&mx, &my);
nuclear@9 318 if(scr && (bndiff = bnmask ^ prev_bnmask)) {
nuclear@9 319 for(int i=0; i<8; i++) {
nuclear@9 320 int bit = 1 << i;
nuclear@9 321 if(bndiff & bit) {
nuclear@9 322 scr->handle_mbutton(i, bnmask & bit, mx, my);
nuclear@9 323 }
nuclear@9 324 }
nuclear@7 325 }
nuclear@9 326 prev_bnmask = bnmask;
nuclear@9 327
nuclear@9 328 if(scr && (mx != prev_mx || my != prev_my)) {
nuclear@9 329 scr->handle_mmotion(mx, my);
nuclear@7 330 }
nuclear@9 331 prev_mx = mx;
nuclear@9 332 prev_my = my;
nuclear@10 333
nuclear@10 334 mouse_x = mx;
nuclear@10 335 mouse_y = my;
nuclear@7 336 }
nuclear@7 337
nuclear@1 338
nuclear@1 339 static struct {
nuclear@1 340 int opt;
nuclear@1 341 const char *lopt;
nuclear@1 342 const char *desc;
nuclear@1 343 } options[] = {
nuclear@1 344 {'s', "size", "resolution <xres>x<yres>[:bpp]"},
nuclear@6 345 {'n', "novid", "don't switch video mode (for debugging)"},
nuclear@1 346 {'h', "help", "print usage information and exit"},
nuclear@1 347 {-1, 0, 0}
nuclear@1 348 };
nuclear@1 349
nuclear@1 350 static void print_usage(const char *argv0)
nuclear@1 351 {
nuclear@1 352 printf("%s usage\n", argv0);
nuclear@1 353 for(int i=0; options[i].opt != -1; i++) {
nuclear@1 354 printf(" -%c, -%s: %s\n", options[i].opt, options[i].lopt, options[i].desc);
nuclear@1 355 }
nuclear@1 356 exit(0);
nuclear@1 357 }
nuclear@1 358
nuclear@1 359 static bool parse_args(int argc, char **argv)
nuclear@1 360 {
nuclear@1 361 for(int i=1; i<argc; i++) {
nuclear@1 362 if(argv[i][0] == '-') {
nuclear@1 363 int opt = -1;
nuclear@1 364
nuclear@1 365 for(int j=0; options[j].opt != -1; j++) {
nuclear@1 366 if(argv[i][2] == 0) {
nuclear@1 367 if(argv[i][1] == options[j].opt) {
nuclear@1 368 opt = options[j].opt;
nuclear@1 369 break;
nuclear@1 370 }
nuclear@1 371 } else {
nuclear@1 372 if(strcmp(argv[i] + 1, options[j].lopt) == 0) {
nuclear@1 373 opt = options[j].opt;
nuclear@1 374 break;
nuclear@1 375 }
nuclear@1 376 }
nuclear@1 377 }
nuclear@1 378
nuclear@1 379 switch(opt) {
nuclear@1 380 case 's':
nuclear@9 381 if(sscanf(argv[++i], "%dx%d:%d", &fb_width, &fb_height, &fb_bpp) < 2) {
nuclear@1 382 fprintf(stderr, "%s must be followed by a resolution: WxH\n", argv[i - 1]);
nuclear@1 383 return false;
nuclear@1 384 }
nuclear@1 385 break;
nuclear@1 386
nuclear@6 387 case 'n':
nuclear@6 388 novideo = true;
nuclear@6 389 break;
nuclear@6 390
nuclear@1 391 case 'h':
nuclear@1 392 print_usage(argv[0]); // doesn't return
nuclear@1 393 break;
nuclear@1 394
nuclear@1 395 default:
nuclear@1 396 fprintf(stderr, "unknown option: %s\n", argv[i]);
nuclear@1 397 return false;
nuclear@1 398 }
nuclear@1 399 } else {
nuclear@1 400 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
nuclear@1 401 return false;
nuclear@1 402 }
nuclear@1 403 }
nuclear@1 404 return true;
nuclear@1 405 }
nuclear@7 406
nuclear@7 407 static void sig(int s)
nuclear@7 408 {
nuclear@7 409 cleanup();
nuclear@7 410 fprintf(stderr, "signal caught: %d\n", s);
nuclear@9 411 exit(1);
nuclear@7 412 }