1f220fa62Smrg/* 2f220fa62Smrg * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) 3f220fa62Smrg * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. 4f220fa62Smrg * 5f220fa62Smrg * Permission is hereby granted, free of charge, to any person obtaining a 6f220fa62Smrg * copy of this software and associated documentation files (the "Software"), 7f220fa62Smrg * to deal in the Software without restriction, including without limitation 8f220fa62Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9f220fa62Smrg * and/or sell copies of the Software, and to permit persons to whom the 10f220fa62Smrg * Software is furnished to do so, subject to the following conditions: 11f220fa62Smrg * 12f220fa62Smrg * The above copyright notice including the dates of first publication and 13f220fa62Smrg * either this permission notice or a reference to 14f220fa62Smrg * http://oss.sgi.com/projects/FreeB/ 15f220fa62Smrg * shall be included in all copies or substantial portions of the Software. 16f220fa62Smrg * 17f220fa62Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18f220fa62Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19f220fa62Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20f220fa62Smrg * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21f220fa62Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 22f220fa62Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23f220fa62Smrg * SOFTWARE. 24f220fa62Smrg * 25f220fa62Smrg * Except as contained in this notice, the name of Silicon Graphics, Inc. 26f220fa62Smrg * shall not be used in advertising or otherwise to promote the sale, use or 27f220fa62Smrg * other dealings in this Software without prior written authorization from 28f220fa62Smrg * Silicon Graphics, Inc. 29f220fa62Smrg */ 30f220fa62Smrg/* 31f220fa62Smrg** Author: Eric Veach, July 1994. 32f220fa62Smrg** 33f220fa62Smrg*/ 34f220fa62Smrg 35f220fa62Smrg#include "gluos.h" 36f220fa62Smrg#include "mesh.h" 37f220fa62Smrg#include "tess.h" 38f220fa62Smrg#include "normal.h" 39f220fa62Smrg#include <math.h> 40f220fa62Smrg#include <assert.h> 41f220fa62Smrg 42f220fa62Smrg#ifndef TRUE 43f220fa62Smrg#define TRUE 1 44f220fa62Smrg#endif 45f220fa62Smrg#ifndef FALSE 46f220fa62Smrg#define FALSE 0 47f220fa62Smrg#endif 48f220fa62Smrg 49f220fa62Smrg#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2]) 50f220fa62Smrg 51f220fa62Smrg#if 0 52f220fa62Smrgstatic void Normalize( GLdouble v[3] ) 53f220fa62Smrg{ 54f220fa62Smrg GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; 55f220fa62Smrg 56f220fa62Smrg assert( len > 0 ); 57f220fa62Smrg len = sqrt( len ); 58f220fa62Smrg v[0] /= len; 59f220fa62Smrg v[1] /= len; 60f220fa62Smrg v[2] /= len; 61f220fa62Smrg} 62f220fa62Smrg#endif 63f220fa62Smrg 64f220fa62Smrg#undef ABS 65f220fa62Smrg#define ABS(x) ((x) < 0 ? -(x) : (x)) 66f220fa62Smrg 67f220fa62Smrgstatic int LongAxis( GLdouble v[3] ) 68f220fa62Smrg{ 69f220fa62Smrg int i = 0; 70f220fa62Smrg 71f220fa62Smrg if( ABS(v[1]) > ABS(v[0]) ) { i = 1; } 72f220fa62Smrg if( ABS(v[2]) > ABS(v[i]) ) { i = 2; } 73f220fa62Smrg return i; 74f220fa62Smrg} 75f220fa62Smrg 76f220fa62Smrgstatic void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] ) 77f220fa62Smrg{ 78f220fa62Smrg GLUvertex *v, *v1, *v2; 79f220fa62Smrg GLdouble c, tLen2, maxLen2; 80f220fa62Smrg GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3]; 81f220fa62Smrg GLUvertex *maxVert[3], *minVert[3]; 82f220fa62Smrg GLUvertex *vHead = &tess->mesh->vHead; 83f220fa62Smrg int i; 84f220fa62Smrg 85f220fa62Smrg maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD; 86f220fa62Smrg minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD; 87f220fa62Smrg 88f220fa62Smrg for( v = vHead->next; v != vHead; v = v->next ) { 89f220fa62Smrg for( i = 0; i < 3; ++i ) { 90f220fa62Smrg c = v->coords[i]; 91f220fa62Smrg if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; } 92f220fa62Smrg if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; } 93f220fa62Smrg } 94f220fa62Smrg } 95f220fa62Smrg 96f220fa62Smrg /* Find two vertices separated by at least 1/sqrt(3) of the maximum 97f220fa62Smrg * distance between any two vertices 98f220fa62Smrg */ 99f220fa62Smrg i = 0; 100f220fa62Smrg if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; } 101f220fa62Smrg if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; } 102f220fa62Smrg if( minVal[i] >= maxVal[i] ) { 103f220fa62Smrg /* All vertices are the same -- normal doesn't matter */ 104f220fa62Smrg norm[0] = 0; norm[1] = 0; norm[2] = 1; 105f220fa62Smrg return; 106f220fa62Smrg } 107f220fa62Smrg 108f220fa62Smrg /* Look for a third vertex which forms the triangle with maximum area 109f220fa62Smrg * (Length of normal == twice the triangle area) 110f220fa62Smrg */ 111f220fa62Smrg maxLen2 = 0; 112f220fa62Smrg v1 = minVert[i]; 113f220fa62Smrg v2 = maxVert[i]; 114f220fa62Smrg d1[0] = v1->coords[0] - v2->coords[0]; 115f220fa62Smrg d1[1] = v1->coords[1] - v2->coords[1]; 116f220fa62Smrg d1[2] = v1->coords[2] - v2->coords[2]; 117f220fa62Smrg for( v = vHead->next; v != vHead; v = v->next ) { 118f220fa62Smrg d2[0] = v->coords[0] - v2->coords[0]; 119f220fa62Smrg d2[1] = v->coords[1] - v2->coords[1]; 120f220fa62Smrg d2[2] = v->coords[2] - v2->coords[2]; 121f220fa62Smrg tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1]; 122f220fa62Smrg tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2]; 123f220fa62Smrg tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0]; 124f220fa62Smrg tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2]; 125f220fa62Smrg if( tLen2 > maxLen2 ) { 126f220fa62Smrg maxLen2 = tLen2; 127f220fa62Smrg norm[0] = tNorm[0]; 128f220fa62Smrg norm[1] = tNorm[1]; 129f220fa62Smrg norm[2] = tNorm[2]; 130f220fa62Smrg } 131f220fa62Smrg } 132f220fa62Smrg 133f220fa62Smrg if( maxLen2 <= 0 ) { 134f220fa62Smrg /* All points lie on a single line -- any decent normal will do */ 135f220fa62Smrg norm[0] = norm[1] = norm[2] = 0; 136f220fa62Smrg norm[LongAxis(d1)] = 1; 137f220fa62Smrg } 138f220fa62Smrg} 139f220fa62Smrg 140f220fa62Smrg 141f220fa62Smrgstatic void CheckOrientation( GLUtesselator *tess ) 142f220fa62Smrg{ 143f220fa62Smrg GLdouble area; 144f220fa62Smrg GLUface *f, *fHead = &tess->mesh->fHead; 145f220fa62Smrg GLUvertex *v, *vHead = &tess->mesh->vHead; 146f220fa62Smrg GLUhalfEdge *e; 147f220fa62Smrg 148f220fa62Smrg /* When we compute the normal automatically, we choose the orientation 149f220fa62Smrg * so that the sum of the signed areas of all contours is non-negative. 150f220fa62Smrg */ 151f220fa62Smrg area = 0; 152f220fa62Smrg for( f = fHead->next; f != fHead; f = f->next ) { 153f220fa62Smrg e = f->anEdge; 154f220fa62Smrg if( e->winding <= 0 ) continue; 155f220fa62Smrg do { 156f220fa62Smrg area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t); 157f220fa62Smrg e = e->Lnext; 158f220fa62Smrg } while( e != f->anEdge ); 159f220fa62Smrg } 160f220fa62Smrg if( area < 0 ) { 161f220fa62Smrg /* Reverse the orientation by flipping all the t-coordinates */ 162f220fa62Smrg for( v = vHead->next; v != vHead; v = v->next ) { 163f220fa62Smrg v->t = - v->t; 164f220fa62Smrg } 165f220fa62Smrg tess->tUnit[0] = - tess->tUnit[0]; 166f220fa62Smrg tess->tUnit[1] = - tess->tUnit[1]; 167f220fa62Smrg tess->tUnit[2] = - tess->tUnit[2]; 168f220fa62Smrg } 169f220fa62Smrg} 170f220fa62Smrg 171f220fa62Smrg#ifdef FOR_TRITE_TEST_PROGRAM 172f220fa62Smrg#include <stdlib.h> 173f220fa62Smrgextern int RandomSweep; 174f220fa62Smrg#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0) 175f220fa62Smrg#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0) 176f220fa62Smrg#else 177f220fa62Smrg#if defined(SLANTED_SWEEP) 178f220fa62Smrg/* The "feature merging" is not intended to be complete. There are 179f220fa62Smrg * special cases where edges are nearly parallel to the sweep line 180f220fa62Smrg * which are not implemented. The algorithm should still behave 181f220fa62Smrg * robustly (ie. produce a reasonable tesselation) in the presence 182f220fa62Smrg * of such edges, however it may miss features which could have been 183f220fa62Smrg * merged. We could minimize this effect by choosing the sweep line 184f220fa62Smrg * direction to be something unusual (ie. not parallel to one of the 185f220fa62Smrg * coordinate axes). 186f220fa62Smrg */ 187f220fa62Smrg#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */ 188f220fa62Smrg#define S_UNIT_Y 0.86052074622010633 189f220fa62Smrg#else 190f220fa62Smrg#define S_UNIT_X 1.0 191f220fa62Smrg#define S_UNIT_Y 0.0 192f220fa62Smrg#endif 193f220fa62Smrg#endif 194f220fa62Smrg 195f220fa62Smrg/* Determine the polygon normal and project vertices onto the plane 196f220fa62Smrg * of the polygon. 197f220fa62Smrg */ 198f220fa62Smrgvoid __gl_projectPolygon( GLUtesselator *tess ) 199f220fa62Smrg{ 200f220fa62Smrg GLUvertex *v, *vHead = &tess->mesh->vHead; 201f220fa62Smrg GLdouble norm[3]; 202f220fa62Smrg GLdouble *sUnit, *tUnit; 203f220fa62Smrg int i, computedNormal = FALSE; 204f220fa62Smrg 205f220fa62Smrg norm[0] = tess->normal[0]; 206f220fa62Smrg norm[1] = tess->normal[1]; 207f220fa62Smrg norm[2] = tess->normal[2]; 208f220fa62Smrg if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { 209f220fa62Smrg ComputeNormal( tess, norm ); 210f220fa62Smrg computedNormal = TRUE; 211f220fa62Smrg } 212f220fa62Smrg sUnit = tess->sUnit; 213f220fa62Smrg tUnit = tess->tUnit; 214f220fa62Smrg i = LongAxis( norm ); 215f220fa62Smrg 216f220fa62Smrg#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT) 217f220fa62Smrg /* Choose the initial sUnit vector to be approximately perpendicular 218f220fa62Smrg * to the normal. 219f220fa62Smrg */ 220f220fa62Smrg Normalize( norm ); 221f220fa62Smrg 222f220fa62Smrg sUnit[i] = 0; 223f220fa62Smrg sUnit[(i+1)%3] = S_UNIT_X; 224f220fa62Smrg sUnit[(i+2)%3] = S_UNIT_Y; 225f220fa62Smrg 226f220fa62Smrg /* Now make it exactly perpendicular */ 227f220fa62Smrg w = Dot( sUnit, norm ); 228f220fa62Smrg sUnit[0] -= w * norm[0]; 229f220fa62Smrg sUnit[1] -= w * norm[1]; 230f220fa62Smrg sUnit[2] -= w * norm[2]; 231f220fa62Smrg Normalize( sUnit ); 232f220fa62Smrg 233f220fa62Smrg /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */ 234f220fa62Smrg tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1]; 235f220fa62Smrg tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2]; 236f220fa62Smrg tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0]; 237f220fa62Smrg Normalize( tUnit ); 238f220fa62Smrg#else 239f220fa62Smrg /* Project perpendicular to a coordinate axis -- better numerically */ 240f220fa62Smrg sUnit[i] = 0; 241f220fa62Smrg sUnit[(i+1)%3] = S_UNIT_X; 242f220fa62Smrg sUnit[(i+2)%3] = S_UNIT_Y; 243f220fa62Smrg 244f220fa62Smrg tUnit[i] = 0; 245f220fa62Smrg tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y; 246f220fa62Smrg tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X; 247f220fa62Smrg#endif 248f220fa62Smrg 249f220fa62Smrg /* Project the vertices onto the sweep plane */ 250f220fa62Smrg for( v = vHead->next; v != vHead; v = v->next ) { 251f220fa62Smrg v->s = Dot( v->coords, sUnit ); 252f220fa62Smrg v->t = Dot( v->coords, tUnit ); 253f220fa62Smrg } 254f220fa62Smrg if( computedNormal ) { 255f220fa62Smrg CheckOrientation( tess ); 256f220fa62Smrg } 257f220fa62Smrg} 258