# HG changeset patch # User John Tsiombikas # Date 1394465082 -7200 # Node ID 17a5107b6fa4ed222e3fb6d555c6debb00b7ccc4 # Parent e234f2a4b6faaa85bee48cf3d42184de273b6cab - added perspective correct interpolation - added recording functionality - added video capture functionality diff -r e234f2a4b6fa -r 17a5107b6fa4 GNUmakefile --- a/GNUmakefile Mon Sep 23 07:42:56 2013 +0300 +++ b/GNUmakefile Mon Mar 10 17:24:42 2014 +0200 @@ -1,4 +1,4 @@ -obj = src/main.o \ +obj = src/main.o src/record.o \ src/mingl.o src/mglrast.o src/mglclip.o src/mglgen.o \ src/texture.o src/palman.o \ src/scene.o src/cvec.o src/fixedp.o \ @@ -7,11 +7,12 @@ bin = deepstone dbg = -g -#opt = -O3 -ffast-math +opt = -O3 -ffast-math +def = -DRAST_FLOAT -DDBG_USE_FLOAT -DTEXMAP_PERSP_CORRECT CC = gcc -CFLAGS = -pedantic -Wall $(dbg) $(opt) `pkg-config --cflags sdl` -Isrc -Isrc/dosemu $(add_cflags) -DRAST_FLOAT -DDBG_USE_FLOAT -LDFLAGS = `pkg-config --libs sdl` -lm +CFLAGS = -pedantic -Wall $(dbg) $(opt) `pkg-config --cflags sdl` -Isrc -Isrc/dosemu $(add_cflags) $(def) +LDFLAGS = `pkg-config --libs sdl` -lm -limago #LDFLAGS = -Llib64 -Wl,-rpath=./lib64 -lSDL -lm #LDFLAGS = -m32 -Llib32 -Wl,-rpath=./lib32 -lSDL-1.2 -lm diff -r e234f2a4b6fa -r 17a5107b6fa4 Makefile --- a/Makefile Mon Sep 23 07:42:56 2013 +0300 +++ b/Makefile Mon Mar 10 17:24:42 2014 +0200 @@ -1,4 +1,4 @@ -obj = main.obj & +obj = main.obj record.obj & wvga.obj dpmi.obj timer.obj mouse.obj keyb.obj & mingl.obj mglrast.obj mglclip.obj mglgen.obj & texture.obj palman.obj scene.obj cvec.obj & diff -r e234f2a4b6fa -r 17a5107b6fa4 src/dosemu/dosemu.c --- a/src/dosemu/dosemu.c Mon Sep 23 07:42:56 2013 +0300 +++ b/src/dosemu/dosemu.c Mon Mar 10 17:24:42 2014 +0200 @@ -5,6 +5,7 @@ #include #include #include +#include #include "wvga.h" #include "conio.h" #include "mouse.h" @@ -12,6 +13,7 @@ #include "timer.h" static void proc_events(void); +static void capture_frame(unsigned char *frame); static void init_sdl() { @@ -29,6 +31,12 @@ /* ----- graphics (wvga.c implementation) ----- */ static SDL_Surface *fbsurf; static int scale = 3; +static int frames_to_capture; + +static struct { + unsigned char r, g, b; +} palette[256]; + int set_video_mode(int mode) { @@ -99,6 +107,10 @@ if(SDL_SetPalette(fbsurf, SDL_LOGPAL | SDL_PHYSPAL, &col, idx, 1) != 1) { fprintf(stderr, "set_palette failed to set the required color\n"); } + + palette[idx].r = r; + palette[idx].g = g; + palette[idx].b = b; } void copy_frame(void *pixels) @@ -130,6 +142,10 @@ } SDL_Flip(fbsurf); + if(frames_to_capture > 0) { + capture_frame(pixels); + --frames_to_capture; + } /* also print fps every second ... */ { @@ -150,10 +166,77 @@ } } +#define spin_delay(ms) \ + do { \ + unsigned int end = SDL_GetTicks() + ms; \ + while((prev_msec = SDL_GetTicks()) < end); \ + } while(0) + +#define FRAME_INTERVAL (1000/70) void wait_vsync(void) { + static int prev_msec; + int msec, dt, tleft; + + msec = SDL_GetTicks(); + + dt = msec - prev_msec; + + tleft = FRAME_INTERVAL - dt; + if(tleft > 0) { + int coarse = tleft & 0xfffffff8; + tleft = tleft & 7; + + if(coarse) { + SDL_Delay(coarse); + } + if(tleft) { + spin_delay(tleft); + } else { + prev_msec = SDL_GetTicks(); + } + } else { + prev_msec = msec; + } } +static int cap_count = 0; +void begin_capture(int frames) +{ + frames_to_capture = frames; +} + +void end_capture(void) +{ + cap_count = 0; + frames_to_capture = 0; +} + +#define NUMPIX (320 * 200) +static void capture_frame(unsigned char *frame) +{ + static unsigned char rgbpix[NUMPIX * 4]; + char fname[32]; + int i; + unsigned char *src, *dest; + + sprintf(fname, "frame%04d.png", cap_count++); + + src = frame; + dest = rgbpix; + + for(i=0; i #include +#include #include +#include #include #include #include "wvga.h" @@ -11,35 +13,46 @@ #include "texture.h" #include "palman.h" #include "scene.h" +#include "record.h" #define DEG2RAD(x) (M_PI * (x) / 180.0) static int init(void); static void shutdown(void); -static void update(unsigned long dtmsec); +static void update(unsigned long msec, unsigned long dtmsec); static void redraw(void); static int proc_events(void); static void mouse_button(int bn, int x, int y); static void mouse_motion(int x, int y); static void sighandler(int s); +static int parse_args(int argc, char **argv); static float cam_x, cam_y, cam_z; static float cam_theta, cam_phi; static float walk_speed = 6.0; -static float look_speed = 1.0; +static float look_speed = 0.3; static int mouse_look = 1; +static int use_vsync; static void *fbuf; static struct scene scn; +#define REC_FNAME "game.rec" +static int rec_playing, rec_recording; +static unsigned long rec_start_time; -int main(void) + +int main(int argc, char **argv) { unsigned long prev_msec = 0; + if(parse_args(argc, argv) == -1) { + return 1; + } + if(init() == -1) { return 1; } @@ -53,7 +66,7 @@ break; } - update(dt); + update(msec, dt); redraw(); } @@ -144,7 +157,7 @@ cam_z -= -sin(angle) * dx + cos(angle) * dy; } -static void update(unsigned long dtmsec) +static void update(unsigned long msec, unsigned long dtmsec) { float dt = (float)dtmsec / 1000.0f; float offs = walk_speed * dt; @@ -160,6 +173,21 @@ if(kb_isdown('d') || kb_isdown('D')) cam_move(offs, 0); + + if(rec_playing) { + rec_get(msec - rec_start_time, &cam_x, &cam_y, &cam_z, &cam_theta, &cam_phi); + } else if(rec_recording) { + static float px, py, pz, ptheta, pphi; + + if(cam_x != px || cam_y != py || cam_z != pz || cam_theta != ptheta || cam_phi != pphi) { + rec_add(msec - rec_start_time, cam_x, cam_y, cam_z, cam_theta, cam_phi); + px = cam_x; + py = cam_y; + pz = cam_z; + ptheta = cam_theta; + pphi = cam_phi; + } + } } static void redraw(void) @@ -181,6 +209,9 @@ scn_render(&scn); copy_frame(fbuf); + if(use_vsync) { + wait_vsync(); + } } static int proc_events(void) @@ -194,10 +225,66 @@ case 27: return 0; + case '\b': + begin_capture(1); + break; + case '\\': + { + static int capturing; + if(capturing) { + printf("stop video capture\n"); + end_capture(); + capturing = 0; + } else { + printf("start video capture\n"); + begin_capture(INT_MAX); + capturing = 1; + } + } + break; + case '`': mouse_look = !mouse_look; break; + case 'r': + if(rec_recording) { + /* stop recording and save it */ + rec_recording = 0; + printf("done, saving %s\n", REC_FNAME); + rec_save(REC_FNAME); + } else { + printf("recording ...\n"); + rec_recording = 1; + rec_playing = 0; + rec_reset(); + rec_start_time = get_msec(); + } + break; + + case 'l': + printf("loading recording %s\n", REC_FNAME); + rec_recording = 0; + rec_playing = 0; + rec_reset(); + rec_load(REC_FNAME); + break; + + case ' ': + if(rec_recording) { + break; + } + + if(rec_playing) { + printf("stop rec playback\n"); + rec_playing = 0; + } else { + printf("start rec playback\n"); + rec_playing = 1; + rec_start_time = get_msec(); + } + break; + default: break; } @@ -285,3 +372,26 @@ exit(1); } + +static int parse_args(int argc, char **argv) +{ + int i; + + for(i=1; iheight; yend = 0; +#ifdef TEXMAP_PERSP_CORRECT + for(i=0; i +#include +#include +#include +#include "record.h" + +struct event { + unsigned long tm; + float x, y, z; + float theta, phi; + + struct event *next; +}; + +static struct event *head, *tail; +static struct event *iter; +static int num_events; + +void rec_reset(void) +{ + while(head) { + iter = head; + head = head->next; + free(iter); + } + num_events = 0; +} + +int rec_load(const char *fname) +{ + FILE *fp; + int i; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "failed to open recording: %s: %s\n", fname, strerror(errno)); + return -1; + } + fread(&num_events, sizeof num_events, 1, fp); + + head = tail = 0; + + for(i=0; inext = ev; + tail = ev; + } + ev->next = 0; + } + iter = 0; + + fclose(fp); + return 0; +} + +int rec_save(const char *fname) +{ + FILE *fp; + struct event *ev; + + if(!(fp = fopen(fname, "wb"))) { + fprintf(stderr, "failed to open recording: %s: %s\n", fname, strerror(errno)); + return -1; + } + fwrite(&num_events, sizeof num_events, 1, fp); + + ev = head; + while(ev) { + fwrite(ev, sizeof *ev, 1, fp); + ev = ev->next; + } + + fclose(fp); + return 0; +} + +void rec_add(unsigned long tm, float x, float y, float z, float theta, float phi) +{ + struct event *ev = malloc(sizeof *ev); + if(!ev) { + fprintf(stderr, "failed to append rec-event: %s\n", strerror(errno)); + return; + } + ev->tm = tm; + ev->x = x; + ev->y = y; + ev->z = z; + ev->theta = theta; + ev->phi = phi; + + ev->next = 0; + if(head) { + tail->next = ev; + tail = ev; + } else { + head = tail = ev; + } + + num_events++; +} + +void rec_get(unsigned long tm, float *x, float *y, float *z, float *theta, float *phi) +{ + if(!iter || iter->tm > tm) { + iter = head; + } + + while(iter && iter->next) { + if(iter->next->tm > tm) { + break; + } + iter = iter->next; + } + + if(iter) { + *x = iter->x; + *y = iter->y; + *z = iter->z; + *theta = iter->theta; + *phi = iter->phi; + } +} diff -r e234f2a4b6fa -r 17a5107b6fa4 src/record.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/record.h Mon Mar 10 17:24:42 2014 +0200 @@ -0,0 +1,11 @@ +#ifndef RECORD_H_ +#define RECORD_H_ + +int rec_load(const char *fname); +int rec_save(const char *fname); + +void rec_reset(void); +void rec_add(unsigned long tm, float x, float y, float z, float theta, float phi); +void rec_get(unsigned long tm, float *x, float *y, float *z, float *theta, float *phi); + +#endif /* RECORD_H_ */ diff -r e234f2a4b6fa -r 17a5107b6fa4 src/scantmpl.h --- a/src/scantmpl.h Mon Sep 23 07:42:56 2013 +0300 +++ b/src/scantmpl.h Mon Mar 10 17:24:42 2014 +0200 @@ -9,6 +9,9 @@ fixed e, de, dfde; #endif #ifdef INTERP_TEX +#ifdef TEXMAP_PERSP_CORRECT + fixed w, dw, dfdw; +#endif fixed u, v, du, dv, dfdu, dfdv; #endif fixed x; @@ -31,6 +34,11 @@ dfde = fixed_div(de, dy); #endif #ifdef INTERP_TEX +#ifdef TEXMAP_PERSP_CORRECT + dw = v1->pos.w - v0->pos.w; + dfdw = fixed_div(dw, dy); +#endif + du = v1->tc.x - v0->tc.x; dv = v1->tc.y - v0->tc.y; dfdu = fixed_div(du, dy); @@ -59,6 +67,9 @@ e = v0->energy; #endif #ifdef INTERP_TEX +#ifdef TEXMAP_PERSP_CORRECT + w = v0->pos.w; +#endif u = v0->tc.x; v = v0->tc.y; #endif @@ -73,6 +84,9 @@ e = v0->energy + fixed_mul(dfde, lines); #endif #ifdef INTERP_TEX +#ifdef TEXMAP_PERSP_CORRECT + w = v0->pos.w + fixed_mul(dfdw, lines); +#endif u = v0->tc.x + fixed_mul(dfdu, lines); v = v0->tc.y + fixed_mul(dfdv, lines); #endif @@ -102,6 +116,11 @@ #endif #ifdef INTERP_TEX +#ifdef TEXMAP_PERSP_CORRECT + edge[i].pos.w = w; + w += dfdw; +#endif + edge[i].tc.x = u; edge[i].tc.y = v; u += dfdu; @@ -126,6 +145,8 @@ #ifdef INTERP_TEX unsigned int tx, ty; fixed u, v, du, dv, dfdu, dfdv; + fixed w, dw, dfdw; + fixed tu, tv; #endif VERTEX *left, *right; @@ -179,6 +200,12 @@ dfde = fixed_div(de, dx); #endif #ifdef INTERP_TEX +#ifdef TEXMAP_PERSP_CORRECT + w = left[y].pos.w; + dw = right[y].pos.w - w; + dfdw = fixed_div(dw, dx); +#endif + u = left[y].tc.x; v = left[y].tc.y; du = right[y].tc.x - u; @@ -200,6 +227,12 @@ e = left[y].energy + fixed_mul(dfde, dist); #endif #ifdef INTERP_TEX +#ifdef TEXMAP_PERSP_CORRECT + dw = right[y].pos.w - left[y].pos.w; + dfdw = fixed_div(dw, dx); + w = left[y].pos.w + fixed_mul(dfdw, dist); +#endif + du = right[y].tc.x - left[y].tc.x; dv = right[y].tc.y - left[y].tc.y; dfdu = fixed_div(du, dx); @@ -225,13 +258,16 @@ unsigned short *zptr = fb->zbuf[ZTILE(pix)] + ZTILE_OFFS(pix); if(z < 0 || z >= fixedi(1) || zval > *zptr) { -# ifdef INTERP_TEX +#ifdef INTERP_TEX u += dfdu; v += dfdv; -# endif -# ifdef INTERP_ENERGY +#ifdef TEXMAP_PERSP_CORRECT + w += dfdw; +#endif +#endif /* INTERP_TEX */ +#ifdef INTERP_ENERGY e += dfde; -# endif +#endif z += dfdz; continue; } @@ -240,13 +276,23 @@ z += dfdz; #endif #ifdef INTERP_TEX - tx = (unsigned int)fixed_int(fixed_mul(u, fixedi(st->tex.width))) & st->tex.xmask; - ty = (unsigned int)fixed_int(fixed_mul(v, fixedi(st->tex.height))) & st->tex.ymask; +#ifdef TEXMAP_PERSP_CORRECT + tu = fixed_div(u, w); + tv = fixed_div(v, w); +#else + tu = u; + tv = v; +#endif + tx = (unsigned int)fixed_int(fixed_mul(tu, fixedi(st->tex.width))) & st->tex.xmask; + ty = (unsigned int)fixed_int(fixed_mul(tv, fixedi(st->tex.height))) & st->tex.ymask; c = st->tex.pixels[(ty << st->tex.xshift) + tx]; u += dfdu; v += dfdv; +#ifdef TEXMAP_PERSP_CORRECT + w += dfdw; #endif +#endif /* INTERP_TEX */ #ifdef INTERP_ENERGY c += fixed_int(fixed_mul(e, fixedi(st->col_range))); e += dfde; diff -r e234f2a4b6fa -r 17a5107b6fa4 src/test.c --- a/src/test.c Mon Sep 23 07:42:56 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,450 +0,0 @@ -#include -#include -#include -#include -#include -#include "wvga.h" -#include "mingl.h" -#include "timer.h" -#include "mouse.h" -#include "palman.h" -#include "texture.h" - -static int init(void); -static void shutdown(void); -static void redraw(void); -static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx); -static int keyb(char key); -static void mouse_button(int bn, int x, int y); -static void mouse_motion(int x, int y); -static void sighandler(int s); -static int parse_args(int argc, char **argv); -static void print_perf(void); - -static unsigned char *fbuf; - -static struct texture *tex; -static char *texfile; - -static int white_base, red_base, green_base, blue_base; -static int grad_range; - -static int use_vsync = 1; -static int under_windows = 0; -static unsigned long num_frm; - -enum { CUBE, SPHERE, TORUS, NUM_PRIMS }; -static int prim = SPHERE; -static int auto_rotate = 1; -static float cam_theta, cam_phi, cam_zoom = 4.0; - -static int mx, my; - -int main(int argc, char **argv) -{ - int mbn, prev_mx = -1, prev_my = -1, prev_mbn = 0; - - if(parse_args(argc, argv) == -1) { - return 1; - } - - if(init() == -1) { - return 1; - } - - reset_timer(); - - for(;;) { - if(kbhit()) { - if(keyb(getch()) == 0) { - break; - } - } - - mbn = read_mouse(&mx, &my); - if(mbn != prev_mbn) { - mouse_button(mbn, mx, my); - prev_mbn = mbn; - } - if(mx != prev_mx || my != prev_my) { - if(mbn) { - mouse_motion(mx, my); - } - prev_mx = mx; - prev_my = my; - } - - redraw(); - } - - shutdown(); - print_perf(); - return 0; -} - -static int init(void) -{ - int i; - struct palm_color *pal; - - init_timer(under_windows ? 0 : 100); - - set_video_mode(0x13); - - signal(SIGINT, sighandler); - signal(SIGSEGV, sighandler); - signal(SIGFPE, sighandler); - signal(SIGILL, sighandler); - signal(SIGABRT, sighandler); - - have_mouse(); - - - if(mgl_init(320, 200) == -1) { - fprintf(stderr, "mgl init failed\n"); - return -1; - } - fbuf = mgl_framebuffer(); - - - if(!texfile) { - palm_add_color(255, 255, 255); - palm_add_color(255, 0, 0); - palm_add_color(0, 255, 0); - palm_add_color(0, 0, 255); - palm_build(); - - white_base = palm_color_base(255, 255, 255); - red_base = palm_color_base(255, 0, 0); - green_base = palm_color_base(0, 255, 0); - blue_base = palm_color_base(0, 0, 255); - - tex = tex_gen_checker(64, 64, 3, 3, red_base, blue_base); - } else { - if(!(tex = load_texture(texfile))) { - return -1; - } - - palm_build(); - get_texture_pixels(tex); - - mgl_enable(MGL_TEXTURE_2D); - } - - grad_range = palm_color_range(); - - pal = palm_palette(); - for(i=0; iwidth, tex->height, tex->pixels); - - return 0; -} - -static void shutdown(void) -{ - mgl_free(); - set_video_mode(3); -} - -static void redraw(void) -{ - float angle = get_msec() / 10.0; - mgl_clear(0); - mgl_clear_depth(); - - mgl_matrix_mode(MGL_MODELVIEW); - mgl_load_identity(); - mgl_translate(0, 0, -cam_zoom); - if(auto_rotate) { - mgl_rotate(angle * 0.5, 1, 0, 0); - mgl_rotate(angle, 0, 0, 1); - } else { - mgl_rotate(cam_phi, 1, 0, 0); - mgl_rotate(cam_theta, 0, 1, 0); - } - - switch(prim) { - case TORUS: - mgl_index(green_base); - mgl_torus(1.0, 0.25, 16, 8); - break; - case SPHERE: - mgl_index(blue_base); - mgl_sphere(1.0, 16, 8); - break; - case CUBE: - mgl_index(red_base); - mgl_cube(1.0); - } - - if(!auto_rotate) { - draw_cursor(fbuf, 320, 200, mx, my, white_base + grad_range - 1); - } - - copy_frame(fbuf); - if(use_vsync) { - wait_vsync(); - } - num_frm++; -} - -static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx) -{ - static char img[] = - "oo........" - "oxo......." - "oxxo......" - "oxxxo....." - "oxxxxo...." - "oxxxxxo..." - "oxxxxxxo.." - "oxxxxxxxo." - "oxxxxxxxxo" - "oxxxxxoooo" - "oxxoxxo..." - "oxo.oxxo.." - "oo..oxxo.." - ".....oxxo." - ".....oxxo." - "......oo.."; - int i, j, w = 10, h = 16; - - if(mx < 0 || my < 0) { - return; - } - if(mx + w >= xsz) { - w = xsz - mx; - } - if(my + h >= ysz) { - h = ysz - my; - } - - fb += my * xsz + mx; - for(i=0; i 90) cam_phi = 90; - if(cam_phi < -90) cam_phi = -90; - } - if(bnstate & MOUSE_RIGHT) { - cam_zoom += dy * 0.1; - if(cam_zoom < 0.0) { - cam_zoom = 0.0; - } - } -} - -static void sighandler(int s) -{ - set_video_mode(3); - - switch(s) { - case SIGABRT: - fprintf(stderr, "abort\n"); - break; - - case SIGILL: - fprintf(stderr, "illegal operation\n"); - break; - - case SIGSEGV: - fprintf(stderr, "segmentation fault\n"); - break; - - case SIGINT: - fprintf(stderr, "interrupted\n"); - break; - - case SIGFPE: - fprintf(stderr, "floating point exception\n"); - break; - - default: - fprintf(stderr, "unexpected signal\n"); - } - - exit(1); -} - -static int parse_args(int argc, char **argv) -{ - int i; - - for(i=1; i