File indexing completed on 2024-04-21 14:46:25

0001 /*
0002 ** Author: Eric Veach, July 1994.
0003 **
0004 */
0005 
0006 #include "gluos.h"
0007 #include <assert.h>
0008 #include <stddef.h>
0009 #include "mesh.h"
0010 #include "tess.h"
0011 #include "render.h"
0012 
0013 #ifndef TRUE
0014 #define TRUE 1
0015 #endif
0016 #ifndef FALSE
0017 #define FALSE 0
0018 #endif
0019 
0020 /* This structure remembers the information we need about a primitive
0021  * to be able to render it later, once we have determined which
0022  * primitive is able to use the most triangles.
0023  */
0024 struct FaceCount
0025 {
0026     long size;           /* number of triangles used */
0027     GLUhalfEdge *eStart; /* edge where this primitive starts */
0028     void (*render)(GLUtesselator *, GLUhalfEdge *, long);
0029     /* routine to render this primitive */
0030 };
0031 
0032 static struct FaceCount MaximumFan(GLUhalfEdge *eOrig);
0033 static struct FaceCount MaximumStrip(GLUhalfEdge *eOrig);
0034 
0035 static void RenderFan(GLUtesselator *tess, GLUhalfEdge *eStart, long size);
0036 static void RenderStrip(GLUtesselator *tess, GLUhalfEdge *eStart, long size);
0037 static void RenderTriangle(GLUtesselator *tess, GLUhalfEdge *eStart, long size);
0038 
0039 static void RenderMaximumFaceGroup(GLUtesselator *tess, GLUface *fOrig);
0040 static void RenderLonelyTriangles(GLUtesselator *tess, GLUface *head);
0041 
0042 /************************ Strips and Fans decomposition ******************/
0043 
0044 /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
0045  * fans, strips, and separate triangles.  A substantial effort is made
0046  * to use as few rendering primitives as possible (ie. to make the fans
0047  * and strips as large as possible).
0048  *
0049  * The rendering output is provided as callbacks (see the api).
0050  */
0051 void __gl_renderMesh(GLUtesselator *tess, GLUmesh *mesh)
0052 {
0053     GLUface *f;
0054 
0055     /* Make a list of separate triangles so we can render them all at once */
0056     tess->lonelyTriList = NULL;
0057 
0058     for (f = mesh->fHead.next; f != &mesh->fHead; f = f->next)
0059     {
0060         f->marked = FALSE;
0061     }
0062     for (f = mesh->fHead.next; f != &mesh->fHead; f = f->next)
0063     {
0064         /* We examine all faces in an arbitrary order.  Whenever we find
0065      * an unprocessed face F, we output a group of faces including F
0066      * whose size is maximum.
0067      */
0068         if (f->inside && !f->marked)
0069         {
0070             RenderMaximumFaceGroup(tess, f);
0071             assert(f->marked);
0072         }
0073     }
0074     if (tess->lonelyTriList != NULL)
0075     {
0076         RenderLonelyTriangles(tess, tess->lonelyTriList);
0077         tess->lonelyTriList = NULL;
0078     }
0079 }
0080 
0081 static void RenderMaximumFaceGroup(GLUtesselator *tess, GLUface *fOrig)
0082 {
0083     /* We want to find the largest triangle fan or strip of unmarked faces
0084    * which includes the given face fOrig.  There are 3 possible fans
0085    * passing through fOrig (one centered at each vertex), and 3 possible
0086    * strips (one for each CCW permutation of the vertices).  Our strategy
0087    * is to try all of these, and take the primitive which uses the most
0088    * triangles (a greedy approach).
0089    */
0090     GLUhalfEdge *e = fOrig->anEdge;
0091     struct FaceCount max, newFace;
0092 
0093     max.size   = 1;
0094     max.eStart = e;
0095     max.render = &RenderTriangle;
0096 
0097     if (!tess->flagBoundary)
0098     {
0099         newFace = MaximumFan(e);
0100         if (newFace.size > max.size)
0101         {
0102             max = newFace;
0103         }
0104         newFace = MaximumFan(e->Lnext);
0105         if (newFace.size > max.size)
0106         {
0107             max = newFace;
0108         }
0109         newFace = MaximumFan(e->Lprev);
0110         if (newFace.size > max.size)
0111         {
0112             max = newFace;
0113         }
0114 
0115         newFace = MaximumStrip(e);
0116         if (newFace.size > max.size)
0117         {
0118             max = newFace;
0119         }
0120         newFace = MaximumStrip(e->Lnext);
0121         if (newFace.size > max.size)
0122         {
0123             max = newFace;
0124         }
0125         newFace = MaximumStrip(e->Lprev);
0126         if (newFace.size > max.size)
0127         {
0128             max = newFace;
0129         }
0130     }
0131     (*(max.render))(tess, max.eStart, max.size);
0132 }
0133 
0134 /* Macros which keep track of faces we have marked temporarily, and allow
0135  * us to backtrack when necessary.  With triangle fans, this is not
0136  * really necessary, since the only awkward case is a loop of triangles
0137  * around a single origin vertex.  However with strips the situation is
0138  * more complicated, and we need a general tracking method like the
0139  * one here.
0140  */
0141 #define Marked(f) (!(f)->inside || (f)->marked)
0142 
0143 #define AddToTrail(f, t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
0144 
0145 #define FreeTrail(t)                  \
0146     do                                \
0147     {                                 \
0148         while ((t) != NULL)           \
0149         {                             \
0150             (t)->marked = FALSE;      \
0151             t           = (t)->trail; \
0152         }                             \
0153     } while (0) /* absorb trailing semicolon */
0154 
0155 static struct FaceCount MaximumFan(GLUhalfEdge *eOrig)
0156 {
0157     /* eOrig->Lface is the face we want to render.  We want to find the size
0158    * of a maximal fan around eOrig->Org.  To do this we just walk around
0159    * the origin vertex as far as possible in both directions.
0160    */
0161     struct FaceCount newFace = { 0, NULL, &RenderFan };
0162     GLUface *trail           = NULL;
0163     GLUhalfEdge *e;
0164 
0165     for (e = eOrig; !Marked(e->Lface); e = e->Onext)
0166     {
0167         AddToTrail(e->Lface, trail);
0168         ++newFace.size;
0169     }
0170     for (e = eOrig; !Marked(e->Rface); e = e->Oprev)
0171     {
0172         AddToTrail(e->Rface, trail);
0173         ++newFace.size;
0174     }
0175     newFace.eStart = e;
0176     /*LINTED*/
0177     FreeTrail(trail);
0178     return newFace;
0179 }
0180 
0181 #define IsEven(n) (((n)&1) == 0)
0182 
0183 static struct FaceCount MaximumStrip(GLUhalfEdge *eOrig)
0184 {
0185     /* Here we are looking for a maximal strip that contains the vertices
0186    * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
0187    * reverse, such that all triangles are oriented CCW).
0188    *
0189    * Again we walk forward and backward as far as possible.  However for
0190    * strips there is a twist: to get CCW orientations, there must be
0191    * an *even* number of triangles in the strip on one side of eOrig.
0192    * We walk the strip starting on a side with an even number of triangles;
0193    * if both side have an odd number, we are forced to shorten one side.
0194    */
0195     struct FaceCount newFace = { 0, NULL, &RenderStrip };
0196     long headSize = 0, tailSize = 0;
0197     GLUface *trail = NULL;
0198     GLUhalfEdge *e, *eTail, *eHead;
0199 
0200     for (e = eOrig; !Marked(e->Lface); ++tailSize, e = e->Onext)
0201     {
0202         AddToTrail(e->Lface, trail);
0203         ++tailSize;
0204         e = e->Dprev;
0205         if (Marked(e->Lface))
0206             break;
0207         AddToTrail(e->Lface, trail);
0208     }
0209     eTail = e;
0210 
0211     for (e = eOrig; !Marked(e->Rface); ++headSize, e = e->Dnext)
0212     {
0213         AddToTrail(e->Rface, trail);
0214         ++headSize;
0215         e = e->Oprev;
0216         if (Marked(e->Rface))
0217             break;
0218         AddToTrail(e->Rface, trail);
0219     }
0220     eHead = e;
0221 
0222     newFace.size = tailSize + headSize;
0223     if (IsEven(tailSize))
0224     {
0225         newFace.eStart = eTail->Sym;
0226     }
0227     else if (IsEven(headSize))
0228     {
0229         newFace.eStart = eHead;
0230     }
0231     else
0232     {
0233         /* Both sides have odd length, we must shorten one of them.  In fact,
0234      * we must start from eHead to guarantee inclusion of eOrig->Lface.
0235      */
0236         --newFace.size;
0237         newFace.eStart = eHead->Onext;
0238     }
0239     /*LINTED*/
0240     FreeTrail(trail);
0241     return newFace;
0242 }
0243 
0244 static void RenderTriangle(GLUtesselator *tess, GLUhalfEdge *e, long size)
0245 {
0246     /* Just add the triangle to a triangle list, so we can render all
0247    * the separate triangles at once.
0248    */
0249     assert(size == 1);
0250     AddToTrail(e->Lface, tess->lonelyTriList);
0251 }
0252 
0253 static void RenderLonelyTriangles(GLUtesselator *tess, GLUface *f)
0254 {
0255     /* Now we render all the separate triangles which could not be
0256    * grouped into a triangle fan or strip.
0257    */
0258     GLUhalfEdge *e;
0259     int newState;
0260     int edgeState = -1; /* force edge state output for first vertex */
0261 
0262     CALL_BEGIN_OR_BEGIN_DATA(GL_TRIANGLES);
0263 
0264     for (; f != NULL; f = f->trail)
0265     {
0266         /* Loop once for each edge (there will always be 3 edges) */
0267 
0268         e = f->anEdge;
0269         do
0270         {
0271             if (tess->flagBoundary)
0272             {
0273                 /* Set the "edge state" to TRUE just before we output the
0274      * first vertex of each edge on the polygon boundary.
0275      */
0276                 newState = !e->Rface->inside;
0277                 if (edgeState != newState)
0278                 {
0279                     edgeState = newState;
0280                     CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(edgeState);
0281                 }
0282             }
0283             CALL_VERTEX_OR_VERTEX_DATA(e->Org->data);
0284 
0285             e = e->Lnext;
0286         } while (e != f->anEdge);
0287     }
0288     CALL_END_OR_END_DATA();
0289 }
0290 
0291 static void RenderFan(GLUtesselator *tess, GLUhalfEdge *e, long size)
0292 {
0293     /* Render as many CCW triangles as possible in a fan starting from
0294    * edge "e".  The fan *should* contain exactly "size" triangles
0295    * (otherwise we've goofed up somewhere).
0296    */
0297     CALL_BEGIN_OR_BEGIN_DATA(GL_TRIANGLE_FAN);
0298     CALL_VERTEX_OR_VERTEX_DATA(e->Org->data);
0299     CALL_VERTEX_OR_VERTEX_DATA(e->Dst->data);
0300 
0301     while (!Marked(e->Lface))
0302     {
0303         e->Lface->marked = TRUE;
0304         --size;
0305         e = e->Onext;
0306         CALL_VERTEX_OR_VERTEX_DATA(e->Dst->data);
0307     }
0308 
0309     assert(size == 0);
0310     CALL_END_OR_END_DATA();
0311 }
0312 
0313 static void RenderStrip(GLUtesselator *tess, GLUhalfEdge *e, long size)
0314 {
0315     /* Render as many CCW triangles as possible in a strip starting from
0316    * edge "e".  The strip *should* contain exactly "size" triangles
0317    * (otherwise we've goofed up somewhere).
0318    */
0319     CALL_BEGIN_OR_BEGIN_DATA(GL_TRIANGLE_STRIP);
0320     CALL_VERTEX_OR_VERTEX_DATA(e->Org->data);
0321     CALL_VERTEX_OR_VERTEX_DATA(e->Dst->data);
0322 
0323     while (!Marked(e->Lface))
0324     {
0325         e->Lface->marked = TRUE;
0326         --size;
0327         e = e->Dprev;
0328         CALL_VERTEX_OR_VERTEX_DATA(e->Org->data);
0329         if (Marked(e->Lface))
0330             break;
0331 
0332         e->Lface->marked = TRUE;
0333         --size;
0334         e = e->Onext;
0335         CALL_VERTEX_OR_VERTEX_DATA(e->Dst->data);
0336     }
0337 
0338     assert(size == 0);
0339     CALL_END_OR_END_DATA();
0340 }
0341 
0342 /************************ Boundary contour decomposition ******************/
0343 
0344 /* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
0345  * contour for each face marked "inside".  The rendering output is
0346  * provided as callbacks (see the api).
0347  */
0348 void __gl_renderBoundary(GLUtesselator *tess, GLUmesh *mesh)
0349 {
0350     GLUface *f;
0351     GLUhalfEdge *e;
0352 
0353     for (f = mesh->fHead.next; f != &mesh->fHead; f = f->next)
0354     {
0355         if (f->inside)
0356         {
0357             CALL_BEGIN_OR_BEGIN_DATA(GL_LINE_LOOP);
0358             e = f->anEdge;
0359             do
0360             {
0361                 CALL_VERTEX_OR_VERTEX_DATA(e->Org->data);
0362                 e = e->Lnext;
0363             } while (e != f->anEdge);
0364             CALL_END_OR_END_DATA();
0365         }
0366     }
0367 }
0368 
0369 /************************ Quick-and-dirty decomposition ******************/
0370 
0371 #define SIGN_INCONSISTENT 2
0372 
0373 static int ComputeNormal(GLUtesselator *tess, GLdouble norm[3], int check)
0374 /*
0375  * If check==FALSE, we compute the polygon normal and place it in norm[].
0376  * If check==TRUE, we check that each triangle in the fan from v0 has a
0377  * consistent orientation with respect to norm[].  If triangles are
0378  * consistently oriented CCW, return 1; if CW, return -1; if all triangles
0379  * are degenerate return 0; otherwise (no consistent orientation) return
0380  * SIGN_INCONSISTENT.
0381  */
0382 {
0383     CachedVertex *v0 = tess->cache;
0384     CachedVertex *vn = v0 + tess->cacheCount;
0385     CachedVertex *vc;
0386     GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
0387     int sign = 0;
0388 
0389     /* Find the polygon normal.  It is important to get a reasonable
0390    * normal even when the polygon is self-intersecting (eg. a bowtie).
0391    * Otherwise, the computed normal could be very tiny, but perpendicular
0392    * to the true plane of the polygon due to numerical noise.  Then all
0393    * the triangles would appear to be degenerate and we would incorrectly
0394    * decompose the polygon as a fan (or simply not render it at all).
0395    *
0396    * We use a sum-of-triangles normal algorithm rather than the more
0397    * efficient sum-of-trapezoids method (used in CheckOrientation()
0398    * in normal.c).  This lets us explicitly reverse the signed area
0399    * of some triangles to get a reasonable normal in the self-intersecting
0400    * case.
0401    */
0402     if (!check)
0403     {
0404         norm[0] = norm[1] = norm[2] = 0.0;
0405     }
0406 
0407     vc = v0 + 1;
0408     xc = vc->coords[0] - v0->coords[0];
0409     yc = vc->coords[1] - v0->coords[1];
0410     zc = vc->coords[2] - v0->coords[2];
0411     while (++vc < vn)
0412     {
0413         xp = xc;
0414         yp = yc;
0415         zp = zc;
0416         xc = vc->coords[0] - v0->coords[0];
0417         yc = vc->coords[1] - v0->coords[1];
0418         zc = vc->coords[2] - v0->coords[2];
0419 
0420         /* Compute (vp - v0) cross (vc - v0) */
0421         n[0] = yp * zc - zp * yc;
0422         n[1] = zp * xc - xp * zc;
0423         n[2] = xp * yc - yp * xc;
0424 
0425         dot = n[0] * norm[0] + n[1] * norm[1] + n[2] * norm[2];
0426         if (!check)
0427         {
0428             /* Reverse the contribution of back-facing triangles to get
0429        * a reasonable normal for self-intersecting polygons (see above)
0430        */
0431             if (dot >= 0)
0432             {
0433                 norm[0] += n[0];
0434                 norm[1] += n[1];
0435                 norm[2] += n[2];
0436             }
0437             else
0438             {
0439                 norm[0] -= n[0];
0440                 norm[1] -= n[1];
0441                 norm[2] -= n[2];
0442             }
0443         }
0444         else if (dot != 0)
0445         {
0446             /* Check the new orientation for consistency with previous triangles */
0447             if (dot > 0)
0448             {
0449                 if (sign < 0)
0450                     return SIGN_INCONSISTENT;
0451                 sign = 1;
0452             }
0453             else
0454             {
0455                 if (sign > 0)
0456                     return SIGN_INCONSISTENT;
0457                 sign = -1;
0458             }
0459         }
0460     }
0461     return sign;
0462 }
0463 
0464 /* __gl_renderCache( tess ) takes a single contour and tries to render it
0465  * as a triangle fan.  This handles convex polygons, as well as some
0466  * non-convex polygons if we get lucky.
0467  *
0468  * Returns TRUE if the polygon was successfully rendered.  The rendering
0469  * output is provided as callbacks (see the api).
0470  */
0471 GLboolean __gl_renderCache(GLUtesselator *tess)
0472 {
0473     CachedVertex *v0 = tess->cache;
0474     CachedVertex *vn = v0 + tess->cacheCount;
0475     CachedVertex *vc;
0476     GLdouble norm[3];
0477     int sign;
0478 
0479     if (tess->cacheCount < 3)
0480     {
0481         /* Degenerate contour -- no output */
0482         return TRUE;
0483     }
0484 
0485     norm[0] = tess->normal[0];
0486     norm[1] = tess->normal[1];
0487     norm[2] = tess->normal[2];
0488     if (norm[0] == 0 && norm[1] == 0 && norm[2] == 0)
0489     {
0490         ComputeNormal(tess, norm, FALSE);
0491     }
0492 
0493     sign = ComputeNormal(tess, norm, TRUE);
0494     if (sign == SIGN_INCONSISTENT)
0495     {
0496         /* Fan triangles did not have a consistent orientation */
0497         return FALSE;
0498     }
0499     if (sign == 0)
0500     {
0501         /* All triangles were degenerate */
0502         return TRUE;
0503     }
0504 
0505     /* Make sure we do the right thing for each winding rule */
0506     switch (tess->windingRule)
0507     {
0508         case GLU_TESS_WINDING_ODD:
0509         case GLU_TESS_WINDING_NONZERO:
0510             break;
0511         case GLU_TESS_WINDING_POSITIVE:
0512             if (sign < 0)
0513                 return TRUE;
0514             break;
0515         case GLU_TESS_WINDING_NEGATIVE:
0516             if (sign > 0)
0517                 return TRUE;
0518             break;
0519         case GLU_TESS_WINDING_ABS_GEQ_TWO:
0520             return TRUE;
0521     }
0522 
0523     CALL_BEGIN_OR_BEGIN_DATA(tess->boundaryOnly ? GL_LINE_LOOP :
0524                                                   (tess->cacheCount > 3) ? GL_TRIANGLE_FAN : GL_TRIANGLES);
0525 
0526     CALL_VERTEX_OR_VERTEX_DATA(v0->data);
0527     if (sign > 0)
0528     {
0529         for (vc = v0 + 1; vc < vn; ++vc)
0530         {
0531             CALL_VERTEX_OR_VERTEX_DATA(vc->data);
0532         }
0533     }
0534     else
0535     {
0536         for (vc = vn - 1; vc > v0; --vc)
0537         {
0538             CALL_VERTEX_OR_VERTEX_DATA(vc->data);
0539         }
0540     }
0541     CALL_END_OR_END_DATA();
0542     return TRUE;
0543 }