deepstone

changeset 38:17a5107b6fa4

- added perspective correct interpolation - added recording functionality - added video capture functionality
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 10 Mar 2014 17:24:42 +0200
parents e234f2a4b6fa
children f9b1ff21fd62
files GNUmakefile Makefile src/dosemu/dosemu.c src/main.c src/mglrast.c src/mingl.c src/record.c src/record.h src/scantmpl.h src/test.c src/wvga.c src/wvga.h
diffstat 12 files changed, 422 insertions(+), 466 deletions(-) [+]
line diff
     1.1 --- a/GNUmakefile	Mon Sep 23 07:42:56 2013 +0300
     1.2 +++ b/GNUmakefile	Mon Mar 10 17:24:42 2014 +0200
     1.3 @@ -1,4 +1,4 @@
     1.4 -obj = src/main.o \
     1.5 +obj = src/main.o src/record.o \
     1.6  	  src/mingl.o src/mglrast.o src/mglclip.o src/mglgen.o \
     1.7  	  src/texture.o src/palman.o \
     1.8  	  src/scene.o src/cvec.o src/fixedp.o \
     1.9 @@ -7,11 +7,12 @@
    1.10  bin = deepstone
    1.11  
    1.12  dbg = -g
    1.13 -#opt = -O3 -ffast-math
    1.14 +opt = -O3 -ffast-math
    1.15 +def = -DRAST_FLOAT -DDBG_USE_FLOAT -DTEXMAP_PERSP_CORRECT
    1.16  
    1.17  CC = gcc
    1.18 -CFLAGS = -pedantic -Wall $(dbg) $(opt) `pkg-config --cflags sdl` -Isrc -Isrc/dosemu $(add_cflags) -DRAST_FLOAT -DDBG_USE_FLOAT
    1.19 -LDFLAGS = `pkg-config --libs sdl` -lm
    1.20 +CFLAGS = -pedantic -Wall $(dbg) $(opt) `pkg-config --cflags sdl` -Isrc -Isrc/dosemu $(add_cflags) $(def)
    1.21 +LDFLAGS = `pkg-config --libs sdl` -lm -limago
    1.22  #LDFLAGS = -Llib64 -Wl,-rpath=./lib64 -lSDL -lm
    1.23  #LDFLAGS = -m32 -Llib32 -Wl,-rpath=./lib32 -lSDL-1.2 -lm
    1.24  
     2.1 --- a/Makefile	Mon Sep 23 07:42:56 2013 +0300
     2.2 +++ b/Makefile	Mon Mar 10 17:24:42 2014 +0200
     2.3 @@ -1,4 +1,4 @@
     2.4 -obj = main.obj &
     2.5 +obj = main.obj record.obj &
     2.6  	  wvga.obj dpmi.obj timer.obj mouse.obj keyb.obj &
     2.7  	  mingl.obj mglrast.obj mglclip.obj mglgen.obj &
     2.8  	  texture.obj palman.obj scene.obj cvec.obj &
     3.1 --- a/src/dosemu/dosemu.c	Mon Sep 23 07:42:56 2013 +0300
     3.2 +++ b/src/dosemu/dosemu.c	Mon Mar 10 17:24:42 2014 +0200
     3.3 @@ -5,6 +5,7 @@
     3.4  #include <stdlib.h>
     3.5  #include <assert.h>
     3.6  #include <SDL.h>
     3.7 +#include <imago2.h>
     3.8  #include "wvga.h"
     3.9  #include "conio.h"
    3.10  #include "mouse.h"
    3.11 @@ -12,6 +13,7 @@
    3.12  #include "timer.h"
    3.13  
    3.14  static void proc_events(void);
    3.15 +static void capture_frame(unsigned char *frame);
    3.16  
    3.17  static void init_sdl()
    3.18  {
    3.19 @@ -29,6 +31,12 @@
    3.20  /* ----- graphics (wvga.c implementation) ----- */
    3.21  static SDL_Surface *fbsurf;
    3.22  static int scale = 3;
    3.23 +static int frames_to_capture;
    3.24 +
    3.25 +static struct {
    3.26 +	unsigned char r, g, b;
    3.27 +} palette[256];
    3.28 +
    3.29  
    3.30  int set_video_mode(int mode)
    3.31  {
    3.32 @@ -99,6 +107,10 @@
    3.33  	if(SDL_SetPalette(fbsurf, SDL_LOGPAL | SDL_PHYSPAL, &col, idx, 1) != 1) {
    3.34  		fprintf(stderr, "set_palette failed to set the required color\n");
    3.35  	}
    3.36 +
    3.37 +	palette[idx].r = r;
    3.38 +	palette[idx].g = g;
    3.39 +	palette[idx].b = b;
    3.40  }
    3.41  
    3.42  void copy_frame(void *pixels)
    3.43 @@ -130,6 +142,10 @@
    3.44  	}
    3.45  	SDL_Flip(fbsurf);
    3.46  
    3.47 +	if(frames_to_capture > 0) {
    3.48 +		capture_frame(pixels);
    3.49 +		--frames_to_capture;
    3.50 +	}
    3.51  
    3.52  	/* also print fps every second ... */
    3.53  	{
    3.54 @@ -150,10 +166,77 @@
    3.55  	}
    3.56  }
    3.57  
    3.58 +#define spin_delay(ms) \
    3.59 +	do { \
    3.60 +		unsigned int end = SDL_GetTicks() + ms; \
    3.61 +		while((prev_msec = SDL_GetTicks()) < end); \
    3.62 +	} while(0)
    3.63 +
    3.64 +#define FRAME_INTERVAL	(1000/70)
    3.65  void wait_vsync(void)
    3.66  {
    3.67 +	static int prev_msec;
    3.68 +	int msec, dt, tleft;
    3.69 +
    3.70 +	msec = SDL_GetTicks();
    3.71 +
    3.72 +	dt = msec - prev_msec;
    3.73 +
    3.74 +	tleft = FRAME_INTERVAL - dt;
    3.75 +	if(tleft > 0) {
    3.76 +		int coarse = tleft & 0xfffffff8;
    3.77 +		tleft = tleft & 7;
    3.78 +
    3.79 +		if(coarse) {
    3.80 +			SDL_Delay(coarse);
    3.81 +		}
    3.82 +		if(tleft) {
    3.83 +			spin_delay(tleft);
    3.84 +		} else {
    3.85 +			prev_msec = SDL_GetTicks();
    3.86 +		}
    3.87 +	} else {
    3.88 +		prev_msec = msec;
    3.89 +	}
    3.90  }
    3.91  
    3.92 +static int cap_count = 0;
    3.93 +void begin_capture(int frames)
    3.94 +{
    3.95 +	frames_to_capture = frames;
    3.96 +}
    3.97 +
    3.98 +void end_capture(void)
    3.99 +{
   3.100 +	cap_count = 0;
   3.101 +	frames_to_capture = 0;
   3.102 +}
   3.103 +
   3.104 +#define NUMPIX	(320 * 200)
   3.105 +static void capture_frame(unsigned char *frame)
   3.106 +{
   3.107 +	static unsigned char rgbpix[NUMPIX * 4];
   3.108 +	char fname[32];
   3.109 +	int i;
   3.110 +	unsigned char *src, *dest;
   3.111 +
   3.112 +	sprintf(fname, "frame%04d.png", cap_count++);
   3.113 +
   3.114 +	src = frame;
   3.115 +	dest = rgbpix;
   3.116 +
   3.117 +	for(i=0; i<NUMPIX; i++) {
   3.118 +		unsigned char c = *src++;
   3.119 +		*dest++ = palette[c].r;
   3.120 +		*dest++ = palette[c].g;
   3.121 +		*dest++ = palette[c].b;
   3.122 +		*dest++ = 255;
   3.123 +	}
   3.124 +
   3.125 +	img_save_pixels(fname, rgbpix, 320, 200, IMG_FMT_RGBA32);
   3.126 +}
   3.127 +
   3.128 +
   3.129  /* ----- event handling (conio.h) ----- */
   3.130  static SDL_Event *keybev;
   3.131  static int mousex, mousey, bnmask;
     4.1 --- a/src/main.c	Mon Sep 23 07:42:56 2013 +0300
     4.2 +++ b/src/main.c	Mon Mar 10 17:24:42 2014 +0200
     4.3 @@ -1,6 +1,8 @@
     4.4  #include <stdio.h>
     4.5  #include <stdlib.h>
     4.6 +#include <string.h>
     4.7  #include <math.h>
     4.8 +#include <limits.h>
     4.9  #include <signal.h>
    4.10  #include <conio.h>
    4.11  #include "wvga.h"
    4.12 @@ -11,35 +13,46 @@
    4.13  #include "texture.h"
    4.14  #include "palman.h"
    4.15  #include "scene.h"
    4.16 +#include "record.h"
    4.17  
    4.18  #define DEG2RAD(x)	(M_PI * (x) / 180.0)
    4.19  
    4.20  static int init(void);
    4.21  static void shutdown(void);
    4.22 -static void update(unsigned long dtmsec);
    4.23 +static void update(unsigned long msec, unsigned long dtmsec);
    4.24  static void redraw(void);
    4.25  static int proc_events(void);
    4.26  static void mouse_button(int bn, int x, int y);
    4.27  static void mouse_motion(int x, int y);
    4.28  static void sighandler(int s);
    4.29 +static int parse_args(int argc, char **argv);
    4.30  
    4.31  
    4.32  static float cam_x, cam_y, cam_z;
    4.33  static float cam_theta, cam_phi;
    4.34  
    4.35  static float walk_speed = 6.0;
    4.36 -static float look_speed = 1.0;
    4.37 +static float look_speed = 0.3;
    4.38  
    4.39  static int mouse_look = 1;
    4.40 +static int use_vsync;
    4.41  
    4.42  static void *fbuf;
    4.43  static struct scene scn;
    4.44  
    4.45 +#define REC_FNAME	"game.rec"
    4.46 +static int rec_playing, rec_recording;
    4.47 +static unsigned long rec_start_time;
    4.48  
    4.49 -int main(void)
    4.50 +
    4.51 +int main(int argc, char **argv)
    4.52  {
    4.53  	unsigned long prev_msec = 0;
    4.54  
    4.55 +	if(parse_args(argc, argv) == -1) {
    4.56 +		return 1;
    4.57 +	}
    4.58 +
    4.59  	if(init() == -1) {
    4.60  		return 1;
    4.61  	}
    4.62 @@ -53,7 +66,7 @@
    4.63  			break;
    4.64  		}
    4.65  
    4.66 -		update(dt);
    4.67 +		update(msec, dt);
    4.68  		redraw();
    4.69  	}
    4.70  
    4.71 @@ -144,7 +157,7 @@
    4.72  	cam_z -= -sin(angle) * dx + cos(angle) * dy;
    4.73  }
    4.74  
    4.75 -static void update(unsigned long dtmsec)
    4.76 +static void update(unsigned long msec, unsigned long dtmsec)
    4.77  {
    4.78  	float dt = (float)dtmsec / 1000.0f;
    4.79  	float offs = walk_speed * dt;
    4.80 @@ -160,6 +173,21 @@
    4.81  
    4.82  	if(kb_isdown('d') || kb_isdown('D'))
    4.83  		cam_move(offs, 0);
    4.84 +
    4.85 +	if(rec_playing) {
    4.86 +		rec_get(msec - rec_start_time, &cam_x, &cam_y, &cam_z, &cam_theta, &cam_phi);
    4.87 +	} else if(rec_recording) {
    4.88 +		static float px, py, pz, ptheta, pphi;
    4.89 +
    4.90 +		if(cam_x != px || cam_y != py || cam_z != pz || cam_theta != ptheta || cam_phi != pphi) {
    4.91 +			rec_add(msec - rec_start_time, cam_x, cam_y, cam_z, cam_theta, cam_phi);
    4.92 +			px = cam_x;
    4.93 +			py = cam_y;
    4.94 +			pz = cam_z;
    4.95 +			ptheta = cam_theta;
    4.96 +			pphi = cam_phi;
    4.97 +		}
    4.98 +	}
    4.99  }
   4.100  
   4.101  static void redraw(void)
   4.102 @@ -181,6 +209,9 @@
   4.103  	scn_render(&scn);
   4.104  
   4.105  	copy_frame(fbuf);
   4.106 +	if(use_vsync) {
   4.107 +		wait_vsync();
   4.108 +	}
   4.109  }
   4.110  
   4.111  static int proc_events(void)
   4.112 @@ -194,10 +225,66 @@
   4.113  		case 27:
   4.114  			return 0;
   4.115  
   4.116 +		case '\b':
   4.117 +			begin_capture(1);
   4.118 +			break;
   4.119 +		case '\\':
   4.120 +			{
   4.121 +				static int capturing;
   4.122 +				if(capturing) {
   4.123 +					printf("stop video capture\n");
   4.124 +					end_capture();
   4.125 +					capturing = 0;
   4.126 +				} else {
   4.127 +					printf("start video capture\n");
   4.128 +					begin_capture(INT_MAX);
   4.129 +					capturing = 1;
   4.130 +				}
   4.131 +			}
   4.132 +			break;
   4.133 +
   4.134  		case '`':
   4.135  			mouse_look = !mouse_look;
   4.136  			break;
   4.137  
   4.138 +		case 'r':
   4.139 +			if(rec_recording) {
   4.140 +				/* stop recording and save it */
   4.141 +				rec_recording = 0;
   4.142 +				printf("done, saving %s\n", REC_FNAME);
   4.143 +				rec_save(REC_FNAME);
   4.144 +			} else {
   4.145 +				printf("recording ...\n");
   4.146 +				rec_recording = 1;
   4.147 +				rec_playing = 0;
   4.148 +				rec_reset();
   4.149 +				rec_start_time = get_msec();
   4.150 +			}
   4.151 +			break;
   4.152 +
   4.153 +		case 'l':
   4.154 +			printf("loading recording %s\n", REC_FNAME);
   4.155 +			rec_recording = 0;
   4.156 +			rec_playing = 0;
   4.157 +			rec_reset();
   4.158 +			rec_load(REC_FNAME);
   4.159 +			break;
   4.160 +
   4.161 +		case ' ':
   4.162 +			if(rec_recording) {
   4.163 +				break;
   4.164 +			}
   4.165 +
   4.166 +			if(rec_playing) {
   4.167 +				printf("stop rec playback\n");
   4.168 +				rec_playing = 0;
   4.169 +			} else {
   4.170 +				printf("start rec playback\n");
   4.171 +				rec_playing = 1;
   4.172 +				rec_start_time = get_msec();
   4.173 +			}
   4.174 +			break;
   4.175 +
   4.176  		default:
   4.177  			break;
   4.178  		}
   4.179 @@ -285,3 +372,26 @@
   4.180  
   4.181  	exit(1);
   4.182  }
   4.183 +
   4.184 +static int parse_args(int argc, char **argv)
   4.185 +{
   4.186 +	int i;
   4.187 +
   4.188 +	for(i=1; i<argc; i++) {
   4.189 +		if(argv[i][0] == '-') {
   4.190 +			if(strcmp(argv[i], "-vsync") == 0) {
   4.191 +				use_vsync = 1;
   4.192 +			} else {
   4.193 +				goto invalid;
   4.194 +			}
   4.195 +		} else {
   4.196 +			goto invalid;
   4.197 +		}
   4.198 +	}
   4.199 +
   4.200 +	return 0;
   4.201 +
   4.202 +invalid:
   4.203 +	fprintf(stderr, "invalid argument: %s\n", argv[i]);
   4.204 +	return -1;
   4.205 +}
     5.1 --- a/src/mglrast.c	Mon Sep 23 07:42:56 2013 +0300
     5.2 +++ b/src/mglrast.c	Mon Mar 10 17:24:42 2014 +0200
     5.3 @@ -187,6 +187,14 @@
     5.4  	ybeg = fb->height;
     5.5  	yend = 0;
     5.6  
     5.7 +#ifdef TEXMAP_PERSP_CORRECT
     5.8 +	for(i=0; i<numv; i++) {
     5.9 +		v[i].tc.x /= v[i].pos.w;
    5.10 +		v[i].tc.y /= v[i].pos.w;
    5.11 +		v[i].pos.w = 1.0 / v[i].pos.w;
    5.12 +	}
    5.13 +#endif
    5.14 +
    5.15  	for(i=0; i<numv; i++) {
    5.16  		struct vertex *v0 = v + i;
    5.17  		struct vertex *v1 = v + (i + 1) % numv;
     6.1 --- a/src/mingl.c	Mon Sep 23 07:42:56 2013 +0300
     6.2 +++ b/src/mingl.c	Mon Mar 10 17:24:42 2014 +0200
     6.3 @@ -553,6 +553,7 @@
     6.4  	xform[10] = c;
     6.5  	xform[11] = -1.0f;
     6.6  	xform[14] = d;
     6.7 +	xform[15] = 0;
     6.8  
     6.9  	mgl_mult_matrix(xform);
    6.10  }
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/record.c	Mon Mar 10 17:24:42 2014 +0200
     7.3 @@ -0,0 +1,135 @@
     7.4 +#include <stdio.h>
     7.5 +#include <stdlib.h>
     7.6 +#include <string.h>
     7.7 +#include <errno.h>
     7.8 +#include "record.h"
     7.9 +
    7.10 +struct event {
    7.11 +	unsigned long tm;
    7.12 +	float x, y, z;
    7.13 +	float theta, phi;
    7.14 +
    7.15 +	struct event *next;
    7.16 +};
    7.17 +
    7.18 +static struct event *head, *tail;
    7.19 +static struct event *iter;
    7.20 +static int num_events;
    7.21 +
    7.22 +void rec_reset(void)
    7.23 +{
    7.24 +	while(head) {
    7.25 +		iter = head;
    7.26 +		head = head->next;
    7.27 +		free(iter);
    7.28 +	}
    7.29 +	num_events = 0;
    7.30 +}
    7.31 +
    7.32 +int rec_load(const char *fname)
    7.33 +{
    7.34 +	FILE *fp;
    7.35 +	int i;
    7.36 +
    7.37 +	if(!(fp = fopen(fname, "rb"))) {
    7.38 +		fprintf(stderr, "failed to open recording: %s: %s\n", fname, strerror(errno));
    7.39 +		return -1;
    7.40 +	}
    7.41 +	fread(&num_events, sizeof num_events, 1, fp);
    7.42 +
    7.43 +	head = tail = 0;
    7.44 +
    7.45 +	for(i=0; i<num_events; i++) {
    7.46 +		struct event *ev = malloc(sizeof *ev);
    7.47 +		if(!ev) {
    7.48 +			perror("failed to allocate event structure");
    7.49 +			fclose(fp);
    7.50 +			return -1;
    7.51 +		}
    7.52 +		if(fread(ev, sizeof *ev, 1, fp) < 1) {
    7.53 +			perror("unexpected end of file");
    7.54 +			fclose(fp);
    7.55 +			return -1;
    7.56 +		}
    7.57 +
    7.58 +		if(!head) {
    7.59 +			head = tail = ev;
    7.60 +		} else {
    7.61 +			tail->next = ev;
    7.62 +			tail = ev;
    7.63 +		}
    7.64 +		ev->next = 0;
    7.65 +	}
    7.66 +	iter = 0;
    7.67 +
    7.68 +	fclose(fp);
    7.69 +	return 0;
    7.70 +}
    7.71 +
    7.72 +int rec_save(const char *fname)
    7.73 +{
    7.74 +	FILE *fp;
    7.75 +	struct event *ev;
    7.76 +
    7.77 +	if(!(fp = fopen(fname, "wb"))) {
    7.78 +		fprintf(stderr, "failed to open recording: %s: %s\n", fname, strerror(errno));
    7.79 +		return -1;
    7.80 +	}
    7.81 +	fwrite(&num_events, sizeof num_events, 1, fp);
    7.82 +
    7.83 +	ev = head;
    7.84 +	while(ev) {
    7.85 +		fwrite(ev, sizeof *ev, 1, fp);
    7.86 +		ev = ev->next;
    7.87 +	}
    7.88 +
    7.89 +	fclose(fp);
    7.90 +	return 0;
    7.91 +}
    7.92 +
    7.93 +void rec_add(unsigned long tm, float x, float y, float z, float theta, float phi)
    7.94 +{
    7.95 +	struct event *ev = malloc(sizeof *ev);
    7.96 +	if(!ev) {
    7.97 +		fprintf(stderr, "failed to append rec-event: %s\n", strerror(errno));
    7.98 +		return;
    7.99 +	}
   7.100 +	ev->tm = tm;
   7.101 +	ev->x = x;
   7.102 +	ev->y = y;
   7.103 +	ev->z = z;
   7.104 +	ev->theta = theta;
   7.105 +	ev->phi = phi;
   7.106 +
   7.107 +	ev->next = 0;
   7.108 +	if(head) {
   7.109 +		tail->next = ev;
   7.110 +		tail = ev;
   7.111 +	} else {
   7.112 +		head = tail = ev;
   7.113 +	}
   7.114 +
   7.115 +	num_events++;
   7.116 +}
   7.117 +
   7.118 +void rec_get(unsigned long tm, float *x, float *y, float *z, float *theta, float *phi)
   7.119 +{
   7.120 +	if(!iter || iter->tm > tm) {
   7.121 +		iter = head;
   7.122 +	}
   7.123 +
   7.124 +	while(iter && iter->next) {
   7.125 +		if(iter->next->tm > tm) {
   7.126 +			break;
   7.127 +		}
   7.128 +		iter = iter->next;
   7.129 +	}
   7.130 +
   7.131 +	if(iter) {
   7.132 +		*x = iter->x;
   7.133 +		*y = iter->y;
   7.134 +		*z = iter->z;
   7.135 +		*theta = iter->theta;
   7.136 +		*phi = iter->phi;
   7.137 +	}
   7.138 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/record.h	Mon Mar 10 17:24:42 2014 +0200
     8.3 @@ -0,0 +1,11 @@
     8.4 +#ifndef RECORD_H_
     8.5 +#define RECORD_H_
     8.6 +
     8.7 +int rec_load(const char *fname);
     8.8 +int rec_save(const char *fname);
     8.9 +
    8.10 +void rec_reset(void);
    8.11 +void rec_add(unsigned long tm, float x, float y, float z, float theta, float phi);
    8.12 +void rec_get(unsigned long tm, float *x, float *y, float *z, float *theta, float *phi);
    8.13 +
    8.14 +#endif	/* RECORD_H_ */
     9.1 --- a/src/scantmpl.h	Mon Sep 23 07:42:56 2013 +0300
     9.2 +++ b/src/scantmpl.h	Mon Mar 10 17:24:42 2014 +0200
     9.3 @@ -9,6 +9,9 @@
     9.4  	fixed e, de, dfde;
     9.5  #endif
     9.6  #ifdef INTERP_TEX
     9.7 +#ifdef TEXMAP_PERSP_CORRECT
     9.8 +	fixed w, dw, dfdw;
     9.9 +#endif
    9.10  	fixed u, v, du, dv, dfdu, dfdv;
    9.11  #endif
    9.12  	fixed x;
    9.13 @@ -31,6 +34,11 @@
    9.14  	dfde = fixed_div(de, dy);
    9.15  #endif
    9.16  #ifdef INTERP_TEX
    9.17 +#ifdef TEXMAP_PERSP_CORRECT
    9.18 +	dw = v1->pos.w - v0->pos.w;
    9.19 +	dfdw = fixed_div(dw, dy);
    9.20 +#endif
    9.21 +
    9.22  	du = v1->tc.x - v0->tc.x;
    9.23  	dv = v1->tc.y - v0->tc.y;
    9.24  	dfdu = fixed_div(du, dy);
    9.25 @@ -59,6 +67,9 @@
    9.26  		e = v0->energy;
    9.27  #endif
    9.28  #ifdef INTERP_TEX
    9.29 +#ifdef TEXMAP_PERSP_CORRECT
    9.30 +		w = v0->pos.w;
    9.31 +#endif
    9.32  		u = v0->tc.x;
    9.33  		v = v0->tc.y;
    9.34  #endif
    9.35 @@ -73,6 +84,9 @@
    9.36  		e = v0->energy + fixed_mul(dfde, lines);
    9.37  #endif
    9.38  #ifdef INTERP_TEX
    9.39 +#ifdef TEXMAP_PERSP_CORRECT
    9.40 +		w = v0->pos.w + fixed_mul(dfdw, lines);
    9.41 +#endif
    9.42  		u = v0->tc.x + fixed_mul(dfdu, lines);
    9.43  		v = v0->tc.y + fixed_mul(dfdv, lines);
    9.44  #endif
    9.45 @@ -102,6 +116,11 @@
    9.46  #endif
    9.47  
    9.48  #ifdef INTERP_TEX
    9.49 +#ifdef TEXMAP_PERSP_CORRECT
    9.50 +		edge[i].pos.w = w;
    9.51 +		w += dfdw;
    9.52 +#endif
    9.53 +
    9.54  		edge[i].tc.x = u;
    9.55  		edge[i].tc.y = v;
    9.56  		u += dfdu;
    9.57 @@ -126,6 +145,8 @@
    9.58  #ifdef INTERP_TEX
    9.59  	unsigned int tx, ty;
    9.60  	fixed u, v, du, dv, dfdu, dfdv;
    9.61 +	fixed w, dw, dfdw;
    9.62 +	fixed tu, tv;
    9.63  #endif
    9.64  	VERTEX *left, *right;
    9.65  
    9.66 @@ -179,6 +200,12 @@
    9.67  		dfde = fixed_div(de, dx);
    9.68  #endif
    9.69  #ifdef INTERP_TEX
    9.70 +#ifdef TEXMAP_PERSP_CORRECT
    9.71 +		w = left[y].pos.w;
    9.72 +		dw = right[y].pos.w - w;
    9.73 +		dfdw = fixed_div(dw, dx);
    9.74 +#endif
    9.75 +
    9.76  		u = left[y].tc.x;
    9.77  		v = left[y].tc.y;
    9.78  		du = right[y].tc.x - u;
    9.79 @@ -200,6 +227,12 @@
    9.80  		e = left[y].energy + fixed_mul(dfde, dist);
    9.81  #endif
    9.82  #ifdef INTERP_TEX
    9.83 +#ifdef TEXMAP_PERSP_CORRECT
    9.84 +		dw = right[y].pos.w - left[y].pos.w;
    9.85 +		dfdw = fixed_div(dw, dx);
    9.86 +		w = left[y].pos.w + fixed_mul(dfdw, dist);
    9.87 +#endif
    9.88 +
    9.89  		du = right[y].tc.x - left[y].tc.x;
    9.90  		dv = right[y].tc.y - left[y].tc.y;
    9.91  		dfdu = fixed_div(du, dx);
    9.92 @@ -225,13 +258,16 @@
    9.93  		unsigned short *zptr = fb->zbuf[ZTILE(pix)] + ZTILE_OFFS(pix);
    9.94  
    9.95  		if(z < 0 || z >= fixedi(1) || zval > *zptr) {
    9.96 -# ifdef INTERP_TEX
    9.97 +#ifdef INTERP_TEX
    9.98  			u += dfdu;
    9.99  			v += dfdv;
   9.100 -# endif
   9.101 -# ifdef INTERP_ENERGY
   9.102 +#ifdef TEXMAP_PERSP_CORRECT
   9.103 +			w += dfdw;
   9.104 +#endif
   9.105 +#endif	/* INTERP_TEX */
   9.106 +#ifdef INTERP_ENERGY
   9.107  			e += dfde;
   9.108 -# endif
   9.109 +#endif
   9.110  			z += dfdz;
   9.111  			continue;
   9.112  		}
   9.113 @@ -240,13 +276,23 @@
   9.114  		z += dfdz;
   9.115  #endif
   9.116  #ifdef INTERP_TEX
   9.117 -		tx = (unsigned int)fixed_int(fixed_mul(u, fixedi(st->tex.width))) & st->tex.xmask;
   9.118 -		ty = (unsigned int)fixed_int(fixed_mul(v, fixedi(st->tex.height))) & st->tex.ymask;
   9.119 +#ifdef TEXMAP_PERSP_CORRECT
   9.120 +		tu = fixed_div(u, w);
   9.121 +		tv = fixed_div(v, w);
   9.122 +#else
   9.123 +		tu = u;
   9.124 +		tv = v;
   9.125 +#endif
   9.126 +		tx = (unsigned int)fixed_int(fixed_mul(tu, fixedi(st->tex.width))) & st->tex.xmask;
   9.127 +		ty = (unsigned int)fixed_int(fixed_mul(tv, fixedi(st->tex.height))) & st->tex.ymask;
   9.128  		c = st->tex.pixels[(ty << st->tex.xshift) + tx];
   9.129  
   9.130  		u += dfdu;
   9.131  		v += dfdv;
   9.132 +#ifdef TEXMAP_PERSP_CORRECT
   9.133 +		w += dfdw;
   9.134  #endif
   9.135 +#endif	/* INTERP_TEX */
   9.136  #ifdef INTERP_ENERGY
   9.137  		c += fixed_int(fixed_mul(e, fixedi(st->col_range)));
   9.138  		e += dfde;
    10.1 --- a/src/test.c	Mon Sep 23 07:42:56 2013 +0300
    10.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.3 @@ -1,450 +0,0 @@
    10.4 -#include <stdio.h>
    10.5 -#include <stdlib.h>
    10.6 -#include <string.h>
    10.7 -#include <signal.h>
    10.8 -#include <conio.h>
    10.9 -#include "wvga.h"
   10.10 -#include "mingl.h"
   10.11 -#include "timer.h"
   10.12 -#include "mouse.h"
   10.13 -#include "palman.h"
   10.14 -#include "texture.h"
   10.15 -
   10.16 -static int init(void);
   10.17 -static void shutdown(void);
   10.18 -static void redraw(void);
   10.19 -static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx);
   10.20 -static int keyb(char key);
   10.21 -static void mouse_button(int bn, int x, int y);
   10.22 -static void mouse_motion(int x, int y);
   10.23 -static void sighandler(int s);
   10.24 -static int parse_args(int argc, char **argv);
   10.25 -static void print_perf(void);
   10.26 -
   10.27 -static unsigned char *fbuf;
   10.28 -
   10.29 -static struct texture *tex;
   10.30 -static char *texfile;
   10.31 -
   10.32 -static int white_base, red_base, green_base, blue_base;
   10.33 -static int grad_range;
   10.34 -
   10.35 -static int use_vsync = 1;
   10.36 -static int under_windows = 0;
   10.37 -static unsigned long num_frm;
   10.38 -
   10.39 -enum { CUBE, SPHERE, TORUS, NUM_PRIMS };
   10.40 -static int prim = SPHERE;
   10.41 -static int auto_rotate = 1;
   10.42 -static float cam_theta, cam_phi, cam_zoom = 4.0;
   10.43 -
   10.44 -static int mx, my;
   10.45 -
   10.46 -int main(int argc, char **argv)
   10.47 -{
   10.48 -	int mbn, prev_mx = -1, prev_my = -1, prev_mbn = 0;
   10.49 -
   10.50 -	if(parse_args(argc, argv) == -1) {
   10.51 -		return 1;
   10.52 -	}
   10.53 -
   10.54 -	if(init() == -1) {
   10.55 -		return 1;
   10.56 -	}
   10.57 -
   10.58 -	reset_timer();
   10.59 -
   10.60 -	for(;;) {
   10.61 -        if(kbhit()) {
   10.62 -			if(keyb(getch()) == 0) {
   10.63 -				break;
   10.64 -            }
   10.65 -        }
   10.66 -
   10.67 -		mbn = read_mouse(&mx, &my);
   10.68 -		if(mbn != prev_mbn) {
   10.69 -			mouse_button(mbn, mx, my);
   10.70 -			prev_mbn = mbn;
   10.71 -		}
   10.72 -		if(mx != prev_mx || my != prev_my) {
   10.73 -			if(mbn) {
   10.74 -				mouse_motion(mx, my);
   10.75 -			}
   10.76 -			prev_mx = mx;
   10.77 -			prev_my = my;
   10.78 -		}
   10.79 -
   10.80 -		redraw();
   10.81 -	}
   10.82 -
   10.83 -	shutdown();
   10.84 -	print_perf();
   10.85 -	return 0;
   10.86 -}
   10.87 -
   10.88 -static int init(void)
   10.89 -{
   10.90 -	int i;
   10.91 -	struct palm_color *pal;
   10.92 -
   10.93 -	init_timer(under_windows ? 0 : 100);
   10.94 -
   10.95 -	set_video_mode(0x13);
   10.96 -
   10.97 -	signal(SIGINT, sighandler);
   10.98 -	signal(SIGSEGV, sighandler);
   10.99 -	signal(SIGFPE, sighandler);
  10.100 -	signal(SIGILL, sighandler);
  10.101 -	signal(SIGABRT, sighandler);
  10.102 -
  10.103 -	have_mouse();
  10.104 -
  10.105 -
  10.106 -	if(mgl_init(320, 200) == -1) {
  10.107 -		fprintf(stderr, "mgl init failed\n");
  10.108 -		return -1;
  10.109 -	}
  10.110 -	fbuf = mgl_framebuffer();
  10.111 -
  10.112 -
  10.113 -	if(!texfile) {
  10.114 -		palm_add_color(255, 255, 255);
  10.115 -		palm_add_color(255, 0, 0);
  10.116 -		palm_add_color(0, 255, 0);
  10.117 -		palm_add_color(0, 0, 255);
  10.118 -		palm_build();
  10.119 -
  10.120 -		white_base = palm_color_base(255, 255, 255);
  10.121 -		red_base = palm_color_base(255, 0, 0);
  10.122 -		green_base = palm_color_base(0, 255, 0);
  10.123 -		blue_base = palm_color_base(0, 0, 255);
  10.124 -
  10.125 -		tex = tex_gen_checker(64, 64, 3, 3, red_base, blue_base);
  10.126 -	} else {
  10.127 -		if(!(tex = load_texture(texfile))) {
  10.128 -			return -1;
  10.129 -		}
  10.130 -
  10.131 -		palm_build();
  10.132 -		get_texture_pixels(tex);
  10.133 -
  10.134 -		mgl_enable(MGL_TEXTURE_2D);
  10.135 -	}
  10.136 -
  10.137 -	grad_range = palm_color_range();
  10.138 -
  10.139 -	pal = palm_palette();
  10.140 -	for(i=0; i<palm_palette_size(); i++) {
  10.141 -		set_pal_entry(i, pal[i].r, pal[i].g, pal[i].b);
  10.142 -	}
  10.143 -
  10.144 -	mgl_enable(MGL_CULL_FACE);
  10.145 -	mgl_enable(MGL_DEPTH_TEST);
  10.146 -	mgl_enable(MGL_SMOOTH);
  10.147 -	mgl_color_range(grad_range - 1);	/* gradient range */
  10.148 -
  10.149 -	mgl_enable(MGL_LIGHTING);
  10.150 -	mgl_light_intensity(0, 1.0);
  10.151 -	mgl_light_position(0, -0.5, 0.5, 1, 0);
  10.152 -
  10.153 -	mgl_matrix_mode(MGL_PROJECTION);
  10.154 -	mgl_load_identity();
  10.155 -	mgl_perspective(45.0, 320.0 / 200.0, 0.5, 100.0);
  10.156 -
  10.157 -	mgl_teximage(tex->width, tex->height, tex->pixels);
  10.158 -
  10.159 -    return 0;
  10.160 -}
  10.161 -
  10.162 -static void shutdown(void)
  10.163 -{
  10.164 -	mgl_free();
  10.165 -    set_video_mode(3);
  10.166 -}
  10.167 -
  10.168 -static void redraw(void)
  10.169 -{
  10.170 -	float angle = get_msec() / 10.0;
  10.171 -	mgl_clear(0);
  10.172 -	mgl_clear_depth();
  10.173 -
  10.174 -	mgl_matrix_mode(MGL_MODELVIEW);
  10.175 -	mgl_load_identity();
  10.176 -	mgl_translate(0, 0, -cam_zoom);
  10.177 -	if(auto_rotate) {
  10.178 -		mgl_rotate(angle * 0.5, 1, 0, 0);
  10.179 -		mgl_rotate(angle, 0, 0, 1);
  10.180 -	} else {
  10.181 -		mgl_rotate(cam_phi, 1, 0, 0);
  10.182 -		mgl_rotate(cam_theta, 0, 1, 0);
  10.183 -	}
  10.184 -
  10.185 -	switch(prim) {
  10.186 -	case TORUS:
  10.187 -		mgl_index(green_base);
  10.188 -		mgl_torus(1.0, 0.25, 16, 8);
  10.189 -		break;
  10.190 -	case SPHERE:
  10.191 -		mgl_index(blue_base);
  10.192 -		mgl_sphere(1.0, 16, 8);
  10.193 -		break;
  10.194 -	case CUBE:
  10.195 -		mgl_index(red_base);
  10.196 -		mgl_cube(1.0);
  10.197 -	}
  10.198 -
  10.199 -	if(!auto_rotate) {
  10.200 -		draw_cursor(fbuf, 320, 200, mx, my, white_base + grad_range - 1);
  10.201 -	}
  10.202 -
  10.203 -    copy_frame(fbuf);
  10.204 -	if(use_vsync) {
  10.205 -		wait_vsync();
  10.206 -	}
  10.207 -	num_frm++;
  10.208 -}
  10.209 -
  10.210 -static void draw_cursor(unsigned char *fb, int xsz, int ysz, int mx, int my, int cidx)
  10.211 -{
  10.212 -	static char img[] =
  10.213 -		"oo........"
  10.214 -		"oxo......."
  10.215 -		"oxxo......"
  10.216 -		"oxxxo....."
  10.217 -		"oxxxxo...."
  10.218 -		"oxxxxxo..."
  10.219 -		"oxxxxxxo.."
  10.220 -		"oxxxxxxxo."
  10.221 -		"oxxxxxxxxo"
  10.222 -		"oxxxxxoooo"
  10.223 -		"oxxoxxo..."
  10.224 -		"oxo.oxxo.."
  10.225 -		"oo..oxxo.."
  10.226 -		".....oxxo."
  10.227 -		".....oxxo."
  10.228 -		"......oo..";
  10.229 -	int i, j, w = 10, h = 16;
  10.230 -
  10.231 -	if(mx < 0 || my < 0) {
  10.232 -		return;
  10.233 -	}
  10.234 -	if(mx + w >= xsz) {
  10.235 -		w = xsz - mx;
  10.236 -	}
  10.237 -	if(my + h >= ysz) {
  10.238 -		h = ysz - my;
  10.239 -	}
  10.240 -
  10.241 -	fb += my * xsz + mx;
  10.242 -	for(i=0; i<h; i++) {
  10.243 -		for(j=0; j<w; j++) {
  10.244 -			char c = img[(i << 3) + (i << 1) + j];
  10.245 -			if(c != '.') {
  10.246 -				fb[j] = c == 'x' ? 0 : cidx;
  10.247 -			}
  10.248 -		}
  10.249 -		fb += xsz;
  10.250 -	}
  10.251 -}
  10.252 -
  10.253 -static int keyb(char key)
  10.254 -{
  10.255 -	switch(key) {
  10.256 -	case 'q':
  10.257 -	case 27:
  10.258 -		return 0;
  10.259 -
  10.260 -	case 's':
  10.261 -		if(mgl_isenabled(MGL_SMOOTH)) {
  10.262 -			mgl_disable(MGL_SMOOTH);
  10.263 -		} else {
  10.264 -			mgl_enable(MGL_SMOOTH);
  10.265 -		}
  10.266 -		break;
  10.267 -
  10.268 -	case 't':
  10.269 -		if(mgl_isenabled(MGL_TEXTURE_2D)) {
  10.270 -			mgl_disable(MGL_TEXTURE_2D);
  10.271 -		} else {
  10.272 -			mgl_enable(MGL_TEXTURE_2D);
  10.273 -		}
  10.274 -		break;
  10.275 -
  10.276 -	case 'z':
  10.277 -		if(mgl_isenabled(MGL_DEPTH_TEST)) {
  10.278 -			mgl_disable(MGL_DEPTH_TEST);
  10.279 -		} else {
  10.280 -			mgl_enable(MGL_DEPTH_TEST);
  10.281 -		}
  10.282 -		break;
  10.283 -
  10.284 -	case ' ':
  10.285 -		auto_rotate = !auto_rotate;
  10.286 -		break;
  10.287 -
  10.288 -	case 'p':
  10.289 -		prim = (prim + 1) % NUM_PRIMS;
  10.290 -		break;
  10.291 -
  10.292 -	case 'c':
  10.293 -		if(mgl_isenabled(MGL_CULL_FACE)) {
  10.294 -			mgl_disable(MGL_CULL_FACE);
  10.295 -		} else {
  10.296 -			mgl_enable(MGL_CULL_FACE);
  10.297 -		}
  10.298 -		break;
  10.299 -
  10.300 -	default:
  10.301 -		break;
  10.302 -	}
  10.303 -	return 1;
  10.304 -}
  10.305 -
  10.306 -static int bnstate;
  10.307 -static int prev_x, prev_y;
  10.308 -
  10.309 -static void mouse_button(int bn, int x, int y)
  10.310 -{
  10.311 -	bnstate = bn;
  10.312 -	prev_x = x;
  10.313 -	prev_y = y;
  10.314 -}
  10.315 -
  10.316 -static void mouse_motion(int x, int y)
  10.317 -{
  10.318 -	int dx, dy;
  10.319 -
  10.320 -	dx = x - prev_x;
  10.321 -	dy = y - prev_y;
  10.322 -	prev_x = x;
  10.323 -	prev_y = y;
  10.324 -
  10.325 -	if(bnstate & MOUSE_LEFT) {
  10.326 -		cam_theta += dx;
  10.327 -		cam_phi += dy;
  10.328 -
  10.329 -		if(cam_phi > 90) cam_phi = 90;
  10.330 -		if(cam_phi < -90) cam_phi = -90;
  10.331 -	}
  10.332 -	if(bnstate & MOUSE_RIGHT) {
  10.333 -		cam_zoom += dy * 0.1;
  10.334 -		if(cam_zoom < 0.0) {
  10.335 -			cam_zoom = 0.0;
  10.336 -		}
  10.337 -	}
  10.338 -}
  10.339 -
  10.340 -static void sighandler(int s)
  10.341 -{
  10.342 -	set_video_mode(3);
  10.343 -
  10.344 -	switch(s) {
  10.345 -	case SIGABRT:
  10.346 -		fprintf(stderr, "abort\n");
  10.347 -		break;
  10.348 -
  10.349 -	case SIGILL:
  10.350 -		fprintf(stderr, "illegal operation\n");
  10.351 -		break;
  10.352 -
  10.353 -	case SIGSEGV:
  10.354 -		fprintf(stderr, "segmentation fault\n");
  10.355 -		break;
  10.356 -
  10.357 -	case SIGINT:
  10.358 -		fprintf(stderr, "interrupted\n");
  10.359 -		break;
  10.360 -
  10.361 -	case SIGFPE:
  10.362 -		fprintf(stderr, "floating point exception\n");
  10.363 -		break;
  10.364 -
  10.365 -	default:
  10.366 -		fprintf(stderr, "unexpected signal\n");
  10.367 -	}
  10.368 -
  10.369 -	exit(1);
  10.370 -}
  10.371 -
  10.372 -static int parse_args(int argc, char **argv)
  10.373 -{
  10.374 -	int i;
  10.375 -
  10.376 -	for(i=1; i<argc; i++) {
  10.377 -		if(argv[i][0] == '-') {
  10.378 -			if(argv[i][2] != 0) {
  10.379 -				goto invalid;
  10.380 -			}
  10.381 -			switch(argv[i][1]) {
  10.382 -			case 'a':
  10.383 -				auto_rotate = !auto_rotate;
  10.384 -				break;
  10.385 -
  10.386 -			case 't':
  10.387 -				texfile = argv[++i];
  10.388 -				break;
  10.389 -
  10.390 -			case 'v':
  10.391 -				use_vsync = !use_vsync;
  10.392 -				break;
  10.393 -
  10.394 -			case 'p':
  10.395 -				if(strcmp(argv[++i], "cube") == 0) {
  10.396 -					prim = CUBE;
  10.397 -				} else if(strcmp(argv[i], "sphere") == 0) {
  10.398 -					prim = SPHERE;
  10.399 -				} else if(strcmp(argv[i], "torus") == 0) {
  10.400 -					prim = TORUS;
  10.401 -				} else {
  10.402 -					goto invalid;
  10.403 -				}
  10.404 -				break;
  10.405 -
  10.406 -			case 'w':
  10.407 -				under_windows = 1;
  10.408 -				break;
  10.409 -
  10.410 -			case 'h':
  10.411 -				printf("Usage %s [options]\n", argv[0]);
  10.412 -				printf("options:\n");
  10.413 -				printf(" -p  select one of (cube|sphere|torus)\n");
  10.414 -				printf(" -v  use vsync\n");
  10.415 -				printf(" -w  run under windows\n");
  10.416 -				printf(" -h  print usage information and exit\n");
  10.417 -				exit(0);
  10.418 -
  10.419 -			default:
  10.420 -				goto invalid;
  10.421 -			}
  10.422 -		} else {
  10.423 -			goto invalid;
  10.424 -		}
  10.425 -	}
  10.426 -
  10.427 -	return 0;
  10.428 -
  10.429 -invalid:
  10.430 -	fprintf(stderr, "invalid argument: %s\n", argv[i]);
  10.431 -	return -1;
  10.432 -}
  10.433 -
  10.434 -
  10.435 -static void print_perf(void)
  10.436 -{
  10.437 -	unsigned long msec, avg_frame_time;
  10.438 -	float sec, fps;
  10.439 -
  10.440 -	msec = get_msec();
  10.441 -	if(!num_frm || msec < 1000) {
  10.442 -		printf("leaving so soon? (%lu ms)\n", msec);
  10.443 -		return;
  10.444 -	}
  10.445 -
  10.446 -	sec = msec / 1000.0f;
  10.447 -	fps = (float)num_frm / sec;
  10.448 -	avg_frame_time = msec / num_frm;
  10.449 -
  10.450 -	printf("%lu frames in %.2f seconds\n", num_frm, sec);
  10.451 -	printf("  avg. frame time: %lu ms\n", avg_frame_time);
  10.452 -	printf("  avg. framerate: %.2f fps\n", fps);
  10.453 -}
    11.1 --- a/src/wvga.c	Mon Sep 23 07:42:56 2013 +0300
    11.2 +++ b/src/wvga.c	Mon Mar 10 17:24:42 2014 +0200
    11.3 @@ -89,3 +89,11 @@
    11.4  		jz l2
    11.5  	}
    11.6  }
    11.7 +
    11.8 +void begin_capture(int frames)
    11.9 +{
   11.10 +}
   11.11 +
   11.12 +void end_capture(void)
   11.13 +{
   11.14 +}
    12.1 --- a/src/wvga.h	Mon Sep 23 07:42:56 2013 +0300
    12.2 +++ b/src/wvga.h	Mon Mar 10 17:24:42 2014 +0200
    12.3 @@ -9,4 +9,7 @@
    12.4  
    12.5  void wait_vsync(void);
    12.6  
    12.7 +void begin_capture(int frames);
    12.8 +void end_capture(void);
    12.9 +
   12.10  #endif	/* WVGA_H_ */