deepstone

diff src/mglclip.c @ 28:11d14f688485

added clipping
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 22 Sep 2013 06:38:08 +0300
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/mglclip.c	Sun Sep 22 06:38:08 2013 +0300
     1.3 @@ -0,0 +1,189 @@
     1.4 +#include <stdio.h>
     1.5 +#include <string.h>
     1.6 +#include <assert.h>
     1.7 +#include "mingl.h"
     1.8 +#include "mglimpl.h"
     1.9 +
    1.10 +static struct state *st;
    1.11 +
    1.12 +static float distance_signed(vec3_t p, const struct plane *plane);
    1.13 +static int intersect(const ray3_t *ray, const struct plane *plane, float *t);
    1.14 +static int clip_polygon(struct vertex *vout, int *voutnum, const struct vertex *vin, int vnum,
    1.15 +		const struct plane *plane);
    1.16 +
    1.17 +#define ZNEAR	MAX_CLIP_PLANES
    1.18 +
    1.19 +int mgl_clip_init(struct state *state)
    1.20 +{
    1.21 +	st = state;
    1.22 +
    1.23 +	memset(st->clip_planes, 0, sizeof st->clip_planes);
    1.24 +
    1.25 +	/* always setup a near clipping plane */
    1.26 +	st->clip_planes[ZNEAR].normal.x = st->clip_planes[ZNEAR].normal.y = 0;
    1.27 +	st->clip_planes[ZNEAR].normal.z = -1;
    1.28 +	st->clip_planes[ZNEAR].pt.x = st->clip_planes[ZNEAR].pt.y = 0;
    1.29 +	st->clip_planes[ZNEAR].pt.z = -0.5;
    1.30 +
    1.31 +	return 0;
    1.32 +}
    1.33 +
    1.34 +int mgl_clip_poly(struct vertex *v, int vnum)
    1.35 +{
    1.36 +	int i, res, clipped_vnum;
    1.37 +	struct vertex tmp[6];
    1.38 +
    1.39 +	for(i=0; i<MAX_CLIP_PLANES + 1; i++) {
    1.40 +		if(i < ZNEAR && !mgl_isenabled(MGL_CLIP_PLANE0 + i)) {
    1.41 +			continue;
    1.42 +		}
    1.43 +
    1.44 +		res = clip_polygon(tmp, &clipped_vnum, v, vnum, st->clip_planes + i);
    1.45 +		if(res == -1) {
    1.46 +			/* the polygon was completely outside */
    1.47 +			return 0;
    1.48 +		}
    1.49 +		if(res == 0) {
    1.50 +			/* the polygon was clipped, update v and vnum */
    1.51 +			vnum = clipped_vnum;
    1.52 +			memcpy(v, tmp, clipped_vnum * sizeof *v);
    1.53 +		}
    1.54 +		/* otherwise the polygon was completely inside, nothing to do... */
    1.55 +	}
    1.56 +
    1.57 +	return vnum;
    1.58 +}
    1.59 +
    1.60 +static float distance_signed(vec3_t p, const struct plane *plane)
    1.61 +{
    1.62 +	vec3_t ptdir;
    1.63 +	ptdir.x = p.x - plane->pt.x;
    1.64 +	ptdir.y = p.y - plane->pt.y;
    1.65 +	ptdir.z = p.z - plane->pt.z;
    1.66 +
    1.67 +	return vec3_dot(ptdir, plane->normal);
    1.68 +}
    1.69 +
    1.70 +static int intersect(const ray3_t *ray, const struct plane *plane, float *t)
    1.71 +{
    1.72 +	vec3_t orig_pt_dir;
    1.73 +
    1.74 +	float ndotdir = vec3_dot(plane->normal, ray->dir);
    1.75 +	if(fabs(ndotdir) < 1e-4) {
    1.76 +		*t = 0.0f;
    1.77 +		return 0;
    1.78 +	}
    1.79 +
    1.80 +	orig_pt_dir.x = plane->pt.x - ray->origin.x;
    1.81 +	orig_pt_dir.y = plane->pt.y - ray->origin.y;
    1.82 +	orig_pt_dir.z = plane->pt.z - ray->origin.z;
    1.83 +
    1.84 +	*t = vec3_dot(plane->normal, orig_pt_dir) / ndotdir;
    1.85 +	return 1;
    1.86 +}
    1.87 +
    1.88 +static int clip_edge(struct vertex *poly, int *vnum, const struct vertex *v0,
    1.89 +		const struct vertex *v1, const struct plane *plane);
    1.90 +
    1.91 +/* returns:
    1.92 + *  1 -> both inside
    1.93 + *  0 -> straddling and clipped
    1.94 + * -1 -> both outside
    1.95 + *
    1.96 + * the size of the vout polygon is returned throug voutnum
    1.97 + */
    1.98 +static int clip_polygon(struct vertex *vout, int *voutnum, const struct vertex *vin, int vnum,
    1.99 +		const struct plane *plane)
   1.100 +{
   1.101 +	int i;
   1.102 +	int edges_clipped = 0;
   1.103 +	int out_vnum = 0;
   1.104 +
   1.105 +	for(i=0; i<vnum; i++) {
   1.106 +		int res = clip_edge(vout, &out_vnum, vin + i, vin + (i + 1) % vnum, plane);
   1.107 +		if(res == 0) {
   1.108 +			edges_clipped++;
   1.109 +		}
   1.110 +	}
   1.111 +
   1.112 +	if(out_vnum <= 0) {
   1.113 +		assert(edges_clipped == 0);
   1.114 +		return -1;
   1.115 +	}
   1.116 +
   1.117 +	*voutnum = out_vnum;
   1.118 +	return edges_clipped > 0 ? 0 : 1;
   1.119 +}
   1.120 +
   1.121 +/* returns:
   1.122 + *  1 -> both inside
   1.123 + *  0 -> straddling and clipped
   1.124 + * -1 -> both outside
   1.125 + *
   1.126 + *  also returns the size of the polygon through vnumptr
   1.127 + */
   1.128 +static int clip_edge(struct vertex *poly, int *vnumptr, const struct vertex *v0,
   1.129 +		const struct vertex *v1, const struct plane *plane)
   1.130 +{
   1.131 +	vec3_t pos0, pos1;
   1.132 +	float d0, d1, t;
   1.133 +	ray3_t ray;
   1.134 +	int vnum = *vnumptr;
   1.135 +
   1.136 +	pos0.x = v0->pos.x; pos0.y = v0->pos.y; pos0.z = v0->pos.z;
   1.137 +	pos1.x = v1->pos.x; pos1.y = v1->pos.y; pos1.z = v1->pos.z;
   1.138 +
   1.139 +	d0 = distance_signed(pos0, plane);
   1.140 +	d1 = distance_signed(pos1, plane);
   1.141 +
   1.142 +	ray.origin = pos0;
   1.143 +	ray.dir.x = pos1.x - pos0.x;
   1.144 +	ray.dir.y = pos1.y - pos0.y;
   1.145 +	ray.dir.z = pos1.z - pos0.z;
   1.146 +
   1.147 +	if(d0 >= 0.0) {
   1.148 +		/* start inside */
   1.149 +		if(d1 >= 0.0) {
   1.150 +			/* all inside */
   1.151 +			poly[vnum++] = *v1;	/* append v1 */
   1.152 +			*vnumptr = vnum;
   1.153 +			return 1;
   1.154 +		} else {
   1.155 +			/* going out */
   1.156 +			intersect(&ray, plane, &t);
   1.157 +
   1.158 +			ray3_point(poly[vnum].pos, ray, t);
   1.159 +			poly[vnum].pos.w = 1.0;
   1.160 +
   1.161 +			vec3_lerp(poly[vnum].norm, v0->norm, v1->norm, t);
   1.162 +			vec2_lerp(poly[vnum].tc, v0->tc, v1->tc, t);
   1.163 +			poly[vnum].energy = v0->energy + (v1->energy - v0->energy) * t;
   1.164 +			poly[vnum].cidx = v0->cidx;
   1.165 +			vnum++;	/* append new vertex on the intersection point */
   1.166 +		}
   1.167 +	} else {
   1.168 +		/* start outside */
   1.169 +		if(d1 >= 0) {
   1.170 +			/* going in */
   1.171 +			intersect(&ray, plane, &t);
   1.172 +
   1.173 +			ray3_point(poly[vnum].pos, ray, t);
   1.174 +			poly[vnum].pos.w = 1.0;
   1.175 +
   1.176 +			vec3_lerp(poly[vnum].norm, v0->norm, v1->norm, t);
   1.177 +			vec2_lerp(poly[vnum].tc, v0->tc, v1->tc, t);
   1.178 +			poly[vnum].energy = v0->energy + (v1->energy - v0->energy) * t;
   1.179 +			poly[vnum].cidx = v0->cidx;
   1.180 +			vnum++;	/* append new vertex on the intersection point */
   1.181 +
   1.182 +			/* then append v1 ... */
   1.183 +			poly[vnum++] = *v1;
   1.184 +		} else {
   1.185 +			/* all outside */
   1.186 +			return -1;
   1.187 +		}
   1.188 +	}
   1.189 +
   1.190 +	*vnumptr = vnum;
   1.191 +	return 0;
   1.192 +}