📄 tess.c
字号:
/*
** License Applicability. Except to the extent portions of this file are
** made subject to an alternative license as permitted in the SGI Free
** Software License B, Version 1.1 (the "License"), the contents of this
** file are subject only to the provisions of the License. You may not use
** this file except in compliance with the License. You may obtain a copy
** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
**
** http://oss.sgi.com/projects/FreeB
**
** Note that, as provided in the License, the Software is distributed on an
** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
**
** Original Code. The Original Code is: OpenGL Sample Implementation,
** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
** Copyright in any portions created by third parties is as indicated
** elsewhere herein. All Rights Reserved.
**
** Additional Notice Provisions: The application programming interfaces
** established by SGI in conjunction with the Original Code are The
** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
** Window System(R) (Version 1.3), released October 19, 1998. This software
** was created using the OpenGL(R) version 1.2.1 Sample Implementation
** published by SGI, but has not been independently verified as being
** compliant with the OpenGL(R) version 1.2.1 Specification.
**
*/
/*
** Author: Eric Veach, July 1994.
**
*/
#include "gluos.h"
#include <stddef.h>
#include <assert.h>
#include <setjmp.h>
#include "memalloc.h"
#include "tess.h"
#include "mesh.h"
#include "normal.h"
#include "sweep.h"
#include "tessmono.h"
#include "render.h"
#define GLU_TESS_DEFAULT_TOLERANCE 0.0
#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
#define TRUE 1
#define FALSE 0
/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
GLfloat weight[4], void **dataOut ) {}
/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
void *polygonData ) {}
/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
void *data[4],
GLfloat weight[4],
void **outData,
void *polygonData ) {}
/* Half-edges are allocated in pairs (see mesh.c) */
typedef struct { GLUhalfEdge e, eSym; } EdgePair;
#undef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
MAX(sizeof(GLUvertex),sizeof(GLUface))))
GLUtesselator * GLAPIENTRY
gluNewTess( void )
{
GLUtesselator *tess;
/* Only initialize fields which can be changed by the api. Other fields
* are initialized where they are used.
*/
if (memInit( MAX_FAST_ALLOC ) == 0) {
return 0; /* out of memory */
}
tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
if (tess == NULL) {
return 0; /* out of memory */
}
tess->state = T_DORMANT;
tess->normal[0] = 0;
tess->normal[1] = 0;
tess->normal[2] = 0;
tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
tess->windingRule = GLU_TESS_WINDING_ODD;
tess->flagBoundary = FALSE;
tess->boundaryOnly = FALSE;
tess->callBegin = &noBegin;
tess->callEdgeFlag = &noEdgeFlag;
tess->callVertex = &noVertex;
tess->callEnd = &noEnd;
tess->callError = &noError;
tess->callCombine = &noCombine;
tess->callMesh = &noMesh;
tess->callBeginData= &__gl_noBeginData;
tess->callEdgeFlagData= &__gl_noEdgeFlagData;
tess->callVertexData= &__gl_noVertexData;
tess->callEndData= &__gl_noEndData;
tess->callErrorData= &__gl_noErrorData;
tess->callCombineData= &__gl_noCombineData;
tess->polygonData= NULL;
return tess;
}
static void MakeDormant( GLUtesselator *tess )
{
/* Return the tessellator to its original dormant state. */
if( tess->mesh != NULL ) {
__gl_meshDeleteMesh( tess->mesh );
}
tess->state = T_DORMANT;
tess->lastEdge = NULL;
tess->mesh = NULL;
}
#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
static void GotoState( GLUtesselator *tess, enum TessState newState )
{
while( tess->state != newState ) {
/* We change the current state one level at a time, to get to
* the desired state.
*/
if( tess->state < newState ) {
switch( tess->state ) {
case T_DORMANT:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
gluTessBeginPolygon( tess, NULL );
break;
case T_IN_POLYGON:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
gluTessBeginContour( tess );
break;
default:
;
}
} else {
switch( tess->state ) {
case T_IN_CONTOUR:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
gluTessEndContour( tess );
break;
case T_IN_POLYGON:
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
/* gluTessEndPolygon( tess ) is too much work! */
MakeDormant( tess );
break;
default:
;
}
}
}
}
void GLAPIENTRY
gluDeleteTess( GLUtesselator *tess )
{
RequireState( tess, T_DORMANT );
memFree( tess );
}
void GLAPIENTRY
gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
{
GLenum windingRule;
switch( which ) {
case GLU_TESS_TOLERANCE:
if( value < 0.0 || value > 1.0 ) break;
tess->relTolerance = value;
return;
case GLU_TESS_WINDING_RULE:
windingRule = (GLenum) value;
if( windingRule != value ) break; /* not an integer */
switch( windingRule ) {
case GLU_TESS_WINDING_ODD:
case GLU_TESS_WINDING_NONZERO:
case GLU_TESS_WINDING_POSITIVE:
case GLU_TESS_WINDING_NEGATIVE:
case GLU_TESS_WINDING_ABS_GEQ_TWO:
tess->windingRule = windingRule;
return;
default:
break;
}
case GLU_TESS_BOUNDARY_ONLY:
tess->boundaryOnly = (value != 0);
return;
default:
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
return;
}
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
}
/* Returns tessellator property */
void GLAPIENTRY
gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
{
switch (which) {
case GLU_TESS_TOLERANCE:
/* tolerance should be in range [0..1] */
assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
*value= tess->relTolerance;
break;
case GLU_TESS_WINDING_RULE:
assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
tess->windingRule == GLU_TESS_WINDING_NONZERO ||
tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
*value= tess->windingRule;
break;
case GLU_TESS_BOUNDARY_ONLY:
assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
*value= tess->boundaryOnly;
break;
default:
*value= 0.0;
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
break;
}
} /* gluGetTessProperty() */
void GLAPIENTRY
gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
{
tess->normal[0] = x;
tess->normal[1] = y;
tess->normal[2] = z;
}
void GLAPIENTRY
gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn)
{
switch( which ) {
case GLU_TESS_BEGIN:
tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
return;
case GLU_TESS_BEGIN_DATA:
tess->callBeginData = (fn == NULL) ?
&__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
return;
case GLU_TESS_EDGE_FLAG:
tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
(void (GLAPIENTRY *)(GLboolean)) fn;
/* If the client wants boundary edges to be flagged,
* we render everything as separate triangles (no strips or fans).
*/
tess->flagBoundary = (fn != NULL);
return;
case GLU_TESS_EDGE_FLAG_DATA:
tess->callEdgeFlagData= (fn == NULL) ?
&__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
/* If the client wants boundary edges to be flagged,
* we render everything as separate triangles (no strips or fans).
*/
tess->flagBoundary = (fn != NULL);
return;
case GLU_TESS_VERTEX:
tess->callVertex = (fn == NULL) ? &noVertex :
(void (GLAPIENTRY *)(void *)) fn;
return;
case GLU_TESS_VERTEX_DATA:
tess->callVertexData = (fn == NULL) ?
&__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
return;
case GLU_TESS_END:
tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
return;
case GLU_TESS_END_DATA:
tess->callEndData = (fn == NULL) ? &__gl_noEndData :
(void (GLAPIENTRY *)(void *)) fn;
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -