Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

483 lines
15 KiB

5 years ago
  1. /*
  2. ** Copyright 1994, Silicon Graphics, Inc.
  3. ** All Rights Reserved.
  4. **
  5. ** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6. ** the contents of this file may not be disclosed to third parties, copied or
  7. ** duplicated in any form, in whole or in part, without the prior written
  8. ** permission of Silicon Graphics, Inc.
  9. **
  10. ** RESTRICTED RIGHTS LEGEND:
  11. ** Use, duplication or disclosure by the Government is subject to restrictions
  12. ** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13. ** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14. ** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15. ** rights reserved under the Copyright Laws of the United States.
  16. **
  17. ** Author: Eric Veach, July 1994.
  18. */
  19. #include <assert.h>
  20. #include <stddef.h>
  21. #include "mesh.h"
  22. #include "tess.h"
  23. #include "render.h"
  24. #define TRUE 1
  25. #define FALSE 0
  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. static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
  37. static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
  38. static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
  39. static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
  40. static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
  41. long size );
  42. static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
  43. static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
  44. /************************ Strips and Fans decomposition ******************/
  45. /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
  46. * fans, strips, and separate triangles. A substantial effort is made
  47. * to use as few rendering primitives as possible (ie. to make the fans
  48. * and strips as large as possible).
  49. *
  50. * The rendering output is provided as callbacks (see the api).
  51. */
  52. void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
  53. {
  54. GLUface *f;
  55. /* Make a list of separate triangles so we can render them all at once */
  56. tess->lonelyTriList = NULL;
  57. for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
  58. f->marked = FALSE;
  59. }
  60. for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
  61. /* We examine all faces in an arbitrary order. Whenever we find
  62. * an unprocessed face F, we output a group of faces including F
  63. * whose size is maximum.
  64. */
  65. if( f->inside && ! f->marked ) {
  66. RenderMaximumFaceGroup( tess, f );
  67. assert( f->marked );
  68. }
  69. }
  70. if( tess->lonelyTriList != NULL ) {
  71. RenderLonelyTriangles( tess, tess->lonelyTriList );
  72. tess->lonelyTriList = NULL;
  73. }
  74. }
  75. static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
  76. {
  77. /* We want to find the largest triangle fan or strip of unmarked faces
  78. * which includes the given face fOrig. There are 3 possible fans
  79. * passing through fOrig (one centered at each vertex), and 3 possible
  80. * strips (one for each CCW permutation of the vertices). Our strategy
  81. * is to try all of these, and take the primitive which uses the most
  82. * triangles (a greedy approach).
  83. */
  84. GLUhalfEdge *e = fOrig->anEdge;
  85. struct FaceCount max, newFace;
  86. max.size = 1;
  87. max.eStart = e;
  88. max.render = &RenderTriangle;
  89. if( ! tess->flagBoundary ) {
  90. newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
  91. newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
  92. newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
  93. newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
  94. newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
  95. newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
  96. }
  97. (*(max.render))( tess, max.eStart, max.size );
  98. }
  99. /* Macros which keep track of faces we have marked temporarily, and allow
  100. * us to backtrack when necessary. With triangle fans, this is not
  101. * really necessary, since the only awkward case is a loop of triangles
  102. * around a single origin vertex. However with strips the situation is
  103. * more complicated, and we need a general tracking method like the
  104. * one here.
  105. */
  106. #define Marked(f) (! (f)->inside || (f)->marked)
  107. #define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
  108. #define FreeTrail(t) if( 1 ) { \
  109. while( (t) != NULL ) { \
  110. (t)->marked = FALSE; t = (t)->trail; \
  111. } \
  112. } else /* absorb trailing semicolon */
  113. static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
  114. {
  115. /* eOrig->Lface is the face we want to render. We want to find the size
  116. * of a maximal fan around eOrig->Org. To do this we just walk around
  117. * the origin vertex as far as possible in both directions.
  118. */
  119. struct FaceCount newFace = { 0, NULL, &RenderFan };
  120. GLUface *trail = NULL;
  121. GLUhalfEdge *e;
  122. for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
  123. AddToTrail( e->Lface, trail );
  124. ++newFace.size;
  125. }
  126. for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
  127. AddToTrail( e->Rface, trail );
  128. ++newFace.size;
  129. }
  130. newFace.eStart = e;
  131. /*LINTED*/
  132. FreeTrail( trail );
  133. return newFace;
  134. }
  135. #define IsEven(n) (((n) & 1) == 0)
  136. static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
  137. {
  138. /* Here we are looking for a maximal strip that contains the vertices
  139. * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
  140. * reverse, such that all triangles are oriented CCW).
  141. *
  142. * Again we walk forward and backward as far as possible. However for
  143. * strips there is a twist: to get CCW orientations, there must be
  144. * an *even* number of triangles in the strip on one side of eOrig.
  145. * We walk the strip starting on a side with an even number of triangles;
  146. * if both side have an odd number, we are forced to shorten one side.
  147. */
  148. struct FaceCount newFace = { 0, NULL, &RenderStrip };
  149. long headSize = 0, tailSize = 0;
  150. GLUface *trail = NULL;
  151. GLUhalfEdge *e, *eTail, *eHead;
  152. for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
  153. AddToTrail( e->Lface, trail );
  154. ++tailSize;
  155. e = e->Dprev;
  156. if( Marked( e->Lface )) break;
  157. AddToTrail( e->Lface, trail );
  158. }
  159. eTail = e;
  160. for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
  161. AddToTrail( e->Rface, trail );
  162. ++headSize;
  163. e = e->Oprev;
  164. if( Marked( e->Rface )) break;
  165. AddToTrail( e->Rface, trail );
  166. }
  167. eHead = e;
  168. newFace.size = tailSize + headSize;
  169. if( IsEven( tailSize )) {
  170. newFace.eStart = eTail->Sym;
  171. } else if( IsEven( headSize )) {
  172. newFace.eStart = eHead;
  173. } else {
  174. /* Both sides have odd length, we must shorten one of them. In fact,
  175. * we must start from eHead to guarantee inclusion of eOrig->Lface.
  176. */
  177. --newFace.size;
  178. newFace.eStart = eHead->Onext;
  179. }
  180. /*LINTED*/
  181. FreeTrail( trail );
  182. return newFace;
  183. }
  184. static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
  185. {
  186. /* Just add the triangle to a triangle list, so we can render all
  187. * the separate triangles at once.
  188. */
  189. assert( size == 1 );
  190. AddToTrail( e->Lface, tess->lonelyTriList );
  191. }
  192. static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
  193. {
  194. /* Now we render all the separate triangles which could not be
  195. * grouped into a triangle fan or strip.
  196. */
  197. GLUhalfEdge *e;
  198. int newState;
  199. int edgeState = -1; /* force edge state output for first vertex */
  200. CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
  201. for( ; f != NULL; f = f->trail ) {
  202. /* Loop once for each edge (there will always be 3 edges) */
  203. e = f->anEdge;
  204. do {
  205. if( tess->flagBoundary ) {
  206. /* Set the "edge state" to TRUE just before we output the
  207. * first vertex of each edge on the polygon boundary.
  208. */
  209. newState = ! e->Rface->inside;
  210. if( edgeState != newState ) {
  211. edgeState = newState;
  212. CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
  213. }
  214. }
  215. CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
  216. e = e->Lnext;
  217. } while( e != f->anEdge );
  218. }
  219. CALL_END_OR_END_DATA();
  220. }
  221. static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
  222. {
  223. /* Render as many CCW triangles as possible in a fan starting from
  224. * edge "e". The fan *should* contain exactly "size" triangles
  225. * (otherwise we've goofed up somewhere).
  226. */
  227. CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
  228. CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
  229. CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
  230. while( ! Marked( e->Lface )) {
  231. e->Lface->marked = TRUE;
  232. --size;
  233. e = e->Onext;
  234. CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
  235. }
  236. assert( size == 0 );
  237. CALL_END_OR_END_DATA();
  238. }
  239. static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
  240. {
  241. /* Render as many CCW triangles as possible in a strip starting from
  242. * edge "e". The strip *should* contain exactly "size" triangles
  243. * (otherwise we've goofed up somewhere).
  244. */
  245. CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
  246. CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
  247. CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
  248. while( ! Marked( e->Lface )) {
  249. e->Lface->marked = TRUE;
  250. --size;
  251. e = e->Dprev;
  252. CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
  253. if( Marked( e->Lface )) break;
  254. e->Lface->marked = TRUE;
  255. --size;
  256. e = e->Onext;
  257. CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
  258. }
  259. assert( size == 0 );
  260. CALL_END_OR_END_DATA();
  261. }
  262. /************************ Boundary contour decomposition ******************/
  263. /* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
  264. * contour for each face marked "inside". The rendering output is
  265. * provided as callbacks (see the api).
  266. */
  267. void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
  268. {
  269. GLUface *f;
  270. GLUhalfEdge *e;
  271. for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
  272. if( f->inside ) {
  273. CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
  274. e = f->anEdge;
  275. do {
  276. CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
  277. e = e->Lnext;
  278. } while( e != f->anEdge );
  279. CALL_END_OR_END_DATA();
  280. }
  281. }
  282. }
  283. /************************ Quick-and-dirty decomposition ******************/
  284. #define SIGN_INCONSISTENT 2
  285. static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
  286. /*
  287. * If check==FALSE, we compute the polygon normal and place it in norm[].
  288. * If check==TRUE, we check that each triangle in the fan from v0 has a
  289. * consistent orientation with respect to norm[]. If triangles are
  290. * consistently oriented CCW, return 1; if CW, return -1; if all triangles
  291. * are degenerate return 0; otherwise (no consistent orientation) return
  292. * SIGN_INCONSISTENT.
  293. */
  294. {
  295. CachedVertex *v0 = tess->cache;
  296. CachedVertex *vn = v0 + tess->cacheCount;
  297. CachedVertex *vc;
  298. GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
  299. int sign = 0;
  300. /* Find the polygon normal. It is important to get a reasonable
  301. * normal even when the polygon is self-intersecting (eg. a bowtie).
  302. * Otherwise, the computed normal could be very tiny, but perpendicular
  303. * to the true plane of the polygon due to numerical noise. Then all
  304. * the triangles would appear to be degenerate and we would incorrectly
  305. * decompose the polygon as a fan (or simply not render it at all).
  306. *
  307. * We use a sum-of-triangles normal algorithm rather than the more
  308. * efficient sum-of-trapezoids method (used in CheckOrientation()
  309. * in normal.c). This lets us explicitly reverse the signed area
  310. * of some triangles to get a reasonable normal in the self-intersecting
  311. * case.
  312. */
  313. if( ! check ) {
  314. norm[0] = norm[1] = norm[2] = 0.0;
  315. }
  316. vc = v0 + 1;
  317. xc = vc->coords[0] - v0->coords[0];
  318. yc = vc->coords[1] - v0->coords[1];
  319. zc = vc->coords[2] - v0->coords[2];
  320. while( ++vc < vn ) {
  321. xp = xc; yp = yc; zp = zc;
  322. xc = vc->coords[0] - v0->coords[0];
  323. yc = vc->coords[1] - v0->coords[1];
  324. zc = vc->coords[2] - v0->coords[2];
  325. /* Compute (vp - v0) cross (vc - v0) */
  326. n[0] = yp*zc - zp*yc;
  327. n[1] = zp*xc - xp*zc;
  328. n[2] = xp*yc - yp*xc;
  329. dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
  330. if( ! check ) {
  331. /* Reverse the contribution of back-facing triangles to get
  332. * a reasonable normal for self-intersecting polygons (see above)
  333. */
  334. if( dot >= 0 ) {
  335. norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
  336. } else {
  337. norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
  338. }
  339. } else if( dot != 0 ) {
  340. /* Check the new orientation for consistency with previous triangles */
  341. if( dot > 0 ) {
  342. if( sign < 0 ) return SIGN_INCONSISTENT;
  343. sign = 1;
  344. } else {
  345. if( sign > 0 ) return SIGN_INCONSISTENT;
  346. sign = -1;
  347. }
  348. }
  349. }
  350. return sign;
  351. }
  352. /* __gl_renderCache( tess ) takes a single contour and tries to render it
  353. * as a triangle fan. This handles convex polygons, as well as some
  354. * non-convex polygons if we get lucky.
  355. *
  356. * Returns TRUE if the polygon was successfully rendered. The rendering
  357. * output is provided as callbacks (see the api).
  358. */
  359. GLboolean __gl_renderCache( GLUtesselator *tess )
  360. {
  361. CachedVertex *v0 = tess->cache;
  362. CachedVertex *vn = v0 + tess->cacheCount;
  363. CachedVertex *vc;
  364. GLdouble norm[3];
  365. int sign;
  366. if( tess->cacheCount < 3 ) {
  367. /* Degenerate contour -- no output */
  368. return TRUE;
  369. }
  370. norm[0] = tess->normal[0];
  371. norm[1] = tess->normal[1];
  372. norm[2] = tess->normal[2];
  373. if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
  374. ComputeNormal( tess, norm, FALSE );
  375. }
  376. sign = ComputeNormal( tess, norm, TRUE );
  377. if( sign == SIGN_INCONSISTENT ) {
  378. /* Fan triangles did not have a consistent orientation */
  379. return FALSE;
  380. }
  381. if( sign == 0 ) {
  382. /* All triangles were degenerate */
  383. return TRUE;
  384. }
  385. /* Make sure we do the right thing for each winding rule */
  386. switch( tess->windingRule ) {
  387. case GLU_TESS_WINDING_ODD:
  388. case GLU_TESS_WINDING_NONZERO:
  389. break;
  390. case GLU_TESS_WINDING_POSITIVE:
  391. if( sign < 0 ) return TRUE;
  392. break;
  393. case GLU_TESS_WINDING_NEGATIVE:
  394. if( sign > 0 ) return TRUE;
  395. break;
  396. case GLU_TESS_WINDING_ABS_GEQ_TWO:
  397. return TRUE;
  398. }
  399. CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
  400. : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
  401. : GL_TRIANGLES );
  402. CALL_VERTEX_OR_VERTEX_DATA( v0->data );
  403. if( sign > 0 ) {
  404. for( vc = v0+1; vc < vn; ++vc ) {
  405. CALL_VERTEX_OR_VERTEX_DATA( vc->data );
  406. }
  407. } else {
  408. for( vc = vn-1; vc > v0; --vc ) {
  409. CALL_VERTEX_OR_VERTEX_DATA( vc->data );
  410. }
  411. }
  412. CALL_END_OR_END_DATA();
  413. return TRUE;
  414. }