summaryrefslogtreecommitdiff
path: root/src/glu/mesa/tess.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glu/mesa/tess.c')
-rw-r--r--src/glu/mesa/tess.c369
1 files changed, 369 insertions, 0 deletions
diff --git a/src/glu/mesa/tess.c b/src/glu/mesa/tess.c
new file mode 100644
index 0000000000..c773fbaae4
--- /dev/null
+++ b/src/glu/mesa/tess.c
@@ -0,0 +1,369 @@
+/* $Id: tess.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ * Copyright (C) 1995-1999 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: tess.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.11 1999/02/27 13:55:31 brianp
+ * fixed BeOS-related GLU typedef problems
+ *
+ * Revision 1.10 1999/01/03 03:23:15 brianp
+ * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
+ *
+ * Revision 1.9 1998/06/01 01:10:29 brianp
+ * small update for Next/OpenStep from Alexander Mai
+ *
+ * Revision 1.8 1998/02/04 00:27:58 brianp
+ * cygnus changes from Stephane Rehel
+ *
+ * Revision 1.7 1998/01/16 03:35:26 brianp
+ * fixed Windows compilation warnings (Theodore Jump)
+ *
+ * Revision 1.6 1997/09/17 01:51:48 brianp
+ * changed glu*Callback() functions to match prototype in glu.h
+ *
+ * Revision 1.5 1997/07/24 01:28:44 brianp
+ * changed precompiled header symbol from PCH to PC_HEADER
+ *
+ * Revision 1.4 1997/05/28 02:29:38 brianp
+ * added support for precompiled headers (PCH), inserted APIENTRY keyword
+ *
+ * Revision 1.3 1996/11/12 01:23:02 brianp
+ * added test to prevent free(vertex) when vertex==NULL in delete_contours()
+ *
+ * Revision 1.2 1996/10/22 22:57:19 brianp
+ * better error handling in gluBegin/EndPolygon() from Erich Eder
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+/*
+ * This file is part of the polygon tesselation code contributed by
+ * Bogdan Sikorski
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdlib.h>
+#include "tess.h"
+#endif
+
+
+/*
+ * This is ugly, but seems the easiest way to do things to make the
+ * code work under YellowBox for Windows
+ */
+#if defined(OPENSTEP) && defined(GLCALLBACK)
+#undef GLCALLBACK
+#define GLCALLBACK
+#endif
+
+
+extern void tess_test_polygon(GLUtriangulatorObj *);
+extern void tess_find_contour_hierarchies(GLUtriangulatorObj *);
+extern void tess_handle_holes(GLUtriangulatorObj *);
+extern void tess_tesselate(GLUtriangulatorObj *);
+extern void tess_tesselate_with_edge_flag(GLUtriangulatorObj *);
+static void delete_contours(GLUtriangulatorObj *);
+
+#ifdef __CYGWIN32__
+#define _CALLBACK
+#else
+#define _CALLBACK GLCALLBACK
+#endif
+
+void init_callbacks(tess_callbacks *callbacks)
+{
+ callbacks->begin = ( void (_CALLBACK*)(GLenum) ) 0;
+ callbacks->edgeFlag = ( void (_CALLBACK*)(GLboolean) ) 0;
+ callbacks->vertex = ( void (_CALLBACK*)(void*) ) 0;
+ callbacks->end = ( void (_CALLBACK*)(void) ) 0;
+ callbacks->error = ( void (_CALLBACK*)(GLenum) ) 0;
+}
+
+void tess_call_user_error(GLUtriangulatorObj *tobj, GLenum gluerr)
+{
+ if(tobj->error==GLU_NO_ERROR)
+ tobj->error=gluerr;
+ if(tobj->callbacks.error!=NULL)
+ (tobj->callbacks.error)(gluerr);
+}
+
+GLUtriangulatorObj* GLAPIENTRY gluNewTess( void )
+{
+ GLUtriangulatorObj *tobj;
+ tobj = (GLUtriangulatorObj *) malloc(sizeof(struct GLUtesselator));
+ if (!tobj)
+ return NULL;
+ tobj->contours=tobj->last_contour=NULL;
+ init_callbacks(&tobj->callbacks);
+ tobj->error=GLU_NO_ERROR;
+ tobj->current_polygon=NULL;
+ tobj->contour_cnt=0;
+ return tobj;
+}
+
+
+void GLAPIENTRY gluTessCallback( GLUtriangulatorObj *tobj, GLenum which,
+ void (GLCALLBACK *fn)() )
+{
+ switch(which)
+ {
+ case GLU_BEGIN:
+ tobj->callbacks.begin = (void (_CALLBACK*)(GLenum)) fn;
+ break;
+ case GLU_EDGE_FLAG:
+ tobj->callbacks.edgeFlag = (void (_CALLBACK*)(GLboolean)) fn;
+ break;
+ case GLU_VERTEX:
+ tobj->callbacks.vertex = (void (_CALLBACK*)(void *)) fn;
+ break;
+ case GLU_END:
+ tobj->callbacks.end = (void (_CALLBACK*)(void)) fn;
+ break;
+ case GLU_ERROR:
+ tobj->callbacks.error = (void (_CALLBACK*)(GLenum)) fn;
+ break;
+ default:
+ tobj->error=GLU_INVALID_ENUM;
+ break;
+ }
+}
+
+
+
+void GLAPIENTRY gluDeleteTess( GLUtriangulatorObj *tobj )
+{
+ if(tobj->error==GLU_NO_ERROR && tobj->contour_cnt)
+ /* was gluEndPolygon called? */
+ tess_call_user_error(tobj,GLU_TESS_ERROR1);
+ /* delete all internal structures */
+ delete_contours(tobj);
+ free(tobj);
+}
+
+
+void GLAPIENTRY gluBeginPolygon( GLUtriangulatorObj *tobj )
+{
+/*
+ if(tobj->error!=GLU_NO_ERROR)
+ return;
+*/
+ tobj->error = GLU_NO_ERROR;
+ if(tobj->current_polygon!=NULL)
+ {
+ /* gluEndPolygon was not called */
+ tess_call_user_error(tobj,GLU_TESS_ERROR1);
+ /* delete all internal structures */
+ delete_contours(tobj);
+ }
+ else
+ {
+ if((tobj->current_polygon=
+ (tess_polygon *)malloc(sizeof(tess_polygon)))==NULL)
+ {
+ tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ tobj->current_polygon->vertex_cnt=0;
+ tobj->current_polygon->vertices=
+ tobj->current_polygon->last_vertex=NULL;
+ }
+}
+
+
+void GLAPIENTRY gluEndPolygon( GLUtriangulatorObj *tobj )
+{
+ /*tess_contour *contour_ptr;*/
+
+ /* there was an error */
+ if(tobj->error!=GLU_NO_ERROR) goto end;
+
+ /* check if gluBeginPolygon was called */
+ if(tobj->current_polygon==NULL)
+ {
+ tess_call_user_error(tobj,GLU_TESS_ERROR2);
+ return;
+ }
+ tess_test_polygon(tobj);
+ /* there was an error */
+ if(tobj->error!=GLU_NO_ERROR) goto end;
+
+ /* any real contours? */
+ if(tobj->contour_cnt==0)
+ {
+ /* delete all internal structures */
+ delete_contours(tobj);
+ return;
+ }
+ tess_find_contour_hierarchies(tobj);
+ /* there was an error */
+ if(tobj->error!=GLU_NO_ERROR) goto end;
+
+ tess_handle_holes(tobj);
+ /* there was an error */
+ if(tobj->error!=GLU_NO_ERROR) goto end;
+
+ /* if no callbacks, nothing to do */
+ if(tobj->callbacks.begin!=NULL && tobj->callbacks.vertex!=NULL &&
+ tobj->callbacks.end!=NULL)
+ {
+ if(tobj->callbacks.edgeFlag==NULL)
+ tess_tesselate(tobj);
+ else
+ tess_tesselate_with_edge_flag(tobj);
+ }
+
+end:
+ /* delete all internal structures */
+ delete_contours(tobj);
+}
+
+
+void GLAPIENTRY gluNextContour( GLUtriangulatorObj *tobj, GLenum type )
+{
+ if(tobj->error!=GLU_NO_ERROR)
+ return;
+ if(tobj->current_polygon==NULL)
+ {
+ tess_call_user_error(tobj,GLU_TESS_ERROR2);
+ return;
+ }
+ /* first contour? */
+ if(tobj->current_polygon->vertex_cnt)
+ tess_test_polygon(tobj);
+}
+
+
+void GLAPIENTRY gluTessVertex( GLUtriangulatorObj *tobj, GLdouble v[3], void *data )
+{
+ tess_polygon *polygon=tobj->current_polygon;
+ tess_vertex *last_vertex_ptr;
+
+ if(tobj->error!=GLU_NO_ERROR)
+ return;
+ if(polygon==NULL)
+ {
+ tess_call_user_error(tobj,GLU_TESS_ERROR2);
+ return;
+ }
+ last_vertex_ptr=polygon->last_vertex;
+ if(last_vertex_ptr==NULL)
+ {
+ if((last_vertex_ptr=(tess_vertex *)
+ malloc(sizeof(tess_vertex)))==NULL)
+ {
+ tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ polygon->vertices=last_vertex_ptr;
+ polygon->last_vertex=last_vertex_ptr;
+ last_vertex_ptr->data=data;
+ last_vertex_ptr->location[0]=v[0];
+ last_vertex_ptr->location[1]=v[1];
+ last_vertex_ptr->location[2]=v[2];
+ last_vertex_ptr->next=NULL;
+ last_vertex_ptr->previous=NULL;
+ ++(polygon->vertex_cnt);
+ }
+ else
+ {
+ tess_vertex *vertex_ptr;
+
+ /* same point twice? */
+ if(fabs(last_vertex_ptr->location[0]-v[0]) < EPSILON &&
+ fabs(last_vertex_ptr->location[1]-v[1]) < EPSILON &&
+ fabs(last_vertex_ptr->location[2]-v[2]) < EPSILON)
+ {
+ tess_call_user_error(tobj,GLU_TESS_ERROR6);
+ return;
+ }
+ if((vertex_ptr=(tess_vertex *)
+ malloc(sizeof(tess_vertex)))==NULL)
+ {
+ tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ vertex_ptr->data=data;
+ vertex_ptr->location[0]=v[0];
+ vertex_ptr->location[1]=v[1];
+ vertex_ptr->location[2]=v[2];
+ vertex_ptr->next=NULL;
+ vertex_ptr->previous=last_vertex_ptr;
+ ++(polygon->vertex_cnt);
+ last_vertex_ptr->next=vertex_ptr;
+ polygon->last_vertex=vertex_ptr;
+ }
+}
+
+
+static void delete_contours(GLUtriangulatorObj *tobj)
+{
+ tess_polygon *polygon=tobj->current_polygon;
+ tess_contour *contour,*contour_tmp;
+ tess_vertex *vertex,*vertex_tmp;
+
+ /* remove current_polygon list - if exists due to detected error */
+ if(polygon!=NULL)
+ {
+ if (polygon->vertices)
+ {
+ for(vertex=polygon->vertices;vertex!=polygon->last_vertex;)
+ {
+ vertex_tmp=vertex->next;
+ free(vertex);
+ vertex=vertex_tmp;
+ }
+ free(vertex);
+ }
+ free(polygon);
+ tobj->current_polygon=NULL;
+ }
+ /* remove all contour data */
+ for(contour=tobj->contours;contour!=NULL;)
+ {
+ for(vertex=contour->vertices;vertex!=contour->last_vertex;)
+ {
+ vertex_tmp=vertex->next;
+ free(vertex);
+ vertex=vertex_tmp;
+ }
+ free(vertex);
+ contour_tmp=contour->next;
+ free(contour);
+ contour=contour_tmp;
+ }
+ tobj->contours=tobj->last_contour=NULL;
+ tobj->contour_cnt=0;
+}
+
+
+