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 <stddef.h> 37f220fa62Smrg#include <assert.h> 38f220fa62Smrg#include <setjmp.h> 39f220fa62Smrg#include "memalloc.h" 40f220fa62Smrg#include "tess.h" 41f220fa62Smrg#include "mesh.h" 42f220fa62Smrg#include "normal.h" 43f220fa62Smrg#include "sweep.h" 44f220fa62Smrg#include "tessmono.h" 45f220fa62Smrg#include "render.h" 46f220fa62Smrg 47f220fa62Smrg#define GLU_TESS_DEFAULT_TOLERANCE 0.0 48f220fa62Smrg#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */ 49f220fa62Smrg 50f220fa62Smrg#ifndef TRUE 51f220fa62Smrg#define TRUE 1 52f220fa62Smrg#endif 53f220fa62Smrg#ifndef FALSE 54f220fa62Smrg#define FALSE 0 55f220fa62Smrg#endif 56f220fa62Smrg 57f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {} 58f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {} 59f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {} 60f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {} 61f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {} 62f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4], 63f220fa62Smrg GLfloat weight[4], void **dataOut ) {} 64f220fa62Smrg/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {} 65f220fa62Smrg 66f220fa62Smrg 67f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type, 68f220fa62Smrg void *polygonData ) {} 69f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, 70f220fa62Smrg void *polygonData ) {} 71f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data, 72f220fa62Smrg void *polygonData ) {} 73f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {} 74f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum, 75f220fa62Smrg void *polygonData ) {} 76f220fa62Smrg/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], 77f220fa62Smrg void *data[4], 78f220fa62Smrg GLfloat weight[4], 79f220fa62Smrg void **outData, 80f220fa62Smrg void *polygonData ) {} 81f220fa62Smrg 82f220fa62Smrg/* Half-edges are allocated in pairs (see mesh.c) */ 83f220fa62Smrgtypedef struct { GLUhalfEdge e, eSym; } EdgePair; 84f220fa62Smrg 85f220fa62Smrg#undef MAX 86f220fa62Smrg#define MAX(a,b) ((a) > (b) ? (a) : (b)) 87f220fa62Smrg#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \ 88f220fa62Smrg MAX(sizeof(GLUvertex),sizeof(GLUface)))) 89f220fa62Smrg 90f220fa62Smrg 91f220fa62SmrgGLUtesselator * GLAPIENTRY 92f220fa62SmrggluNewTess( void ) 93f220fa62Smrg{ 94f220fa62Smrg GLUtesselator *tess; 95f220fa62Smrg 96f220fa62Smrg /* Only initialize fields which can be changed by the api. Other fields 97f220fa62Smrg * are initialized where they are used. 98f220fa62Smrg */ 99f220fa62Smrg 100f220fa62Smrg if (memInit( MAX_FAST_ALLOC ) == 0) { 101f220fa62Smrg return 0; /* out of memory */ 102f220fa62Smrg } 103f220fa62Smrg tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator )); 104f220fa62Smrg if (tess == NULL) { 105f220fa62Smrg return 0; /* out of memory */ 106f220fa62Smrg } 107f220fa62Smrg 108f220fa62Smrg tess->state = T_DORMANT; 109f220fa62Smrg 110f220fa62Smrg tess->normal[0] = 0; 111f220fa62Smrg tess->normal[1] = 0; 112f220fa62Smrg tess->normal[2] = 0; 113f220fa62Smrg 114f220fa62Smrg tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE; 115f220fa62Smrg tess->windingRule = GLU_TESS_WINDING_ODD; 116f220fa62Smrg tess->flagBoundary = FALSE; 117f220fa62Smrg tess->boundaryOnly = FALSE; 118f220fa62Smrg 119f220fa62Smrg tess->callBegin = &noBegin; 120f220fa62Smrg tess->callEdgeFlag = &noEdgeFlag; 121f220fa62Smrg tess->callVertex = &noVertex; 122f220fa62Smrg tess->callEnd = &noEnd; 123f220fa62Smrg 124f220fa62Smrg tess->callError = &noError; 125f220fa62Smrg tess->callCombine = &noCombine; 126f220fa62Smrg tess->callMesh = &noMesh; 127f220fa62Smrg 128f220fa62Smrg tess->callBeginData= &__gl_noBeginData; 129f220fa62Smrg tess->callEdgeFlagData= &__gl_noEdgeFlagData; 130f220fa62Smrg tess->callVertexData= &__gl_noVertexData; 131f220fa62Smrg tess->callEndData= &__gl_noEndData; 132f220fa62Smrg tess->callErrorData= &__gl_noErrorData; 133f220fa62Smrg tess->callCombineData= &__gl_noCombineData; 134f220fa62Smrg 135f220fa62Smrg tess->polygonData= NULL; 136f220fa62Smrg 137f220fa62Smrg return tess; 138f220fa62Smrg} 139f220fa62Smrg 140f220fa62Smrgstatic void MakeDormant( GLUtesselator *tess ) 141f220fa62Smrg{ 142f220fa62Smrg /* Return the tessellator to its original dormant state. */ 143f220fa62Smrg 144f220fa62Smrg if( tess->mesh != NULL ) { 145f220fa62Smrg __gl_meshDeleteMesh( tess->mesh ); 146f220fa62Smrg } 147f220fa62Smrg tess->state = T_DORMANT; 148f220fa62Smrg tess->lastEdge = NULL; 149f220fa62Smrg tess->mesh = NULL; 150f220fa62Smrg} 151f220fa62Smrg 152f220fa62Smrg#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s) 153f220fa62Smrg 154f220fa62Smrgstatic void GotoState( GLUtesselator *tess, enum TessState newState ) 155f220fa62Smrg{ 156f220fa62Smrg while( tess->state != newState ) { 157f220fa62Smrg /* We change the current state one level at a time, to get to 158f220fa62Smrg * the desired state. 159f220fa62Smrg */ 160f220fa62Smrg if( tess->state < newState ) { 161f220fa62Smrg switch( tess->state ) { 162f220fa62Smrg case T_DORMANT: 163f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON ); 164f220fa62Smrg gluTessBeginPolygon( tess, NULL ); 165f220fa62Smrg break; 166f220fa62Smrg case T_IN_POLYGON: 167f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR ); 168f220fa62Smrg gluTessBeginContour( tess ); 169f220fa62Smrg break; 170f220fa62Smrg default: 171f220fa62Smrg ; 172f220fa62Smrg } 173f220fa62Smrg } else { 174f220fa62Smrg switch( tess->state ) { 175f220fa62Smrg case T_IN_CONTOUR: 176f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR ); 177f220fa62Smrg gluTessEndContour( tess ); 178f220fa62Smrg break; 179f220fa62Smrg case T_IN_POLYGON: 180f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON ); 181f220fa62Smrg /* gluTessEndPolygon( tess ) is too much work! */ 182f220fa62Smrg MakeDormant( tess ); 183f220fa62Smrg break; 184f220fa62Smrg default: 185f220fa62Smrg ; 186f220fa62Smrg } 187f220fa62Smrg } 188f220fa62Smrg } 189f220fa62Smrg} 190f220fa62Smrg 191f220fa62Smrg 192f220fa62Smrgvoid GLAPIENTRY 193f220fa62SmrggluDeleteTess( GLUtesselator *tess ) 194f220fa62Smrg{ 195f220fa62Smrg RequireState( tess, T_DORMANT ); 196f220fa62Smrg memFree( tess ); 197f220fa62Smrg} 198f220fa62Smrg 199f220fa62Smrg 200f220fa62Smrgvoid GLAPIENTRY 201f220fa62SmrggluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value ) 202f220fa62Smrg{ 203f220fa62Smrg GLenum windingRule; 204f220fa62Smrg 205f220fa62Smrg switch( which ) { 206f220fa62Smrg case GLU_TESS_TOLERANCE: 207f220fa62Smrg if( value < 0.0 || value > 1.0 ) break; 208f220fa62Smrg tess->relTolerance = value; 209f220fa62Smrg return; 210f220fa62Smrg 211f220fa62Smrg case GLU_TESS_WINDING_RULE: 212f220fa62Smrg windingRule = (GLenum) value; 213f220fa62Smrg if( windingRule != value ) break; /* not an integer */ 214f220fa62Smrg 215f220fa62Smrg switch( windingRule ) { 216f220fa62Smrg case GLU_TESS_WINDING_ODD: 217f220fa62Smrg case GLU_TESS_WINDING_NONZERO: 218f220fa62Smrg case GLU_TESS_WINDING_POSITIVE: 219f220fa62Smrg case GLU_TESS_WINDING_NEGATIVE: 220f220fa62Smrg case GLU_TESS_WINDING_ABS_GEQ_TWO: 221f220fa62Smrg tess->windingRule = windingRule; 222f220fa62Smrg return; 223f220fa62Smrg default: 224f220fa62Smrg break; 225f220fa62Smrg } 226f220fa62Smrg 227f220fa62Smrg case GLU_TESS_BOUNDARY_ONLY: 228f220fa62Smrg tess->boundaryOnly = (value != 0); 229f220fa62Smrg return; 230f220fa62Smrg 231f220fa62Smrg default: 232f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); 233f220fa62Smrg return; 234f220fa62Smrg } 235f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE ); 236f220fa62Smrg} 237f220fa62Smrg 238f220fa62Smrg/* Returns tessellator property */ 239f220fa62Smrgvoid GLAPIENTRY 240f220fa62SmrggluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value ) 241f220fa62Smrg{ 242f220fa62Smrg switch (which) { 243f220fa62Smrg case GLU_TESS_TOLERANCE: 244f220fa62Smrg /* tolerance should be in range [0..1] */ 245f220fa62Smrg assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0); 246f220fa62Smrg *value= tess->relTolerance; 247f220fa62Smrg break; 248f220fa62Smrg case GLU_TESS_WINDING_RULE: 249f220fa62Smrg assert(tess->windingRule == GLU_TESS_WINDING_ODD || 250f220fa62Smrg tess->windingRule == GLU_TESS_WINDING_NONZERO || 251f220fa62Smrg tess->windingRule == GLU_TESS_WINDING_POSITIVE || 252f220fa62Smrg tess->windingRule == GLU_TESS_WINDING_NEGATIVE || 253f220fa62Smrg tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO); 254f220fa62Smrg *value= tess->windingRule; 255f220fa62Smrg break; 256f220fa62Smrg case GLU_TESS_BOUNDARY_ONLY: 257f220fa62Smrg assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE); 258f220fa62Smrg *value= tess->boundaryOnly; 259f220fa62Smrg break; 260f220fa62Smrg default: 261f220fa62Smrg *value= 0.0; 262f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); 263f220fa62Smrg break; 264f220fa62Smrg } 265f220fa62Smrg} /* gluGetTessProperty() */ 266f220fa62Smrg 267f220fa62Smrgvoid GLAPIENTRY 268f220fa62SmrggluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z ) 269f220fa62Smrg{ 270f220fa62Smrg tess->normal[0] = x; 271f220fa62Smrg tess->normal[1] = y; 272f220fa62Smrg tess->normal[2] = z; 273f220fa62Smrg} 274f220fa62Smrg 275f220fa62Smrgvoid GLAPIENTRY 276f220fa62SmrggluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn) 277f220fa62Smrg{ 278f220fa62Smrg switch( which ) { 279f220fa62Smrg case GLU_TESS_BEGIN: 280f220fa62Smrg tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn; 281f220fa62Smrg return; 282f220fa62Smrg case GLU_TESS_BEGIN_DATA: 283f220fa62Smrg tess->callBeginData = (fn == NULL) ? 284f220fa62Smrg &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn; 285f220fa62Smrg return; 286f220fa62Smrg case GLU_TESS_EDGE_FLAG: 287f220fa62Smrg tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag : 288f220fa62Smrg (void (GLAPIENTRY *)(GLboolean)) fn; 289f220fa62Smrg /* If the client wants boundary edges to be flagged, 290f220fa62Smrg * we render everything as separate triangles (no strips or fans). 291f220fa62Smrg */ 292f220fa62Smrg tess->flagBoundary = (fn != NULL); 293f220fa62Smrg return; 294f220fa62Smrg case GLU_TESS_EDGE_FLAG_DATA: 295f220fa62Smrg tess->callEdgeFlagData= (fn == NULL) ? 296f220fa62Smrg &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn; 297f220fa62Smrg /* If the client wants boundary edges to be flagged, 298f220fa62Smrg * we render everything as separate triangles (no strips or fans). 299f220fa62Smrg */ 300f220fa62Smrg tess->flagBoundary = (fn != NULL); 301f220fa62Smrg return; 302f220fa62Smrg case GLU_TESS_VERTEX: 303f220fa62Smrg tess->callVertex = (fn == NULL) ? &noVertex : 304f220fa62Smrg (void (GLAPIENTRY *)(void *)) fn; 305f220fa62Smrg return; 306f220fa62Smrg case GLU_TESS_VERTEX_DATA: 307f220fa62Smrg tess->callVertexData = (fn == NULL) ? 308f220fa62Smrg &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn; 309f220fa62Smrg return; 310f220fa62Smrg case GLU_TESS_END: 311f220fa62Smrg tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn; 312f220fa62Smrg return; 313f220fa62Smrg case GLU_TESS_END_DATA: 314f220fa62Smrg tess->callEndData = (fn == NULL) ? &__gl_noEndData : 315f220fa62Smrg (void (GLAPIENTRY *)(void *)) fn; 316f220fa62Smrg return; 317f220fa62Smrg case GLU_TESS_ERROR: 318f220fa62Smrg tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn; 319f220fa62Smrg return; 320f220fa62Smrg case GLU_TESS_ERROR_DATA: 321f220fa62Smrg tess->callErrorData = (fn == NULL) ? 322f220fa62Smrg &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn; 323f220fa62Smrg return; 324f220fa62Smrg case GLU_TESS_COMBINE: 325f220fa62Smrg tess->callCombine = (fn == NULL) ? &noCombine : 326f220fa62Smrg (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn; 327f220fa62Smrg return; 328f220fa62Smrg case GLU_TESS_COMBINE_DATA: 329f220fa62Smrg tess->callCombineData = (fn == NULL) ? &__gl_noCombineData : 330f220fa62Smrg (void (GLAPIENTRY *)(GLdouble [3], 331f220fa62Smrg void *[4], 332f220fa62Smrg GLfloat [4], 333f220fa62Smrg void **, 334f220fa62Smrg void *)) fn; 335f220fa62Smrg return; 336f220fa62Smrg case GLU_TESS_MESH: 337f220fa62Smrg tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn; 338f220fa62Smrg return; 339f220fa62Smrg default: 340f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); 341f220fa62Smrg return; 342f220fa62Smrg } 343f220fa62Smrg} 344f220fa62Smrg 345f220fa62Smrgstatic int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) 346f220fa62Smrg{ 347f220fa62Smrg GLUhalfEdge *e; 348f220fa62Smrg 349f220fa62Smrg e = tess->lastEdge; 350f220fa62Smrg if( e == NULL ) { 351f220fa62Smrg /* Make a self-loop (one vertex, one edge). */ 352f220fa62Smrg 353f220fa62Smrg e = __gl_meshMakeEdge( tess->mesh ); 354f220fa62Smrg if (e == NULL) return 0; 355f220fa62Smrg if ( !__gl_meshSplice( e, e->Sym ) ) return 0; 356f220fa62Smrg } else { 357f220fa62Smrg /* Create a new vertex and edge which immediately follow e 358f220fa62Smrg * in the ordering around the left face. 359f220fa62Smrg */ 360f220fa62Smrg if (__gl_meshSplitEdge( e ) == NULL) return 0; 361f220fa62Smrg e = e->Lnext; 362f220fa62Smrg } 363f220fa62Smrg 364f220fa62Smrg /* The new vertex is now e->Org. */ 365f220fa62Smrg e->Org->data = data; 366f220fa62Smrg e->Org->coords[0] = coords[0]; 367f220fa62Smrg e->Org->coords[1] = coords[1]; 368f220fa62Smrg e->Org->coords[2] = coords[2]; 369f220fa62Smrg 370f220fa62Smrg /* The winding of an edge says how the winding number changes as we 371f220fa62Smrg * cross from the edge''s right face to its left face. We add the 372f220fa62Smrg * vertices in such an order that a CCW contour will add +1 to 373f220fa62Smrg * the winding number of the region inside the contour. 374f220fa62Smrg */ 375f220fa62Smrg e->winding = 1; 376f220fa62Smrg e->Sym->winding = -1; 377f220fa62Smrg 378f220fa62Smrg tess->lastEdge = e; 379f220fa62Smrg 380f220fa62Smrg return 1; 381f220fa62Smrg} 382f220fa62Smrg 383f220fa62Smrg 384f220fa62Smrgstatic void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) 385f220fa62Smrg{ 386f220fa62Smrg CachedVertex *v = &tess->cache[tess->cacheCount]; 387f220fa62Smrg 388f220fa62Smrg v->data = data; 389f220fa62Smrg v->coords[0] = coords[0]; 390f220fa62Smrg v->coords[1] = coords[1]; 391f220fa62Smrg v->coords[2] = coords[2]; 392f220fa62Smrg ++tess->cacheCount; 393f220fa62Smrg} 394f220fa62Smrg 395f220fa62Smrg 396f220fa62Smrgstatic int EmptyCache( GLUtesselator *tess ) 397f220fa62Smrg{ 398f220fa62Smrg CachedVertex *v = tess->cache; 399f220fa62Smrg CachedVertex *vLast; 400f220fa62Smrg 401f220fa62Smrg tess->mesh = __gl_meshNewMesh(); 402f220fa62Smrg if (tess->mesh == NULL) return 0; 403f220fa62Smrg 404f220fa62Smrg for( vLast = v + tess->cacheCount; v < vLast; ++v ) { 405f220fa62Smrg if ( !AddVertex( tess, v->coords, v->data ) ) return 0; 406f220fa62Smrg } 407f220fa62Smrg tess->cacheCount = 0; 408f220fa62Smrg tess->emptyCache = FALSE; 409f220fa62Smrg 410f220fa62Smrg return 1; 411f220fa62Smrg} 412f220fa62Smrg 413f220fa62Smrg 414f220fa62Smrgvoid GLAPIENTRY 415f220fa62SmrggluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) 416f220fa62Smrg{ 417f220fa62Smrg int i, tooLarge = FALSE; 418f220fa62Smrg GLdouble x, clamped[3]; 419f220fa62Smrg 420f220fa62Smrg RequireState( tess, T_IN_CONTOUR ); 421f220fa62Smrg 422f220fa62Smrg if( tess->emptyCache ) { 423f220fa62Smrg if ( !EmptyCache( tess ) ) { 424f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); 425f220fa62Smrg return; 426f220fa62Smrg } 427f220fa62Smrg tess->lastEdge = NULL; 428f220fa62Smrg } 429f220fa62Smrg for( i = 0; i < 3; ++i ) { 430f220fa62Smrg x = coords[i]; 431f220fa62Smrg if( x < - GLU_TESS_MAX_COORD ) { 432f220fa62Smrg x = - GLU_TESS_MAX_COORD; 433f220fa62Smrg tooLarge = TRUE; 434f220fa62Smrg } 435f220fa62Smrg if( x > GLU_TESS_MAX_COORD ) { 436f220fa62Smrg x = GLU_TESS_MAX_COORD; 437f220fa62Smrg tooLarge = TRUE; 438f220fa62Smrg } 439f220fa62Smrg clamped[i] = x; 440f220fa62Smrg } 441f220fa62Smrg if( tooLarge ) { 442f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE ); 443f220fa62Smrg } 444f220fa62Smrg 445f220fa62Smrg if( tess->mesh == NULL ) { 446f220fa62Smrg if( tess->cacheCount < TESS_MAX_CACHE ) { 447f220fa62Smrg CacheVertex( tess, clamped, data ); 448f220fa62Smrg return; 449f220fa62Smrg } 450f220fa62Smrg if ( !EmptyCache( tess ) ) { 451f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); 452f220fa62Smrg return; 453f220fa62Smrg } 454f220fa62Smrg } 455f220fa62Smrg if ( !AddVertex( tess, clamped, data ) ) { 456f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); 457f220fa62Smrg } 458f220fa62Smrg} 459f220fa62Smrg 460f220fa62Smrg 461f220fa62Smrgvoid GLAPIENTRY 462f220fa62SmrggluTessBeginPolygon( GLUtesselator *tess, void *data ) 463f220fa62Smrg{ 464f220fa62Smrg RequireState( tess, T_DORMANT ); 465f220fa62Smrg 466f220fa62Smrg tess->state = T_IN_POLYGON; 467f220fa62Smrg tess->cacheCount = 0; 468f220fa62Smrg tess->emptyCache = FALSE; 469f220fa62Smrg tess->mesh = NULL; 470f220fa62Smrg 471f220fa62Smrg tess->polygonData= data; 472f220fa62Smrg} 473f220fa62Smrg 474f220fa62Smrg 475f220fa62Smrgvoid GLAPIENTRY 476f220fa62SmrggluTessBeginContour( GLUtesselator *tess ) 477f220fa62Smrg{ 478f220fa62Smrg RequireState( tess, T_IN_POLYGON ); 479f220fa62Smrg 480f220fa62Smrg tess->state = T_IN_CONTOUR; 481f220fa62Smrg tess->lastEdge = NULL; 482f220fa62Smrg if( tess->cacheCount > 0 ) { 483f220fa62Smrg /* Just set a flag so we don't get confused by empty contours 484f220fa62Smrg * -- these can be generated accidentally with the obsolete 485f220fa62Smrg * NextContour() interface. 486f220fa62Smrg */ 487f220fa62Smrg tess->emptyCache = TRUE; 488f220fa62Smrg } 489f220fa62Smrg} 490f220fa62Smrg 491f220fa62Smrg 492f220fa62Smrgvoid GLAPIENTRY 493f220fa62SmrggluTessEndContour( GLUtesselator *tess ) 494f220fa62Smrg{ 495f220fa62Smrg RequireState( tess, T_IN_CONTOUR ); 496f220fa62Smrg tess->state = T_IN_POLYGON; 497f220fa62Smrg} 498f220fa62Smrg 499f220fa62Smrgvoid GLAPIENTRY 500f220fa62SmrggluTessEndPolygon( GLUtesselator *tess ) 501f220fa62Smrg{ 502f220fa62Smrg GLUmesh *mesh; 503f220fa62Smrg 504f220fa62Smrg if (setjmp(tess->env) != 0) { 505f220fa62Smrg /* come back here if out of memory */ 506f220fa62Smrg CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); 507f220fa62Smrg return; 508f220fa62Smrg } 509f220fa62Smrg 510f220fa62Smrg RequireState( tess, T_IN_POLYGON ); 511f220fa62Smrg tess->state = T_DORMANT; 512f220fa62Smrg 513f220fa62Smrg if( tess->mesh == NULL ) { 514f220fa62Smrg if( ! tess->flagBoundary && tess->callMesh == &noMesh ) { 515f220fa62Smrg 516f220fa62Smrg /* Try some special code to make the easy cases go quickly 517f220fa62Smrg * (eg. convex polygons). This code does NOT handle multiple contours, 518f220fa62Smrg * intersections, edge flags, and of course it does not generate 519f220fa62Smrg * an explicit mesh either. 520f220fa62Smrg */ 521f220fa62Smrg if( __gl_renderCache( tess )) { 522f220fa62Smrg tess->polygonData= NULL; 523f220fa62Smrg return; 524f220fa62Smrg } 525f220fa62Smrg } 526f220fa62Smrg if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/ 527f220fa62Smrg } 528f220fa62Smrg 529f220fa62Smrg /* Determine the polygon normal and project vertices onto the plane 530f220fa62Smrg * of the polygon. 531f220fa62Smrg */ 532f220fa62Smrg __gl_projectPolygon( tess ); 533f220fa62Smrg 534f220fa62Smrg /* __gl_computeInterior( tess ) computes the planar arrangement specified 535f220fa62Smrg * by the given contours, and further subdivides this arrangement 536f220fa62Smrg * into regions. Each region is marked "inside" if it belongs 537f220fa62Smrg * to the polygon, according to the rule given by tess->windingRule. 538f220fa62Smrg * Each interior region is guaranteed be monotone. 539f220fa62Smrg */ 540f220fa62Smrg if ( !__gl_computeInterior( tess ) ) { 541f220fa62Smrg longjmp(tess->env,1); /* could've used a label */ 542f220fa62Smrg } 543f220fa62Smrg 544f220fa62Smrg mesh = tess->mesh; 545f220fa62Smrg if( ! tess->fatalError ) { 546f220fa62Smrg int rc = 1; 547f220fa62Smrg 548f220fa62Smrg /* If the user wants only the boundary contours, we throw away all edges 549f220fa62Smrg * except those which separate the interior from the exterior. 550f220fa62Smrg * Otherwise we tessellate all the regions marked "inside". 551f220fa62Smrg */ 552f220fa62Smrg if( tess->boundaryOnly ) { 553f220fa62Smrg rc = __gl_meshSetWindingNumber( mesh, 1, TRUE ); 554f220fa62Smrg } else { 555f220fa62Smrg rc = __gl_meshTessellateInterior( mesh ); 556f220fa62Smrg } 557f220fa62Smrg if (rc == 0) longjmp(tess->env,1); /* could've used a label */ 558f220fa62Smrg 559f220fa62Smrg __gl_meshCheckMesh( mesh ); 560f220fa62Smrg 561f220fa62Smrg if( tess->callBegin != &noBegin || tess->callEnd != &noEnd 562f220fa62Smrg || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag 563f220fa62Smrg || tess->callBeginData != &__gl_noBeginData 564f220fa62Smrg || tess->callEndData != &__gl_noEndData 565f220fa62Smrg || tess->callVertexData != &__gl_noVertexData 566f220fa62Smrg || tess->callEdgeFlagData != &__gl_noEdgeFlagData ) 567f220fa62Smrg { 568f220fa62Smrg if( tess->boundaryOnly ) { 569f220fa62Smrg __gl_renderBoundary( tess, mesh ); /* output boundary contours */ 570f220fa62Smrg } else { 571f220fa62Smrg __gl_renderMesh( tess, mesh ); /* output strips and fans */ 572f220fa62Smrg } 573f220fa62Smrg } 574f220fa62Smrg if( tess->callMesh != &noMesh ) { 575f220fa62Smrg 576f220fa62Smrg /* Throw away the exterior faces, so that all faces are interior. 577f220fa62Smrg * This way the user doesn't have to check the "inside" flag, 578f220fa62Smrg * and we don't need to even reveal its existence. It also leaves 579f220fa62Smrg * the freedom for an implementation to not generate the exterior 580f220fa62Smrg * faces in the first place. 581f220fa62Smrg */ 582f220fa62Smrg __gl_meshDiscardExterior( mesh ); 583f220fa62Smrg (*tess->callMesh)( mesh ); /* user wants the mesh itself */ 584f220fa62Smrg tess->mesh = NULL; 585f220fa62Smrg tess->polygonData= NULL; 586f220fa62Smrg return; 587f220fa62Smrg } 588f220fa62Smrg } 589f220fa62Smrg __gl_meshDeleteMesh( mesh ); 590f220fa62Smrg tess->polygonData= NULL; 591f220fa62Smrg tess->mesh = NULL; 592f220fa62Smrg} 593f220fa62Smrg 594f220fa62Smrg 595f220fa62Smrg/*XXXblythe unused function*/ 596f220fa62Smrg#if 0 597f220fa62Smrgvoid GLAPIENTRY 598f220fa62SmrggluDeleteMesh( GLUmesh *mesh ) 599f220fa62Smrg{ 600f220fa62Smrg __gl_meshDeleteMesh( mesh ); 601f220fa62Smrg} 602f220fa62Smrg#endif 603f220fa62Smrg 604f220fa62Smrg 605f220fa62Smrg 606f220fa62Smrg/*******************************************************/ 607f220fa62Smrg 608f220fa62Smrg/* Obsolete calls -- for backward compatibility */ 609f220fa62Smrg 610f220fa62Smrgvoid GLAPIENTRY 611f220fa62SmrggluBeginPolygon( GLUtesselator *tess ) 612f220fa62Smrg{ 613f220fa62Smrg gluTessBeginPolygon( tess, NULL ); 614f220fa62Smrg gluTessBeginContour( tess ); 615f220fa62Smrg} 616f220fa62Smrg 617f220fa62Smrg 618f220fa62Smrg/*ARGSUSED*/ 619f220fa62Smrgvoid GLAPIENTRY 620f220fa62SmrggluNextContour( GLUtesselator *tess, GLenum type ) 621f220fa62Smrg{ 622f220fa62Smrg gluTessEndContour( tess ); 623f220fa62Smrg gluTessBeginContour( tess ); 624f220fa62Smrg} 625f220fa62Smrg 626f220fa62Smrg 627f220fa62Smrgvoid GLAPIENTRY 628f220fa62SmrggluEndPolygon( GLUtesselator *tess ) 629f220fa62Smrg{ 630f220fa62Smrg gluTessEndContour( tess ); 631f220fa62Smrg gluTessEndPolygon( tess ); 632f220fa62Smrg} 633