nuclear@0: /* nuclear@0: 256-color 3D graphics hack for real-mode DOS. nuclear@0: Copyright (C) 2011 John Tsiombikas nuclear@0: nuclear@0: This program is free software: you can redistribute it and/or modify nuclear@0: it under the terms of the GNU General Public License as published by nuclear@0: the Free Software Foundation, either version 3 of the License, or nuclear@0: (at your option) any later version. nuclear@0: nuclear@0: This program is distributed in the hope that it will be useful, nuclear@0: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@0: GNU General Public License for more details. nuclear@0: nuclear@0: You should have received a copy of the GNU General Public License nuclear@0: along with this program. If not, see . nuclear@0: */ nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "vga.h" nuclear@0: #include "mingl.h" nuclear@0: #include "timer.h" nuclear@0: #include "mouse.h" nuclear@1: #include "palman.h" nuclear@3: #include "texture.h" nuclear@0: nuclear@0: static int init(void); nuclear@0: static void shutdown(void); nuclear@0: static void redraw(void); nuclear@0: static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx); nuclear@0: static int keyb(char key); nuclear@0: static void mouse_button(int bn, int x, int y); nuclear@0: static void mouse_motion(int x, int y); nuclear@0: static void sighandler(int s); nuclear@0: static int parse_args(int argc, char **argv); nuclear@0: static void print_perf(void); nuclear@0: nuclear@0: static unsigned char *fbuf; nuclear@0: nuclear@3: static struct texture *tex; nuclear@4: static char *texfile; nuclear@3: nuclear@1: static int white_base, red_base, green_base, blue_base; nuclear@1: static int grad_range; nuclear@1: nuclear@0: static int use_vsync = 1; nuclear@0: static int under_windows = 0; nuclear@0: static unsigned long num_frm; nuclear@0: nuclear@0: enum { CUBE, SPHERE, TORUS, NUM_PRIMS }; nuclear@0: static int prim = SPHERE; nuclear@0: static int auto_rotate = 1; nuclear@9: static float cam_theta, cam_phi, cam_zoom = 4.0; nuclear@0: nuclear@0: static int mx, my; nuclear@0: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@0: int mbn, prev_mx = -1, prev_my = -1, prev_mbn = 0; nuclear@0: nuclear@0: if(parse_args(argc, argv) == -1) { nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: if(init() == -1) { nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: reset_timer(); nuclear@0: nuclear@0: for(;;) { nuclear@0: if(kbhit()) { nuclear@0: if(keyb(getch()) == 0) { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: mbn = read_mouse(&mx, &my); nuclear@0: if(mbn != prev_mbn) { nuclear@0: mouse_button(mbn, mx, my); nuclear@0: prev_mbn = mbn; nuclear@0: } nuclear@0: if(mx != prev_mx || my != prev_my) { nuclear@0: if(mbn) { nuclear@0: mouse_motion(mx, my); nuclear@0: } nuclear@0: prev_mx = mx; nuclear@0: prev_my = my; nuclear@0: } nuclear@0: nuclear@0: redraw(); nuclear@0: } nuclear@0: nuclear@0: shutdown(); nuclear@0: print_perf(); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static int init(void) nuclear@0: { nuclear@0: int i; nuclear@1: struct palm_color *pal; nuclear@0: nuclear@0: init_timer(under_windows ? 0 : 100); nuclear@0: nuclear@0: set_video_mode(0x13); nuclear@0: nuclear@0: signal(SIGINT, sighandler); nuclear@0: signal(SIGSEGV, sighandler); nuclear@0: signal(SIGFPE, sighandler); nuclear@0: signal(SIGILL, sighandler); nuclear@0: signal(SIGABRT, sighandler); nuclear@0: nuclear@10: have_mouse(); nuclear@10: nuclear@1: nuclear@4: if(mgl_init(320, 200) == -1) { nuclear@4: fprintf(stderr, "mgl init failed\n"); nuclear@4: return -1; nuclear@4: } nuclear@4: fbuf = mgl_framebuffer(); nuclear@4: nuclear@4: nuclear@4: if(!texfile) { nuclear@4: palm_add_color(255, 255, 255); nuclear@4: palm_add_color(255, 0, 0); nuclear@4: palm_add_color(0, 255, 0); nuclear@4: palm_add_color(0, 0, 255); nuclear@4: palm_build(); nuclear@4: nuclear@4: white_base = palm_color_base(255, 255, 255); nuclear@4: red_base = palm_color_base(255, 0, 0); nuclear@4: green_base = palm_color_base(0, 255, 0); nuclear@4: blue_base = palm_color_base(0, 0, 255); nuclear@4: nuclear@4: tex = tex_gen_checker(64, 64, 3, 3, red_base, blue_base); nuclear@4: } else { nuclear@4: if(!(tex = load_texture(texfile))) { nuclear@4: return -1; nuclear@4: } nuclear@4: nuclear@4: palm_build(); nuclear@4: get_texture_pixels(tex); nuclear@4: nuclear@4: mgl_enable(MGL_TEXTURE_2D); nuclear@4: } nuclear@4: nuclear@1: grad_range = palm_color_range(); nuclear@1: nuclear@1: pal = palm_palette(); nuclear@1: for(i=0; iwidth, tex->height, tex->pixels); nuclear@3: nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static void shutdown(void) nuclear@0: { nuclear@0: mgl_free(); nuclear@0: set_video_mode(3); nuclear@0: } nuclear@0: nuclear@0: static void redraw(void) nuclear@0: { nuclear@0: float angle = get_msec() / 10.0; nuclear@0: mgl_clear(0); nuclear@9: mgl_clear_depth(); nuclear@0: nuclear@0: mgl_matrix_mode(MGL_MODELVIEW); nuclear@0: mgl_load_identity(); nuclear@18: mgl_translate(0, 0, -cam_zoom); nuclear@0: if(auto_rotate) { nuclear@18: mgl_rotate(angle * 0.5, 1, 0, 0); nuclear@0: mgl_rotate(angle, 0, 0, 1); nuclear@0: } else { nuclear@18: mgl_rotate(cam_phi, 1, 0, 0); nuclear@0: mgl_rotate(cam_theta, 0, 1, 0); nuclear@0: } nuclear@0: nuclear@0: switch(prim) { nuclear@0: case TORUS: nuclear@1: mgl_index(green_base); nuclear@0: mgl_torus(1.0, 0.25, 16, 8); nuclear@0: break; nuclear@0: case SPHERE: nuclear@1: mgl_index(blue_base); nuclear@0: mgl_sphere(1.0, 16, 8); nuclear@0: break; nuclear@0: case CUBE: nuclear@1: mgl_index(red_base); nuclear@0: mgl_cube(1.0); nuclear@0: } nuclear@0: nuclear@0: if(!auto_rotate) { nuclear@1: draw_cursor(fbuf, 320, 200, mx, my, white_base + grad_range - 1); nuclear@0: } nuclear@0: nuclear@0: copy_frame(fbuf); nuclear@0: if(use_vsync) { nuclear@0: wait_vsync(); nuclear@0: } nuclear@0: num_frm++; nuclear@0: } nuclear@0: nuclear@0: static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx) nuclear@0: { nuclear@0: static char img[] = nuclear@0: "oo........" nuclear@0: "oxo......." nuclear@0: "oxxo......" nuclear@0: "oxxxo....." nuclear@0: "oxxxxo...." nuclear@0: "oxxxxxo..." nuclear@0: "oxxxxxxo.." nuclear@0: "oxxxxxxxo." nuclear@0: "oxxxxxxxxo" nuclear@0: "oxxxxxoooo" nuclear@0: "oxxoxxo..." nuclear@0: "oxo.oxxo.." nuclear@0: "oo..oxxo.." nuclear@0: ".....oxxo." nuclear@0: ".....oxxo." nuclear@0: "......oo.."; nuclear@0: int i, j, w = 10, h = 16; nuclear@0: nuclear@0: if(mx < 0 || my < 0) { nuclear@0: return; nuclear@0: } nuclear@0: if(mx + w >= xsz) { nuclear@0: w = xsz - mx; nuclear@0: } nuclear@0: if(my + h >= ysz) { nuclear@0: h = ysz - my; nuclear@0: } nuclear@0: nuclear@0: fb += my * xsz + mx; nuclear@0: for(i=0; i 90) cam_phi = 90; nuclear@0: if(cam_phi < -90) cam_phi = -90; nuclear@0: } nuclear@9: if(bnstate & MOUSE_RIGHT) { nuclear@9: cam_zoom += dy * 0.1; nuclear@9: if(cam_zoom < 0.0) { nuclear@9: cam_zoom = 0.0; nuclear@9: } nuclear@9: } nuclear@0: } nuclear@0: nuclear@0: static void sighandler(int s) nuclear@0: { nuclear@0: set_video_mode(3); nuclear@0: nuclear@0: switch(s) { nuclear@0: case SIGABRT: nuclear@0: fprintf(stderr, "abort\n"); nuclear@0: break; nuclear@0: nuclear@0: case SIGILL: nuclear@0: fprintf(stderr, "illegal operation\n"); nuclear@0: break; nuclear@0: nuclear@0: case SIGSEGV: nuclear@0: fprintf(stderr, "segmentation fault\n"); nuclear@0: break; nuclear@0: nuclear@0: case SIGINT: nuclear@0: fprintf(stderr, "interrupted\n"); nuclear@0: break; nuclear@0: nuclear@0: case SIGFPE: nuclear@0: fprintf(stderr, "floating point exception\n"); nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: fprintf(stderr, "unexpected signal\n"); nuclear@0: } nuclear@0: nuclear@0: exit(1); nuclear@0: } nuclear@0: nuclear@0: static int parse_args(int argc, char **argv) nuclear@0: { nuclear@0: int i; nuclear@0: nuclear@0: for(i=1; i