Source code of Windows XP (NT5)
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.

234 lines
6.7 KiB

  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 "mesh.h"
  20. #include "tess.h"
  21. #include "normal.h"
  22. #include <math.h>
  23. #include <assert.h>
  24. #define TRUE 1
  25. #define FALSE 0
  26. #define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
  27. static void Normalize( GLdouble v[3] )
  28. {
  29. GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
  30. assert( len > 0 );
  31. len = sqrt( len );
  32. v[0] /= len;
  33. v[1] /= len;
  34. v[2] /= len;
  35. }
  36. #define ABS(x) ((x) < 0 ? -(x) : (x))
  37. static int LongAxis( GLdouble v[3] )
  38. {
  39. int i = 0;
  40. if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
  41. if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
  42. return i;
  43. }
  44. static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
  45. {
  46. GLUvertex *v, *v1, *v2;
  47. GLdouble c, tLen2, maxLen2;
  48. GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
  49. GLUvertex *maxVert[3], *minVert[3];
  50. GLUvertex *vHead = &tess->mesh->vHead;
  51. int i;
  52. maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
  53. minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
  54. for( v = vHead->next; v != vHead; v = v->next ) {
  55. for( i = 0; i < 3; ++i ) {
  56. c = v->coords[i];
  57. if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
  58. if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
  59. }
  60. }
  61. /* Find two vertices separated by at least 1/sqrt(3) of the maximum
  62. * distance between any two vertices
  63. */
  64. i = 0;
  65. if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
  66. if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
  67. if( minVal[i] >= maxVal[i] ) {
  68. /* All vertices are the same -- normal doesn't matter */
  69. norm[0] = 0; norm[1] = 0; norm[2] = 1;
  70. return;
  71. }
  72. /* Look for a third vertex which forms the triangle with maximum area
  73. * (Length of normal == twice the triangle area)
  74. */
  75. maxLen2 = 0;
  76. v1 = minVert[i];
  77. v2 = maxVert[i];
  78. d1[0] = v1->coords[0] - v2->coords[0];
  79. d1[1] = v1->coords[1] - v2->coords[1];
  80. d1[2] = v1->coords[2] - v2->coords[2];
  81. for( v = vHead->next; v != vHead; v = v->next ) {
  82. d2[0] = v->coords[0] - v2->coords[0];
  83. d2[1] = v->coords[1] - v2->coords[1];
  84. d2[2] = v->coords[2] - v2->coords[2];
  85. tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
  86. tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
  87. tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
  88. tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
  89. if( tLen2 > maxLen2 ) {
  90. maxLen2 = tLen2;
  91. norm[0] = tNorm[0];
  92. norm[1] = tNorm[1];
  93. norm[2] = tNorm[2];
  94. }
  95. }
  96. if( maxLen2 <= 0 ) {
  97. /* All points lie on a single line -- any decent normal will do */
  98. norm[0] = norm[1] = norm[2] = 0;
  99. norm[LongAxis(d1)] = 1;
  100. }
  101. }
  102. static void CheckOrientation( GLUtesselator *tess )
  103. {
  104. GLdouble area;
  105. GLUface *f, *fHead = &tess->mesh->fHead;
  106. GLUvertex *v, *vHead = &tess->mesh->vHead;
  107. GLUhalfEdge *e;
  108. /* When we compute the normal automatically, we choose the orientation
  109. * so that the the sum of the signed areas of all contours is non-negative.
  110. */
  111. area = 0;
  112. for( f = fHead->next; f != fHead; f = f->next ) {
  113. e = f->anEdge;
  114. if( e->winding <= 0 ) continue;
  115. do {
  116. area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
  117. e = e->Lnext;
  118. } while( e != f->anEdge );
  119. }
  120. if( area < 0 ) {
  121. /* Reverse the orientation by flipping all the t-coordinates */
  122. for( v = vHead->next; v != vHead; v = v->next ) {
  123. v->t = - v->t;
  124. }
  125. tess->tUnit[0] = - tess->tUnit[0];
  126. tess->tUnit[1] = - tess->tUnit[1];
  127. tess->tUnit[2] = - tess->tUnit[2];
  128. }
  129. }
  130. #ifdef DEBUG
  131. #include <stdlib.h>
  132. extern int RandomSweep;
  133. #define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0)
  134. #define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0)
  135. #else
  136. #if defined(SLANTED_SWEEP)
  137. /* The "feature merging" is not intended to be complete. There are
  138. * special cases where edges are nearly parallel to the sweep line
  139. * which are not implemented. The algorithm should still behave
  140. * robustly (ie. produce a reasonable tesselation) in the presence
  141. * of such edges, however it may miss features which could have been
  142. * merged. We could minimize this effect by choosing the sweep line
  143. * direction to be something unusual (ie. not parallel to one of the
  144. * coordinate axes).
  145. */
  146. #define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
  147. #define S_UNIT_Y 0.86052074622010633
  148. #else
  149. #define S_UNIT_X 1.0
  150. #define S_UNIT_Y 0.0
  151. #endif
  152. #endif
  153. /* Determine the polygon normal and project vertices onto the plane
  154. * of the polygon.
  155. */
  156. void __gl_projectPolygon( GLUtesselator *tess )
  157. {
  158. GLUvertex *v, *vHead = &tess->mesh->vHead;
  159. GLdouble w, norm[3];
  160. GLdouble *sUnit, *tUnit;
  161. int i, computedNormal = FALSE;
  162. norm[0] = tess->normal[0];
  163. norm[1] = tess->normal[1];
  164. norm[2] = tess->normal[2];
  165. if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
  166. ComputeNormal( tess, norm );
  167. computedNormal = TRUE;
  168. }
  169. sUnit = tess->sUnit;
  170. tUnit = tess->tUnit;
  171. i = LongAxis( norm );
  172. #if defined(DEBUG) || defined(TRUE_PROJECT)
  173. /* Choose the initial sUnit vector to be approximately perpendicular
  174. * to the normal.
  175. */
  176. Normalize( norm );
  177. sUnit[i] = 0;
  178. sUnit[(i+1)%3] = S_UNIT_X;
  179. sUnit[(i+2)%3] = S_UNIT_Y;
  180. /* Now make it exactly perpendicular */
  181. w = Dot( sUnit, norm );
  182. sUnit[0] -= w * norm[0];
  183. sUnit[1] -= w * norm[1];
  184. sUnit[2] -= w * norm[2];
  185. Normalize( sUnit );
  186. /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
  187. tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
  188. tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
  189. tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
  190. Normalize( tUnit );
  191. #else
  192. /* Project perpendicular to a coordinate axis -- better numerically */
  193. sUnit[i] = 0;
  194. sUnit[(i+1)%3] = S_UNIT_X;
  195. sUnit[(i+2)%3] = S_UNIT_Y;
  196. tUnit[i] = 0;
  197. tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
  198. tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
  199. #endif
  200. /* Project the vertices onto the sweep plane */
  201. for( v = vHead->next; v != vHead; v = v->next ) {
  202. v->s = Dot( v->coords, sUnit );
  203. v->t = Dot( v->coords, tUnit );
  204. }
  205. if( computedNormal ) {
  206. CheckOrientation( tess );
  207. }
  208. }