deepstone

changeset 28:11d14f688485

added clipping
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 22 Sep 2013 06:38:08 +0300
parents dcfe615c4c5f
children 5fa2983bfe61
files Makefile dosemu/dosemu.c src/main.c src/mglclip.c src/mglimpl.h src/mglrast.c src/mingl.c src/mingl.h src/scantmpl.h src/test.c src/vmath.h
diffstat 11 files changed, 403 insertions(+), 90 deletions(-) [+]
line diff
     1.1 --- a/Makefile	Sun Sep 22 02:47:46 2013 +0300
     1.2 +++ b/Makefile	Sun Sep 22 06:38:08 2013 +0300
     1.3 @@ -1,5 +1,5 @@
     1.4  obj = src/main.o \
     1.5 -	  src/mingl.o src/mglrast.o src/mglgen.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  	  dosemu/dosemu.o
    1.10 @@ -7,8 +7,7 @@
    1.11  bin = deepstone
    1.12  
    1.13  CC = gcc
    1.14 -CFLAGS = -pedantic -Wall -g `pkg-config --cflags sdl` -Isrc -Idosemu
    1.15 -#-DRAST_FLOAT -DDBG_USE_FLOAT
    1.16 +CFLAGS = -pedantic -Wall -g `pkg-config --cflags sdl` -Isrc -Idosemu -DRAST_FLOAT -DDBG_USE_FLOAT
    1.17  LDFLAGS = `pkg-config --libs sdl` -lm
    1.18  
    1.19  $(bin): $(obj)
     2.1 --- a/dosemu/dosemu.c	Sun Sep 22 02:47:46 2013 +0300
     2.2 +++ b/dosemu/dosemu.c	Sun Sep 22 06:38:08 2013 +0300
     2.3 @@ -14,19 +14,27 @@
     2.4  
     2.5  /* ----- graphics (wvga.c implementation) ----- */
     2.6  static SDL_Surface *fbsurf;
     2.7 -
     2.8 -#define DOUBLESZ	(fbsurf->w != 320)
     2.9 +static int scale = 1;
    2.10  
    2.11  int set_video_mode(int mode)
    2.12  {
    2.13  	int resx = 320, resy = 200;
    2.14  	unsigned int sdl_flags = SDL_HWPALETTE;
    2.15 +	char *env;
    2.16  
    2.17  	if(getenv("DOSEMU_DOUBLESIZE")) {
    2.18 -		resx *= 2;
    2.19 -		resy *= 2;
    2.20 +		scale = 2;
    2.21  	}
    2.22  
    2.23 +	if((env = getenv("DOSEMU_SCALE"))) {
    2.24 +		int n = atoi(env);
    2.25 +		if(n > 0) {
    2.26 +			scale = n;
    2.27 +		}
    2.28 +	}
    2.29 +	resx *= scale;
    2.30 +	resy *= scale;
    2.31 +
    2.32  	if(getenv("DOSEMU_FULLSCREEN")) {
    2.33  		sdl_flags |= SDL_FULLSCREEN;
    2.34  	}
    2.35 @@ -39,7 +47,7 @@
    2.36  			abort();
    2.37  		}
    2.38  		SDL_WM_SetCaption("Deepstone", 0);
    2.39 -		SDL_ShowCursor(0);
    2.40 +		/*SDL_ShowCursor(0);*/
    2.41  		SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
    2.42  		break;
    2.43  
    2.44 @@ -86,17 +94,17 @@
    2.45  		SDL_LockSurface(fbsurf);
    2.46  	}
    2.47  
    2.48 -	if(DOUBLESZ) {
    2.49 -		int i, j;
    2.50 -		Uint16 *dest = fbsurf->pixels;
    2.51 +	if(scale > 1) {
    2.52 +		int i, j, xsz, ysz;
    2.53 +		unsigned char *dest = fbsurf->pixels;
    2.54  
    2.55 -		for(i=0; i<200; i++) {
    2.56 -			for(j=0; j<320; j++) {
    2.57 -				Uint16 twopix = ((Uint16)*frame << 8) | (Uint16)*frame;
    2.58 -				dest[j] = dest[j + 320] = twopix;
    2.59 -				frame++;
    2.60 +		xsz = 320 * scale;
    2.61 +		ysz = 200 * scale;
    2.62 +
    2.63 +		for(i=0; i<ysz; i++) {
    2.64 +			for(j=0; j<xsz; j++) {
    2.65 +				*dest++ = frame[(i / scale) * 320 + (j / scale)];
    2.66  			}
    2.67 -			dest += fbsurf->pitch;
    2.68  		}
    2.69  	} else {
    2.70  		memcpy(fbsurf->pixels, frame, 64000);
    2.71 @@ -163,13 +171,8 @@
    2.72  			return;
    2.73  
    2.74  		case SDL_MOUSEMOTION:
    2.75 -			mousex = ev.motion.x;
    2.76 -			mousey = ev.motion.y;
    2.77 -
    2.78 -			if(DOUBLESZ) {
    2.79 -				mousex /= 2;
    2.80 -				mousey /= 2;
    2.81 -			}
    2.82 +			mousex = ev.motion.x / scale;
    2.83 +			mousey = ev.motion.y / scale;
    2.84  			break;
    2.85  
    2.86  		case SDL_MOUSEBUTTONDOWN:
     3.1 --- a/src/main.c	Sun Sep 22 02:47:46 2013 +0300
     3.2 +++ b/src/main.c	Sun Sep 22 06:38:08 2013 +0300
     3.3 @@ -51,6 +51,12 @@
     3.4  
     3.5  static int init(void)
     3.6  {
     3.7 +	float vfov, hfov, aspect;
     3.8 +
     3.9 +	aspect = 320.0 / 200.0;
    3.10 +	vfov = 60.0;
    3.11 +	hfov = vfov * aspect;
    3.12 +
    3.13  	init_timer(100);
    3.14  
    3.15  	set_video_mode(0x13);
    3.16 @@ -74,7 +80,18 @@
    3.17  
    3.18  	mgl_matrix_mode(MGL_PROJECTION);
    3.19  	mgl_load_identity();
    3.20 -	mgl_perspective(45.0, 320.0 / 200.0, 0.5, 200.0);
    3.21 +	mgl_perspective(vfov, aspect, 0.5, 200.0);
    3.22 +
    3.23 +#if 0
    3.24 +	mgl_enable(MGL_CLIP_PLANE0);
    3.25 +	mgl_enable(MGL_CLIP_PLANE1);
    3.26 +	mgl_enable(MGL_CLIP_PLANE2);
    3.27 +	mgl_enable(MGL_CLIP_PLANE3);
    3.28 +	mgl_clip_plane(MGL_CLIP_PLANE0, -1, 0, -1, 0);	/* positive X */
    3.29 +	mgl_clip_plane(MGL_CLIP_PLANE1, 1, 0, -1, 0);	/* negative X */
    3.30 +	mgl_clip_plane(MGL_CLIP_PLANE2, 0, -1, -0.5, 0);	/* positive Y */
    3.31 +	mgl_clip_plane(MGL_CLIP_PLANE3, 0, 1, -0.5, 0);	/* negative Y */
    3.32 +#endif
    3.33  
    3.34  	/* setup palette */
    3.35  	palm_add_color(255, 255, 255);
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/mglclip.c	Sun Sep 22 06:38:08 2013 +0300
     4.3 @@ -0,0 +1,189 @@
     4.4 +#include <stdio.h>
     4.5 +#include <string.h>
     4.6 +#include <assert.h>
     4.7 +#include "mingl.h"
     4.8 +#include "mglimpl.h"
     4.9 +
    4.10 +static struct state *st;
    4.11 +
    4.12 +static float distance_signed(vec3_t p, const struct plane *plane);
    4.13 +static int intersect(const ray3_t *ray, const struct plane *plane, float *t);
    4.14 +static int clip_polygon(struct vertex *vout, int *voutnum, const struct vertex *vin, int vnum,
    4.15 +		const struct plane *plane);
    4.16 +
    4.17 +#define ZNEAR	MAX_CLIP_PLANES
    4.18 +
    4.19 +int mgl_clip_init(struct state *state)
    4.20 +{
    4.21 +	st = state;
    4.22 +
    4.23 +	memset(st->clip_planes, 0, sizeof st->clip_planes);
    4.24 +
    4.25 +	/* always setup a near clipping plane */
    4.26 +	st->clip_planes[ZNEAR].normal.x = st->clip_planes[ZNEAR].normal.y = 0;
    4.27 +	st->clip_planes[ZNEAR].normal.z = -1;
    4.28 +	st->clip_planes[ZNEAR].pt.x = st->clip_planes[ZNEAR].pt.y = 0;
    4.29 +	st->clip_planes[ZNEAR].pt.z = -0.5;
    4.30 +
    4.31 +	return 0;
    4.32 +}
    4.33 +
    4.34 +int mgl_clip_poly(struct vertex *v, int vnum)
    4.35 +{
    4.36 +	int i, res, clipped_vnum;
    4.37 +	struct vertex tmp[6];
    4.38 +
    4.39 +	for(i=0; i<MAX_CLIP_PLANES + 1; i++) {
    4.40 +		if(i < ZNEAR && !mgl_isenabled(MGL_CLIP_PLANE0 + i)) {
    4.41 +			continue;
    4.42 +		}
    4.43 +
    4.44 +		res = clip_polygon(tmp, &clipped_vnum, v, vnum, st->clip_planes + i);
    4.45 +		if(res == -1) {
    4.46 +			/* the polygon was completely outside */
    4.47 +			return 0;
    4.48 +		}
    4.49 +		if(res == 0) {
    4.50 +			/* the polygon was clipped, update v and vnum */
    4.51 +			vnum = clipped_vnum;
    4.52 +			memcpy(v, tmp, clipped_vnum * sizeof *v);
    4.53 +		}
    4.54 +		/* otherwise the polygon was completely inside, nothing to do... */
    4.55 +	}
    4.56 +
    4.57 +	return vnum;
    4.58 +}
    4.59 +
    4.60 +static float distance_signed(vec3_t p, const struct plane *plane)
    4.61 +{
    4.62 +	vec3_t ptdir;
    4.63 +	ptdir.x = p.x - plane->pt.x;
    4.64 +	ptdir.y = p.y - plane->pt.y;
    4.65 +	ptdir.z = p.z - plane->pt.z;
    4.66 +
    4.67 +	return vec3_dot(ptdir, plane->normal);
    4.68 +}
    4.69 +
    4.70 +static int intersect(const ray3_t *ray, const struct plane *plane, float *t)
    4.71 +{
    4.72 +	vec3_t orig_pt_dir;
    4.73 +
    4.74 +	float ndotdir = vec3_dot(plane->normal, ray->dir);
    4.75 +	if(fabs(ndotdir) < 1e-4) {
    4.76 +		*t = 0.0f;
    4.77 +		return 0;
    4.78 +	}
    4.79 +
    4.80 +	orig_pt_dir.x = plane->pt.x - ray->origin.x;
    4.81 +	orig_pt_dir.y = plane->pt.y - ray->origin.y;
    4.82 +	orig_pt_dir.z = plane->pt.z - ray->origin.z;
    4.83 +
    4.84 +	*t = vec3_dot(plane->normal, orig_pt_dir) / ndotdir;
    4.85 +	return 1;
    4.86 +}
    4.87 +
    4.88 +static int clip_edge(struct vertex *poly, int *vnum, const struct vertex *v0,
    4.89 +		const struct vertex *v1, const struct plane *plane);
    4.90 +
    4.91 +/* returns:
    4.92 + *  1 -> both inside
    4.93 + *  0 -> straddling and clipped
    4.94 + * -1 -> both outside
    4.95 + *
    4.96 + * the size of the vout polygon is returned throug voutnum
    4.97 + */
    4.98 +static int clip_polygon(struct vertex *vout, int *voutnum, const struct vertex *vin, int vnum,
    4.99 +		const struct plane *plane)
   4.100 +{
   4.101 +	int i;
   4.102 +	int edges_clipped = 0;
   4.103 +	int out_vnum = 0;
   4.104 +
   4.105 +	for(i=0; i<vnum; i++) {
   4.106 +		int res = clip_edge(vout, &out_vnum, vin + i, vin + (i + 1) % vnum, plane);
   4.107 +		if(res == 0) {
   4.108 +			edges_clipped++;
   4.109 +		}
   4.110 +	}
   4.111 +
   4.112 +	if(out_vnum <= 0) {
   4.113 +		assert(edges_clipped == 0);
   4.114 +		return -1;
   4.115 +	}
   4.116 +
   4.117 +	*voutnum = out_vnum;
   4.118 +	return edges_clipped > 0 ? 0 : 1;
   4.119 +}
   4.120 +
   4.121 +/* returns:
   4.122 + *  1 -> both inside
   4.123 + *  0 -> straddling and clipped
   4.124 + * -1 -> both outside
   4.125 + *
   4.126 + *  also returns the size of the polygon through vnumptr
   4.127 + */
   4.128 +static int clip_edge(struct vertex *poly, int *vnumptr, const struct vertex *v0,
   4.129 +		const struct vertex *v1, const struct plane *plane)
   4.130 +{
   4.131 +	vec3_t pos0, pos1;
   4.132 +	float d0, d1, t;
   4.133 +	ray3_t ray;
   4.134 +	int vnum = *vnumptr;
   4.135 +
   4.136 +	pos0.x = v0->pos.x; pos0.y = v0->pos.y; pos0.z = v0->pos.z;
   4.137 +	pos1.x = v1->pos.x; pos1.y = v1->pos.y; pos1.z = v1->pos.z;
   4.138 +
   4.139 +	d0 = distance_signed(pos0, plane);
   4.140 +	d1 = distance_signed(pos1, plane);
   4.141 +
   4.142 +	ray.origin = pos0;
   4.143 +	ray.dir.x = pos1.x - pos0.x;
   4.144 +	ray.dir.y = pos1.y - pos0.y;
   4.145 +	ray.dir.z = pos1.z - pos0.z;
   4.146 +
   4.147 +	if(d0 >= 0.0) {
   4.148 +		/* start inside */
   4.149 +		if(d1 >= 0.0) {
   4.150 +			/* all inside */
   4.151 +			poly[vnum++] = *v1;	/* append v1 */
   4.152 +			*vnumptr = vnum;
   4.153 +			return 1;
   4.154 +		} else {
   4.155 +			/* going out */
   4.156 +			intersect(&ray, plane, &t);
   4.157 +
   4.158 +			ray3_point(poly[vnum].pos, ray, t);
   4.159 +			poly[vnum].pos.w = 1.0;
   4.160 +
   4.161 +			vec3_lerp(poly[vnum].norm, v0->norm, v1->norm, t);
   4.162 +			vec2_lerp(poly[vnum].tc, v0->tc, v1->tc, t);
   4.163 +			poly[vnum].energy = v0->energy + (v1->energy - v0->energy) * t;
   4.164 +			poly[vnum].cidx = v0->cidx;
   4.165 +			vnum++;	/* append new vertex on the intersection point */
   4.166 +		}
   4.167 +	} else {
   4.168 +		/* start outside */
   4.169 +		if(d1 >= 0) {
   4.170 +			/* going in */
   4.171 +			intersect(&ray, plane, &t);
   4.172 +
   4.173 +			ray3_point(poly[vnum].pos, ray, t);
   4.174 +			poly[vnum].pos.w = 1.0;
   4.175 +
   4.176 +			vec3_lerp(poly[vnum].norm, v0->norm, v1->norm, t);
   4.177 +			vec2_lerp(poly[vnum].tc, v0->tc, v1->tc, t);
   4.178 +			poly[vnum].energy = v0->energy + (v1->energy - v0->energy) * t;
   4.179 +			poly[vnum].cidx = v0->cidx;
   4.180 +			vnum++;	/* append new vertex on the intersection point */
   4.181 +
   4.182 +			/* then append v1 ... */
   4.183 +			poly[vnum++] = *v1;
   4.184 +		} else {
   4.185 +			/* all outside */
   4.186 +			return -1;
   4.187 +		}
   4.188 +	}
   4.189 +
   4.190 +	*vnumptr = vnum;
   4.191 +	return 0;
   4.192 +}
     5.1 --- a/src/mglimpl.h	Sun Sep 22 02:47:46 2013 +0300
     5.2 +++ b/src/mglimpl.h	Sun Sep 22 06:38:08 2013 +0300
     5.3 @@ -5,6 +5,7 @@
     5.4  
     5.5  #define MATRIX_STACK_SIZE	8
     5.6  #define MAX_LIGHTS			4
     5.7 +#define MAX_CLIP_PLANES		6
     5.8  
     5.9  #define ZTILE_SIZE			16384
    5.10  #define ZTILE_SHIFT			14
    5.11 @@ -34,6 +35,11 @@
    5.12  	int cidx;
    5.13  };
    5.14  
    5.15 +struct plane {
    5.16 +	vec3_t pt;
    5.17 +	vec3_t normal;
    5.18 +};
    5.19 +
    5.20  struct texture {
    5.21  	int width, height;
    5.22  	int xshift, yshift;
    5.23 @@ -47,12 +53,15 @@
    5.24  	int mmode, mtop[2];
    5.25  	mat4_t matrix[2][MATRIX_STACK_SIZE];
    5.26  	int prim;
    5.27 -	struct vertex curv, v[4];
    5.28 +	struct vertex curv, v[6];
    5.29  	int vidx;
    5.30  	int vp[4];	/* viewport */
    5.31  	int col_range;	/* color interpolation range */
    5.32  	vec4_t lpos[MAX_LIGHTS];
    5.33  	float lint[MAX_LIGHTS];
    5.34 +	float ambient;
    5.35 +
    5.36 +	struct plane clip_planes[MAX_CLIP_PLANES + 1];
    5.37  
    5.38  	struct texture tex;
    5.39  };
    5.40 @@ -64,6 +73,7 @@
    5.41  	int num_ztiles;
    5.42  };
    5.43  
    5.44 +#define IS_ENABLED(f, x)	((f) & (1 << (x)))
    5.45  
    5.46  #define vertex_to_fixedvertex(v, vx) \
    5.47  	do { \
    5.48 @@ -91,4 +101,7 @@
    5.49  void mgl_draw_line(struct vertex *v0, struct vertex *v1);
    5.50  void mgl_draw_poly(struct vertex *v, int numv);
    5.51  
    5.52 +int mgl_clip_init(struct state *state);
    5.53 +int mgl_clip_poly(struct vertex *v, int vnum);
    5.54 +
    5.55  #endif	/* MGL_IMPL_H_ */
     6.1 --- a/src/mglrast.c	Sun Sep 22 02:47:46 2013 +0300
     6.2 +++ b/src/mglrast.c	Sun Sep 22 06:38:08 2013 +0300
     6.3 @@ -146,13 +146,13 @@
     6.4  	};
     6.5  	int bits = 0;
     6.6  
     6.7 -	if((st->flags & MGL_TEXTURE_2D) && st->tex.pixels) {
     6.8 +	if(IS_ENABLED(st->flags, MGL_TEXTURE_2D) && st->tex.pixels) {
     6.9  		bits |= 4;
    6.10  	}
    6.11 -	if(st->flags & MGL_SMOOTH) {
    6.12 +	if(IS_ENABLED(st->flags, MGL_SMOOTH)) {
    6.13  		bits |= 2;
    6.14  	}
    6.15 -	if((st->flags & MGL_DEPTH_TEST) && fb->zbuf) {
    6.16 +	if(IS_ENABLED(st->flags, MGL_DEPTH_TEST) && fb->zbuf) {
    6.17  		bits |= 1;
    6.18  	}
    6.19  
     7.1 --- a/src/mingl.c	Sun Sep 22 02:47:46 2013 +0300
     7.2 +++ b/src/mingl.c	Sun Sep 22 06:38:08 2013 +0300
     7.3 @@ -24,7 +24,8 @@
     7.4  
     7.5  static void transform(vec4_t *res, vec4_t *v, float *mat);
     7.6  static void transform3(vec3_t *res, vec3_t *v, float *mat);
     7.7 -static void vertex_proc(struct vertex *vert);
     7.8 +static void vertex_proc_view(struct vertex *vert);
     7.9 +static int vertex_proc_proj(struct vertex *vert);
    7.10  static int calc_shiftmask(int val, int *shiftp, unsigned int *maskp);
    7.11  
    7.12  static struct state st;
    7.13 @@ -75,6 +76,9 @@
    7.14  		st.lint[i] = 0.0f;
    7.15  	}
    7.16  
    7.17 +	st.ambient = 0.1;
    7.18 +
    7.19 +	mgl_clip_init(&st);
    7.20  	return 0;
    7.21  }
    7.22  
    7.23 @@ -133,19 +137,19 @@
    7.24  	}
    7.25  }
    7.26  
    7.27 -void mgl_enable(unsigned int bit)
    7.28 +void mgl_enable(unsigned int what)
    7.29  {
    7.30 -	st.flags |= bit;
    7.31 +	st.flags |= (1 << what);
    7.32  }
    7.33  
    7.34 -void mgl_disable(unsigned int bit)
    7.35 +void mgl_disable(unsigned int what)
    7.36  {
    7.37 -	st.flags &= ~bit;
    7.38 +	st.flags &= ~(1 << what);
    7.39  }
    7.40  
    7.41 -int mgl_isenabled(unsigned int bit)
    7.42 +int mgl_isenabled(unsigned int what)
    7.43  {
    7.44 -	return (st.flags & bit) != 0;
    7.45 +	return IS_ENABLED(st.flags, what);
    7.46  }
    7.47  
    7.48  void mgl_front_face(int ff)
    7.49 @@ -158,6 +162,16 @@
    7.50  	st.cullface = cf;
    7.51  }
    7.52  
    7.53 +void mgl_set_ambient(float amb)
    7.54 +{
    7.55 +	st.ambient = amb;
    7.56 +}
    7.57 +
    7.58 +float mgl_get_ambient(void)
    7.59 +{
    7.60 +	return st.ambient;
    7.61 +}
    7.62 +
    7.63  void mgl_color_range(int rng)
    7.64  {
    7.65  	st.col_range = rng;
    7.66 @@ -228,25 +242,43 @@
    7.67  	st.v[st.vidx].norm = st.curv.norm;
    7.68  	st.v[st.vidx].tc = st.curv.tc;
    7.69  
    7.70 -	vertex_proc(st.v + st.vidx);
    7.71 +	/* T&L up to view space, to perform user-clipping */
    7.72 +	vertex_proc_view(st.v + st.vidx);
    7.73  
    7.74  	if(++st.vidx >= st.prim) {
    7.75 +		st.vidx = 0;
    7.76 +
    7.77  		switch(st.prim) {
    7.78  		case MGL_POINTS:
    7.79 +			vertex_proc_proj(st.v);
    7.80  			mgl_draw_point(st.v);
    7.81  			break;
    7.82  		case MGL_LINES:
    7.83 +			vertex_proc_proj(st.v);
    7.84 +			vertex_proc_proj(st.v + 1);
    7.85  			mgl_draw_line(st.v, st.v + 1);
    7.86  			break;
    7.87  		case MGL_TRIANGLES:
    7.88  		case MGL_QUADS:
    7.89 -			mgl_draw_poly(st.v, st.prim);
    7.90 +			{
    7.91 +				int nverts = mgl_clip_poly(st.v, st.prim);
    7.92 +				if(nverts > 0) {
    7.93 +					int i;
    7.94 +					/* passed clipping, perform projection for all verts and draw */
    7.95 +					for(i=0; i<nverts; i++) {
    7.96 +						if(vertex_proc_proj(st.v + i) == -1) {
    7.97 +							printf("this shouldn't happen!\n");
    7.98 +							return;
    7.99 +						}
   7.100 +					}
   7.101 +					mgl_draw_poly(st.v, nverts);
   7.102 +				}
   7.103 +			}
   7.104  			break;
   7.105  		default:
   7.106  			fprintf(stderr, "invalid primitive: %d\n", st.prim);
   7.107  			abort();
   7.108  		}
   7.109 -		st.vidx = 0;
   7.110  	}
   7.111  }
   7.112  
   7.113 @@ -289,21 +321,20 @@
   7.114  	res->z = mat[2] * v->x + mat[6] * v->y + mat[10] * v->z;
   7.115  }
   7.116  
   7.117 -static void vertex_proc(struct vertex *vert)
   7.118 +static void vertex_proc_view(struct vertex *vert)
   7.119  {
   7.120 -	vec4_t pview, pclip;
   7.121 +	vec4_t pview;
   7.122  
   7.123  	float *mvmat = st.matrix[MGL_MODELVIEW][st.mtop[MGL_MODELVIEW]];
   7.124 -	float *pmat = st.matrix[MGL_PROJECTION][st.mtop[MGL_PROJECTION]];
   7.125  
   7.126  	/* modelview transformation */
   7.127  	transform(&pview, &vert->pos, mvmat);
   7.128  
   7.129 -	if(st.flags & MGL_LIGHTING) {
   7.130 -		if((st.flags & MGL_SMOOTH) || st.vidx == 0) {
   7.131 +	if(mgl_isenabled(MGL_LIGHTING)) {
   7.132 +		if(mgl_isenabled(MGL_SMOOTH) || st.vidx == 0) {
   7.133  			int i;
   7.134  			vec3_t norm;
   7.135 -			float irrad = 0.0f;
   7.136 +			float irrad = st.ambient;
   7.137  
   7.138  			transform3(&norm, &vert->norm, mvmat);
   7.139  
   7.140 @@ -331,18 +362,27 @@
   7.141  					irrad += ndotl * st.lint[i];
   7.142  				}
   7.143  			}
   7.144 -			vert->energy = irrad;
   7.145 +			vert->energy = irrad > 1.0 ? 1.0 : irrad;
   7.146  		} else {
   7.147  			vert->energy = st.v[0].energy;
   7.148  		}
   7.149  	}
   7.150  
   7.151 -	transform(&pclip, &pview, pmat);
   7.152 +	vert->pos = pview;
   7.153 +}
   7.154 +
   7.155 +static int vertex_proc_proj(struct vertex *vert)
   7.156 +{
   7.157 +	vec4_t pclip;
   7.158 +
   7.159 +	float *pmat = st.matrix[MGL_PROJECTION][st.mtop[MGL_PROJECTION]];
   7.160 +
   7.161 +	transform(&pclip, &vert->pos, pmat);
   7.162  	/* TODO clipping in homogenous clip space */
   7.163  
   7.164 -	if(pclip.w < 1e-6 && pclip.w > -1e-6) {
   7.165 +	if(pclip.w < 1e-6) {
   7.166  		vert->pos.x = vert->pos.y = vert->pos.z = vert->pos.w = 0.0f;
   7.167 -		return;
   7.168 +		return -1;
   7.169  	}
   7.170  
   7.171  	/* perspective division */
   7.172 @@ -354,6 +394,8 @@
   7.173  	/* viewport transformation */
   7.174  	vert->pos.x = st.vp[0] + st.vp[2] * (vert->pos.x * 0.5 + 0.5);
   7.175  	vert->pos.y = st.vp[1] + st.vp[3] * (-vert->pos.y * 0.5 + 0.5);
   7.176 +
   7.177 +	return 0;
   7.178  }
   7.179  
   7.180  void mgl_viewport(int x, int y, int width, int height)
   7.181 @@ -534,6 +576,29 @@
   7.182  	}
   7.183  }
   7.184  
   7.185 +void mgl_clip_plane(int id, float nx, float ny, float nz, float dist)
   7.186 +{
   7.187 +	id -= MGL_CLIP_PLANE0;
   7.188 +
   7.189 +	if(id < 0 || id > MAX_CLIP_PLANES) {
   7.190 +		return;
   7.191 +	}
   7.192 +
   7.193 +	st.clip_planes[id].normal.x = nx;
   7.194 +	st.clip_planes[id].normal.y = ny;
   7.195 +	st.clip_planes[id].normal.z = nz;
   7.196 +	NORMALIZE(st.clip_planes[id].normal);
   7.197 +
   7.198 +	st.clip_planes[id].pt.x = st.clip_planes[id].normal.x * dist;
   7.199 +	st.clip_planes[id].pt.y = st.clip_planes[id].normal.y * dist;
   7.200 +	st.clip_planes[id].pt.z = st.clip_planes[id].normal.z * dist;
   7.201 +
   7.202 +	printf("set clip plane %d -> n[%f %f %f]  p[%f %f %f]\n", id,
   7.203 +			st.clip_planes[id].normal.x, st.clip_planes[id].normal.y, st.clip_planes[id].normal.z,
   7.204 +			st.clip_planes[id].pt.x, st.clip_planes[id].pt.y, st.clip_planes[id].pt.z);
   7.205 +
   7.206 +}
   7.207 +
   7.208  #define MAX_SHIFT	12
   7.209  static int calc_shiftmask(int val, int *shiftp, unsigned int *maskp)
   7.210  {
     8.1 --- a/src/mingl.h	Sun Sep 22 02:47:46 2013 +0300
     8.2 +++ b/src/mingl.h	Sun Sep 22 06:38:08 2013 +0300
     8.3 @@ -1,29 +1,18 @@
     8.4 -/*
     8.5 -256-color 3D graphics hack for real-mode DOS.
     8.6 -Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
     8.7 -
     8.8 -This program is free software: you can redistribute it and/or modify
     8.9 -it under the terms of the GNU General Public License as published by
    8.10 -the Free Software Foundation, either version 3 of the License, or
    8.11 -(at your option) any later version.
    8.12 -
    8.13 -This program is distributed in the hope that it will be useful,
    8.14 -but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.15 -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    8.16 -GNU General Public License for more details.
    8.17 -
    8.18 -You should have received a copy of the GNU General Public License
    8.19 -along with this program.  If not, see <http://www.gnu.org/licenses/>.
    8.20 -*/
    8.21  #ifndef MINGL_H_
    8.22  #define MINGL_H_
    8.23  
    8.24  /* enable bitflags */
    8.25 -#define MGL_CULL_FACE	1
    8.26 -#define MGL_DEPTH_TEST	2
    8.27 -#define MGL_SMOOTH		4
    8.28 -#define MGL_LIGHTING	8
    8.29 -#define MGL_TEXTURE_2D	16
    8.30 +#define MGL_CULL_FACE	0
    8.31 +#define MGL_DEPTH_TEST	1
    8.32 +#define MGL_SMOOTH		2
    8.33 +#define MGL_LIGHTING	3
    8.34 +#define MGL_TEXTURE_2D	4
    8.35 +#define MGL_CLIP_PLANE0	5
    8.36 +#define MGL_CLIP_PLANE1	6
    8.37 +#define MGL_CLIP_PLANE2	7
    8.38 +#define MGL_CLIP_PLANE3 8
    8.39 +#define MGL_CLIP_PLANE4	9
    8.40 +#define MGL_CLIP_PLANE5	10
    8.41  
    8.42  /* primitives */
    8.43  #define MGL_POINTS		1
    8.44 @@ -57,6 +46,9 @@
    8.45  void mgl_front_face(int ff);
    8.46  void mgl_cull_face(int cf);
    8.47  
    8.48 +void mgl_set_ambient(float amb);
    8.49 +float mgl_get_ambient(void);
    8.50 +
    8.51  void mgl_color_range(int rng);
    8.52  void mgl_light_intensity(int ltidx, float intens);
    8.53  void mgl_light_position(int ltidx, float x, float y, float z, float w);
    8.54 @@ -91,6 +83,8 @@
    8.55  
    8.56  void mgl_teximage(int width, int height, unsigned char *pixels);
    8.57  
    8.58 +void mgl_clip_plane(int id, float nx, float ny, float nz, float dist);
    8.59 +
    8.60  void mgl_cube(float sz);
    8.61  void mgl_sphere(float rad, int usub, int vsub);
    8.62  void mgl_sphere_part(float rad, int usub, int vsub, float umax, float vmax);
     9.1 --- a/src/scantmpl.h	Sun Sep 22 02:47:46 2013 +0300
     9.2 +++ b/src/scantmpl.h	Sun Sep 22 06:38:08 2013 +0300
     9.3 @@ -133,7 +133,7 @@
     9.4  	x1 = (int)fixed_round(vright[y].pos.x);
     9.5  
     9.6  	if(x1 < x0) {
     9.7 -		if(st->flags & MGL_CULL_FACE) {
     9.8 +		if(IS_ENABLED(st->flags, MGL_CULL_FACE)) {
     9.9  			return;
    9.10  		}
    9.11  		tmp = x0;
    10.1 --- a/src/test.c	Sun Sep 22 02:47:46 2013 +0300
    10.2 +++ b/src/test.c	Sun Sep 22 06:38:08 2013 +0300
    10.3 @@ -286,6 +286,14 @@
    10.4  		prim = (prim + 1) % NUM_PRIMS;
    10.5  		break;
    10.6  
    10.7 +	case 'c':
    10.8 +		if(mgl_isenabled(MGL_CULL_FACE)) {
    10.9 +			mgl_disable(MGL_CULL_FACE);
   10.10 +		} else {
   10.11 +			mgl_enable(MGL_CULL_FACE);
   10.12 +		}
   10.13 +		break;
   10.14 +
   10.15  	default:
   10.16  		break;
   10.17  	}
    11.1 --- a/src/vmath.h	Sun Sep 22 02:47:46 2013 +0300
    11.2 +++ b/src/vmath.h	Sun Sep 22 06:38:08 2013 +0300
    11.3 @@ -32,48 +32,73 @@
    11.4  	fixed x, y;
    11.5  } vec2x_t;
    11.6  
    11.7 +typedef struct {
    11.8 +	vec3_t origin, dir;
    11.9 +} ray3_t;
   11.10 +
   11.11 +#define vec3_dot(a, b)	((a).x * (b).x + (a).y * (b).y + (a).z * (b).z)
   11.12 +
   11.13 +#define vec2_lerp(res, a, b, t) \
   11.14 +	do { \
   11.15 +		(res).x = (a).x + ((b).x - (a).x) * (t); \
   11.16 +		(res).y = (a).y + ((b).y - (a).y) * (t); \
   11.17 +	} while(0)
   11.18 +
   11.19 +#define vec3_lerp(res, a, b, t) \
   11.20 +	do { \
   11.21 +		(res).x = (a).x + ((b).x - (a).x) * (t); \
   11.22 +		(res).y = (a).y + ((b).y - (a).y) * (t); \
   11.23 +		(res).z = (a).z + ((b).z - (a).z) * (t); \
   11.24 +	} while(0)
   11.25 +
   11.26 +#define ray3_point(res, ray, t) \
   11.27 +	do { \
   11.28 +		(res).x = (ray).origin.x + (ray).dir.x * (t); \
   11.29 +		(res).y = (ray).origin.y + (ray).dir.y * (t); \
   11.30 +		(res).z = (ray).origin.z + (ray).dir.z * (t); \
   11.31 +	} while(0)
   11.32  
   11.33  #define vec2_to_fixed2(v, f) \
   11.34  	do { \
   11.35 -		f.x = fixedf(v.x); \
   11.36 -		f.y = fixedf(v.y); \
   11.37 +		(f).x = fixedf((v).x); \
   11.38 +		(f).y = fixedf((v).y); \
   11.39  	} while(0)
   11.40  
   11.41  #define vec3_to_fixed3(v, f) \
   11.42  	do { \
   11.43 -		f.x = fixedf(v.x); \
   11.44 -		f.y = fixedf(v.y); \
   11.45 -		f.z = fixedf(v.z); \
   11.46 +		(f).x = fixedf((v).x); \
   11.47 +		(f).y = fixedf((v).y); \
   11.48 +		(f).z = fixedf((v).z); \
   11.49  	} while(0)
   11.50  
   11.51  #define vec4_to_fixed4(v, f) \
   11.52  	do { \
   11.53 -		f.x = fixedf(v.x); \
   11.54 -		f.y = fixedf(v.y); \
   11.55 -		f.z = fixedf(v.z); \
   11.56 -		f.w = fixedf(v.w); \
   11.57 +		(f).x = fixedf((v).x); \
   11.58 +		(f).y = fixedf((v).y); \
   11.59 +		(f).z = fixedf((v).z); \
   11.60 +		(f).w = fixedf((v).w); \
   11.61  	} while(0)
   11.62  
   11.63  
   11.64  #define fixed2_to_vec2(f, v) \
   11.65  	do { \
   11.66 -		v.x = fixed_float(f.x); \
   11.67 -		v.y = fixed_float(f.y); \
   11.68 +		(v).x = fixed_float((f).x); \
   11.69 +		(v).y = fixed_float((f).y); \
   11.70  	} while(0)
   11.71  
   11.72  #define fixed3_to_vec3(f, v) \
   11.73  	do { \
   11.74 -		v.x = fixed_float(f.x); \
   11.75 -		v.y = fixed_float(f.y); \
   11.76 -		v.z = fixed_float(f.z); \
   11.77 +		(v).x = fixed_float((f).x); \
   11.78 +		(v).y = fixed_float((f).y); \
   11.79 +		(v).z = fixed_float((f).z); \
   11.80  	} while(0)
   11.81  
   11.82  #define fixed4_to_vec4(f, v) \
   11.83  	do { \
   11.84 -		v.x = fixed_float(f.x); \
   11.85 -		v.y = fixed_float(f.y); \
   11.86 -		v.z = fixed_float(f.z); \
   11.87 -		v.w = fixed_float(f.w); \
   11.88 +		(v).x = fixed_float((f).x); \
   11.89 +		(v).y = fixed_float((f).y); \
   11.90 +		(v).z = fixed_float((f).z); \
   11.91 +		(v).w = fixed_float((f).w); \
   11.92  	} while(0)
   11.93  
   11.94