xref: /reactos/dll/opengl/glu32/src/libtess/render.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3*c2c66affSColin Finck  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4*c2c66affSColin Finck  *
5*c2c66affSColin Finck  * Permission is hereby granted, free of charge, to any person obtaining a
6*c2c66affSColin Finck  * copy of this software and associated documentation files (the "Software"),
7*c2c66affSColin Finck  * to deal in the Software without restriction, including without limitation
8*c2c66affSColin Finck  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*c2c66affSColin Finck  * and/or sell copies of the Software, and to permit persons to whom the
10*c2c66affSColin Finck  * Software is furnished to do so, subject to the following conditions:
11*c2c66affSColin Finck  *
12*c2c66affSColin Finck  * The above copyright notice including the dates of first publication and
13*c2c66affSColin Finck  * either this permission notice or a reference to
14*c2c66affSColin Finck  * http://oss.sgi.com/projects/FreeB/
15*c2c66affSColin Finck  * shall be included in all copies or substantial portions of the Software.
16*c2c66affSColin Finck  *
17*c2c66affSColin Finck  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18*c2c66affSColin Finck  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19*c2c66affSColin Finck  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20*c2c66affSColin Finck  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21*c2c66affSColin Finck  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22*c2c66affSColin Finck  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23*c2c66affSColin Finck  * SOFTWARE.
24*c2c66affSColin Finck  *
25*c2c66affSColin Finck  * Except as contained in this notice, the name of Silicon Graphics, Inc.
26*c2c66affSColin Finck  * shall not be used in advertising or otherwise to promote the sale, use or
27*c2c66affSColin Finck  * other dealings in this Software without prior written authorization from
28*c2c66affSColin Finck  * Silicon Graphics, Inc.
29*c2c66affSColin Finck  */
30*c2c66affSColin Finck /*
31*c2c66affSColin Finck ** Author: Eric Veach, July 1994.
32*c2c66affSColin Finck **
33*c2c66affSColin Finck */
34*c2c66affSColin Finck 
35*c2c66affSColin Finck #include "gluos.h"
36*c2c66affSColin Finck #include <assert.h>
37*c2c66affSColin Finck //#include <stddef.h>
38*c2c66affSColin Finck //#include "mesh.h"
39*c2c66affSColin Finck #include "tess.h"
40*c2c66affSColin Finck //#include "render.h"
41*c2c66affSColin Finck 
42*c2c66affSColin Finck #ifndef TRUE
43*c2c66affSColin Finck #define TRUE 1
44*c2c66affSColin Finck #endif
45*c2c66affSColin Finck #ifndef FALSE
46*c2c66affSColin Finck #define FALSE 0
47*c2c66affSColin Finck #endif
48*c2c66affSColin Finck 
49*c2c66affSColin Finck /* This structure remembers the information we need about a primitive
50*c2c66affSColin Finck  * to be able to render it later, once we have determined which
51*c2c66affSColin Finck  * primitive is able to use the most triangles.
52*c2c66affSColin Finck  */
53*c2c66affSColin Finck struct FaceCount {
54*c2c66affSColin Finck   long		size;		/* number of triangles used */
55*c2c66affSColin Finck   GLUhalfEdge	*eStart;	/* edge where this primitive starts */
56*c2c66affSColin Finck   void		(*render)(GLUtesselator *, GLUhalfEdge *, long);
57*c2c66affSColin Finck                                 /* routine to render this primitive */
58*c2c66affSColin Finck };
59*c2c66affSColin Finck 
60*c2c66affSColin Finck static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
61*c2c66affSColin Finck static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
62*c2c66affSColin Finck 
63*c2c66affSColin Finck static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
64*c2c66affSColin Finck static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
65*c2c66affSColin Finck static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
66*c2c66affSColin Finck 			    long size );
67*c2c66affSColin Finck 
68*c2c66affSColin Finck static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
69*c2c66affSColin Finck static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
70*c2c66affSColin Finck 
71*c2c66affSColin Finck 
72*c2c66affSColin Finck 
73*c2c66affSColin Finck /************************ Strips and Fans decomposition ******************/
74*c2c66affSColin Finck 
75*c2c66affSColin Finck /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
76*c2c66affSColin Finck  * fans, strips, and separate triangles.  A substantial effort is made
77*c2c66affSColin Finck  * to use as few rendering primitives as possible (ie. to make the fans
78*c2c66affSColin Finck  * and strips as large as possible).
79*c2c66affSColin Finck  *
80*c2c66affSColin Finck  * The rendering output is provided as callbacks (see the api).
81*c2c66affSColin Finck  */
__gl_renderMesh(GLUtesselator * tess,GLUmesh * mesh)82*c2c66affSColin Finck void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
83*c2c66affSColin Finck {
84*c2c66affSColin Finck   GLUface *f;
85*c2c66affSColin Finck 
86*c2c66affSColin Finck   /* Make a list of separate triangles so we can render them all at once */
87*c2c66affSColin Finck   tess->lonelyTriList = NULL;
88*c2c66affSColin Finck 
89*c2c66affSColin Finck   for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
90*c2c66affSColin Finck     f->marked = FALSE;
91*c2c66affSColin Finck   }
92*c2c66affSColin Finck   for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
93*c2c66affSColin Finck 
94*c2c66affSColin Finck     /* We examine all faces in an arbitrary order.  Whenever we find
95*c2c66affSColin Finck      * an unprocessed face F, we output a group of faces including F
96*c2c66affSColin Finck      * whose size is maximum.
97*c2c66affSColin Finck      */
98*c2c66affSColin Finck     if( f->inside && ! f->marked ) {
99*c2c66affSColin Finck       RenderMaximumFaceGroup( tess, f );
100*c2c66affSColin Finck       assert( f->marked );
101*c2c66affSColin Finck     }
102*c2c66affSColin Finck   }
103*c2c66affSColin Finck   if( tess->lonelyTriList != NULL ) {
104*c2c66affSColin Finck     RenderLonelyTriangles( tess, tess->lonelyTriList );
105*c2c66affSColin Finck     tess->lonelyTriList = NULL;
106*c2c66affSColin Finck   }
107*c2c66affSColin Finck }
108*c2c66affSColin Finck 
109*c2c66affSColin Finck 
RenderMaximumFaceGroup(GLUtesselator * tess,GLUface * fOrig)110*c2c66affSColin Finck static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
111*c2c66affSColin Finck {
112*c2c66affSColin Finck   /* We want to find the largest triangle fan or strip of unmarked faces
113*c2c66affSColin Finck    * which includes the given face fOrig.  There are 3 possible fans
114*c2c66affSColin Finck    * passing through fOrig (one centered at each vertex), and 3 possible
115*c2c66affSColin Finck    * strips (one for each CCW permutation of the vertices).  Our strategy
116*c2c66affSColin Finck    * is to try all of these, and take the primitive which uses the most
117*c2c66affSColin Finck    * triangles (a greedy approach).
118*c2c66affSColin Finck    */
119*c2c66affSColin Finck   GLUhalfEdge *e = fOrig->anEdge;
120*c2c66affSColin Finck   struct FaceCount max, newFace;
121*c2c66affSColin Finck 
122*c2c66affSColin Finck   max.size = 1;
123*c2c66affSColin Finck   max.eStart = e;
124*c2c66affSColin Finck   max.render = &RenderTriangle;
125*c2c66affSColin Finck 
126*c2c66affSColin Finck   if( ! tess->flagBoundary ) {
127*c2c66affSColin Finck     newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
128*c2c66affSColin Finck     newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
129*c2c66affSColin Finck     newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
130*c2c66affSColin Finck 
131*c2c66affSColin Finck     newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
132*c2c66affSColin Finck     newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
133*c2c66affSColin Finck     newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
134*c2c66affSColin Finck   }
135*c2c66affSColin Finck   (*(max.render))( tess, max.eStart, max.size );
136*c2c66affSColin Finck }
137*c2c66affSColin Finck 
138*c2c66affSColin Finck 
139*c2c66affSColin Finck /* Macros which keep track of faces we have marked temporarily, and allow
140*c2c66affSColin Finck  * us to backtrack when necessary.  With triangle fans, this is not
141*c2c66affSColin Finck  * really necessary, since the only awkward case is a loop of triangles
142*c2c66affSColin Finck  * around a single origin vertex.  However with strips the situation is
143*c2c66affSColin Finck  * more complicated, and we need a general tracking method like the
144*c2c66affSColin Finck  * one here.
145*c2c66affSColin Finck  */
146*c2c66affSColin Finck #define Marked(f)	(! (f)->inside || (f)->marked)
147*c2c66affSColin Finck 
148*c2c66affSColin Finck #define AddToTrail(f,t)	((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
149*c2c66affSColin Finck 
150*c2c66affSColin Finck #define FreeTrail(t)	do { \
151*c2c66affSColin Finck 			  while( (t) != NULL ) { \
152*c2c66affSColin Finck 			    (t)->marked = FALSE; t = (t)->trail; \
153*c2c66affSColin Finck 			  } \
154*c2c66affSColin Finck 			} while(0) /* absorb trailing semicolon */
155*c2c66affSColin Finck 
156*c2c66affSColin Finck 
157*c2c66affSColin Finck 
MaximumFan(GLUhalfEdge * eOrig)158*c2c66affSColin Finck static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
159*c2c66affSColin Finck {
160*c2c66affSColin Finck   /* eOrig->Lface is the face we want to render.  We want to find the size
161*c2c66affSColin Finck    * of a maximal fan around eOrig->Org.  To do this we just walk around
162*c2c66affSColin Finck    * the origin vertex as far as possible in both directions.
163*c2c66affSColin Finck    */
164*c2c66affSColin Finck   struct FaceCount newFace = { 0, NULL, &RenderFan };
165*c2c66affSColin Finck   GLUface *trail = NULL;
166*c2c66affSColin Finck   GLUhalfEdge *e;
167*c2c66affSColin Finck 
168*c2c66affSColin Finck   for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
169*c2c66affSColin Finck     AddToTrail( e->Lface, trail );
170*c2c66affSColin Finck     ++newFace.size;
171*c2c66affSColin Finck   }
172*c2c66affSColin Finck   for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
173*c2c66affSColin Finck     AddToTrail( e->Rface, trail );
174*c2c66affSColin Finck     ++newFace.size;
175*c2c66affSColin Finck   }
176*c2c66affSColin Finck   newFace.eStart = e;
177*c2c66affSColin Finck   /*LINTED*/
178*c2c66affSColin Finck   FreeTrail( trail );
179*c2c66affSColin Finck   return newFace;
180*c2c66affSColin Finck }
181*c2c66affSColin Finck 
182*c2c66affSColin Finck 
183*c2c66affSColin Finck #define IsEven(n)	(((n) & 1) == 0)
184*c2c66affSColin Finck 
MaximumStrip(GLUhalfEdge * eOrig)185*c2c66affSColin Finck static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
186*c2c66affSColin Finck {
187*c2c66affSColin Finck   /* Here we are looking for a maximal strip that contains the vertices
188*c2c66affSColin Finck    * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
189*c2c66affSColin Finck    * reverse, such that all triangles are oriented CCW).
190*c2c66affSColin Finck    *
191*c2c66affSColin Finck    * Again we walk forward and backward as far as possible.  However for
192*c2c66affSColin Finck    * strips there is a twist: to get CCW orientations, there must be
193*c2c66affSColin Finck    * an *even* number of triangles in the strip on one side of eOrig.
194*c2c66affSColin Finck    * We walk the strip starting on a side with an even number of triangles;
195*c2c66affSColin Finck    * if both side have an odd number, we are forced to shorten one side.
196*c2c66affSColin Finck    */
197*c2c66affSColin Finck   struct FaceCount newFace = { 0, NULL, &RenderStrip };
198*c2c66affSColin Finck   long headSize = 0, tailSize = 0;
199*c2c66affSColin Finck   GLUface *trail = NULL;
200*c2c66affSColin Finck   GLUhalfEdge *e, *eTail, *eHead;
201*c2c66affSColin Finck 
202*c2c66affSColin Finck   for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
203*c2c66affSColin Finck     AddToTrail( e->Lface, trail );
204*c2c66affSColin Finck     ++tailSize;
205*c2c66affSColin Finck     e = e->Dprev;
206*c2c66affSColin Finck     if( Marked( e->Lface )) break;
207*c2c66affSColin Finck     AddToTrail( e->Lface, trail );
208*c2c66affSColin Finck   }
209*c2c66affSColin Finck   eTail = e;
210*c2c66affSColin Finck 
211*c2c66affSColin Finck   for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
212*c2c66affSColin Finck     AddToTrail( e->Rface, trail );
213*c2c66affSColin Finck     ++headSize;
214*c2c66affSColin Finck     e = e->Oprev;
215*c2c66affSColin Finck     if( Marked( e->Rface )) break;
216*c2c66affSColin Finck     AddToTrail( e->Rface, trail );
217*c2c66affSColin Finck   }
218*c2c66affSColin Finck   eHead = e;
219*c2c66affSColin Finck 
220*c2c66affSColin Finck   newFace.size = tailSize + headSize;
221*c2c66affSColin Finck   if( IsEven( tailSize )) {
222*c2c66affSColin Finck     newFace.eStart = eTail->Sym;
223*c2c66affSColin Finck   } else if( IsEven( headSize )) {
224*c2c66affSColin Finck     newFace.eStart = eHead;
225*c2c66affSColin Finck   } else {
226*c2c66affSColin Finck     /* Both sides have odd length, we must shorten one of them.  In fact,
227*c2c66affSColin Finck      * we must start from eHead to guarantee inclusion of eOrig->Lface.
228*c2c66affSColin Finck      */
229*c2c66affSColin Finck     --newFace.size;
230*c2c66affSColin Finck     newFace.eStart = eHead->Onext;
231*c2c66affSColin Finck   }
232*c2c66affSColin Finck   /*LINTED*/
233*c2c66affSColin Finck   FreeTrail( trail );
234*c2c66affSColin Finck   return newFace;
235*c2c66affSColin Finck }
236*c2c66affSColin Finck 
237*c2c66affSColin Finck 
RenderTriangle(GLUtesselator * tess,GLUhalfEdge * e,long size)238*c2c66affSColin Finck static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
239*c2c66affSColin Finck {
240*c2c66affSColin Finck   /* Just add the triangle to a triangle list, so we can render all
241*c2c66affSColin Finck    * the separate triangles at once.
242*c2c66affSColin Finck    */
243*c2c66affSColin Finck   assert( size == 1 );
244*c2c66affSColin Finck   AddToTrail( e->Lface, tess->lonelyTriList );
245*c2c66affSColin Finck }
246*c2c66affSColin Finck 
247*c2c66affSColin Finck 
RenderLonelyTriangles(GLUtesselator * tess,GLUface * f)248*c2c66affSColin Finck static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
249*c2c66affSColin Finck {
250*c2c66affSColin Finck   /* Now we render all the separate triangles which could not be
251*c2c66affSColin Finck    * grouped into a triangle fan or strip.
252*c2c66affSColin Finck    */
253*c2c66affSColin Finck   GLUhalfEdge *e;
254*c2c66affSColin Finck   int newState;
255*c2c66affSColin Finck   int edgeState = -1;	/* force edge state output for first vertex */
256*c2c66affSColin Finck 
257*c2c66affSColin Finck   CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
258*c2c66affSColin Finck 
259*c2c66affSColin Finck   for( ; f != NULL; f = f->trail ) {
260*c2c66affSColin Finck     /* Loop once for each edge (there will always be 3 edges) */
261*c2c66affSColin Finck 
262*c2c66affSColin Finck     e = f->anEdge;
263*c2c66affSColin Finck     do {
264*c2c66affSColin Finck       if( tess->flagBoundary ) {
265*c2c66affSColin Finck 	/* Set the "edge state" to TRUE just before we output the
266*c2c66affSColin Finck 	 * first vertex of each edge on the polygon boundary.
267*c2c66affSColin Finck 	 */
268*c2c66affSColin Finck 	newState = ! e->Rface->inside;
269*c2c66affSColin Finck 	if( edgeState != newState ) {
270*c2c66affSColin Finck 	  edgeState = newState;
271*c2c66affSColin Finck           CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
272*c2c66affSColin Finck 	}
273*c2c66affSColin Finck       }
274*c2c66affSColin Finck       CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
275*c2c66affSColin Finck 
276*c2c66affSColin Finck       e = e->Lnext;
277*c2c66affSColin Finck     } while( e != f->anEdge );
278*c2c66affSColin Finck   }
279*c2c66affSColin Finck   CALL_END_OR_END_DATA();
280*c2c66affSColin Finck }
281*c2c66affSColin Finck 
282*c2c66affSColin Finck 
RenderFan(GLUtesselator * tess,GLUhalfEdge * e,long size)283*c2c66affSColin Finck static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
284*c2c66affSColin Finck {
285*c2c66affSColin Finck   /* Render as many CCW triangles as possible in a fan starting from
286*c2c66affSColin Finck    * edge "e".  The fan *should* contain exactly "size" triangles
287*c2c66affSColin Finck    * (otherwise we've goofed up somewhere).
288*c2c66affSColin Finck    */
289*c2c66affSColin Finck   CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
290*c2c66affSColin Finck   CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
291*c2c66affSColin Finck   CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
292*c2c66affSColin Finck 
293*c2c66affSColin Finck   while( ! Marked( e->Lface )) {
294*c2c66affSColin Finck     e->Lface->marked = TRUE;
295*c2c66affSColin Finck     --size;
296*c2c66affSColin Finck     e = e->Onext;
297*c2c66affSColin Finck     CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
298*c2c66affSColin Finck   }
299*c2c66affSColin Finck 
300*c2c66affSColin Finck   assert( size == 0 );
301*c2c66affSColin Finck   CALL_END_OR_END_DATA();
302*c2c66affSColin Finck }
303*c2c66affSColin Finck 
304*c2c66affSColin Finck 
RenderStrip(GLUtesselator * tess,GLUhalfEdge * e,long size)305*c2c66affSColin Finck static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
306*c2c66affSColin Finck {
307*c2c66affSColin Finck   /* Render as many CCW triangles as possible in a strip starting from
308*c2c66affSColin Finck    * edge "e".  The strip *should* contain exactly "size" triangles
309*c2c66affSColin Finck    * (otherwise we've goofed up somewhere).
310*c2c66affSColin Finck    */
311*c2c66affSColin Finck   CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
312*c2c66affSColin Finck   CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
313*c2c66affSColin Finck   CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
314*c2c66affSColin Finck 
315*c2c66affSColin Finck   while( ! Marked( e->Lface )) {
316*c2c66affSColin Finck     e->Lface->marked = TRUE;
317*c2c66affSColin Finck     --size;
318*c2c66affSColin Finck     e = e->Dprev;
319*c2c66affSColin Finck     CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
320*c2c66affSColin Finck     if( Marked( e->Lface )) break;
321*c2c66affSColin Finck 
322*c2c66affSColin Finck     e->Lface->marked = TRUE;
323*c2c66affSColin Finck     --size;
324*c2c66affSColin Finck     e = e->Onext;
325*c2c66affSColin Finck     CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
326*c2c66affSColin Finck   }
327*c2c66affSColin Finck 
328*c2c66affSColin Finck   assert( size == 0 );
329*c2c66affSColin Finck   CALL_END_OR_END_DATA();
330*c2c66affSColin Finck }
331*c2c66affSColin Finck 
332*c2c66affSColin Finck 
333*c2c66affSColin Finck /************************ Boundary contour decomposition ******************/
334*c2c66affSColin Finck 
335*c2c66affSColin Finck /* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
336*c2c66affSColin Finck  * contour for each face marked "inside".  The rendering output is
337*c2c66affSColin Finck  * provided as callbacks (see the api).
338*c2c66affSColin Finck  */
__gl_renderBoundary(GLUtesselator * tess,GLUmesh * mesh)339*c2c66affSColin Finck void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
340*c2c66affSColin Finck {
341*c2c66affSColin Finck   GLUface *f;
342*c2c66affSColin Finck   GLUhalfEdge *e;
343*c2c66affSColin Finck 
344*c2c66affSColin Finck   for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
345*c2c66affSColin Finck     if( f->inside ) {
346*c2c66affSColin Finck       CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
347*c2c66affSColin Finck       e = f->anEdge;
348*c2c66affSColin Finck       do {
349*c2c66affSColin Finck         CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
350*c2c66affSColin Finck 	e = e->Lnext;
351*c2c66affSColin Finck       } while( e != f->anEdge );
352*c2c66affSColin Finck       CALL_END_OR_END_DATA();
353*c2c66affSColin Finck     }
354*c2c66affSColin Finck   }
355*c2c66affSColin Finck }
356*c2c66affSColin Finck 
357*c2c66affSColin Finck 
358*c2c66affSColin Finck /************************ Quick-and-dirty decomposition ******************/
359*c2c66affSColin Finck 
360*c2c66affSColin Finck #define SIGN_INCONSISTENT 2
361*c2c66affSColin Finck 
ComputeNormal(GLUtesselator * tess,GLdouble norm[3],int check)362*c2c66affSColin Finck static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
363*c2c66affSColin Finck /*
364*c2c66affSColin Finck  * If check==FALSE, we compute the polygon normal and place it in norm[].
365*c2c66affSColin Finck  * If check==TRUE, we check that each triangle in the fan from v0 has a
366*c2c66affSColin Finck  * consistent orientation with respect to norm[].  If triangles are
367*c2c66affSColin Finck  * consistently oriented CCW, return 1; if CW, return -1; if all triangles
368*c2c66affSColin Finck  * are degenerate return 0; otherwise (no consistent orientation) return
369*c2c66affSColin Finck  * SIGN_INCONSISTENT.
370*c2c66affSColin Finck  */
371*c2c66affSColin Finck {
372*c2c66affSColin Finck   CachedVertex *v0 = tess->cache;
373*c2c66affSColin Finck   CachedVertex *vn = v0 + tess->cacheCount;
374*c2c66affSColin Finck   CachedVertex *vc;
375*c2c66affSColin Finck   GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
376*c2c66affSColin Finck   int sign = 0;
377*c2c66affSColin Finck 
378*c2c66affSColin Finck   /* Find the polygon normal.  It is important to get a reasonable
379*c2c66affSColin Finck    * normal even when the polygon is self-intersecting (eg. a bowtie).
380*c2c66affSColin Finck    * Otherwise, the computed normal could be very tiny, but perpendicular
381*c2c66affSColin Finck    * to the true plane of the polygon due to numerical noise.  Then all
382*c2c66affSColin Finck    * the triangles would appear to be degenerate and we would incorrectly
383*c2c66affSColin Finck    * decompose the polygon as a fan (or simply not render it at all).
384*c2c66affSColin Finck    *
385*c2c66affSColin Finck    * We use a sum-of-triangles normal algorithm rather than the more
386*c2c66affSColin Finck    * efficient sum-of-trapezoids method (used in CheckOrientation()
387*c2c66affSColin Finck    * in normal.c).  This lets us explicitly reverse the signed area
388*c2c66affSColin Finck    * of some triangles to get a reasonable normal in the self-intersecting
389*c2c66affSColin Finck    * case.
390*c2c66affSColin Finck    */
391*c2c66affSColin Finck   if( ! check ) {
392*c2c66affSColin Finck     norm[0] = norm[1] = norm[2] = 0.0;
393*c2c66affSColin Finck   }
394*c2c66affSColin Finck 
395*c2c66affSColin Finck   vc = v0 + 1;
396*c2c66affSColin Finck   xc = vc->coords[0] - v0->coords[0];
397*c2c66affSColin Finck   yc = vc->coords[1] - v0->coords[1];
398*c2c66affSColin Finck   zc = vc->coords[2] - v0->coords[2];
399*c2c66affSColin Finck   while( ++vc < vn ) {
400*c2c66affSColin Finck     xp = xc; yp = yc; zp = zc;
401*c2c66affSColin Finck     xc = vc->coords[0] - v0->coords[0];
402*c2c66affSColin Finck     yc = vc->coords[1] - v0->coords[1];
403*c2c66affSColin Finck     zc = vc->coords[2] - v0->coords[2];
404*c2c66affSColin Finck 
405*c2c66affSColin Finck     /* Compute (vp - v0) cross (vc - v0) */
406*c2c66affSColin Finck     n[0] = yp*zc - zp*yc;
407*c2c66affSColin Finck     n[1] = zp*xc - xp*zc;
408*c2c66affSColin Finck     n[2] = xp*yc - yp*xc;
409*c2c66affSColin Finck 
410*c2c66affSColin Finck     dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
411*c2c66affSColin Finck     if( ! check ) {
412*c2c66affSColin Finck       /* Reverse the contribution of back-facing triangles to get
413*c2c66affSColin Finck        * a reasonable normal for self-intersecting polygons (see above)
414*c2c66affSColin Finck        */
415*c2c66affSColin Finck       if( dot >= 0 ) {
416*c2c66affSColin Finck 	norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
417*c2c66affSColin Finck       } else {
418*c2c66affSColin Finck 	norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
419*c2c66affSColin Finck       }
420*c2c66affSColin Finck     } else if( dot != 0 ) {
421*c2c66affSColin Finck       /* Check the new orientation for consistency with previous triangles */
422*c2c66affSColin Finck       if( dot > 0 ) {
423*c2c66affSColin Finck 	if( sign < 0 ) return SIGN_INCONSISTENT;
424*c2c66affSColin Finck 	sign = 1;
425*c2c66affSColin Finck       } else {
426*c2c66affSColin Finck 	if( sign > 0 ) return SIGN_INCONSISTENT;
427*c2c66affSColin Finck 	sign = -1;
428*c2c66affSColin Finck       }
429*c2c66affSColin Finck     }
430*c2c66affSColin Finck   }
431*c2c66affSColin Finck   return sign;
432*c2c66affSColin Finck }
433*c2c66affSColin Finck 
434*c2c66affSColin Finck /* __gl_renderCache( tess ) takes a single contour and tries to render it
435*c2c66affSColin Finck  * as a triangle fan.  This handles convex polygons, as well as some
436*c2c66affSColin Finck  * non-convex polygons if we get lucky.
437*c2c66affSColin Finck  *
438*c2c66affSColin Finck  * Returns TRUE if the polygon was successfully rendered.  The rendering
439*c2c66affSColin Finck  * output is provided as callbacks (see the api).
440*c2c66affSColin Finck  */
__gl_renderCache(GLUtesselator * tess)441*c2c66affSColin Finck GLboolean __gl_renderCache( GLUtesselator *tess )
442*c2c66affSColin Finck {
443*c2c66affSColin Finck   CachedVertex *v0 = tess->cache;
444*c2c66affSColin Finck   CachedVertex *vn = v0 + tess->cacheCount;
445*c2c66affSColin Finck   CachedVertex *vc;
446*c2c66affSColin Finck   GLdouble norm[3];
447*c2c66affSColin Finck   int sign;
448*c2c66affSColin Finck 
449*c2c66affSColin Finck   if( tess->cacheCount < 3 ) {
450*c2c66affSColin Finck     /* Degenerate contour -- no output */
451*c2c66affSColin Finck     return TRUE;
452*c2c66affSColin Finck   }
453*c2c66affSColin Finck 
454*c2c66affSColin Finck   norm[0] = tess->normal[0];
455*c2c66affSColin Finck   norm[1] = tess->normal[1];
456*c2c66affSColin Finck   norm[2] = tess->normal[2];
457*c2c66affSColin Finck   if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
458*c2c66affSColin Finck     ComputeNormal( tess, norm, FALSE );
459*c2c66affSColin Finck   }
460*c2c66affSColin Finck 
461*c2c66affSColin Finck   sign = ComputeNormal( tess, norm, TRUE );
462*c2c66affSColin Finck   if( sign == SIGN_INCONSISTENT ) {
463*c2c66affSColin Finck     /* Fan triangles did not have a consistent orientation */
464*c2c66affSColin Finck     return FALSE;
465*c2c66affSColin Finck   }
466*c2c66affSColin Finck   if( sign == 0 ) {
467*c2c66affSColin Finck     /* All triangles were degenerate */
468*c2c66affSColin Finck     return TRUE;
469*c2c66affSColin Finck   }
470*c2c66affSColin Finck 
471*c2c66affSColin Finck   /* Make sure we do the right thing for each winding rule */
472*c2c66affSColin Finck   switch( tess->windingRule ) {
473*c2c66affSColin Finck   case GLU_TESS_WINDING_ODD:
474*c2c66affSColin Finck   case GLU_TESS_WINDING_NONZERO:
475*c2c66affSColin Finck     break;
476*c2c66affSColin Finck   case GLU_TESS_WINDING_POSITIVE:
477*c2c66affSColin Finck     if( sign < 0 ) return TRUE;
478*c2c66affSColin Finck     break;
479*c2c66affSColin Finck   case GLU_TESS_WINDING_NEGATIVE:
480*c2c66affSColin Finck     if( sign > 0 ) return TRUE;
481*c2c66affSColin Finck     break;
482*c2c66affSColin Finck   case GLU_TESS_WINDING_ABS_GEQ_TWO:
483*c2c66affSColin Finck     return TRUE;
484*c2c66affSColin Finck   }
485*c2c66affSColin Finck 
486*c2c66affSColin Finck   CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
487*c2c66affSColin Finck 			  : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
488*c2c66affSColin Finck 			  : GL_TRIANGLES );
489*c2c66affSColin Finck 
490*c2c66affSColin Finck   CALL_VERTEX_OR_VERTEX_DATA( v0->data );
491*c2c66affSColin Finck   if( sign > 0 ) {
492*c2c66affSColin Finck     for( vc = v0+1; vc < vn; ++vc ) {
493*c2c66affSColin Finck       CALL_VERTEX_OR_VERTEX_DATA( vc->data );
494*c2c66affSColin Finck     }
495*c2c66affSColin Finck   } else {
496*c2c66affSColin Finck     for( vc = vn-1; vc > v0; --vc ) {
497*c2c66affSColin Finck       CALL_VERTEX_OR_VERTEX_DATA( vc->data );
498*c2c66affSColin Finck     }
499*c2c66affSColin Finck   }
500*c2c66affSColin Finck   CALL_END_OR_END_DATA();
501*c2c66affSColin Finck   return TRUE;
502*c2c66affSColin Finck }
503