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