deepstone

view 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 source
1 #include <stdio.h>
2 #include <string.h>
3 #include <assert.h>
4 #include "mingl.h"
5 #include "mglimpl.h"
7 static struct state *st;
9 static float distance_signed(vec3_t p, const struct plane *plane);
10 static int intersect(const ray3_t *ray, const struct plane *plane, float *t);
11 static int clip_polygon(struct vertex *vout, int *voutnum, const struct vertex *vin, int vnum,
12 const struct plane *plane);
14 #define ZNEAR MAX_CLIP_PLANES
16 int mgl_clip_init(struct state *state)
17 {
18 st = state;
20 memset(st->clip_planes, 0, sizeof st->clip_planes);
22 /* always setup a near clipping plane */
23 st->clip_planes[ZNEAR].normal.x = st->clip_planes[ZNEAR].normal.y = 0;
24 st->clip_planes[ZNEAR].normal.z = -1;
25 st->clip_planes[ZNEAR].pt.x = st->clip_planes[ZNEAR].pt.y = 0;
26 st->clip_planes[ZNEAR].pt.z = -0.5;
28 return 0;
29 }
31 int mgl_clip_poly(struct vertex *v, int vnum)
32 {
33 int i, res, clipped_vnum;
34 struct vertex tmp[6];
36 for(i=0; i<MAX_CLIP_PLANES + 1; i++) {
37 if(i < ZNEAR && !mgl_isenabled(MGL_CLIP_PLANE0 + i)) {
38 continue;
39 }
41 res = clip_polygon(tmp, &clipped_vnum, v, vnum, st->clip_planes + i);
42 if(res == -1) {
43 /* the polygon was completely outside */
44 return 0;
45 }
46 if(res == 0) {
47 /* the polygon was clipped, update v and vnum */
48 vnum = clipped_vnum;
49 memcpy(v, tmp, clipped_vnum * sizeof *v);
50 }
51 /* otherwise the polygon was completely inside, nothing to do... */
52 }
54 return vnum;
55 }
57 static float distance_signed(vec3_t p, const struct plane *plane)
58 {
59 vec3_t ptdir;
60 ptdir.x = p.x - plane->pt.x;
61 ptdir.y = p.y - plane->pt.y;
62 ptdir.z = p.z - plane->pt.z;
64 return vec3_dot(ptdir, plane->normal);
65 }
67 static int intersect(const ray3_t *ray, const struct plane *plane, float *t)
68 {
69 vec3_t orig_pt_dir;
71 float ndotdir = vec3_dot(plane->normal, ray->dir);
72 if(fabs(ndotdir) < 1e-4) {
73 *t = 0.0f;
74 return 0;
75 }
77 orig_pt_dir.x = plane->pt.x - ray->origin.x;
78 orig_pt_dir.y = plane->pt.y - ray->origin.y;
79 orig_pt_dir.z = plane->pt.z - ray->origin.z;
81 *t = vec3_dot(plane->normal, orig_pt_dir) / ndotdir;
82 return 1;
83 }
85 static int clip_edge(struct vertex *poly, int *vnum, const struct vertex *v0,
86 const struct vertex *v1, const struct plane *plane);
88 /* returns:
89 * 1 -> both inside
90 * 0 -> straddling and clipped
91 * -1 -> both outside
92 *
93 * the size of the vout polygon is returned throug voutnum
94 */
95 static int clip_polygon(struct vertex *vout, int *voutnum, const struct vertex *vin, int vnum,
96 const struct plane *plane)
97 {
98 int i;
99 int edges_clipped = 0;
100 int out_vnum = 0;
102 for(i=0; i<vnum; i++) {
103 int res = clip_edge(vout, &out_vnum, vin + i, vin + (i + 1) % vnum, plane);
104 if(res == 0) {
105 edges_clipped++;
106 }
107 }
109 if(out_vnum <= 0) {
110 assert(edges_clipped == 0);
111 return -1;
112 }
114 *voutnum = out_vnum;
115 return edges_clipped > 0 ? 0 : 1;
116 }
118 /* returns:
119 * 1 -> both inside
120 * 0 -> straddling and clipped
121 * -1 -> both outside
122 *
123 * also returns the size of the polygon through vnumptr
124 */
125 static int clip_edge(struct vertex *poly, int *vnumptr, const struct vertex *v0,
126 const struct vertex *v1, const struct plane *plane)
127 {
128 vec3_t pos0, pos1;
129 float d0, d1, t;
130 ray3_t ray;
131 int vnum = *vnumptr;
133 pos0.x = v0->pos.x; pos0.y = v0->pos.y; pos0.z = v0->pos.z;
134 pos1.x = v1->pos.x; pos1.y = v1->pos.y; pos1.z = v1->pos.z;
136 d0 = distance_signed(pos0, plane);
137 d1 = distance_signed(pos1, plane);
139 ray.origin = pos0;
140 ray.dir.x = pos1.x - pos0.x;
141 ray.dir.y = pos1.y - pos0.y;
142 ray.dir.z = pos1.z - pos0.z;
144 if(d0 >= 0.0) {
145 /* start inside */
146 if(d1 >= 0.0) {
147 /* all inside */
148 poly[vnum++] = *v1; /* append v1 */
149 *vnumptr = vnum;
150 return 1;
151 } else {
152 /* going out */
153 intersect(&ray, plane, &t);
155 ray3_point(poly[vnum].pos, ray, t);
156 poly[vnum].pos.w = 1.0;
158 vec3_lerp(poly[vnum].norm, v0->norm, v1->norm, t);
159 vec2_lerp(poly[vnum].tc, v0->tc, v1->tc, t);
160 poly[vnum].energy = v0->energy + (v1->energy - v0->energy) * t;
161 poly[vnum].cidx = v0->cidx;
162 vnum++; /* append new vertex on the intersection point */
163 }
164 } else {
165 /* start outside */
166 if(d1 >= 0) {
167 /* going in */
168 intersect(&ray, plane, &t);
170 ray3_point(poly[vnum].pos, ray, t);
171 poly[vnum].pos.w = 1.0;
173 vec3_lerp(poly[vnum].norm, v0->norm, v1->norm, t);
174 vec2_lerp(poly[vnum].tc, v0->tc, v1->tc, t);
175 poly[vnum].energy = v0->energy + (v1->energy - v0->energy) * t;
176 poly[vnum].cidx = v0->cidx;
177 vnum++; /* append new vertex on the intersection point */
179 /* then append v1 ... */
180 poly[vnum++] = *v1;
181 } else {
182 /* all outside */
183 return -1;
184 }
185 }
187 *vnumptr = vnum;
188 return 0;
189 }