1 /* Copyright (C) 1992-1998 The Geometry Center
2  * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3  *
4  * This file is part of Geomview.
5  *
6  * Geomview is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published
8  * by the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * Geomview is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with Geomview; see the file COPYING.  If not, write
18  * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
19  * USA, or visit http://www.gnu.org.
20  */
21 
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25 
26 #if 0
27 static char copyright[] = "Copyright (C) 1992-1998 The Geometry Center\n\
28 Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips";
29 #endif
30 
31 #include "mgP.h"
32 #include "mgpsP.h"
33 
34 
35 #define WCLIPPLANE 0.001 /* This is as close as we get to the eyeplane */
36 
37 #define XLEFTCLIP		0.0
38 #define XRIGHTCLIP		0.0
39 #define YTOPCLIP		0.0
40 #define YBOTTOMCLIP		0.0
41 #define ZNEARCLIP		(-1.0)
42 #define ZFARCLIP		1.0
43 
44 static int		 xyz[6], clipvertnum = 0;
45 static mgpsprim	 *prim1, *prim2, *primtemp;
46 static CPoint3		 *vts1, *vts2, *vtstemp;
47 
48 /*
49    Function: mgps_dividew()
50    Description: Divide out w coordinate (*after* clipping against WCLIPPLANE)
51    Author: Daeron Meyer
52 */
53 
mgps_dividew(void)54 void mgps_dividew(void)
55 {
56   CPoint3 *curr;
57   float w;
58   int   n;
59 
60   for (n = 0; n < prim1->numvts; n++) {
61     curr = &(vts1[n]);
62     w = curr->w; curr->x /= w; curr->y /= w; curr->z /= w;
63 
64     curr->z += _mgpsc->znudgeby;
65 
66     if (curr->x < XLEFTCLIP) xyz[0]++;
67     if (curr->x >= (float)_mgpsc->xsize - XRIGHTCLIP) xyz[1]++;
68     if (curr->y < YTOPCLIP) xyz[2]++;
69     if (curr->y >= (float)_mgpsc->ysize - YBOTTOMCLIP) xyz[3]++;
70     if (curr->z < ZNEARCLIP) xyz[4]++;
71     if (curr->z >= ZFARCLIP) xyz[5]++;
72 
73   }
74 }
75 
76 /*
77    Function: mgps_cliptoplane()
78    Description: Clip polygon against a coordinate axis plane
79    Author: Daeron Meyer
80 */
mgps_cliptoplane(int coord,float plane,float sign)81 void mgps_cliptoplane(int coord, float plane, float sign)
82 {
83   CPoint3 *prev, *curr, *dest;
84   float i, i1, i2, *c1, *p1, *d1;
85   int n;
86 
87 #ifdef DEBUGCLIP
88   fprintf(stderr, "Clip %d, plane=%f, sign=%f\n", coord, plane, sign);
89 #endif
90   prim2->numvts = 0;
91   prev = &(vts1[prim1->numvts - 1]);
92   i1 = sign * ((float *) prev) [coord] - plane;
93 
94   for (curr=vts1, n=prim1->numvts; n > 0; n--, prev=curr, i1=i2, curr++)
95   {
96     i2 = sign * ((float *) curr) [coord] - plane;
97     if ((i1 <= 0.0) ^ (i2 <= 0.0)) {
98       i =  i1/(i1 - i2);
99       dest = &(vts2[prim2->numvts]);
100       dest->x = prev->x + i * (curr->x - prev->x);
101       dest->y = prev->y + i * (curr->y - prev->y);
102       dest->z = prev->z + i * (curr->z - prev->z);
103       dest->w = prev->w + i * (curr->w - prev->w);
104       if ((i1 <= 0.0) || (prev->drawnext == 0))
105 	dest->drawnext = 0;
106       else
107 	dest->drawnext = 1;
108       c1 = (float *) &(curr->vcol);
109       p1 = (float *) &(prev->vcol);
110       d1 = (float *) &(dest->vcol);
111       d1[0] = p1[0] + i * (c1[0] - p1[0]);
112       d1[1] = p1[1] + i * (c1[1] - p1[1]);
113       d1[2] = p1[2] + i * (c1[2] - p1[2]);
114       d1[3] = p1[3] + i * (c1[3] - p1[3]);
115       prim2->numvts++;
116     }
117     if (i2 <= 0.0)
118     {
119       vts2[prim2->numvts] = *curr;
120       prim2->numvts++;
121     }
122   }
123 #ifdef DEBUGCLIP
124   for (n = 0; n < prim2->numvts; n++)
125   {
126     fprintf(stderr, "%f, %f, %f, %f: %d\n",
127 		vts2[n].x, vts2[n].y, vts2[n].z, vts2[n].w, vts2[n].drawnext);
128   }
129 #endif
130 }
131 
132 
133 /*
134    Function: mgps_primclip()
135    Description: Clip a polygon to fit in the viewing volume
136    Author: Daeron Meyer
137 */
mgps_primclip(mgpsprim * aprim)138 int mgps_primclip(mgpsprim *aprim)
139 {
140    static mgpsprim	 clip;
141    static int		 mykind, n;
142    static vvec		 clipverts;
143    static int		 intersectw;
144 
145    xyz[0]=0; xyz[1]=0; xyz[2]=0; xyz[3]=0; xyz[4]=0; xyz[5]=0;
146 
147    /* give ourselves more space for vertex data if needed */
148    if ((aprim->numvts * 2) > clipvertnum) {
149      if (!clipvertnum)
150        VVINIT(clipverts, CPoint3, clipvertnum);
151 
152      clipvertnum = aprim->numvts * 2;
153      vvneeds(&clipverts, clipvertnum);
154    }
155 
156   /* We might need more space for the final polygon since
157      clipping can produce a polygon with more vertices than
158      it had to begin with. We'll err on the side of safety: */
159 
160   if ((_mgpsc->mysort->cvert + aprim->numvts) > _mgpsc->mysort->pvertnum)
161   {
162     _mgpsc->mysort->pvertnum *= 2;
163     vvneeds(&(_mgpsc->mysort->pverts), _mgpsc->mysort->pvertnum);
164   }
165 
166   mykind = aprim->mykind;
167   prim1 = aprim; prim2 = &clip;
168   vts1 =  &(VVEC(_mgpsc->mysort->pverts, CPoint3)[prim1->index]);
169   vts2 =  &(VVEC(clipverts, CPoint3)[0]);
170 
171   if ((mykind==PRIM_LINE) || (mykind==PRIM_SLINE))
172       vts1[prim1->numvts-1].drawnext = 0;
173 
174   prim2->index = 0;
175   prim2->numvts = prim1->numvts;
176 
177 #define CLIP_POLYS_AND_SWAP(a, b, c) { \
178 mgps_cliptoplane(a, b, c); \
179 if (prim2->numvts == 0) { aprim->numvts = 0; return PRIM_INVIS; } \
180 vtstemp = vts2; vts2 = vts1; vts1 = vtstemp; \
181 primtemp = prim2; prim2 = prim1; prim1 = primtemp; \
182 }
183 
184 
185 #ifdef DEBUGCLIP
186   fprintf(stderr, "BEGIN-CLIP\n");
187   fprintf(stderr, "INITIAL POLY:\n");
188   for (n=0; n < aprim->numvts; n++)
189   {
190     fprintf(stderr, "%f, %f, %f, %f: %d\n",
191 		vts1[n].x, vts1[n].y, vts1[n].z, vts1[n].w, vts1[n].drawnext);
192   }
193   fprintf(stderr,"===========================\n");
194 #endif
195 
196   intersectw = 0;
197   for (n = 0; (n < aprim->numvts) && !intersectw; n++)
198   {
199     if (vts1[n].w < WCLIPPLANE) intersectw = 1;
200   }
201 
202   if (intersectw) CLIP_POLYS_AND_SWAP(3, -WCLIPPLANE, -1.0);
203 
204   mgps_dividew();
205   n = prim1->numvts;
206 
207   if (!intersectw && (xyz[0]+xyz[1]+xyz[2]+xyz[3]+xyz[4]+xyz[5] == 0))
208     return mykind;
209   else
210     if (xyz[0] == n || xyz[1] == n || xyz[2] == n ||
211 		xyz[3] == n || xyz[4] == n || xyz[5] == n)
212 	return PRIM_INVIS;
213 
214   if (xyz[0]) CLIP_POLYS_AND_SWAP(0, -XLEFTCLIP, -1.0);
215   if (xyz[1]) CLIP_POLYS_AND_SWAP(0, (float)_mgpsc->xsize-XRIGHTCLIP, 1.0);
216   if (xyz[2]) CLIP_POLYS_AND_SWAP(1, -YTOPCLIP, -1.0);
217   if (xyz[3]) CLIP_POLYS_AND_SWAP(1, (float)_mgpsc->ysize-YBOTTOMCLIP, 1.0);
218   if (xyz[4]) CLIP_POLYS_AND_SWAP(2, -ZNEARCLIP, -1.0);
219   if (xyz[5]) CLIP_POLYS_AND_SWAP(2, ZFARCLIP, 1.0);
220 
221 
222   if (aprim == prim2) /* If the vertex data ended up in the local
223 			vertex list, then we need to copy it back to the
224 			global vertex list */
225   {
226     prim2->numvts = prim1->numvts;
227 /*
228     for (n=0; n < aprim->numvts; n++)
229     {
230       vts2[n] = vts1[n];
231     }
232 */
233     memcpy(vts2, vts1, sizeof(CPoint3) * prim1->numvts);
234 
235   }
236 
237 #ifdef DEBUGCLIP
238   fprintf(stderr, "FINAL POLY:\n");
239   for (n=0; n < aprim->numvts; n++)
240   {
241     fprintf(stderr, "%f, %f, %f, %f: %d\n",
242 		vts1[n].x, vts1[n].y, vts1[n].z, vts1[n].w, vts1[n].drawnext);
243   }
244   fprintf(stderr, "END-CLIP\n");
245 #endif
246 
247   return mykind;
248 }
249