nuclear@1: #include nuclear@1: #include nuclear@1: #include nuclear@7: #include nuclear@14: #include nuclear@17: #include nuclear@14: #include nuclear@1: #include "inttypes.h" nuclear@1: #include "gfx.h" nuclear@1: #include "keyb.h" nuclear@1: #include "mouse.h" nuclear@1: #include "logger.h" nuclear@6: #include "scene.h" nuclear@9: #include "rayzor.h" nuclear@9: #include "screen.h" nuclear@9: #include "modeller.h" nuclear@9: #include "renderer.h" nuclear@9: #include "scrman.h" nuclear@10: #include "timer.h" nuclear@10: nuclear@10: #ifdef __DOS__ nuclear@10: #undef USE_ASM_SWAPBUF nuclear@10: #endif nuclear@10: nuclear@10: #ifdef USE_ASM_SWAPBUF nuclear@10: // defined in swapbuf.asm nuclear@10: extern "C" void swap_buffers_asm(void *dest, void *src, int xsz, int ysz, int bpp); nuclear@10: #endif nuclear@1: nuclear@6: static bool init(); nuclear@6: static void cleanup(); nuclear@1: static void display(); nuclear@1: static void swap_buffers(); nuclear@9: static void draw_cursor(uint32_t *buf, int mx, int my); nuclear@14: static void screenshot(); nuclear@1: static void handle_keyboard(); nuclear@1: static void handle_mouse(); nuclear@1: static bool parse_args(int argc, char **argv); nuclear@7: static void sig(int s); nuclear@1: nuclear@9: uint32_t *fb_pixels; nuclear@9: int fb_width = 640; nuclear@9: int fb_height = 480; nuclear@9: int fb_bpp = 32; nuclear@9: Scene *scene; nuclear@9: nuclear@6: static bool novideo; nuclear@9: static void *fb; nuclear@1: static int rbits, gbits, bbits; nuclear@1: static int rshift, gshift, bshift; nuclear@1: static unsigned int rmask, gmask, bmask; nuclear@1: nuclear@10: static bool use_asm_swap = true; nuclear@7: static bool use_mouse; nuclear@9: static int mouse_x, mouse_y; nuclear@1: static bool quit; nuclear@14: static bool cap_shot; nuclear@1: nuclear@1: int main(int argc, char **argv) nuclear@1: { nuclear@10: unsigned long start_msec, msec; nuclear@10: unsigned long nframes = 0; nuclear@10: nuclear@1: if(!parse_args(argc, argv)) { nuclear@1: return 1; nuclear@1: } nuclear@6: if(!init()) { nuclear@1: return 1; nuclear@1: } nuclear@1: nuclear@10: start_msec = get_msec(); nuclear@10: nuclear@1: // main loop nuclear@1: for(;;) { nuclear@1: handle_keyboard(); nuclear@1: handle_mouse(); nuclear@1: if(quit) break; nuclear@1: nuclear@1: display(); nuclear@10: ++nframes; nuclear@6: nuclear@6: if(novideo) break; nuclear@1: } nuclear@1: nuclear@10: msec = get_msec() - start_msec; nuclear@10: nuclear@6: cleanup(); nuclear@10: nuclear@10: printf("Average framerate: %g\n", (float)nframes / ((float)msec / 1000.0f)); nuclear@1: printf("Thank you for using Rayzor!\n"); nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@9: void quit_app() nuclear@9: { nuclear@9: quit = true; nuclear@9: } nuclear@9: nuclear@6: static bool init() nuclear@6: { nuclear@7: signal(SIGINT, sig); nuclear@7: signal(SIGSEGV, sig); nuclear@7: signal(SIGILL, sig); nuclear@7: signal(SIGFPE, sig); nuclear@7: nuclear@18: #ifdef __WATCOM__ nuclear@17: // mask all fpe except invalid op nuclear@17: _control87(~_EM_INVALID, _MCW_EM); nuclear@18: #endif nuclear@17: nuclear@10: init_timer(128); nuclear@10: nuclear@6: if(!novideo) { nuclear@6: if(kb_init(32) == -1) { nuclear@6: fprintf(stderr, "failed to initialize keyboard driver\n"); nuclear@6: return false; nuclear@6: } nuclear@6: nuclear@9: if(!(fb = set_video_mode(fb_width, fb_height, fb_bpp))) { nuclear@6: set_text_mode(); nuclear@9: fprintf(stderr, "failed to set video mode: %dx%d %dbpp\n", fb_width, fb_height, fb_bpp); nuclear@6: return false; nuclear@6: } nuclear@9: fb_bpp = get_color_depth(); nuclear@6: get_color_bits(&rbits, &gbits, &bbits); nuclear@6: get_color_shift(&rshift, &gshift, &bshift); nuclear@6: get_color_mask(&rmask, &gmask, &bmask); nuclear@6: nuclear@10: printlog("video resolution: %dx%d\n", fb_width, fb_height); nuclear@9: printlog("bpp: %d (%d %d %d)\n", fb_bpp, rbits, gbits, bbits); nuclear@6: printlog("shift: %d %d %d\n", rshift, gshift, bshift); nuclear@6: printlog("mask: %x %x %x\n", rmask, gmask, bmask); nuclear@7: nuclear@7: if(have_mouse()) { nuclear@7: use_mouse = true; nuclear@9: set_mouse_limits(0, 0, fb_width - 1, fb_height - 1); nuclear@7: } nuclear@6: } else { nuclear@6: logger_output(stdout); nuclear@6: printlog("novideo (debug) mode\n"); nuclear@10: fb_bpp = 24; nuclear@6: rbits = gbits = bbits = 8; nuclear@6: } nuclear@6: nuclear@9: fb_pixels = new uint32_t[fb_width * fb_height * 4]; nuclear@9: if(!fb_pixels) { nuclear@6: return false; nuclear@6: } nuclear@6: nuclear@9: scene = new Scene; nuclear@6: nuclear@6: Sphere *sph = new Sphere; nuclear@17: sph->mtl.diffuse = Vector3(1.0, 0.3, 0.1); nuclear@17: sph->mtl.roughness = 0.4; nuclear@12: scene->add(sph); nuclear@12: nuclear@12: Box *box = new Box; nuclear@17: box->mtl.diffuse = Vector3(0.1, 0.4, 1.0); nuclear@17: box->mtl.roughness = 0.9; nuclear@17: box->set_position(Vector3(0, -1.1, 0)); nuclear@17: box->set_scaling(Vector3(4, 0.1, 4)); nuclear@12: scene->add(box); nuclear@17: nuclear@17: Light *lt = new Light; nuclear@17: lt->set_intensity(0.8); nuclear@17: lt->set_position(Vector3(-10, 10, 10)); nuclear@17: scene->add(lt); nuclear@6: nuclear@9: Modeller *modeller = new Modeller; nuclear@9: if(!modeller->init()) { nuclear@9: return false; nuclear@9: } nuclear@9: add_screen(modeller); nuclear@9: nuclear@9: Renderer *renderer = new Renderer; nuclear@9: if(!renderer->init()) { nuclear@9: return false; nuclear@9: } nuclear@9: add_screen(renderer); nuclear@9: nuclear@9: activate_screen(modeller); // start the modeller screen nuclear@6: return true; nuclear@6: } nuclear@6: nuclear@6: static void cleanup() nuclear@6: { nuclear@9: delete scene; nuclear@9: delete [] fb_pixels; nuclear@6: nuclear@9: destroy_screens(); nuclear@6: nuclear@6: if(!novideo) { nuclear@6: set_text_mode(); nuclear@6: kb_shutdown(); nuclear@6: } nuclear@6: } nuclear@6: nuclear@1: static void display() nuclear@1: { nuclear@9: Screen *scr = active_screen(); nuclear@9: if(scr) { nuclear@9: scr->update(); nuclear@9: scr->draw(); nuclear@9: } nuclear@6: nuclear@7: // draw the mouse cursor nuclear@7: if(use_mouse) { nuclear@9: draw_cursor(fb_pixels, mouse_x, mouse_y); nuclear@7: } nuclear@7: nuclear@14: if(cap_shot) { nuclear@14: screenshot(); nuclear@14: cap_shot = false; nuclear@14: } nuclear@14: nuclear@6: if(!novideo) { nuclear@10: wait_vsync(); nuclear@10: #ifdef USE_ASM_SWAPBUF nuclear@10: swap_buffers_asm(fb, fb_pixels, fb_width, fb_height, fb_bpp); nuclear@10: #else nuclear@6: swap_buffers(); nuclear@10: #endif nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: #define PACK_RGB(r, g, b) \ nuclear@1: ((((r) << rshift) & rmask) | \ nuclear@1: (((g) << gshift) & gmask) | \ nuclear@1: (((b) << bshift) & bmask)) nuclear@1: nuclear@11: #define UNPACK_RED(c) (((c) >> 16) & 0xff) nuclear@9: #define UNPACK_GREEN(c) (((c) >> 8) & 0xff) nuclear@11: #define UNPACK_BLUE(c) ((c) & 0xff) nuclear@9: nuclear@1: static void swap_buffers() nuclear@1: { nuclear@9: uint32_t *src = fb_pixels; nuclear@9: int num_pixels = fb_width * fb_height; nuclear@1: nuclear@9: switch(fb_bpp) { nuclear@1: case 32: nuclear@9: memcpy(fb, fb_pixels, num_pixels * 4); nuclear@1: break; nuclear@1: nuclear@1: case 24: nuclear@9: { nuclear@9: unsigned char *dest = (unsigned char*)fb; nuclear@10: for(int i=0; i> 3) & 0x1f); nuclear@1: } nuclear@1: } nuclear@1: break; nuclear@1: nuclear@1: default: nuclear@1: break; nuclear@1: } nuclear@1: } nuclear@1: nuclear@9: static void draw_cursor(uint32_t *buf, int mx, int my) nuclear@7: { nuclear@9: uint32_t *cptr = buf + my * fb_width + mx; nuclear@7: int i, cw[2] = {4, 4}, ch[2] = {4, 4}; nuclear@7: nuclear@7: if(mx < cw[0]) cw[0] = mx; nuclear@7: if(my < ch[0]) ch[0] = my; nuclear@9: if(fb_width - mx < cw[1]) cw[1] = fb_width - mx - 1; nuclear@9: if(fb_height - my < ch[1]) ch[1] = fb_height - my - 1; nuclear@7: nuclear@7: for(i=1; id_name[i]; i++) { nuclear@14: fname[i] = tolower(dent->d_name[i]); nuclear@14: } nuclear@14: fname[i] = 0; nuclear@14: nuclear@14: if(sscanf(fname, "shot%d.ppm", &num) == 1 && num > shotidx) { nuclear@14: shotidx = num; nuclear@14: } nuclear@14: } nuclear@14: closedir(dir); nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: sprintf(fname, "shot%04d.ppm", ++shotidx); nuclear@14: if(!(fp = fopen(fname, "wb"))) { nuclear@14: printlog("failed to save screenshot %s: %s\n", fname, strerror(errno)); nuclear@14: return; nuclear@14: } nuclear@14: nuclear@17: fprintf(fp, "P6\n# " PPM_COMMENT "\n%d %d\n255\n", fb_width, fb_height); nuclear@14: for(int i=0; ihandle_keyboard(key, true); // TODO also generate release events... nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: static void handle_mouse() nuclear@1: { nuclear@9: static int prev_mx, prev_my, prev_bnmask, bndiff; nuclear@9: int mx, my, bnmask; nuclear@9: Screen *scr = active_screen(); nuclear@7: nuclear@7: if(!use_mouse || novideo) return; nuclear@7: nuclear@7: bnmask = read_mouse(&mx, &my); nuclear@9: if(scr && (bndiff = bnmask ^ prev_bnmask)) { nuclear@9: for(int i=0; i<8; i++) { nuclear@9: int bit = 1 << i; nuclear@9: if(bndiff & bit) { nuclear@9: scr->handle_mbutton(i, bnmask & bit, mx, my); nuclear@9: } nuclear@9: } nuclear@7: } nuclear@9: prev_bnmask = bnmask; nuclear@9: nuclear@9: if(scr && (mx != prev_mx || my != prev_my)) { nuclear@9: scr->handle_mmotion(mx, my); nuclear@7: } nuclear@9: prev_mx = mx; nuclear@9: prev_my = my; nuclear@10: nuclear@10: mouse_x = mx; nuclear@10: mouse_y = my; nuclear@7: } nuclear@7: nuclear@1: nuclear@1: static struct { nuclear@1: int opt; nuclear@1: const char *lopt; nuclear@1: const char *desc; nuclear@1: } options[] = { nuclear@1: {'s', "size", "resolution x[:bpp]"}, nuclear@6: {'n', "novid", "don't switch video mode (for debugging)"}, nuclear@1: {'h', "help", "print usage information and exit"}, nuclear@1: {-1, 0, 0} nuclear@1: }; nuclear@1: nuclear@1: static void print_usage(const char *argv0) nuclear@1: { nuclear@1: printf("%s usage\n", argv0); nuclear@1: for(int i=0; options[i].opt != -1; i++) { nuclear@1: printf(" -%c, -%s: %s\n", options[i].opt, options[i].lopt, options[i].desc); nuclear@1: } nuclear@1: exit(0); nuclear@1: } nuclear@1: nuclear@1: static bool parse_args(int argc, char **argv) nuclear@1: { nuclear@1: for(int i=1; i