From ff5ce773b254ab37cc0e01d62c131a32338b667f Mon Sep 17 00:00:00 2001 From: Gareth Hughes Date: Mon, 6 Dec 1999 09:39:34 +0000 Subject: Merging in work from 3.1/3.2 branch. Tessellator is essentially fully functional now. --- src/glu/mesa/Makefile.BeOS | 2 +- src/glu/mesa/Makefile.BeOS-R4 | 8 +- src/glu/mesa/Makefile.X11 | 4 +- src/glu/mesa/tess.c | 1354 ++++++++++++++++++++++------------------- src/glu/mesa/tess.h | 26 +- 5 files changed, 736 insertions(+), 658 deletions(-) (limited to 'src') diff --git a/src/glu/mesa/Makefile.BeOS b/src/glu/mesa/Makefile.BeOS index 989ad7c157..e8851dea44 100644 --- a/src/glu/mesa/Makefile.BeOS +++ b/src/glu/mesa/Makefile.BeOS @@ -30,7 +30,7 @@ LIBDIR = ../lib SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \ project.c quadric.c tess.c tess_fist.c tess_hash.c tess_heap.c \ - tess_winding.c + tess_winding.c tess_clip.c OBJECTS = $(SOURCES:.c=.o) diff --git a/src/glu/mesa/Makefile.BeOS-R4 b/src/glu/mesa/Makefile.BeOS-R4 index 1285db4c33..ebe3a689d3 100644 --- a/src/glu/mesa/Makefile.BeOS-R4 +++ b/src/glu/mesa/Makefile.BeOS-R4 @@ -19,9 +19,13 @@ # Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# $Id: Makefile.BeOS-R4,v 1.5 1999/10/03 00:53:38 gareth Exp $ +# $Id: Makefile.BeOS-R4,v 1.6 1999/12/06 09:39:34 gareth Exp $ # $Log: Makefile.BeOS-R4,v $ +# Revision 1.6 1999/12/06 09:39:34 gareth +# Merging in work from 3.1/3.2 branch. Tessellator is essentially fully +# functional now. +# # Revision 1.5 1999/10/03 00:53:38 gareth # Added tessellation winding rule files. # @@ -59,7 +63,7 @@ LIBDIR = ../lib SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \ project.c quadric.c tess.c tess_fist.c tess_hash.c tess_heap.c \ - tess_winding.c + tess_winding.c tess_clip.c OBJECTS = $(SOURCES:.c=.o) diff --git a/src/glu/mesa/Makefile.X11 b/src/glu/mesa/Makefile.X11 index 3036001776..4373c8f2b4 100644 --- a/src/glu/mesa/Makefile.X11 +++ b/src/glu/mesa/Makefile.X11 @@ -1,4 +1,4 @@ -# $Id: Makefile.X11,v 1.6 1999/10/03 00:53:38 gareth Exp $ +# $Id: Makefile.X11,v 1.7 1999/12/06 09:39:34 gareth Exp $ # Mesa 3-D graphics library # Version: 3.1 @@ -20,7 +20,7 @@ LIBDIR = ../lib SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \ project.c quadric.c tess.c tess_fist.c tess_hash.c tess_heap.c \ - tess_winding.c + tess_winding.c tess_clip.c OBJECTS = $(SOURCES:.c=.o) diff --git a/src/glu/mesa/tess.c b/src/glu/mesa/tess.c index 7f1b5a5682..f48c6a0171 100644 --- a/src/glu/mesa/tess.c +++ b/src/glu/mesa/tess.c @@ -1,4 +1,4 @@ -/* $Id: tess.c,v 1.21 1999/11/11 03:21:43 kendallb Exp $ */ +/* $Id: tess.c,v 1.22 1999/12/06 09:39:34 gareth Exp $ */ /* * Mesa 3-D graphics library @@ -33,7 +33,9 @@ #include #include #include -#include +#include + +#include "gluP.h" #include "tess.h" #include "tess_macros.h" @@ -42,17 +44,6 @@ #include "tess_grid.h" #endif -/***************************************************************************** - * Internal function prototypes: - *****************************************************************************/ - -static void init_callbacks( tess_callbacks_t *callbacks ); - -static void tess_cleanup( GLUtesselator *tobj ); -static void inspect_current_contour( GLUtesselator *tobj ); - -void delete_contour( tess_contour_t **contour ); -static void delete_all_contours( GLUtesselator *tobj ); #define TESS_CHECK_ERRORS(t) if ( (t)->error != GLU_NO_ERROR ) goto cleanup @@ -62,914 +53,991 @@ GLint tess_dbg_level; /***************************************************************************** + * tess_error_callback * - * GLU TESSELLATION FUNCTIONS + * Internal error handler. Call the user-registered error callback. * + * 2nd arg changed from 'errno' to 'errnum' since MSVC defines errnum as + * a macro (of all things) and thus breaks the build -tjump *****************************************************************************/ +void tess_error_callback( GLUtesselator *tobj, GLenum errnum ) +{ + if ( tobj->error == GLU_NO_ERROR ) + { + tobj->error = errnum; + } + + if ( tobj->callbacks.errorData != NULL ) + { + ( tobj->callbacks.errorData )( errnum, tobj->data ); + } + else if ( tobj->callbacks.error != NULL ) + { + ( tobj->callbacks.error )( errnum ); + } +} /***************************************************************************** - * gluNewTess + * init_callbacks *****************************************************************************/ -GLUtesselator* GLAPIENTRY gluNewTess( void ) +static void init_callbacks( tess_callbacks_t *callbacks ) { - GLUtesselator *tobj; + callbacks->begin = ( void (GLCALLBACKP)(GLenum) ) NULL; + callbacks->beginData = ( void (GLCALLBACKP)(GLenum, void *) ) NULL; + callbacks->edgeFlag = ( void (GLCALLBACKP)(GLboolean) ) NULL; + callbacks->edgeFlagData = ( void (GLCALLBACKP)(GLboolean, void *) ) NULL; + callbacks->vertex = ( void (GLCALLBACKP)(void *) ) NULL; + callbacks->vertexData = ( void (GLCALLBACKP)(void *, void *) ) NULL; + callbacks->end = ( void (GLCALLBACKP)(void) ) NULL; + callbacks->endData = ( void (GLCALLBACKP)(void *) ) NULL; + callbacks->error = ( void (GLCALLBACKP)(GLenum) ) NULL; + callbacks->errorData = ( void (GLCALLBACKP)(GLenum, void *) ) NULL; + callbacks->combine = ( void (GLCALLBACKP)(GLdouble [3], void *[4], + GLfloat [4], void **) ) NULL; + callbacks->combineData = ( void (GLCALLBACKP)(GLdouble [3], void *[4], + GLfloat [4], void **, + void *) ) NULL; +} -#ifdef DEBUG - if ( getenv( "GLU_TESS_DBG_LEVEL" ) ) { - tess_dbg_level = atoi( getenv( "GLU_TESS_DBG_LEVEL" ) ); - } else { - tess_dbg_level = DBG_LEVEL_BASE; - } -#endif - MSG( 15, "-> gluNewTess()\n" ); +/***************************************************************************** + * find_normal + *****************************************************************************/ +static GLenum find_normal( GLUtesselator *tobj ) +{ + tess_contour_t *contour = tobj->current_contour; + tess_vertex_t *va, *vb, *vc; + GLdouble a[3], b[3], c[3]; - tobj = malloc( sizeof(GLUtesselator) ); - if ( tobj == NULL ) { - return NULL; + MSG( 15, " --> find_normal( tobj:%p )\n", tobj ); + + if ( contour == NULL ) { return GLU_ERROR; } + + va = contour->vertices; + vb = va->next; + + /* If va and vb are the same point, keep looking for a different vertex. */ + + while ( IS_EQUAL_3DV( va->coords, vb->coords ) && ( vb != va ) ) { + vb = vb->next; } - init_callbacks( &tobj->callbacks ); + if ( vb == va ) { + /* FIXME: What error is this? */ + tess_error_callback( tobj, GLU_TESS_ERROR7 ); + } - tobj->boundary_only = GL_FALSE; - tobj->winding_rule = GLU_TESS_WINDING_ODD; - tobj->tolerance = 0.0; + SUB_3V( a, vb->coords, va->coords ); - tobj->plane.normal[X] = 0.0; - tobj->plane.normal[Y] = 0.0; - tobj->plane.normal[Z] = 0.0; - tobj->plane.dist = 0.0; + for ( vc = vb->next; vc != va; vc = vc->next ) + { + SUB_3V( b, vc->coords, va->coords ); - tobj->contour_count = 0; - tobj->contours = tobj->last_contour = NULL; - tobj->current_contour = NULL; + CROSS_3V( c, a, b ); - CLEAR_BBOX_2DV( tobj->mins, tobj->maxs ); + if ( ! IS_ZERO_3DV( c ) ) + { + MSG( 15, " using (%.2f,%.2f) -> (%.2f,%.2f) -> (%.2f,%.2f)\n", + va->coords[X], va->coords[Y], + vb->coords[X], vb->coords[Y], + vc->coords[X], vc->coords[Y] ); - tobj->vertex_count = 0; - tobj->sorted_vertices = NULL; -#if 0 - tobj->grid = NULL; -#endif - tobj->cvc_lists = NULL; - tobj->data = NULL; - tobj->edge_flag = GL_FALSE; - tobj->label = 0; + COPY_3V( contour->plane.normal, c ); + NORMALIZE_3DV( contour->plane.normal ); - tobj->error = GLU_NO_ERROR; + contour->plane.dist = - DOT_3V( contour->plane.normal, + va->coords ); - MSG( 15, "<- gluNewTess() tobj:%p\n", tobj ); - return tobj; -} + MSG( 15, " <-- find_normal( tobj:%p ) n: (%.2f, %.2f, %.2f)\n", tobj, contour->plane.normal[X], contour->plane.normal[Y], contour->plane.normal[Z] ); + return GLU_NO_ERROR; + } + } + /* FIXME: What error is this? */ + tess_error_callback( tobj, GLU_TESS_ERROR7 ); + return GLU_ERROR; +} /***************************************************************************** - * gluDeleteTess + * twice_contour_area + * + * Calculate the twice the signed area of the given contour. Used to + * determine the contour's orientation amongst other things. *****************************************************************************/ -void GLAPIENTRY gluDeleteTess( GLUtesselator *tobj ) +GLdouble twice_contour_area( tess_contour_t *contour ) { - MSG( 15, "-> gluDeleteTess( tobj:%p )\n", tobj ); + tess_vertex_t *vertex = contour->vertices; + GLdouble area, x, y; + + area = 0.0; + + x = vertex->v[X]; + y = vertex->v[Y]; + + vertex = vertex->next; - if ( ( tobj->error == GLU_NO_ERROR ) && ( tobj->contour_count > 0 ) ) + do { - /* gluEndPolygon was not called. */ - tess_error_callback( tobj, GLU_TESS_ERROR3 ); + area += ( (vertex->v[X] - x) * (vertex->next->v[Y] - y) - + (vertex->v[Y] - y) * (vertex->next->v[X] - x) ); + vertex = vertex->next; } + while ( vertex != contour->vertices ); - /* Delete all internal structures. */ - tess_cleanup( tobj ); - free( tobj ); - - MSG( 15, "<- gluDeleteTess()\n" ); + return area; } - /***************************************************************************** - * gluTessBeginPolygon + * project_current_contour + * + * Project the contour's vertices onto the tessellation plane. We perform + * a complex rotation here to allow non-axis-aligned tessellation normals. *****************************************************************************/ -void GLAPIENTRY gluTessBeginPolygon( GLUtesselator *tobj, void *polygon_data ) +static void project_current_contour( GLUtesselator *tobj ) { - MSG( 15, "-> gluTessBeginPolygon( tobj:%p data:%p )\n", tobj, polygon_data ); + tess_contour_t *current = tobj->current_contour; + tess_vertex_t *vertex; + GLdouble zaxis[3] = { 0.0, 0.0, 1.0 }, znormal[3], xnormal[3]; + GLdouble dot, rotx, roty; + GLint i; - tobj->error = GLU_NO_ERROR; + MSG( 15, " --> project_current_contour( tobj:%p )\n", tobj ); - if ( tobj->current_contour != NULL ) + if ( current == NULL ) { return; } + + /* Rotate the plane normal around the y-axis. */ + + znormal[X] = current->plane.normal[X]; + znormal[Y] = 0.0; + znormal[Z] = current->plane.normal[Z]; + + dot = DOT_3V( znormal, zaxis ); + current->roty = roty = acos( dot ); + + /* Rotate the plane normal around the x-axis. */ + + xnormal[X] = cos( roty ) * znormal[X] - sin( roty ) * znormal[Z]; + xnormal[Y] = znormal[Y]; + xnormal[Z] = sin( roty ) * znormal[X] + cos( roty ) * znormal[Z]; + + dot = DOT_3V( xnormal, zaxis ); + current->rotx = rotx = acos( dot ); + + for ( vertex = current->vertices, i = 0; + i < current->num_vertices; vertex = vertex->next, i++ ) { - /* gluEndPolygon was not called. */ - tess_error_callback( tobj, GLU_TESS_ERROR3 ); - tess_cleanup( tobj ); + tess_plane_t *plane = ¤t->plane; + GLdouble proj[3], yrot[3], xrot[3]; + + /* FIXME: This needs a cleanup, 'cos I'm sure it's inefficient. */ + + proj[X] = vertex->coords[X] - plane->dist * plane->normal[X]; + proj[Y] = vertex->coords[Y] - plane->dist * plane->normal[Y]; + proj[Z] = vertex->coords[Z] - plane->dist * plane->normal[Z]; + + yrot[X] = cos( roty ) * proj[X] - sin( roty ) * proj[Z]; + yrot[Y] = proj[Y]; + yrot[Z] = sin( roty ) * proj[X] + cos( roty ) * proj[Z]; + + xrot[X] = yrot[X]; + xrot[Y] = cos( rotx ) * yrot[Y] - sin( rotx ) * yrot[Z]; + xrot[Z] = sin( rotx ) * yrot[Y] + cos( rotx ) * yrot[Z]; + + vertex->v[X] = xrot[X]; + vertex->v[Y] = xrot[Y]; + + ACC_BBOX_2V( vertex->v, tobj->mins, tobj->maxs ); + ACC_BBOX_2V( vertex->v, current->mins, current->maxs ); } - tobj->vertex_count = 0; - tobj->data = polygon_data; - tobj->edge_flag = GL_FALSE; - tobj->label = 0; + current->area = twice_contour_area( current ); + current->orientation = ( current->area >= 0.0 ) ? GLU_CCW : GLU_CW; - MSG( 15, "<- gluTessBeginPolygon( tobj:%p data:%p )\n", tobj, polygon_data ); -} + MSG( 15, " area: %.2f orientation: %s\n", + current->area, ( current->orientation == GLU_CCW ) ? "CCW" : "CW" ); + MSG( 15, " <-- project_current_contour( tobj:%p )\n", tobj ); +} /***************************************************************************** - * gluTessBeginContour + * save_current_contour *****************************************************************************/ -void GLAPIENTRY gluTessBeginContour( GLUtesselator *tobj ) +static GLenum save_current_contour( GLUtesselator *tobj ) { - MSG( 15, " -> gluTessBeginContour( tobj:%p )\n", tobj ); - TESS_CHECK_ERRORS( tobj ); + tess_contour_t *current = tobj->current_contour; + tess_vertex_t *vertex; + GLint i; - if ( tobj->current_contour != NULL ) + if ( current == NULL ) { return GLU_ERROR; } + + if ( tobj->contours == NULL ) { - /* gluTessEndContour was not called. */ - tess_error_callback( tobj, GLU_TESS_ERROR4 ); - return; - } + tobj->contours = tobj->last_contour = current; + current->next = current->prev = NULL; - tobj->current_contour = malloc( sizeof(tess_contour_t) ); - if ( tobj->current_contour == NULL ) { - tess_error_callback( tobj, GLU_OUT_OF_MEMORY ); - return; + tobj->orientation = current->orientation; } + else + { + current->prev = tobj->last_contour; - COPY_3V( tobj->current_contour->plane.normal, tobj->plane.normal ); - tobj->current_contour->plane.dist = tobj->plane.dist; - - tobj->current_contour->area = 0.0; - tobj->current_contour->orientation = GLU_UNKNOWN; - - tobj->current_contour->label = 0; - tobj->current_contour->winding = 0; + tobj->last_contour->next = current; + tobj->last_contour = current; - tobj->current_contour->rotx = tobj->current_contour->roty = 0.0; + current->next = NULL; + } - CLEAR_BBOX_2DV( tobj->current_contour->mins, - tobj->current_contour->maxs ); + for ( vertex = current->vertices, i = 0; + i < current->num_vertices; vertex = vertex->next, i++ ) + { + vertex->edge_flag = GL_TRUE; + } - tobj->current_contour->vertex_count = 0; - tobj->current_contour->vertices = - tobj->current_contour->last_vertex = NULL; + current->type = GLU_UNKNOWN; - tobj->current_contour->reflex_vertices = NULL; - tobj->current_contour->cross_vertices = hashtable_init( HT_DEFAULT_SIZE ); + tobj->num_contours++; + tobj->current_contour = NULL; - cleanup: - MSG( 15, " <- gluTessBeginContour( tobj:%p )\n", tobj ); - return; + return GLU_NO_ERROR; } - /***************************************************************************** - * gluTessVertex + * inspect_current_contour *****************************************************************************/ -void GLAPIENTRY gluTessVertex( GLUtesselator *tobj, GLdouble coords[3], - void *vertex_data ) +static void inspect_current_contour( GLUtesselator *tobj ) { - tess_contour_t *current = tobj->current_contour; - tess_vertex_t *last_vertex; + tess_contour_t *current = tobj->current_contour; + GLdouble origin[3] = { 0.0, 0.0, 0.0 }; + GLboolean calc_normal = GL_FALSE; - MSG( 15, " -> gluTessVertex( tobj:%p coords:(%.2f,%.2f,%.2f) )\n", tobj, coords[0], coords[1], coords[2] ); - TESS_CHECK_ERRORS( tobj ); + MSG( 15, " --> inspect_current_contour( tobj:%p )\n", tobj ); - if ( current == NULL ) + if ( current->num_vertices < 3 ) { - /* gluTessBeginContour was not called. */ - tess_error_callback( tobj, GLU_TESS_ERROR2 ); + MSG( 15, " count %d < 3, deleting\n", current->num_vertices ); + delete_contour( &tobj->current_contour ); return; } - tobj->vertex_count++; + current->last_vertex->next = current->vertices; + current->vertices->prev = current->last_vertex; - last_vertex = current->last_vertex; + MSG( 15, " current normal: (%.2f, %.2f, %.2f)\n", current->plane.normal[X], current->plane.normal[Y], current->plane.normal[Z] ); - if ( last_vertex == NULL ) + if ( IS_EQUAL_3DV( current->plane.normal, origin ) ) { - last_vertex = malloc( sizeof(tess_vertex_t) ); - if ( last_vertex == NULL ) { - tess_error_callback( tobj, GLU_OUT_OF_MEMORY ); + /* We haven't been given a normal, so let's take a guess. */ + if ( find_normal( tobj ) == GLU_ERROR ) { return; } - current->vertices = last_vertex; - current->last_vertex = last_vertex; + COPY_3V( tobj->plane.normal, current->plane.normal ); + tobj->plane.dist = current->plane.dist; - last_vertex->index = -1; - last_vertex->data = vertex_data; + calc_normal = GL_TRUE; + } - last_vertex->coords[X] = coords[X]; - last_vertex->coords[Y] = coords[Y]; - last_vertex->coords[Z] = coords[Z]; + project_current_contour( tobj ); - last_vertex->side = 0.0; - last_vertex->label = 0; - last_vertex->mark = 0; + if ( calc_normal && ( tobj->current_contour->orientation == GLU_CW ) ) + { + MSG( 15, " oops, let's try that again...\n" ); - last_vertex->next = NULL; - last_vertex->previous = NULL; + /* + * FIXME: We've used a reflex angle to calculate the normal. At + * the moment, we simply reverse the normal and re-project the + * contour, but this is sloooow... + */ + NEG_3V( tobj->plane.normal ); + NEG_3V( tobj->current_contour->plane.normal ); - current->vertex_count++; + project_current_contour( tobj ); } - else - { - tess_vertex_t *vertex; - - vertex = malloc( sizeof(tess_vertex_t) ); - if ( vertex == NULL ) { - tess_error_callback( tobj, GLU_OUT_OF_MEMORY ); - return; - } - vertex->index = -1; - vertex->data = vertex_data; + if ( save_current_contour( tobj ) == GLU_ERROR ) { + return; + } - vertex->coords[X] = coords[X]; - vertex->coords[Y] = coords[Y]; - vertex->coords[Z] = coords[Z]; + MSG( 15, " <-- inspect_current_contour( tobj:%p )\n", tobj ); +} - vertex->side = 0.0; - vertex->label = 0; - vertex->mark = 0; +/***************************************************************************** + * reverse_contour + *****************************************************************************/ +void reverse_contour( tess_contour_t *contour ) +{ + tess_vertex_t *current = contour->vertices; + GLint i; - vertex->next = NULL; - vertex->previous = last_vertex; + for ( i = 0 ; i < contour->num_vertices ; i++ ) + { + tess_vertex_t *next = current->next; + tess_vertex_t *prev = current->prev; - current->vertex_count++; + current->next = prev; + current->prev = next; - last_vertex->next = vertex; - current->last_vertex = vertex; + current = next; } - cleanup: - MSG( 15, " <- gluTessVertex( tobj:%p )\n", tobj ); - return; -} + contour->orientation = + ( contour->orientation == GLU_CCW ) ? GLU_CW : GLU_CCW; + contour->last_vertex = contour->vertices->prev; +} /***************************************************************************** - * gluTessEndContour + * orient_contours + * + * Sum the signed areas of the contours, and orient the contours such that + * this sum is nonnegative. *****************************************************************************/ -void GLAPIENTRY gluTessEndContour( GLUtesselator *tobj ) +static void orient_contours( GLUtesselator *tobj ) { - MSG( 15, " -> gluTessEndContour( tobj:%p )\n", tobj ); - TESS_CHECK_ERRORS( tobj ); + tess_contour_t *contour = tobj->contours; + GLdouble sum = 0.0; + GLint i; - if ( tobj->current_contour == NULL ) + MSG( 15, " --> orient_contours( tobj:%p )\n", tobj ); + + /* Sum the signed areas of all contours */ + for ( i = 0 ; i < tobj->num_contours ; i++ ) { - /* gluTessBeginContour was not called. */ - tess_error_callback( tobj, GLU_TESS_ERROR2 ); - return; + sum += contour->area; + contour = contour->next; } - if ( tobj->current_contour->vertex_count > 0 ) { - inspect_current_contour( tobj ); - } else { - delete_contour( &tobj->current_contour ); + MSG( 15, " signed area: %.2f\n", sum ); + + if ( sum < -GLU_TESS_EPSILON ) + { + for ( i = 0 ; i < tobj->num_contours ; i++ ) + { + contour->area = ABSD( contour->area ); + reverse_contour( contour ); + + contour = contour->next; + } } + else + { + for ( i = 0 ; i < tobj->num_contours ; i++ ) + { + contour->area = ABSD( contour->area ); - cleanup: - MSG( 15, " <- gluTessEndContour( tobj:%p )\n", tobj ); - return; + contour = contour->next; + } + } + + tobj->orientation = tobj->contours->orientation; + + MSG( 15, " <-- orient_contours( tobj:%p ) orient: %s\n", + tobj, ( tobj->orientation == GLU_CCW ) ? "GLU_CCW" : "GLU_CW" ); } /***************************************************************************** - * gluTessEndPolygon + * delete_contour + * + * Delete the given contour and set the pointer to NULL. *****************************************************************************/ -void GLAPIENTRY gluTessEndPolygon( GLUtesselator *tobj ) +void delete_contour( tess_contour_t **contour ) { - MSG( 15, "-> gluTessEndPolygon( tobj:%p )\n", tobj ); - TESS_CHECK_ERRORS( tobj ); - - if ( tobj->current_contour != NULL ) - { - /* gluTessBeginPolygon was not called. */ - tess_error_callback( tobj, GLU_TESS_ERROR1 ); - return; - } - TESS_CHECK_ERRORS( tobj ); - - /* - * Ensure we have at least one contour to tessellate. If we have none, - * clean up and exit gracefully. - */ - if ( tobj->contour_count == 0 ) { - tess_cleanup( tobj ); - return; - } - - /* Wrap the contour list. */ + tess_vertex_t *vertex, *next; + GLint i; - tobj->last_contour->next = tobj->contours; - tobj->contours->previous = tobj->last_contour; + if ( *contour == NULL ) { return; } - TESS_CHECK_ERRORS( tobj ); + vertex = (*contour)->vertices; - /* - * Before we tessellate the contours, ensure we have the appropriate - * callbacks registered. We at least need the begin, vertex and end - * callbacks to do any meaningful work. - */ - if ( ( ( tobj->callbacks.begin != NULL ) || - ( tobj->callbacks.beginData != NULL ) ) && - ( ( tobj->callbacks.vertex != NULL ) || - ( tobj->callbacks.vertexData != NULL ) ) && - ( ( tobj->callbacks.end != NULL ) || - ( tobj->callbacks.endData != NULL ) ) ) + for ( i = 0 ; i < (*contour)->num_vertices ; i++ ) { - fist_tessellation( tobj ); + next = vertex->next; + free( vertex ); + vertex = next; } - cleanup: - delete_all_contours( tobj ); - MSG( 15, "<- gluTessEndPolygon( tobj:%p )\n", tobj ); + free( *contour ); + *contour = NULL; } - /***************************************************************************** - * gluTessCallback + * delete_all_contours *****************************************************************************/ -void GLAPIENTRY gluTessCallback( GLUtesselator *tobj, GLenum which, - void (GLCALLBACKP fn)() ) +static void delete_all_contours( GLUtesselator *tobj ) { - switch ( which ) + tess_contour_t *current, *next_contour; + GLint i; + + if ( tobj->current_contour != NULL ) { + delete_contour( &tobj->current_contour ); + } + + for ( current = tobj->contours, i = 0 ; i < tobj->num_contours ; i++ ) { - /* Register the begin callbacks. */ - case GLU_TESS_BEGIN: - tobj->callbacks.begin = (void (GLCALLBACKP)(GLenum)) fn; - break; - case GLU_TESS_BEGIN_DATA: - tobj->callbacks.beginData = (void (GLCALLBACKP)(GLenum, void *)) fn; - break; + tess_vertex_t *vertex = current->vertices, *next_vertex; + GLint j; - /* Register the edge flag callbacks. */ - case GLU_TESS_EDGE_FLAG: - tobj->callbacks.edgeFlag = (void (GLCALLBACKP)(GLboolean)) fn; - break; - case GLU_TESS_EDGE_FLAG_DATA: - tobj->callbacks.edgeFlagData = - (void (GLCALLBACKP)(GLboolean, void *)) fn; - break; + for ( j = 0 ; j < current->num_vertices ; j ++ ) + { + next_vertex = vertex->next; + free( vertex ); + vertex = next_vertex; + } + next_contour = current->next; - /* Register the vertex callbacks. */ - case GLU_TESS_VERTEX: - tobj->callbacks.vertex = (void (GLCALLBACKP)(void *)) fn; - break; - case GLU_TESS_VERTEX_DATA: - tobj->callbacks.vertexData = (void (GLCALLBACKP)(void *, void *)) fn; - break; + free( current ); + current = next_contour; + } - /* Register the end callbacks. */ - case GLU_TESS_END: - tobj->callbacks.end = (void (GLCALLBACKP)(void)) fn; - break; - case GLU_TESS_END_DATA: - tobj->callbacks.endData = (void (GLCALLBACKP)(void *)) fn; - break; + tobj->num_contours = tobj->num_vertices = 0; + tobj->contours = tobj->last_contour = NULL; - /* Register the error callbacks. */ - case GLU_TESS_ERROR: - tobj->callbacks.error = (void (GLCALLBACKP)(GLenum)) fn; - break; - case GLU_TESS_ERROR_DATA: - tobj->callbacks.errorData = (void (GLCALLBACKP)(GLenum, void *)) fn; - break; + CLEAR_BBOX_2DV( tobj->mins, tobj->maxs ); +} - /* Register the combine callbacks. */ - case GLU_TESS_COMBINE: - tobj->callbacks.combine = - (void (GLCALLBACKP)(GLdouble[3], void *[4], - GLfloat [4], void **)) fn; - break; - case GLU_TESS_COMBINE_DATA: - tobj->callbacks.combineData = - (void (GLCALLBACKP)(GLdouble[3], void *[4], GLfloat [4], - void **, void *)) fn; - break; - default: - MSG( 1, " gluTessCallback( tobj:%p which:%d ) invalid enum\n", tobj, which ); - tobj->error = GLU_INVALID_ENUM; - break; +/***************************************************************************** + * tess_cleanup + *****************************************************************************/ +static void tess_cleanup( GLUtesselator *tobj ) +{ + MSG( 15, " -> tess_cleanup( tobj:%p )\n", tobj ); + + if ( tobj->current_contour != NULL ) { + delete_contour( &tobj->current_contour ); + } + if ( tobj->contours != NULL ) { + delete_all_contours( tobj ); } + + MSG( 15, " <- tess_cleanup( tobj:%p )\n", tobj ); } /***************************************************************************** - * gluTessProperty - * - * Set the current value of the given property. + * tess_msg *****************************************************************************/ -void GLAPIENTRY gluTessProperty( GLUtesselator *tobj, GLenum which, - GLdouble value ) +INLINE void tess_msg( GLint level, char *format, ... ) { - switch ( which ) - { - case GLU_TESS_BOUNDARY_ONLY: - tobj->boundary_only = (GLboolean) value; - break; +#ifdef DEBUG + va_list ap; + va_start( ap, format ); - case GLU_TESS_TOLERANCE: - MSG( 15, " gluTessProperty( tobj:%p ) tolerance: %0.9f\n", tobj, value ); - tobj->tolerance = value; - break; + if ( level <= tess_dbg_level ) { + vfprintf( DBG_STREAM, format, ap ); + fflush( DBG_STREAM ); + } - case GLU_TESS_WINDING_RULE: - tobj->winding_rule = (GLenum) value; - break; + va_end( ap ); +#endif +} - default: - MSG( 1, " gluTessProperty( tobj:%p which:%d ) invalid enum\n", tobj, which ); - tobj->error = GLU_INVALID_ENUM; - break; - } +INLINE void tess_info( char *file, GLint line ) +{ +#ifdef DEBUG + fprintf( DBG_STREAM, "%9.9s:%d:\t ", file, line ); +#endif } + /***************************************************************************** - * gluGetTessProperty * - * Return the current value of the given property. + * GLU TESSELLATION FUNCTIONS + * *****************************************************************************/ -void GLAPIENTRY gluGetTessProperty( GLUtesselator *tobj, GLenum which, - GLdouble *value ) + + +/***************************************************************************** + * gluNewTess + *****************************************************************************/ +GLUtesselator* GLAPIENTRY gluNewTess( void ) { - switch ( which ) - { - case GLU_TESS_BOUNDARY_ONLY: - *value = tobj->boundary_only; - break; + GLUtesselator *tobj; - case GLU_TESS_TOLERANCE: - *value = tobj->tolerance; - break; +#ifdef DEBUG + if ( getenv( "GLU_TESS_DBG_LEVEL" ) ) { + tess_dbg_level = atoi( getenv( "GLU_TESS_DBG_LEVEL" ) ); + } else { + tess_dbg_level = DBG_LEVEL_BASE; + } +#endif - case GLU_TESS_WINDING_RULE: - *value = tobj->winding_rule; - break; + MSG( 15, "-> gluNewTess()\n" ); - default: - MSG( 1, " gluGetTessProperty( tobj:%p which:%d ) invalid enum\n", tobj, which ); - tobj->error = GLU_INVALID_ENUM; - break; + tobj = malloc( sizeof(GLUtesselator) ); + if ( tobj == NULL ) { + return NULL; } -} + init_callbacks( &tobj->callbacks ); -/***************************************************************************** - * gluTessNormal - * - * Set the current tessellation normal. - *****************************************************************************/ -void GLAPIENTRY gluTessNormal( GLUtesselator *tobj, GLdouble x, - GLdouble y, GLdouble z ) -{ - MSG( 15, " gluTessNormal( tobj:%p n:(%.2f,%.2f,%.2f) )\n", tobj, x, y, z ); + tobj->winding_rule = GLU_TESS_WINDING_ODD; + tobj->boundary_only = GL_FALSE; + tobj->tolerance = GLU_TESS_EPSILON; + tobj->orientation = GLU_UNKNOWN; - tobj->plane.normal[X] = x; - tobj->plane.normal[Y] = y; - tobj->plane.normal[Z] = z; -} + tobj->data = NULL; + tobj->num_contours = 0; + tobj->contours = tobj->last_contour = NULL; + tobj->current_contour = NULL; + CLEAR_BBOX_2DV( tobj->mins, tobj->maxs ); -/***************************************************************************** - * - * OBSOLETE TESSELLATION FUNCTIONS - * - *****************************************************************************/ + tobj->num_vertices = 0; + tobj->sorted_vertices = NULL; +#if 0 + tobj->grid = NULL; +#endif + tobj->edge_flag = GL_FALSE; + tobj->label = 0; -void GLAPIENTRY gluBeginPolygon( GLUtesselator *tobj ) -{ - gluTessBeginPolygon( tobj, NULL ); - gluTessBeginContour( tobj ); -} + ZERO_3V( tobj->plane.normal ); + tobj->plane.dist = 0.0; -void GLAPIENTRY gluNextContour( GLUtesselator *tobj, GLenum type ) -{ - gluTessEndContour( tobj ); - gluTessBeginContour( tobj ); -} + tobj->error = GLU_NO_ERROR; -void GLAPIENTRY gluEndPolygon( GLUtesselator *tobj ) -{ - gluTessEndContour( tobj ); - gluTessEndPolygon( tobj ); + MSG( 15, "<- gluNewTess() tobj:%p\n", tobj ); + return tobj; } - /***************************************************************************** - * tess_error_callback - * - * Internal error handler. Call the user-registered error callback. - * - * 2nd arg changed from 'errno' to 'errnum' since MSVC defines errnum as - * a macro (of all things) and thus breaks the build -tjump + * gluDeleteTess *****************************************************************************/ - -void tess_error_callback( GLUtesselator *tobj, GLenum errnum ) +void GLAPIENTRY gluDeleteTess( GLUtesselator *tobj ) { - if ( tobj->error == GLU_NO_ERROR ) - { - tobj->error = errnum; - } + MSG( 15, "-> gluDeleteTess( tobj:%p )\n", tobj ); - if ( tobj->callbacks.errorData != NULL ) - { - ( tobj->callbacks.errorData )( errnum, tobj->data ); - } - else if ( tobj->callbacks.error != NULL ) + if ( ( tobj->error == GLU_NO_ERROR ) && ( tobj->num_contours > 0 ) ) { - ( tobj->callbacks.error )( errnum ); + /* gluEndPolygon was not called. */ + tess_error_callback( tobj, GLU_TESS_ERROR3 ); } -} - + /* Delete all internal structures. */ + tess_cleanup( tobj ); + free( tobj ); -/***************************************************************************** - * - * INTERNAL FUNCTIONS - * - *****************************************************************************/ + MSG( 15, "<- gluDeleteTess()\n" ); +} /***************************************************************************** - * init_callbacks + * gluTessBeginPolygon *****************************************************************************/ -static void init_callbacks( tess_callbacks_t *callbacks ) +void GLAPIENTRY gluTessBeginPolygon( GLUtesselator *tobj, void *polygon_data ) { - callbacks->begin = ( void (GLCALLBACKP)(GLenum) ) NULL; - callbacks->beginData = ( void (GLCALLBACKP)(GLenum, void *) ) NULL; - callbacks->edgeFlag = ( void (GLCALLBACKP)(GLboolean) ) NULL; - callbacks->edgeFlagData = ( void (GLCALLBACKP)(GLboolean, void *) ) NULL; - callbacks->vertex = ( void (GLCALLBACKP)(void *) ) NULL; - callbacks->vertexData = ( void (GLCALLBACKP)(void *, void *) ) NULL; - callbacks->end = ( void (GLCALLBACKP)(void) ) NULL; - callbacks->endData = ( void (GLCALLBACKP)(void *) ) NULL; - callbacks->error = ( void (GLCALLBACKP)(GLenum) ) NULL; - callbacks->errorData = ( void (GLCALLBACKP)(GLenum, void *) ) NULL; - callbacks->combine = ( void (GLCALLBACKP)(GLdouble [3], void *[4], - GLfloat [4], void **) ) NULL; - callbacks->combineData = ( void (GLCALLBACKP)(GLdouble [3], void *[4], - GLfloat [4], void **, - void *) ) NULL; + MSG( 15, "-> gluTessBeginPolygon( tobj:%p data:%p )\n", tobj, polygon_data ); + + tobj->error = GLU_NO_ERROR; + + if ( tobj->current_contour != NULL ) + { + /* gluEndPolygon was not called. */ + tess_error_callback( tobj, GLU_TESS_ERROR3 ); + tess_cleanup( tobj ); + } + + tobj->data = polygon_data; + tobj->num_vertices = 0; + tobj->edge_flag = GL_FALSE; + tobj->label = 0; + + MSG( 15, "<- gluTessBeginPolygon( tobj:%p data:%p )\n", tobj, polygon_data ); } /***************************************************************************** - * tess_cleanup + * gluTessBeginContour *****************************************************************************/ -static void tess_cleanup( GLUtesselator *tobj ) +void GLAPIENTRY gluTessBeginContour( GLUtesselator *tobj ) { - MSG( 15, " -> tess_cleanup( tobj:%p )\n", tobj ); + MSG( 15, " -> gluTessBeginContour( tobj:%p )\n", tobj ); + TESS_CHECK_ERRORS( tobj ); - if ( tobj->current_contour != NULL ) { - delete_contour( &tobj->current_contour ); + if ( tobj->current_contour != NULL ) + { + /* gluTessEndContour was not called. */ + tess_error_callback( tobj, GLU_TESS_ERROR4 ); + return; } - if ( tobj->contours != NULL ) { - delete_all_contours( tobj ); + + tobj->current_contour = malloc( sizeof(tess_contour_t) ); + if ( tobj->current_contour == NULL ) { + tess_error_callback( tobj, GLU_OUT_OF_MEMORY ); + return; } - MSG( 15, " <- tess_cleanup( tobj:%p )\n", tobj ); + COPY_3V( tobj->current_contour->plane.normal, tobj->plane.normal ); + tobj->current_contour->plane.dist = tobj->plane.dist; + + tobj->current_contour->area = 0.0; + tobj->current_contour->orientation = GLU_UNKNOWN; + + tobj->current_contour->label = 0; + tobj->current_contour->winding = 0; + + /*tobj->current_contour->rotx = tobj->current_contour->roty = 0.0;*/ + + CLEAR_BBOX_2DV( tobj->current_contour->mins, + tobj->current_contour->maxs ); + + tobj->current_contour->num_vertices = 0; + tobj->current_contour->vertices = + tobj->current_contour->last_vertex = NULL; + + tobj->current_contour->reflex_vertices = NULL; + + cleanup: + MSG( 15, " <- gluTessBeginContour( tobj:%p )\n", tobj ); + return; } /***************************************************************************** - * inspect_current_contour + * gluTessVertex *****************************************************************************/ -static GLenum find_normal( GLUtesselator *tobj ); -static void project_current_contour( GLUtesselator *tobj ); -static GLenum save_current_contour( GLUtesselator *tobj ); - -static void inspect_current_contour( GLUtesselator *tobj ) +void GLAPIENTRY gluTessVertex( GLUtesselator *tobj, GLdouble coords[3], + void *vertex_data ) { - tess_contour_t *current = tobj->current_contour; - GLdouble origin[3] = { 0.0, 0.0, 0.0 }; + tess_contour_t *current = tobj->current_contour; + tess_vertex_t *last_vertex; - MSG( 15, " -> inspect_current_contour( tobj:%p )\n", tobj ); + MSG( 15, " -> gluTessVertex( tobj:%p coords:(%.2f,%.2f,%.2f) )\n", tobj, coords[0], coords[1], coords[2] ); + TESS_CHECK_ERRORS( tobj ); - if ( current->vertex_count < 3 ) + if ( current == NULL ) { - MSG( 15, " count %d < 3, deleting\n", current->vertex_count ); - delete_contour( &tobj->current_contour ); + /* gluTessBeginContour was not called. */ + tess_error_callback( tobj, GLU_TESS_ERROR2 ); return; } - current->last_vertex->next = current->vertices; - current->vertices->previous = current->last_vertex; + tobj->num_vertices++; + + last_vertex = current->last_vertex; - if ( ( tobj->contours == NULL ) && - ( COMPARE_3DV( current->plane.normal, origin ) ) ) + if ( last_vertex == NULL ) { - /* We haven't been given a normal, so let's take a guess. */ - if ( find_normal( tobj ) == GLU_ERROR ) { + last_vertex = malloc( sizeof(tess_vertex_t) ); + if ( last_vertex == NULL ) { + tess_error_callback( tobj, GLU_OUT_OF_MEMORY ); return; } - COPY_3V( tobj->plane.normal, current->plane.normal ); - tobj->plane.dist = current->plane.dist; - } - else - { - MSG( 15, " normal: (%.2f,%.2f,%.2f)\n", tobj->plane.normal[X], tobj->plane.normal[Y], tobj->plane.normal[Z] ); - } - - project_current_contour( tobj ); - if ( save_current_contour( tobj ) == GLU_ERROR ) { - return; - } + current->vertices = last_vertex; + current->last_vertex = last_vertex; - MSG( 15, " <- inspect_current_contour( tobj:%p )\n", tobj ); -} + last_vertex->index = -1; + last_vertex->data = vertex_data; -/***************************************************************************** - * find_normal - *****************************************************************************/ -static GLenum find_normal( GLUtesselator *tobj ) -{ - tess_contour_t *contour = tobj->current_contour; - tess_vertex_t *va, *vb, *vc; - GLdouble a[3], b[3], c[3]; + last_vertex->coords[X] = coords[X]; + last_vertex->coords[Y] = coords[Y]; + last_vertex->coords[Z] = coords[Z]; - MSG( 15, " -> find_normal( tobj:%p )\n", tobj ); + last_vertex->v[X] = 0.0; + last_vertex->v[Y] = 0.0; - if ( contour == NULL ) { return GLU_ERROR; } + last_vertex->edge_flag = GL_TRUE; - va = contour->vertices; - vb = va->next; + last_vertex->side = 0.0; - /* If va and vb are the same point, keep looking for a different vertex. */ + last_vertex->next = NULL; + last_vertex->prev = NULL; - while ( COMPARE_3DV( va->coords, vb->coords ) && ( vb != va ) ) { - vb = vb->next; + current->num_vertices++; } + else + { + tess_vertex_t *vertex; - if ( vb == va ) { - /* FIXME: What error is this? */ - tess_error_callback( tobj, GLU_TESS_ERROR7 ); - } + vertex = malloc( sizeof(tess_vertex_t) ); + if ( vertex == NULL ) { + tess_error_callback( tobj, GLU_OUT_OF_MEMORY ); + return; + } - SUB_3V( a, vb->coords, va->coords ); + vertex->index = -1; + vertex->data = vertex_data; - for ( vc = vb->next; vc != va; vc = vc->next ) - { - SUB_3V( b, vc->coords, va->coords ); + vertex->coords[X] = coords[X]; + vertex->coords[Y] = coords[Y]; + vertex->coords[Z] = coords[Z]; - CROSS3( c, a, b ); + vertex->v[X] = 0.0; + vertex->v[Y] = 0.0; - if ( ( ABSD( c[X] ) > EQUAL_EPSILON ) || - ( ABSD( c[Y] ) > EQUAL_EPSILON ) || - ( ABSD( c[Z] ) > EQUAL_EPSILON ) ) - { - COPY_3V( contour->plane.normal, c ); - NORMALIZE_3DV( contour->plane.normal ); + vertex->edge_flag = GL_TRUE; - contour->plane.dist = - DOT3( contour->plane.normal, va->coords ); + vertex->side = 0.0; - MSG( 15, " <- find_normal( tobj:%p ) n: (%.2f,%.2f,%.2f)\n", tobj, contour->plane.normal[X], contour->plane.normal[Y], contour->plane.normal[Z] ); - return GLU_NO_ERROR; - } + vertex->next = NULL; + vertex->prev = last_vertex; + + current->num_vertices++; + + last_vertex->next = vertex; + current->last_vertex = vertex; } - /* FIXME: What error is this? */ - tess_error_callback( tobj, GLU_TESS_ERROR7 ); - return GLU_ERROR; + cleanup: + MSG( 15, " <- gluTessVertex( tobj:%p )\n", tobj ); + return; } + /***************************************************************************** - * project_current_contour + * gluTessEndContour *****************************************************************************/ -static GLdouble twice_contour_area( tess_vertex_t *vertex, - tess_vertex_t *last_vertex ); - -static void project_current_contour( GLUtesselator *tobj ) +void GLAPIENTRY gluTessEndContour( GLUtesselator *tobj ) { - tess_contour_t *current = tobj->current_contour; - tess_vertex_t *vertex; - GLdouble area; - GLdouble zaxis[3] = { 0.0, 0.0, 1.0 }, znormal[3], xnormal[3]; - GLdouble dot, rotx, roty; - GLuint i; - - MSG( 15, " -> project_current_contour( tobj:%p )\n", tobj ); - - if ( current == NULL ) { return; } - - /* Rotate the plane normal around the y-axis. */ + MSG( 15, " -> gluTessEndContour( tobj:%p )\n", tobj ); + TESS_CHECK_ERRORS( tobj ); - znormal[X] = current->plane.normal[X]; - znormal[Y] = 0.0; - znormal[Z] = current->plane.normal[Z]; + if ( tobj->current_contour == NULL ) + { + /* gluTessBeginContour was not called. */ + tess_error_callback( tobj, GLU_TESS_ERROR2 ); + return; + } - dot = DOT3( znormal, zaxis ); - current->roty = roty = acos( dot ); + if ( tobj->current_contour->num_vertices > 0 ) { + inspect_current_contour( tobj ); + } else { + delete_contour( &tobj->current_contour ); + } - /* Rotate the plane normal around the x-axis. */ + cleanup: + MSG( 15, " <- gluTessEndContour( tobj:%p )\n", tobj ); + return; +} - xnormal[X] = cos( roty ) * znormal[X] - sin( roty ) * znormal[Z]; - xnormal[Y] = znormal[Y]; - xnormal[Z] = sin( roty ) * znormal[X] + cos( roty ) * znormal[Z]; - dot = DOT3( xnormal, zaxis ); - current->rotx = rotx = acos( dot ); +/***************************************************************************** + * gluTessEndPolygon + *****************************************************************************/ +void GLAPIENTRY gluTessEndPolygon( GLUtesselator *tobj ) +{ + MSG( 15, "-> gluTessEndPolygon( tobj:%p )\n", tobj ); + TESS_CHECK_ERRORS( tobj ); - for ( vertex = current->vertices, i = 0; - i < current->vertex_count; vertex = vertex->next, i++ ) + if ( tobj->current_contour != NULL ) { - tess_plane_t *plane = ¤t->plane; - GLdouble proj[3], yrot[3], xrot[3]; - - /* FIXME: This needs a cleanup, 'cos I'm sure it's inefficient. */ + /* gluTessBeginPolygon was not called. */ + tess_error_callback( tobj, GLU_TESS_ERROR1 ); + return; + } + TESS_CHECK_ERRORS( tobj ); - proj[X] = vertex->coords[X] - plane->dist * plane->normal[X]; - proj[Y] = vertex->coords[Y] - plane->dist * plane->normal[Y]; - proj[Z] = vertex->coords[Z] - plane->dist * plane->normal[Z]; + /* + * Ensure we have at least one contour to tessellate. If we have none, + * clean up and exit gracefully. + */ + if ( tobj->num_contours == 0 ) { + tess_cleanup( tobj ); + return; + } - yrot[X] = cos( roty ) * proj[X] - sin( roty ) * proj[Z]; - yrot[Y] = proj[Y]; - yrot[Z] = sin( roty ) * proj[X] + cos( roty ) * proj[Z]; + /* Wrap the contour list. */ - xrot[X] = yrot[X]; - xrot[Y] = cos( rotx ) * yrot[Y] - sin( rotx ) * yrot[Z]; - xrot[Z] = sin( rotx ) * yrot[Y] + cos( rotx ) * yrot[Z]; + tobj->last_contour->next = tobj->contours; + tobj->contours->prev = tobj->last_contour; - vertex->v[X] = xrot[X]; - vertex->v[Y] = xrot[Y]; + TESS_CHECK_ERRORS( tobj ); - ACC_BBOX_2V( vertex->v, tobj->mins, tobj->maxs ); - ACC_BBOX_2V( vertex->v, current->mins, current->maxs ); - } + /* Orient the contours correctly */ + orient_contours( tobj ); - area = twice_contour_area( current->vertices, - current->last_vertex ); - if ( area >= 0.0 ) - { - current->orientation = GLU_CCW; - current->area = area; - } - else + /* + * Before we tessellate the contours, ensure we have the appropriate + * callbacks registered. We at least need the begin, vertex and end + * callbacks to do any meaningful work. + */ + if ( ( ( tobj->callbacks.begin != NULL ) || + ( tobj->callbacks.beginData != NULL ) ) && + ( ( tobj->callbacks.vertex != NULL ) || + ( tobj->callbacks.vertexData != NULL ) ) && + ( ( tobj->callbacks.end != NULL ) || + ( tobj->callbacks.endData != NULL ) ) ) { - current->orientation = GLU_CW; - current->area = -area; + fist_tessellation( tobj ); } - MSG( 15, " <- project_current_contour( tobj:%p )\n", tobj ); + cleanup: + delete_all_contours( tobj ); + MSG( 15, "<- gluTessEndPolygon( tobj:%p )\n", tobj ); } + /***************************************************************************** - * twice_contour_area + * gluTessCallback *****************************************************************************/ -static GLdouble twice_contour_area( tess_vertex_t *vertex, - tess_vertex_t *last_vertex ) +void GLAPIENTRY gluTessCallback( GLUtesselator *tobj, GLenum which, + void (GLCALLBACKP fn)() ) { - tess_vertex_t *next; - GLdouble area, x, y; + switch ( which ) + { + /* Register the begin callbacks. */ + case GLU_TESS_BEGIN: + tobj->callbacks.begin = (void (GLCALLBACKP)(GLenum)) fn; + break; + case GLU_TESS_BEGIN_DATA: + tobj->callbacks.beginData = (void (GLCALLBACKP)(GLenum, void *)) fn; + break; - area = 0.0; + /* Register the edge flag callbacks. */ + case GLU_TESS_EDGE_FLAG: + tobj->callbacks.edgeFlag = (void (GLCALLBACKP)(GLboolean)) fn; + break; + case GLU_TESS_EDGE_FLAG_DATA: + tobj->callbacks.edgeFlagData = + (void (GLCALLBACKP)(GLboolean, void *)) fn; + break; - x = vertex->v[X]; - y = vertex->v[Y]; + /* Register the vertex callbacks. */ + case GLU_TESS_VERTEX: + tobj->callbacks.vertex = (void (GLCALLBACKP)(void *)) fn; + break; + case GLU_TESS_VERTEX_DATA: + tobj->callbacks.vertexData = (void (GLCALLBACKP)(void *, void *)) fn; + break; - vertex = vertex->next; + /* Register the end callbacks. */ + case GLU_TESS_END: + tobj->callbacks.end = (void (GLCALLBACKP)(void)) fn; + break; + case GLU_TESS_END_DATA: + tobj->callbacks.endData = (void (GLCALLBACKP)(void *)) fn; + break; - while ( vertex != last_vertex ) - { - next = vertex->next; - area += - (vertex->v[X] - x) * (next->v[Y] - y) - - (vertex->v[Y] - y) * (next->v[X] - x); + /* Register the error callbacks. */ + case GLU_TESS_ERROR: + tobj->callbacks.error = (void (GLCALLBACKP)(GLenum)) fn; + break; + case GLU_TESS_ERROR_DATA: + tobj->callbacks.errorData = (void (GLCALLBACKP)(GLenum, void *)) fn; + break; - vertex = vertex->next; + /* Register the combine callbacks. */ + case GLU_TESS_COMBINE: + tobj->callbacks.combine = + (void (GLCALLBACKP)(GLdouble[3], void *[4], + GLfloat [4], void **)) fn; + break; + case GLU_TESS_COMBINE_DATA: + tobj->callbacks.combineData = + (void (GLCALLBACKP)(GLdouble[3], void *[4], GLfloat [4], + void **, void *)) fn; + break; + + default: + MSG( 1, " gluTessCallback( tobj:%p which:%d ) invalid enum\n", tobj, which ); + tobj->error = GLU_INVALID_ENUM; + break; } - return area; } /***************************************************************************** - * save_current_contour + * gluTessProperty + * + * Set the current value of the given property. *****************************************************************************/ -static GLenum save_current_contour( GLUtesselator *tobj ) +void GLAPIENTRY gluTessProperty( GLUtesselator *tobj, GLenum which, + GLdouble value ) { - tess_contour_t *current = tobj->current_contour; - tess_vertex_t *vertex; - GLuint i; - - if ( current == NULL ) { return GLU_ERROR; } - - if ( tobj->contours == NULL ) - { - tobj->contours = tobj->last_contour = current; - current->next = current->previous = NULL; - } - else + switch ( which ) { - current->previous = tobj->last_contour; + case GLU_TESS_BOUNDARY_ONLY: + tobj->boundary_only = (GLboolean) value; + break; - tobj->last_contour->next = current; - tobj->last_contour = current; + case GLU_TESS_TOLERANCE: + MSG( 15, " gluTessProperty( tobj:%p ) tolerance: %0.9f\n", tobj, value ); + tobj->tolerance = value; + break; - current->next = NULL; - } + case GLU_TESS_WINDING_RULE: + tobj->winding_rule = (GLenum) value; + break; - for ( vertex = current->vertices, i = 0; - i < current->vertex_count; vertex = vertex->next, i++ ) - { - vertex->shadow_vertex = NULL; - vertex->edge_flag = GL_TRUE; + default: + MSG( 1, " gluTessProperty( tobj:%p which:%d ) invalid enum\n", tobj, which ); + tobj->error = GLU_INVALID_ENUM; + break; } - - current->type = GLU_UNKNOWN; - - tobj->contour_count++; - tobj->current_contour = NULL; - - return GLU_NO_ERROR; } + /***************************************************************************** - * delete_contour + * gluGetTessProperty * - * Delete the given contour and set the pointer to NULL. + * Return the current value of the given property. *****************************************************************************/ -void delete_contour( tess_contour_t **contour ) +void GLAPIENTRY gluGetTessProperty( GLUtesselator *tobj, GLenum which, + GLdouble *value ) { - tess_vertex_t *vertex, *next; - GLuint i; + switch ( which ) + { + case GLU_TESS_BOUNDARY_ONLY: + *value = tobj->boundary_only; + break; - if ( *contour == NULL ) { return; } + case GLU_TESS_TOLERANCE: + *value = tobj->tolerance; + break; - vertex = (*contour)->vertices; + case GLU_TESS_WINDING_RULE: + *value = tobj->winding_rule; + break; - for ( i = 0 ; i < (*contour)->vertex_count ; i++ ) - { - next = vertex->next; - free( vertex ); - vertex = next; + default: + MSG( 1, " gluGetTessProperty( tobj:%p which:%d ) invalid enum\n", tobj, which ); + tobj->error = GLU_INVALID_ENUM; + break; } - - free( *contour ); - *contour = NULL; } + /***************************************************************************** - * delete_all_contours + * gluTessNormal + * + * Set the current tessellation normal. *****************************************************************************/ -static void delete_all_contours( GLUtesselator *tobj ) +void GLAPIENTRY gluTessNormal( GLUtesselator *tobj, GLdouble x, + GLdouble y, GLdouble z ) { - tess_contour_t *current, *next_contour; - GLuint i; - - if ( tobj->current_contour != NULL ) { - delete_contour( &tobj->current_contour ); - } - - for ( current = tobj->contours, i = 0 ; i < tobj->contour_count ; i++ ) - { - tess_vertex_t *vertex = current->vertices, *next_vertex; - GLuint j; - - for ( j = 0 ; j < current->vertex_count ; j ++ ) - { - next_vertex = vertex->next; - free( vertex ); - vertex = next_vertex; - } - next_contour = current->next; - - free( current ); - current = next_contour; - } - - tobj->contour_count = tobj->vertex_count = 0; - tobj->contours = tobj->last_contour = NULL; - - CLEAR_BBOX_2DV( tobj->mins, tobj->maxs ); + MSG( 15, " gluTessNormal( tobj:%p n:(%.2f,%.2f,%.2f) )\n", tobj, x, y, z ); - ZERO_3V( tobj->plane.normal ); - tobj->plane.dist = 0.0; + ASSIGN_3V( tobj->plane.normal, x, y, z ); } + /***************************************************************************** - * tess_msg + * + * OBSOLETE TESSELLATION FUNCTIONS + * *****************************************************************************/ -INLINE void tess_msg( int level, char *format, ... ) -{ -#ifdef DEBUG - va_list ap; - va_start( ap, format ); - if ( level <= tess_dbg_level ) { - vfprintf( DBG_STREAM, format, ap ); - fflush( DBG_STREAM ); - } +void GLAPIENTRY gluBeginPolygon( GLUtesselator *tobj ) +{ + gluTessBeginPolygon( tobj, NULL ); + gluTessBeginContour( tobj ); +} - va_end( ap ); -#endif +void GLAPIENTRY gluNextContour( GLUtesselator *tobj, GLenum type ) +{ + gluTessEndContour( tobj ); + gluTessBeginContour( tobj ); } -INLINE void tess_info( char *file, char *line ) +void GLAPIENTRY gluEndPolygon( GLUtesselator *tobj ) { -#ifdef DEBUG - fprintf( DBG_STREAM, "%9.9s:%d:\t ", file, line ); -#endif + gluTessEndContour( tobj ); + gluTessEndPolygon( tobj ); } diff --git a/src/glu/mesa/tess.h b/src/glu/mesa/tess.h index 504ebd0872..5568183073 100644 --- a/src/glu/mesa/tess.h +++ b/src/glu/mesa/tess.h @@ -1,4 +1,4 @@ -/* $Id: tess.h,v 1.15 1999/11/05 20:37:14 gareth Exp $ */ +/* $Id: tess.h,v 1.16 1999/12/06 09:39:34 gareth Exp $ */ /* * Mesa 3-D graphics library @@ -56,33 +56,39 @@ extern "C" { struct GLUtesselator { tess_callbacks_t callbacks; - GLboolean boundary_only; GLenum winding_rule; + GLboolean boundary_only; GLdouble tolerance; - tess_plane_t plane; - GLuint contour_count; + GLenum orientation; + void *data; + GLint num_contours; tess_contour_t *contours, *last_contour; tess_contour_t *current_contour; GLdouble mins[2], maxs[2]; - GLuint vertex_count; + GLint num_vertices; tess_vertex_t **sorted_vertices; #if 0 tess_grid_t *grid; /* Not currently used... */ #endif heap_t *ears; - hashtable_t *cvc_lists; - void *data; GLboolean edge_flag; GLuint label; + tess_plane_t plane; GLenum error; }; /***************************************************************************** - * Tessellation error handler: + * Common tessellation functions: *****************************************************************************/ extern void tess_error_callback( GLUtesselator *, GLenum ); +extern GLdouble twice_contour_area( tess_contour_t *contour ); +extern void reverse_contour( tess_contour_t *contour ); +extern void delete_contour( tess_contour_t **contour ); + +extern void contour_dump( tess_contour_t *contour ); + /***************************************************************************** * Debugging output: @@ -115,8 +121,8 @@ extern int tess_dbg_level; #define MSG tess_msg #endif /* DEBUG */ -extern INLINE void tess_msg( int level, char *format, ... ); -extern INLINE void tess_info( char *file, char *line ); +extern INLINE void tess_msg( GLint level, char *format, ... ); +extern INLINE void tess_info( char *file, GLint line ); #ifdef __cplusplus } -- cgit v1.2.3