ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

render.c
Go to the documentation of this file.
00001 /*
00002 ** License Applicability. Except to the extent portions of this file are
00003 ** made subject to an alternative license as permitted in the SGI Free
00004 ** Software License B, Version 1.1 (the "License"), the contents of this
00005 ** file are subject only to the provisions of the License. You may not use
00006 ** this file except in compliance with the License. You may obtain a copy
00007 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
00008 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
00009 **
00010 ** http://oss.sgi.com/projects/FreeB
00011 **
00012 ** Note that, as provided in the License, the Software is distributed on an
00013 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
00014 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
00015 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
00016 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
00017 **
00018 ** Original Code. The Original Code is: OpenGL Sample Implementation,
00019 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
00020 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
00021 ** Copyright in any portions created by third parties is as indicated
00022 ** elsewhere herein. All Rights Reserved.
00023 **
00024 ** Additional Notice Provisions: The application programming interfaces
00025 ** established by SGI in conjunction with the Original Code are The
00026 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
00027 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
00028 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
00029 ** Window System(R) (Version 1.3), released October 19, 1998. This software
00030 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
00031 ** published by SGI, but has not been independently verified as being
00032 ** compliant with the OpenGL(R) version 1.2.1 Specification.
00033 **
00034 */
00035 /*
00036 ** Author: Eric Veach, July 1994.
00037 **
00038 ** $Date: 2007-10-19 23:21:45 +0000 (Fri, 19 Oct 2007) $ $Revision: 1.1 $
00039 ** $Header: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/glu32/libtess/render.c,v 1.1 2004/02/02 16:39:15 navaraf Exp $
00040 */
00041 
00042 #include "gluos.h"
00043 #include <assert.h>
00044 #include <stddef.h>
00045 #include "mesh.h"
00046 #include "tess.h"
00047 #include "render.h"
00048 
00049 #define TRUE 1
00050 #define FALSE 0
00051 
00052 /* This structure remembers the information we need about a primitive
00053  * to be able to render it later, once we have determined which
00054  * primitive is able to use the most triangles.
00055  */
00056 struct FaceCount {
00057   long      size;       /* number of triangles used */
00058   GLUhalfEdge   *eStart;    /* edge where this primitive starts */
00059   void      (*render)(GLUtesselator *, GLUhalfEdge *, long);
00060                                 /* routine to render this primitive */
00061 };
00062 
00063 static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
00064 static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
00065 
00066 static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
00067 static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
00068 static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
00069                 long size );
00070 
00071 static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
00072 static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
00073 
00074 
00075 
00076 /************************ Strips and Fans decomposition ******************/
00077 
00078 /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
00079  * fans, strips, and separate triangles.  A substantial effort is made
00080  * to use as few rendering primitives as possible (ie. to make the fans
00081  * and strips as large as possible).
00082  *
00083  * The rendering output is provided as callbacks (see the api).
00084  */
00085 void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
00086 {
00087   GLUface *f;
00088 
00089   /* Make a list of separate triangles so we can render them all at once */
00090   tess->lonelyTriList = NULL;
00091 
00092   for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
00093     f->marked = FALSE;
00094   }
00095   for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
00096 
00097     /* We examine all faces in an arbitrary order.  Whenever we find
00098      * an unprocessed face F, we output a group of faces including F
00099      * whose size is maximum.
00100      */
00101     if( f->inside && ! f->marked ) {
00102       RenderMaximumFaceGroup( tess, f );
00103       assert( f->marked );
00104     }
00105   }
00106   if( tess->lonelyTriList != NULL ) {
00107     RenderLonelyTriangles( tess, tess->lonelyTriList );
00108     tess->lonelyTriList = NULL;
00109   }
00110 }
00111 
00112 
00113 static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
00114 {
00115   /* We want to find the largest triangle fan or strip of unmarked faces
00116    * which includes the given face fOrig.  There are 3 possible fans
00117    * passing through fOrig (one centered at each vertex), and 3 possible
00118    * strips (one for each CCW permutation of the vertices).  Our strategy
00119    * is to try all of these, and take the primitive which uses the most
00120    * triangles (a greedy approach).
00121    */
00122   GLUhalfEdge *e = fOrig->anEdge;
00123   struct FaceCount max, newFace;
00124 
00125   max.size = 1;
00126   max.eStart = e;
00127   max.render = &RenderTriangle;
00128 
00129   if( ! tess->flagBoundary ) {
00130     newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
00131     newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
00132     newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
00133 
00134     newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
00135     newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
00136     newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
00137   }
00138   (*(max.render))( tess, max.eStart, max.size );
00139 }
00140 
00141 
00142 /* Macros which keep track of faces we have marked temporarily, and allow
00143  * us to backtrack when necessary.  With triangle fans, this is not
00144  * really necessary, since the only awkward case is a loop of triangles
00145  * around a single origin vertex.  However with strips the situation is
00146  * more complicated, and we need a general tracking method like the
00147  * one here.
00148  */
00149 #define Marked(f)   (! (f)->inside || (f)->marked)
00150 
00151 #define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
00152 
00153 #define FreeTrail(t)    if( 1 ) { \
00154               while( (t) != NULL ) { \
00155                 (t)->marked = FALSE; t = (t)->trail; \
00156               } \
00157             } else /* absorb trailing semicolon */
00158 
00159 
00160 
00161 static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
00162 {
00163   /* eOrig->Lface is the face we want to render.  We want to find the size
00164    * of a maximal fan around eOrig->Org.  To do this we just walk around
00165    * the origin vertex as far as possible in both directions.
00166    */
00167   struct FaceCount newFace = { 0, NULL, &RenderFan };
00168   GLUface *trail = NULL;
00169   GLUhalfEdge *e;
00170 
00171   for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
00172     AddToTrail( e->Lface, trail );
00173     ++newFace.size;
00174   }
00175   for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
00176     AddToTrail( e->Rface, trail );
00177     ++newFace.size;
00178   }
00179   newFace.eStart = e;
00180   /*LINTED*/
00181   FreeTrail( trail );
00182   return newFace;
00183 }
00184 
00185 
00186 #define IsEven(n)   (((n) & 1) == 0)
00187 
00188 static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
00189 {
00190   /* Here we are looking for a maximal strip that contains the vertices
00191    * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
00192    * reverse, such that all triangles are oriented CCW).
00193    *
00194    * Again we walk forward and backward as far as possible.  However for
00195    * strips there is a twist: to get CCW orientations, there must be
00196    * an *even* number of triangles in the strip on one side of eOrig.
00197    * We walk the strip starting on a side with an even number of triangles;
00198    * if both side have an odd number, we are forced to shorten one side.
00199    */
00200   struct FaceCount newFace = { 0, NULL, &RenderStrip };
00201   long headSize = 0, tailSize = 0;
00202   GLUface *trail = NULL;
00203   GLUhalfEdge *e, *eTail, *eHead;
00204 
00205   for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
00206     AddToTrail( e->Lface, trail );
00207     ++tailSize;
00208     e = e->Dprev;
00209     if( Marked( e->Lface )) break;
00210     AddToTrail( e->Lface, trail );
00211   }
00212   eTail = e;
00213 
00214   for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
00215     AddToTrail( e->Rface, trail );
00216     ++headSize;
00217     e = e->Oprev;
00218     if( Marked( e->Rface )) break;
00219     AddToTrail( e->Rface, trail );
00220   }
00221   eHead = e;
00222 
00223   newFace.size = tailSize + headSize;
00224   if( IsEven( tailSize )) {
00225     newFace.eStart = eTail->Sym;
00226   } else if( IsEven( headSize )) {
00227     newFace.eStart = eHead;
00228   } else {
00229     /* Both sides have odd length, we must shorten one of them.  In fact,
00230      * we must start from eHead to guarantee inclusion of eOrig->Lface.
00231      */
00232     --newFace.size;
00233     newFace.eStart = eHead->Onext;
00234   }
00235   /*LINTED*/
00236   FreeTrail( trail );
00237   return newFace;
00238 }
00239 
00240 
00241 static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
00242 {
00243   /* Just add the triangle to a triangle list, so we can render all
00244    * the separate triangles at once.
00245    */
00246   assert( size == 1 );
00247   AddToTrail( e->Lface, tess->lonelyTriList );
00248 }
00249 
00250 
00251 static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
00252 {
00253   /* Now we render all the separate triangles which could not be
00254    * grouped into a triangle fan or strip.
00255    */
00256   GLUhalfEdge *e;
00257   int newState;
00258   int edgeState = -1;   /* force edge state output for first vertex */
00259 
00260   CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
00261 
00262   for( ; f != NULL; f = f->trail ) {
00263     /* Loop once for each edge (there will always be 3 edges) */
00264 
00265     e = f->anEdge;
00266     do {
00267       if( tess->flagBoundary ) {
00268     /* Set the "edge state" to TRUE just before we output the
00269      * first vertex of each edge on the polygon boundary.
00270      */
00271     newState = ! e->Rface->inside;
00272     if( edgeState != newState ) {
00273       edgeState = newState;
00274           CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
00275     }
00276       }
00277       CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
00278 
00279       e = e->Lnext;
00280     } while( e != f->anEdge );
00281   }
00282   CALL_END_OR_END_DATA();
00283 }
00284 
00285 
00286 static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
00287 {
00288   /* Render as many CCW triangles as possible in a fan starting from
00289    * edge "e".  The fan *should* contain exactly "size" triangles
00290    * (otherwise we've goofed up somewhere).
00291    */
00292   CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
00293   CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
00294   CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
00295 
00296   while( ! Marked( e->Lface )) {
00297     e->Lface->marked = TRUE;
00298     --size;
00299     e = e->Onext;
00300     CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
00301   }
00302 
00303   assert( size == 0 );
00304   CALL_END_OR_END_DATA();
00305 }
00306 
00307 
00308 static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
00309 {
00310   /* Render as many CCW triangles as possible in a strip starting from
00311    * edge "e".  The strip *should* contain exactly "size" triangles
00312    * (otherwise we've goofed up somewhere).
00313    */
00314   CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
00315   CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
00316   CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
00317 
00318   while( ! Marked( e->Lface )) {
00319     e->Lface->marked = TRUE;
00320     --size;
00321     e = e->Dprev;
00322     CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
00323     if( Marked( e->Lface )) break;
00324 
00325     e->Lface->marked = TRUE;
00326     --size;
00327     e = e->Onext;
00328     CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
00329   }
00330 
00331   assert( size == 0 );
00332   CALL_END_OR_END_DATA();
00333 }
00334 
00335 
00336 /************************ Boundary contour decomposition ******************/
00337 
00338 /* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
00339  * contour for each face marked "inside".  The rendering output is
00340  * provided as callbacks (see the api).
00341  */
00342 void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
00343 {
00344   GLUface *f;
00345   GLUhalfEdge *e;
00346 
00347   for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
00348     if( f->inside ) {
00349       CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
00350       e = f->anEdge;
00351       do {
00352         CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
00353     e = e->Lnext;
00354       } while( e != f->anEdge );
00355       CALL_END_OR_END_DATA();
00356     }
00357   }
00358 }
00359 
00360 
00361 /************************ Quick-and-dirty decomposition ******************/
00362 
00363 #define SIGN_INCONSISTENT 2
00364 
00365 static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
00366 /*
00367  * If check==FALSE, we compute the polygon normal and place it in norm[].
00368  * If check==TRUE, we check that each triangle in the fan from v0 has a
00369  * consistent orientation with respect to norm[].  If triangles are
00370  * consistently oriented CCW, return 1; if CW, return -1; if all triangles
00371  * are degenerate return 0; otherwise (no consistent orientation) return
00372  * SIGN_INCONSISTENT.
00373  */
00374 {
00375   CachedVertex *v0 = tess->cache;
00376   CachedVertex *vn = v0 + tess->cacheCount;
00377   CachedVertex *vc;
00378   GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
00379   int sign = 0;
00380 
00381   /* Find the polygon normal.  It is important to get a reasonable
00382    * normal even when the polygon is self-intersecting (eg. a bowtie).
00383    * Otherwise, the computed normal could be very tiny, but perpendicular
00384    * to the true plane of the polygon due to numerical noise.  Then all
00385    * the triangles would appear to be degenerate and we would incorrectly
00386    * decompose the polygon as a fan (or simply not render it at all).
00387    *
00388    * We use a sum-of-triangles normal algorithm rather than the more
00389    * efficient sum-of-trapezoids method (used in CheckOrientation()
00390    * in normal.c).  This lets us explicitly reverse the signed area
00391    * of some triangles to get a reasonable normal in the self-intersecting
00392    * case.
00393    */
00394   if( ! check ) {
00395     norm[0] = norm[1] = norm[2] = 0.0;
00396   }
00397 
00398   vc = v0 + 1;
00399   xc = vc->coords[0] - v0->coords[0];
00400   yc = vc->coords[1] - v0->coords[1];
00401   zc = vc->coords[2] - v0->coords[2];
00402   while( ++vc < vn ) {
00403     xp = xc; yp = yc; zp = zc;
00404     xc = vc->coords[0] - v0->coords[0];
00405     yc = vc->coords[1] - v0->coords[1];
00406     zc = vc->coords[2] - v0->coords[2];
00407 
00408     /* Compute (vp - v0) cross (vc - v0) */
00409     n[0] = yp*zc - zp*yc;
00410     n[1] = zp*xc - xp*zc;
00411     n[2] = xp*yc - yp*xc;
00412 
00413     dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
00414     if( ! check ) {
00415       /* Reverse the contribution of back-facing triangles to get
00416        * a reasonable normal for self-intersecting polygons (see above)
00417        */
00418       if( dot >= 0 ) {
00419     norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
00420       } else {
00421     norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
00422       }
00423     } else if( dot != 0 ) {
00424       /* Check the new orientation for consistency with previous triangles */
00425       if( dot > 0 ) {
00426     if( sign < 0 ) return SIGN_INCONSISTENT;
00427     sign = 1;
00428       } else {
00429     if( sign > 0 ) return SIGN_INCONSISTENT;
00430     sign = -1;
00431       }
00432     }
00433   }
00434   return sign;
00435 }
00436 
00437 /* __gl_renderCache( tess ) takes a single contour and tries to render it
00438  * as a triangle fan.  This handles convex polygons, as well as some
00439  * non-convex polygons if we get lucky.
00440  *
00441  * Returns TRUE if the polygon was successfully rendered.  The rendering
00442  * output is provided as callbacks (see the api).
00443  */
00444 GLboolean __gl_renderCache( GLUtesselator *tess )
00445 {
00446   CachedVertex *v0 = tess->cache;
00447   CachedVertex *vn = v0 + tess->cacheCount;
00448   CachedVertex *vc;
00449   GLdouble norm[3];
00450   int sign;
00451 
00452   if( tess->cacheCount < 3 ) {
00453     /* Degenerate contour -- no output */
00454     return TRUE;
00455   }
00456 
00457   norm[0] = tess->normal[0];
00458   norm[1] = tess->normal[1];
00459   norm[2] = tess->normal[2];
00460   if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
00461     ComputeNormal( tess, norm, FALSE );
00462   }
00463 
00464   sign = ComputeNormal( tess, norm, TRUE );
00465   if( sign == SIGN_INCONSISTENT ) {
00466     /* Fan triangles did not have a consistent orientation */
00467     return FALSE;
00468   }
00469   if( sign == 0 ) {
00470     /* All triangles were degenerate */
00471     return TRUE;
00472   }
00473 
00474   /* Make sure we do the right thing for each winding rule */
00475   switch( tess->windingRule ) {
00476   case GLU_TESS_WINDING_ODD:
00477   case GLU_TESS_WINDING_NONZERO:
00478     break;
00479   case GLU_TESS_WINDING_POSITIVE:
00480     if( sign < 0 ) return TRUE;
00481     break;
00482   case GLU_TESS_WINDING_NEGATIVE:
00483     if( sign > 0 ) return TRUE;
00484     break;
00485   case GLU_TESS_WINDING_ABS_GEQ_TWO:
00486     return TRUE;
00487   }
00488 
00489   CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
00490               : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
00491               : GL_TRIANGLES );
00492 
00493   CALL_VERTEX_OR_VERTEX_DATA( v0->data );
00494   if( sign > 0 ) {
00495     for( vc = v0+1; vc < vn; ++vc ) {
00496       CALL_VERTEX_OR_VERTEX_DATA( vc->data );
00497     }
00498   } else {
00499     for( vc = vn-1; vc > v0; --vc ) {
00500       CALL_VERTEX_OR_VERTEX_DATA( vc->data );
00501     }
00502   }
00503   CALL_END_OR_END_DATA();
00504   return TRUE;
00505 }

Generated on Sun May 27 2012 04:23:50 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.