g4tools  5.4.0
render
Go to the documentation of this file.
1 // see license file for original license.
2 
3 #ifndef tools_glutess_render
4 #define tools_glutess_render
5 
6 #include "mesh"
7 
8 /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
9  * fans, strips, and separate triangles. A substantial effort is made
10  * to use as few rendering primitives as possible (ie. to make the fans
11  * and strips as large as possible).
12  *
13  * The rendering output is provided as callbacks (see the api).
14  */
15 //void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh );
16 //void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh );
17 
18 //GLUboolean __gl_renderCache( GLUtesselator *tess );
19 
23 
24 #include "_tess"
25 
26 /* This structure remembers the information we need about a primitive
27  * to be able to render it later, once we have determined which
28  * primitive is able to use the most triangles.
29  */
30 struct FaceCount {
31  long size; /* number of triangles used */
32  GLUhalfEdge *eStart; /* edge where this primitive starts */
33  void (*render)(GLUtesselator *, GLUhalfEdge *, long);
34  /* routine to render this primitive */
35 };
36 
37 inline/*static*/ struct FaceCount static_MaximumFan( GLUhalfEdge *eOrig );
38 inline/*static*/ struct FaceCount static_MaximumStrip( GLUhalfEdge *eOrig );
39 
40 inline/*static*/ void static_RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
41 inline/*static*/ void static_RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
42 inline/*static*/ void static_RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
43  long size );
44 
45 inline/*static*/ void static_RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
46 inline/*static*/ void static_RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
47 
48 
49 
50 /************************ Strips and Fans decomposition ******************/
51 
52 /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
53  * fans, strips, and separate triangles. A substantial effort is made
54  * to use as few rendering primitives as possible (ie. to make the fans
55  * and strips as large as possible).
56  *
57  * The rendering output is provided as callbacks (see the api).
58  */
59 inline void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
60 {
61  GLUface *f;
62 
63  /* Make a list of separate triangles so we can render them all at once */
64  tess->lonelyTriList = NULL;
65 
66  for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
68  }
69  for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
70 
71  /* We examine all faces in an arbitrary order. Whenever we find
72  * an unprocessed face F, we output a group of faces including F
73  * whose size is maximum.
74  */
75  if( f->inside && ! f->marked ) {
77  assert( f->marked );
78  }
79  }
80  if( tess->lonelyTriList != NULL ) {
82  tess->lonelyTriList = NULL;
83  }
84 }
85 
86 
87 inline/*static*/ void static_RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
88 {
89  /* We want to find the largest triangle fan or strip of unmarked faces
90  * which includes the given face fOrig. There are 3 possible fans
91  * passing through fOrig (one centered at each vertex), and 3 possible
92  * strips (one for each CCW permutation of the vertices). Our strategy
93  * is to try all of these, and take the primitive which uses the most
94  * triangles (a greedy approach).
95  */
96  GLUhalfEdge *e = fOrig->anEdge;
97  struct FaceCount max, newFace;
98 
99  max.size = 1;
100  max.eStart = e;
102 
103  if( ! tess->flagBoundary ) {
104  newFace = static_MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
105  newFace = static_MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
106  newFace = static_MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
107 
108  newFace = static_MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
109  newFace = static_MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
110  newFace = static_MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
111  }
112  (*(max.render))( tess, max.eStart, max.size );
113 }
114 
115 
116 /* Macros which keep track of faces we have marked temporarily, and allow
117  * us to backtrack when necessary. With triangle fans, this is not
118  * really necessary, since the only awkward case is a loop of triangles
119  * around a single origin vertex. However with strips the situation is
120  * more complicated, and we need a general tracking method like the
121  * one here.
122  */
123 #define Marked(f) (! (f)->inside || (f)->marked)
124 
125 #define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TOOLS_GLU_TRUE)
126 
127 //#define FreeTrail(t) if( 1 ) { while( (t) != NULL ) { (t)->marked = TOOLS_GLU_FALSE; t = (t)->trail; } } else
128 #define FreeTrail(t) do { while( (t) != NULL ) { (t)->marked = TOOLS_GLU_FALSE; t = (t)->trail; } } while(false)
129 
130 inline/*static*/ struct FaceCount static_MaximumFan( GLUhalfEdge *eOrig )
131 {
132  /* eOrig->Lface is the face we want to render. We want to find the size
133  * of a maximal fan around eOrig->Org. To do this we just walk around
134  * the origin vertex as far as possible in both directions.
135  */
136  struct FaceCount newFace = { 0, NULL, &static_RenderFan };
137  GLUface *trail = NULL;
138  GLUhalfEdge *e;
139 
140  for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
141  AddToTrail( e->Lface, trail );
142  ++newFace.size;
143  }
144  for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
145  AddToTrail( e->Rface, trail );
146  ++newFace.size;
147  }
148  newFace.eStart = e;
149  /*LINTED*/
150  FreeTrail( trail );
151  return newFace;
152 }
153 
154 
155 #define IsEven(n) (((n) & 1) == 0)
156 
157 inline/*static*/ struct FaceCount static_MaximumStrip( GLUhalfEdge *eOrig )
158 {
159  /* Here we are looking for a maximal strip that contains the vertices
160  * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
161  * reverse, such that all triangles are oriented CCW).
162  *
163  * Again we walk forward and backward as far as possible. However for
164  * strips there is a twist: to get CCW orientations, there must be
165  * an *even* number of triangles in the strip on one side of eOrig.
166  * We walk the strip starting on a side with an even number of triangles;
167  * if both side have an odd number, we are forced to shorten one side.
168  */
169  struct FaceCount newFace = { 0, NULL, &static_RenderStrip };
170  long headSize = 0, tailSize = 0;
171  GLUface *trail = NULL;
172  GLUhalfEdge *e, *eTail, *eHead;
173 
174  for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
175  AddToTrail( e->Lface, trail );
176  ++tailSize;
177  e = e->Dprev;
178  if( Marked( e->Lface )) break;
179  AddToTrail( e->Lface, trail );
180  }
181  eTail = e;
182 
183  for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
184  AddToTrail( e->Rface, trail );
185  ++headSize;
186  e = e->Oprev;
187  if( Marked( e->Rface )) break;
188  AddToTrail( e->Rface, trail );
189  }
190  eHead = e;
191 
192  newFace.size = tailSize + headSize;
193  if( IsEven( tailSize )) {
194  newFace.eStart = eTail->Sym;
195  } else if( IsEven( headSize )) {
196  newFace.eStart = eHead;
197  } else {
198  /* Both sides have odd length, we must shorten one of them. In fact,
199  * we must start from eHead to guarantee inclusion of eOrig->Lface.
200  */
201  --newFace.size;
202  newFace.eStart = eHead->Onext;
203  }
204  /*LINTED*/
205  FreeTrail( trail );
206  return newFace;
207 }
208 
209 
210 inline/*static*/ void static_RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
211 {
212  /* Just add the triangle to a triangle list, so we can render all
213  * the separate triangles at once.
214  */
215  assert( size == 1 );
216  AddToTrail( e->Lface, tess->lonelyTriList );
217  (void)size;
218 }
219 
220 
221 inline/*static*/ void static_RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
222 {
223  /* Now we render all the separate triangles which could not be
224  * grouped into a triangle fan or strip.
225  */
226  GLUhalfEdge *e;
227  int newState;
228  int edgeState = -1; /* force edge state output for first vertex */
229 
231 
232  for( ; f != NULL; f = f->trail ) {
233  /* Loop once for each edge (there will always be 3 edges) */
234 
235  e = f->anEdge;
236  do {
237  if( tess->flagBoundary ) {
238  /* Set the "edge state" to TOOLS_GLU_TRUE just before we output the
239  * first vertex of each edge on the polygon boundary.
240  */
241  newState = ! e->Rface->inside;
242  if( edgeState != newState ) {
243  edgeState = newState;
245  }
246  }
248 
249  e = e->Lnext;
250  } while( e != f->anEdge );
251  }
253 }
254 
255 
256 inline/*static*/ void static_RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
257 {
258  /* Render as many CCW triangles as possible in a fan starting from
259  * edge "e". The fan *should* contain exactly "size" triangles
260  * (otherwise we've goofed up somewhere).
261  */
264  CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
265 
266  while( ! Marked( e->Lface )) {
268  --size;
269  e = e->Onext;
270  CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
271  }
272 
273  assert( size == 0 );
275 }
276 
277 
278 inline/*static*/ void static_RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
279 {
280  /* Render as many CCW triangles as possible in a strip starting from
281  * edge "e". The strip *should* contain exactly "size" triangles
282  * (otherwise we've goofed up somewhere).
283  */
286  CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
287 
288  while( ! Marked( e->Lface )) {
290  --size;
291  e = e->Dprev;
293  if( Marked( e->Lface )) break;
294 
296  --size;
297  e = e->Onext;
298  CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
299  }
300 
301  assert( size == 0 );
303 }
304 
305 
306 /************************ Boundary contour decomposition ******************/
307 
308 /* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
309  * contour for each face marked "inside". The rendering output is
310  * provided as callbacks (see the api).
311  */
312 inline void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
313 {
314  GLUface *f;
315  GLUhalfEdge *e;
316 
317  for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
318  if( f->inside ) {
320  e = f->anEdge;
321  do {
323  e = e->Lnext;
324  } while( e != f->anEdge );
326  }
327  }
328 }
329 
330 
331 /************************ Quick-and-dirty decomposition ******************/
332 
333 //#define SIGN_INCONSISTENT 2
334 inline int SIGN_INCONSISTENT() {
335  static const int s_value = 2;
336  return s_value;
337 }
338 
339 inline/*static*/ int static_ComputeNormal( GLUtesselator *tess, GLUdouble norm[3], int check )
340 /*
341  * If check==TOOLS_GLU_FALSE, we compute the polygon normal and place it in norm[].
342  * If check==TOOLS_GLU_TRUE, we check that each triangle in the fan from v0 has a
343  * consistent orientation with respect to norm[]. If triangles are
344  * consistently oriented CCW, return 1; if CW, return -1; if all triangles
345  * are degenerate return 0; otherwise (no consistent orientation) return
346  * SIGN_INCONSISTENT.
347  */
348 {
349  CachedVertex *v0 = tess->cache;
350  CachedVertex *vn = v0 + tess->cacheCount;
351  CachedVertex *vc;
352  GLUdouble dot, xc, yc, zc, xp, yp, zp, n[3];
353  int sign = 0;
354 
355  /* Find the polygon normal. It is important to get a reasonable
356  * normal even when the polygon is self-intersecting (eg. a bowtie).
357  * Otherwise, the computed normal could be very tiny, but perpendicular
358  * to the true plane of the polygon due to numerical noise. Then all
359  * the triangles would appear to be degenerate and we would incorrectly
360  * decompose the polygon as a fan (or simply not render it at all).
361  *
362  * We use a sum-of-triangles normal algorithm rather than the more
363  * efficient sum-of-trapezoids method (used in CheckOrientation()
364  * in normal.c). This lets us explicitly reverse the signed area
365  * of some triangles to get a reasonable normal in the self-intersecting
366  * case.
367  */
368  if( ! check ) {
369  norm[0] = norm[1] = norm[2] = 0.0;
370  }
371 
372  vc = v0 + 1;
373  xc = vc->coords[0] - v0->coords[0];
374  yc = vc->coords[1] - v0->coords[1];
375  zc = vc->coords[2] - v0->coords[2];
376  while( ++vc < vn ) {
377  xp = xc; yp = yc; zp = zc;
378  xc = vc->coords[0] - v0->coords[0];
379  yc = vc->coords[1] - v0->coords[1];
380  zc = vc->coords[2] - v0->coords[2];
381 
382  /* Compute (vp - v0) cross (vc - v0) */
383  n[0] = yp*zc - zp*yc;
384  n[1] = zp*xc - xp*zc;
385  n[2] = xp*yc - yp*xc;
386 
387  dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
388  if( ! check ) {
389  /* Reverse the contribution of back-facing triangles to get
390  * a reasonable normal for self-intersecting polygons (see above)
391  */
392  if( dot >= 0 ) {
393  norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
394  } else {
395  norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
396  }
397  } else if( dot != 0 ) {
398  /* Check the new orientation for consistency with previous triangles */
399  if( dot > 0 ) {
400  if( sign < 0 ) return SIGN_INCONSISTENT();
401  sign = 1;
402  } else {
403  if( sign > 0 ) return SIGN_INCONSISTENT();
404  sign = -1;
405  }
406  }
407  }
408  return sign;
409 }
410 
411 /* __gl_renderCache( tess ) takes a single contour and tries to render it
412  * as a triangle fan. This handles convex polygons, as well as some
413  * non-convex polygons if we get lucky.
414  *
415  * Returns TOOLS_GLU_TRUE if the polygon was successfully rendered. The rendering
416  * output is provided as callbacks (see the api).
417  */
419 {
420  CachedVertex *v0 = tess->cache;
421  CachedVertex *vn = v0 + tess->cacheCount;
422  CachedVertex *vc;
423  GLUdouble norm[3];
424  int sign;
425 
426  if( tess->cacheCount < 3 ) {
427  /* Degenerate contour -- no output */
428  return TOOLS_GLU_TRUE;
429  }
430 
431  norm[0] = tess->normal[0];
432  norm[1] = tess->normal[1];
433  norm[2] = tess->normal[2];
434  if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
435  static_ComputeNormal( tess, norm, TOOLS_GLU_FALSE );
436  }
437 
438  sign = static_ComputeNormal( tess, norm, TOOLS_GLU_TRUE );
439  if( sign == SIGN_INCONSISTENT() ) {
440  /* Fan triangles did not have a consistent orientation */
441  return TOOLS_GLU_FALSE;
442  }
443  if( sign == 0 ) {
444  /* All triangles were degenerate */
445  return TOOLS_GLU_TRUE;
446  }
447 
448  /* Make sure we do the right thing for each winding rule */
449  switch( tess->windingRule ) {
452  break;
454  if( sign < 0 ) return TOOLS_GLU_TRUE;
455  break;
457  if( sign > 0 ) return TOOLS_GLU_TRUE;
458  break;
460  return TOOLS_GLU_TRUE;
461  }
462 
464  : (tess->cacheCount > 3) ? GLU_TRIANGLE_FAN
465  : GLU_TRIANGLES );
466 
468  if( sign > 0 ) {
469  for( vc = v0+1; vc < vn; ++vc ) {
471  }
472  } else {
473  for( vc = vn-1; vc > v0; --vc ) {
475  }
476  }
478  return TOOLS_GLU_TRUE;
479 }
480 
481 #endif
GLUmesh::fHead
GLUface fHead
Definition: mesh:133
GLU_TESS_WINDING_POSITIVE
#define GLU_TESS_WINDING_POSITIVE
Definition: _glu:39
IsEven
#define IsEven(n)
Definition: render:155
GLU_LINE_LOOP
#define GLU_LINE_LOOP
Definition: _glu:85
FaceCount::size
long size
Definition: render:31
static_RenderMaximumFaceGroup
inline void static_RenderMaximumFaceGroup(GLUtesselator *tess, GLUface *fOrig)
Definition: render:87
GLUtesselator::cache
CachedVertex cache[GLU_TESS_MAX_CACHE]
Definition: _tess:76
CALL_END_OR_END_DATA
#define CALL_END_OR_END_DATA()
Definition: _tess:118
GLUmesh
Definition: mesh:131
CachedVertex
Definition: _tess:22
GLUtesselator::normal
GLUdouble normal[3]
Definition: _tess:41
GLUtesselator::lonelyTriList
GLUface * lonelyTriList
Definition: _tess:62
GLUhalfEdge::Lnext
GLUhalfEdge * Lnext
Definition: mesh:110
GLUtesselator::cacheCount
int cacheCount
Definition: _tess:75
GLUface::marked
GLUboolean marked
Definition: mesh:102
GLUhalfEdge
Definition: mesh:106
static_MaximumFan
inline struct FaceCount static_MaximumFan(GLUhalfEdge *eOrig)
Definition: render:130
GLUvertex::data
void * data
Definition: mesh:86
SIGN_INCONSISTENT
int SIGN_INCONSISTENT()
Definition: render:334
FaceCount
inlined C code : ///////////////////////////////////
Definition: render:30
GLUhalfEdge::Sym
GLUhalfEdge * Sym
Definition: mesh:108
GLU_TESS_WINDING_ABS_GEQ_TWO
#define GLU_TESS_WINDING_ABS_GEQ_TWO
Definition: _glu:138
CachedVertex::coords
GLUdouble coords[3]
Definition: _tess:23
GLUtesselator::boundaryOnly
GLUboolean boundaryOnly
Definition: _tess:61
TOOLS_GLU_TRUE
#define TOOLS_GLU_TRUE
Definition: _glu:82
GLUdouble
double GLUdouble
Definition: _glu:16
static_RenderFan
inline void static_RenderFan(GLUtesselator *tess, GLUhalfEdge *eStart, long size)
Definition: render:256
__gl_renderCache
GLUboolean __gl_renderCache(GLUtesselator *tess)
Definition: render:418
FaceCount::eStart
GLUhalfEdge * eStart
Definition: render:32
GLU_TRIANGLES
#define GLU_TRIANGLES
Definition: _glu:86
GLU_TESS_WINDING_NEGATIVE
#define GLU_TESS_WINDING_NEGATIVE
Definition: _glu:40
GLUhalfEdge::Onext
GLUhalfEdge * Onext
Definition: mesh:109
FreeTrail
#define FreeTrail(t)
Definition: render:128
__gl_renderMesh
void __gl_renderMesh(GLUtesselator *tess, GLUmesh *mesh)
Definition: render:59
TOOLS_GLU_FALSE
#define TOOLS_GLU_FALSE
Definition: _glu:81
GLU_TESS_WINDING_ODD
#define GLU_TESS_WINDING_ODD
Definition: _glu:38
tools::file::size
bool size(const std::string &a_file, long &a_size)
Definition: fsize:13
GLUtesselator
Definition: _tess:27
static_ComputeNormal
inline int static_ComputeNormal(GLUtesselator *tess, GLUdouble norm[3], int check)
Definition: render:339
GLUtesselator::windingRule
GLUenum windingRule
Definition: _tess:48
GLUface::trail
GLUface * trail
Definition: mesh:101
CALL_VERTEX_OR_VERTEX_DATA
#define CALL_VERTEX_OR_VERTEX_DATA(a)
Definition: _tess:108
CALL_BEGIN_OR_BEGIN_DATA
#define CALL_BEGIN_OR_BEGIN_DATA(a)
Definition: _tess:103
GLU_TRIANGLE_STRIP
#define GLU_TRIANGLE_STRIP
Definition: _glu:87
GLUboolean
unsigned char GLUboolean
Definition: _glu:18
GLUface::inside
GLUboolean inside
Definition: mesh:103
AddToTrail
#define AddToTrail(f, t)
Definition: render:125
mesh
static_MaximumStrip
inline struct FaceCount static_MaximumStrip(GLUhalfEdge *eOrig)
Definition: render:157
GLUhalfEdge::Lface
GLUface * Lface
Definition: mesh:112
GLU_TRIANGLE_FAN
#define GLU_TRIANGLE_FAN
Definition: _glu:88
GLUface
Definition: mesh:94
GLUhalfEdge::Org
GLUvertex * Org
Definition: mesh:111
GLUface::next
GLUface * next
Definition: mesh:95
static_RenderLonelyTriangles
inline void static_RenderLonelyTriangles(GLUtesselator *tess, GLUface *head)
Definition: render:221
_tess
GLUtesselator::flagBoundary
GLUboolean flagBoundary
Definition: _tess:60
GLU_TESS_WINDING_NONZERO
#define GLU_TESS_WINDING_NONZERO
Definition: _glu:137
Marked
#define Marked(f)
Definition: render:123
CachedVertex::data
void * data
Definition: _tess:24
static_RenderStrip
inline void static_RenderStrip(GLUtesselator *tess, GLUhalfEdge *eStart, long size)
Definition: render:278
__gl_renderBoundary
void __gl_renderBoundary(GLUtesselator *tess, GLUmesh *mesh)
Definition: render:312
static_RenderTriangle
inline void static_RenderTriangle(GLUtesselator *tess, GLUhalfEdge *eStart, long size)
Definition: render:210
CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA
#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a)
Definition: _tess:113
FaceCount::render
void(* render)(GLUtesselator *, GLUhalfEdge *, long)
Definition: render:33
GLUface::anEdge
GLUhalfEdge * anEdge
Definition: mesh:97