Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/Geant4/tools/glutess/render is written in an unsupported language. File is not indexed.

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