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 +}