📄 render.c
字号:
int newState; int edgeState = -1; /* force edge state output for first vertex */ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES ); for( ; f != NULL; f = f->trail ) { /* Loop once for each edge (there will always be 3 edges) */ e = f->anEdge; do { if( tess->flagBoundary ) { /* Set the "edge state" to TRUE just before we output the * first vertex of each edge on the polygon boundary. */ newState = ! e->Rface->inside; if( edgeState != newState ) { edgeState = newState; CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState ); } } CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); e = e->Lnext; } while( e != f->anEdge ); } CALL_END_OR_END_DATA();}static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size ){ /* Render as many CCW triangles as possible in a fan starting from * edge "e". The fan *should* contain exactly "size" triangles * (otherwise we've goofed up somewhere). */ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN ); CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); while( ! Marked( e->Lface )) { e->Lface->marked = TRUE; --size; e = e->Onext; CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); } assert( size == 0 ); CALL_END_OR_END_DATA();}static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size ){ /* Render as many CCW triangles as possible in a strip starting from * edge "e". The strip *should* contain exactly "size" triangles * (otherwise we've goofed up somewhere). */ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP ); CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); while( ! Marked( e->Lface )) { e->Lface->marked = TRUE; --size; e = e->Dprev; CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); if( Marked( e->Lface )) break; e->Lface->marked = TRUE; --size; e = e->Onext; CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); } assert( size == 0 ); CALL_END_OR_END_DATA();}/************************ Boundary contour decomposition ******************//* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one * contour for each face marked "inside". The rendering output is * provided as callbacks (see the api). */void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ){ GLUface *f; GLUhalfEdge *e; for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { if( f->inside ) { CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP ); e = f->anEdge; do { CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); e = e->Lnext; } while( e != f->anEdge ); CALL_END_OR_END_DATA(); } }}/************************ Quick-and-dirty decomposition ******************/#define SIGN_INCONSISTENT 2static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )/* * If check==FALSE, we compute the polygon normal and place it in norm[]. * If check==TRUE, we check that each triangle in the fan from v0 has a * consistent orientation with respect to norm[]. If triangles are * consistently oriented CCW, return 1; if CW, return -1; if all triangles * are degenerate return 0; otherwise (no consistent orientation) return * SIGN_INCONSISTENT. */{ CachedVertex *v0 = tess->cache; CachedVertex *vn = v0 + tess->cacheCount; CachedVertex *vc; GLdouble dot, xc, yc, zc, xp, yp, zp, n[3]; int sign = 0; /* Find the polygon normal. It is important to get a reasonable * normal even when the polygon is self-intersecting (eg. a bowtie). * Otherwise, the computed normal could be very tiny, but perpendicular * to the true plane of the polygon due to numerical noise. Then all * the triangles would appear to be degenerate and we would incorrectly * decompose the polygon as a fan (or simply not render it at all). * * We use a sum-of-triangles normal algorithm rather than the more * efficient sum-of-trapezoids method (used in CheckOrientation() * in normal.c). This lets us explicitly reverse the signed area * of some triangles to get a reasonable normal in the self-intersecting * case. */ if( ! check ) { norm[0] = norm[1] = norm[2] = 0.0; } vc = v0 + 1; xc = vc->coords[0] - v0->coords[0]; yc = vc->coords[1] - v0->coords[1]; zc = vc->coords[2] - v0->coords[2]; while( ++vc < vn ) { xp = xc; yp = yc; zp = zc; xc = vc->coords[0] - v0->coords[0]; yc = vc->coords[1] - v0->coords[1]; zc = vc->coords[2] - v0->coords[2]; /* Compute (vp - v0) cross (vc - v0) */ n[0] = yp*zc - zp*yc; n[1] = zp*xc - xp*zc; n[2] = xp*yc - yp*xc; dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2]; if( ! check ) { /* Reverse the contribution of back-facing triangles to get * a reasonable normal for self-intersecting polygons (see above) */ if( dot >= 0 ) { norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2]; } else { norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2]; } } else if( dot != 0 ) { /* Check the new orientation for consistency with previous triangles */ if( dot > 0 ) { if( sign < 0 ) return SIGN_INCONSISTENT; sign = 1; } else { if( sign > 0 ) return SIGN_INCONSISTENT; sign = -1; } } } return sign;}/* __gl_renderCache( tess ) takes a single contour and tries to render it * as a triangle fan. This handles convex polygons, as well as some * non-convex polygons if we get lucky. * * Returns TRUE if the polygon was successfully rendered. The rendering * output is provided as callbacks (see the api). */GLboolean __gl_renderCache( GLUtesselator *tess ){ CachedVertex *v0 = tess->cache; CachedVertex *vn = v0 + tess->cacheCount; CachedVertex *vc; GLdouble norm[3]; int sign; if( tess->cacheCount < 3 ) { /* Degenerate contour -- no output */ return TRUE; } norm[0] = tess->normal[0]; norm[1] = tess->normal[1]; norm[2] = tess->normal[2]; if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { ComputeNormal( tess, norm, FALSE ); } sign = ComputeNormal( tess, norm, TRUE ); if( sign == SIGN_INCONSISTENT ) { /* Fan triangles did not have a consistent orientation */ return FALSE; } if( sign == 0 ) { /* All triangles were degenerate */ return TRUE; } /* Make sure we do the right thing for each winding rule */ switch( tess->windingRule ) { case GLU_TESS_WINDING_ODD: case GLU_TESS_WINDING_NONZERO: break; case GLU_TESS_WINDING_POSITIVE: if( sign < 0 ) return TRUE; break; case GLU_TESS_WINDING_NEGATIVE: if( sign > 0 ) return TRUE; break; case GLU_TESS_WINDING_ABS_GEQ_TWO: return TRUE; } CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN : GL_TRIANGLES ); CALL_VERTEX_OR_VERTEX_DATA( v0->data ); if( sign > 0 ) { for( vc = v0+1; vc < vn; ++vc ) { CALL_VERTEX_OR_VERTEX_DATA( vc->data ); } } else { for( vc = vn-1; vc > v0; --vc ) { CALL_VERTEX_OR_VERTEX_DATA( vc->data ); } } CALL_END_OR_END_DATA(); return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -