1 | /* $Id: normal.c,v 1.1 2000-02-09 08:47:35 jeroen Exp $ */
|
---|
2 | /*
|
---|
3 | ** License Applicability. Except to the extent portions of this file are
|
---|
4 | ** made subject to an alternative license as permitted in the SGI Free
|
---|
5 | ** Software License B, Version 1.0 (the "License"), the contents of this
|
---|
6 | ** file are subject only to the provisions of the License. You may not use
|
---|
7 | ** this file except in compliance with the License. You may obtain a copy
|
---|
8 | ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
|
---|
9 | ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
|
---|
10 | **
|
---|
11 | ** http://oss.sgi.com/projects/FreeB
|
---|
12 | **
|
---|
13 | ** Note that, as provided in the License, the Software is distributed on an
|
---|
14 | ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
|
---|
15 | ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
|
---|
16 | ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
|
---|
17 | ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
|
---|
18 | **
|
---|
19 | ** Original Code. The Original Code is: OpenGL Sample Implementation,
|
---|
20 | ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
|
---|
21 | ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
|
---|
22 | ** Copyright in any portions created by third parties is as indicated
|
---|
23 | ** elsewhere herein. All Rights Reserved.
|
---|
24 | **
|
---|
25 | ** Additional Notice Provisions: The application programming interfaces
|
---|
26 | ** established by SGI in conjunction with the Original Code are The
|
---|
27 | ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
|
---|
28 | ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
|
---|
29 | ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
|
---|
30 | ** Window System(R) (Version 1.3), released October 19, 1998. This software
|
---|
31 | ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
|
---|
32 | ** published by SGI, but has not been independently verified as being
|
---|
33 | ** compliant with the OpenGL(R) version 1.2.1 Specification.
|
---|
34 | **
|
---|
35 | */
|
---|
36 | /*
|
---|
37 | ** Author: Eric Veach, July 1994.
|
---|
38 | **
|
---|
39 | ** $Date: 2000-02-09 08:47:35 $ $Revision: 1.1 $
|
---|
40 | ** $Header: /home/ktk/tmp/odin/2007/netlabs.cvs/odin32/src/opengl/glu/tess/normal.c,v 1.1 2000-02-09 08:47:35 jeroen Exp $
|
---|
41 | */
|
---|
42 |
|
---|
43 | #include "gluos.h"
|
---|
44 | #include "mesh.h"
|
---|
45 | #include "tess.h"
|
---|
46 | #include "normal.h"
|
---|
47 | #include <math.h>
|
---|
48 | #include <assert.h>
|
---|
49 |
|
---|
50 | #define TRUE 1
|
---|
51 | #define FALSE 0
|
---|
52 |
|
---|
53 | #define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
|
---|
54 |
|
---|
55 | static void Normalize( GLdouble v[3] )
|
---|
56 | {
|
---|
57 | GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
---|
58 |
|
---|
59 | assert( len > 0 );
|
---|
60 | len = sqrt( len );
|
---|
61 | v[0] /= len;
|
---|
62 | v[1] /= len;
|
---|
63 | v[2] /= len;
|
---|
64 | }
|
---|
65 |
|
---|
66 | #define ABS(x) ((x) < 0 ? -(x) : (x))
|
---|
67 |
|
---|
68 | static int LongAxis( GLdouble v[3] )
|
---|
69 | {
|
---|
70 | int i = 0;
|
---|
71 |
|
---|
72 | if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
|
---|
73 | if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
|
---|
74 | return i;
|
---|
75 | }
|
---|
76 |
|
---|
77 | static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
|
---|
78 | {
|
---|
79 | GLUvertex *v, *v1, *v2;
|
---|
80 | GLdouble c, tLen2, maxLen2;
|
---|
81 | GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
|
---|
82 | GLUvertex *maxVert[3], *minVert[3];
|
---|
83 | GLUvertex *vHead = &tess->mesh->vHead;
|
---|
84 | int i;
|
---|
85 |
|
---|
86 | maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
|
---|
87 | minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
|
---|
88 |
|
---|
89 | for( v = vHead->next; v != vHead; v = v->next ) {
|
---|
90 | for( i = 0; i < 3; ++i ) {
|
---|
91 | c = v->coords[i];
|
---|
92 | if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
|
---|
93 | if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
|
---|
94 | }
|
---|
95 | }
|
---|
96 |
|
---|
97 | /* Find two vertices separated by at least 1/sqrt(3) of the maximum
|
---|
98 | * distance between any two vertices
|
---|
99 | */
|
---|
100 | i = 0;
|
---|
101 | if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
|
---|
102 | if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
|
---|
103 | if( minVal[i] >= maxVal[i] ) {
|
---|
104 | /* All vertices are the same -- normal doesn't matter */
|
---|
105 | norm[0] = 0; norm[1] = 0; norm[2] = 1;
|
---|
106 | return;
|
---|
107 | }
|
---|
108 |
|
---|
109 | /* Look for a third vertex which forms the triangle with maximum area
|
---|
110 | * (Length of normal == twice the triangle area)
|
---|
111 | */
|
---|
112 | maxLen2 = 0;
|
---|
113 | v1 = minVert[i];
|
---|
114 | v2 = maxVert[i];
|
---|
115 | d1[0] = v1->coords[0] - v2->coords[0];
|
---|
116 | d1[1] = v1->coords[1] - v2->coords[1];
|
---|
117 | d1[2] = v1->coords[2] - v2->coords[2];
|
---|
118 | for( v = vHead->next; v != vHead; v = v->next ) {
|
---|
119 | d2[0] = v->coords[0] - v2->coords[0];
|
---|
120 | d2[1] = v->coords[1] - v2->coords[1];
|
---|
121 | d2[2] = v->coords[2] - v2->coords[2];
|
---|
122 | tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
|
---|
123 | tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
|
---|
124 | tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
|
---|
125 | tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
|
---|
126 | if( tLen2 > maxLen2 ) {
|
---|
127 | maxLen2 = tLen2;
|
---|
128 | norm[0] = tNorm[0];
|
---|
129 | norm[1] = tNorm[1];
|
---|
130 | norm[2] = tNorm[2];
|
---|
131 | }
|
---|
132 | }
|
---|
133 |
|
---|
134 | if( maxLen2 <= 0 ) {
|
---|
135 | /* All points lie on a single line -- any decent normal will do */
|
---|
136 | norm[0] = norm[1] = norm[2] = 0;
|
---|
137 | norm[LongAxis(d1)] = 1;
|
---|
138 | }
|
---|
139 | }
|
---|
140 |
|
---|
141 |
|
---|
142 | static void CheckOrientation( GLUtesselator *tess )
|
---|
143 | {
|
---|
144 | GLdouble area;
|
---|
145 | GLUface *f, *fHead = &tess->mesh->fHead;
|
---|
146 | GLUvertex *v, *vHead = &tess->mesh->vHead;
|
---|
147 | GLUhalfEdge *e;
|
---|
148 |
|
---|
149 | /* When we compute the normal automatically, we choose the orientation
|
---|
150 | * so that the the sum of the signed areas of all contours is non-negative.
|
---|
151 | */
|
---|
152 | area = 0;
|
---|
153 | for( f = fHead->next; f != fHead; f = f->next ) {
|
---|
154 | e = f->anEdge;
|
---|
155 | if( e->winding <= 0 ) continue;
|
---|
156 | do {
|
---|
157 | area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
|
---|
158 | e = e->Lnext;
|
---|
159 | } while( e != f->anEdge );
|
---|
160 | }
|
---|
161 | if( area < 0 ) {
|
---|
162 | /* Reverse the orientation by flipping all the t-coordinates */
|
---|
163 | for( v = vHead->next; v != vHead; v = v->next ) {
|
---|
164 | v->t = - v->t;
|
---|
165 | }
|
---|
166 | tess->tUnit[0] = - tess->tUnit[0];
|
---|
167 | tess->tUnit[1] = - tess->tUnit[1];
|
---|
168 | tess->tUnit[2] = - tess->tUnit[2];
|
---|
169 | }
|
---|
170 | }
|
---|
171 |
|
---|
172 | #ifdef FOR_TRITE_TEST_PROGRAM
|
---|
173 | #include <stdlib.h>
|
---|
174 | extern int RandomSweep;
|
---|
175 | #define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0)
|
---|
176 | #define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0)
|
---|
177 | #else
|
---|
178 | #if defined(SLANTED_SWEEP)
|
---|
179 | /* The "feature merging" is not intended to be complete. There are
|
---|
180 | * special cases where edges are nearly parallel to the sweep line
|
---|
181 | * which are not implemented. The algorithm should still behave
|
---|
182 | * robustly (ie. produce a reasonable tesselation) in the presence
|
---|
183 | * of such edges, however it may miss features which could have been
|
---|
184 | * merged. We could minimize this effect by choosing the sweep line
|
---|
185 | * direction to be something unusual (ie. not parallel to one of the
|
---|
186 | * coordinate axes).
|
---|
187 | */
|
---|
188 | #define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
|
---|
189 | #define S_UNIT_Y 0.86052074622010633
|
---|
190 | #else
|
---|
191 | #define S_UNIT_X 1.0
|
---|
192 | #define S_UNIT_Y 0.0
|
---|
193 | #endif
|
---|
194 | #endif
|
---|
195 |
|
---|
196 | /* Determine the polygon normal and project vertices onto the plane
|
---|
197 | * of the polygon.
|
---|
198 | */
|
---|
199 | void __gl_projectPolygon( GLUtesselator *tess )
|
---|
200 | {
|
---|
201 | GLUvertex *v, *vHead = &tess->mesh->vHead;
|
---|
202 | GLdouble w, norm[3];
|
---|
203 | GLdouble *sUnit, *tUnit;
|
---|
204 | int i, computedNormal = FALSE;
|
---|
205 |
|
---|
206 | norm[0] = tess->normal[0];
|
---|
207 | norm[1] = tess->normal[1];
|
---|
208 | norm[2] = tess->normal[2];
|
---|
209 | if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
|
---|
210 | ComputeNormal( tess, norm );
|
---|
211 | computedNormal = TRUE;
|
---|
212 | }
|
---|
213 | sUnit = tess->sUnit;
|
---|
214 | tUnit = tess->tUnit;
|
---|
215 | i = LongAxis( norm );
|
---|
216 |
|
---|
217 | #if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
|
---|
218 | /* Choose the initial sUnit vector to be approximately perpendicular
|
---|
219 | * to the normal.
|
---|
220 | */
|
---|
221 | Normalize( norm );
|
---|
222 |
|
---|
223 | sUnit[i] = 0;
|
---|
224 | sUnit[(i+1)%3] = S_UNIT_X;
|
---|
225 | sUnit[(i+2)%3] = S_UNIT_Y;
|
---|
226 |
|
---|
227 | /* Now make it exactly perpendicular */
|
---|
228 | w = Dot( sUnit, norm );
|
---|
229 | sUnit[0] -= w * norm[0];
|
---|
230 | sUnit[1] -= w * norm[1];
|
---|
231 | sUnit[2] -= w * norm[2];
|
---|
232 | Normalize( sUnit );
|
---|
233 |
|
---|
234 | /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
|
---|
235 | tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
|
---|
236 | tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
|
---|
237 | tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
|
---|
238 | Normalize( tUnit );
|
---|
239 | #else
|
---|
240 | /* Project perpendicular to a coordinate axis -- better numerically */
|
---|
241 | sUnit[i] = 0;
|
---|
242 | sUnit[(i+1)%3] = S_UNIT_X;
|
---|
243 | sUnit[(i+2)%3] = S_UNIT_Y;
|
---|
244 |
|
---|
245 | tUnit[i] = 0;
|
---|
246 | tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
|
---|
247 | tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
|
---|
248 | #endif
|
---|
249 |
|
---|
250 | /* Project the vertices onto the sweep plane */
|
---|
251 | for( v = vHead->next; v != vHead; v = v->next ) {
|
---|
252 | v->s = Dot( v->coords, sUnit );
|
---|
253 | v->t = Dot( v->coords, tUnit );
|
---|
254 | }
|
---|
255 | if( computedNormal ) {
|
---|
256 | CheckOrientation( tess );
|
---|
257 | }
|
---|
258 | }
|
---|