Added GLU 1.3 tessellation (except winding rule code).
authorGareth Hughes <gareth@valinux.com>
Fri, 10 Sep 1999 02:03:31 +0000 (02:03 +0000)
committerGareth Hughes <gareth@valinux.com>
Fri, 10 Sep 1999 02:03:31 +0000 (02:03 +0000)
13 files changed:
include/GL/glu.h
include/GL/glu_mangle.h
src/glu/mesa/Makefile.BeOS
src/glu/mesa/Makefile.BeOS-R4
src/glu/mesa/Makefile.X11
src/glu/mesa/MesaGLU.def
src/glu/mesa/descrip.mms
src/glu/mesa/glu.c
src/glu/mesa/mms_depend
src/glu/mesa/polytest.c [deleted file]
src/glu/mesa/tess.c
src/glu/mesa/tess.h
src/glu/mesa/tesselat.c [deleted file]

index b1321c0e97803b800bab00a5ec126109ce68cfe5..1123705547b306e8e0a4d47680bddbe5c93f427e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: glu.h,v 1.1 1999/08/19 00:55:40 jtg Exp $ */
+/* $Id: glu.h,v 1.2 1999/09/10 02:08:18 gareth Exp $ */
 
 /*
  * Mesa 3-D graphics library
 
 /*
  * $Log: glu.h,v $
- * Revision 1.1  1999/08/19 00:55:40  jtg
- * Initial revision
+ * Revision 1.2  1999/09/10 02:08:18  gareth
+ * Added GLU 1.3 tessellation (except winding rule code).
+ *
+ * Revision 1.1.1.1  1999/08/19 00:55:40  jtg
+ * Imported sources
  *
  * Revision 3.6  1999/02/14 03:39:45  brianp
  * updated for BeOS R4
@@ -88,6 +91,7 @@ extern "C" {
 
 
 #define GLU_VERSION_1_1                1
+#define GLU_VERSION_1_2                1
 
 
 #define GLU_TRUE   GL_TRUE
@@ -110,30 +114,42 @@ enum {
        GLU_OUTSIDE     = 100020,
        GLU_INSIDE      = 100021,
 
-       /* Tesselator */
-       GLU_BEGIN       = 100100,
-       GLU_VERTEX      = 100101,
-       GLU_END         = 100102,
-       GLU_ERROR       = 100103,
-       GLU_EDGE_FLAG   = 100104,
-
-       /* Contour types */
-       GLU_CW          = 100120,
-       GLU_CCW         = 100121,
-       GLU_INTERIOR    = 100122,
-       GLU_EXTERIOR    = 100123,
-       GLU_UNKNOWN     = 100124,
-
-       /* Tesselation errors */
-       GLU_TESS_ERROR1 = 100151,  /* missing gluEndPolygon */
-       GLU_TESS_ERROR2 = 100152,  /* missing gluBeginPolygon */
-       GLU_TESS_ERROR3 = 100153,  /* misoriented contour */
-       GLU_TESS_ERROR4 = 100154,  /* vertex/edge intersection */
-       GLU_TESS_ERROR5 = 100155,  /* misoriented or self-intersecting loops */
-       GLU_TESS_ERROR6 = 100156,  /* coincident vertices */
-       GLU_TESS_ERROR7 = 100157,  /* all vertices collinear */
-       GLU_TESS_ERROR8 = 100158,  /* intersecting edges */
-       GLU_TESS_ERROR9 = 100159,  /* not coplanar contours */
+       /* Tessellator */
+       GLU_TESS_BEGIN          = 100100,
+       GLU_TESS_VERTEX         = 100101,
+       GLU_TESS_END            = 100102,
+       GLU_TESS_ERROR          = 100103,
+       GLU_TESS_EDGE_FLAG      = 100104,
+       GLU_TESS_COMBINE        = 100105,
+
+       GLU_TESS_BEGIN_DATA     = 100106,
+       GLU_TESS_VERTEX_DATA    = 100107,
+       GLU_TESS_END_DATA       = 100108,
+       GLU_TESS_ERROR_DATA     = 100109,
+       GLU_TESS_EDGE_FLAG_DATA = 100110,
+       GLU_TESS_COMBINE_DATA   = 100111,
+
+       /* Winding rules */
+       GLU_TESS_WINDING_ODD            = 100130,
+       GLU_TESS_WINDING_NONZERO        = 100131,
+       GLU_TESS_WINDING_POSITIVE       = 100132,
+       GLU_TESS_WINDING_NEGATIVE       = 100133,
+       GLU_TESS_WINDING_ABS_GEQ_TWO    = 100134,
+
+       /* Tessellation properties */
+       GLU_TESS_WINDING_RULE   = 100140,
+       GLU_TESS_BOUNDARY_ONLY  = 100141,
+       GLU_TESS_TOLERANCE      = 100142,
+
+       /* Tessellation errors */
+       GLU_TESS_ERROR1 = 100151,  /* Missing gluBeginPolygon */
+       GLU_TESS_ERROR2 = 100152,  /* Missing gluBeginContour */
+       GLU_TESS_ERROR3 = 100153,  /* Missing gluEndPolygon */
+       GLU_TESS_ERROR4 = 100154,  /* Missing gluEndContour */
+       GLU_TESS_ERROR5 = 100155,  /* */
+       GLU_TESS_ERROR6 = 100156,  /* */
+       GLU_TESS_ERROR7 = 100157,  /* */
+       GLU_TESS_ERROR8 = 100158,  /* */
 
        /* NURBS */
        GLU_AUTO_LOAD_MATRIX    = 100200,
@@ -201,21 +217,39 @@ enum {
 
        /* New in GLU 1.1 */
        GLU_VERSION     = 100800,
-       GLU_EXTENSIONS  = 100801
+       GLU_EXTENSIONS  = 100801,
+
+       /*** GLU 1.0 tessellation - obsolete! ***/
+
+       /* Contour types */
+       GLU_CW          = 100120,
+       GLU_CCW         = 100121,
+       GLU_INTERIOR    = 100122,
+       GLU_EXTERIOR    = 100123,
+       GLU_UNKNOWN     = 100124,
+
+       /* Tessellator */
+       GLU_BEGIN       = GLU_TESS_BEGIN,
+       GLU_VERTEX      = GLU_TESS_VERTEX,
+       GLU_END         = GLU_TESS_END,
+       GLU_ERROR       = GLU_TESS_ERROR,
+       GLU_EDGE_FLAG   = GLU_TESS_EDGE_FLAG
 };
 
 
 /*
- * These are the GLU 1.1 typedefs.  GLU 1.2 has different ones!
+ * These are the GLU 1.1 typedefs.  GLU 1.3 has different ones!
  */
 #if defined(__BEOS__)
-   /* The BeOS does something funky and makes these typedefs in one
-    * of its system headers.
-    */
+    /* The BeOS does something funky and makes these typedefs in one
+     * of its system headers.
+     */
 #else
-   typedef struct GLUquadric GLUquadricObj;
-   typedef struct GLUtesselator GLUtriangulatorObj;
-   typedef struct GLUnurbs GLUnurbsObj;
+    typedef struct GLUquadric GLUquadricObj;
+    typedef struct GLUnurbs GLUnurbsObj;
+
+    /* FIXME: We need to implement the other 1.3 typedefs - GH */
+    typedef struct GLUtesselator GLUtesselator;
 #endif
 
 
@@ -392,25 +426,49 @@ GLUAPI void GLAPIENTRY gluNurbsCallback( GLUnurbsObj *nobj, GLenum which,
 
 /*
  *
- * Polygon tesselation
+ * Polygon tessellation
  *
  */
 
-GLUAPI GLUtriangulatorObj* GLAPIENTRY gluNewTess( void );
+GLUAPI GLUtesselator* GLAPIENTRY gluNewTess( void );
+
+GLUAPI void GLAPIENTRY gluDeleteTess( GLUtesselator *tobj );
+
+GLUAPI void GLAPIENTRY gluTessBeginPolygon( GLUtesselator *tobj,
+                                           void *polygon_data );
+
+GLUAPI void GLAPIENTRY gluTessBeginContour( GLUtesselator *tobj );
+
+GLUAPI void GLAPIENTRY gluTessVertex( GLUtesselator *tobj, GLdouble coords[3],
+                                     void *vertex_data );
+
+GLUAPI void GLAPIENTRY gluTessEndContour( GLUtesselator *tobj );
 
-GLUAPI void GLAPIENTRY gluTessCallback( GLUtriangulatorObj *tobj, GLenum which,
-                                      void (GLCALLBACK *fn)() );
+GLUAPI void GLAPIENTRY gluTessEndPolygon( GLUtesselator *tobj );
 
-GLUAPI void GLAPIENTRY gluDeleteTess( GLUtriangulatorObj *tobj );
+GLUAPI void GLAPIENTRY gluTessProperty( GLUtesselator *tobj, GLenum which,
+                                       GLdouble value );
 
-GLUAPI void GLAPIENTRY gluBeginPolygon( GLUtriangulatorObj *tobj );
+GLUAPI void GLAPIENTRY gluTessNormal( GLUtesselator *tobj, GLdouble x,
+                                     GLdouble y, GLdouble z );
+
+GLUAPI void GLAPIENTRY gluTessCallback( GLUtesselator *tobj, GLenum which,
+                                       void (GLCALLBACK *fn)() );
+
+GLUAPI void GLAPIENTRY gluGetTessProperty( GLUtesselator *tobj, GLenum which,
+                                          GLdouble *value );
+
+/*
+ *
+ * Obsolete 1.0 tessellation functions
+ *
+ */
 
-GLUAPI void GLAPIENTRY gluEndPolygon( GLUtriangulatorObj *tobj );
+GLUAPI void GLAPIENTRY gluBeginPolygon( GLUtesselator *tobj );
 
-GLUAPI void GLAPIENTRY gluNextContour( GLUtriangulatorObj *tobj, GLenum type );
+GLUAPI void GLAPIENTRY gluNextContour( GLUtesselator *tobj, GLenum type );
 
-GLUAPI void GLAPIENTRY gluTessVertex( GLUtriangulatorObj *tobj, GLdouble v[3],
-                                    void *data );
+GLUAPI void GLAPIENTRY gluEndPolygon( GLUtesselator *tobj );
 
 
 
index ed3944c54b1ce697676707ef13485386d11ba479..a52b19617cb0208792304000c5ed55a4aaaf4e26 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: glu_mangle.h,v 1.1 1999/08/19 00:55:40 jtg Exp $ */
+/* $Id: glu_mangle.h,v 1.2 1999/09/10 02:08:19 gareth Exp $ */
 
 /*
  * Mesa 3-D graphics library
 
 /*
  * $Log: glu_mangle.h,v $
- * Revision 1.1  1999/08/19 00:55:40  jtg
- * Initial revision
+ * Revision 1.2  1999/09/10 02:08:19  gareth
+ * Added GLU 1.3 tessellation (except winding rule code).
+ *
+ * Revision 1.1.1.1  1999/08/19 00:55:40  jtg
+ * Imported sources
  *
  * Revision 3.1  1999/06/21 22:00:42  brianp
  * added #ifndef GLU_MANGLE_H stuff
 #define gluPwlCurve mgluPwlCurve
 #define gluNurbsCallback mgluNurbsCallback
 #define gluNewTess mgluNewTess
-#define gluTessCallback mgluTessCallback
 #define gluDeleteTess mgluDeleteTess
+#define gluTessBeginPolygon mgluTessBeginPolygon
+#define gluTessBeginContour mgluTessBeginContour
+#define gluTessVertex mgluTessVertex
+#define gluTessEndPolygon mgluTessEndPolygon
+#define gluTessEndContour mgluTessEndContour
+#define gluTessProperty mgluTessProperty
+#define gluTessNormal mgluTessNormal
+#define gluTessCallback mgluTessCallback
+#define gluGetTessProperty mgluGetTessProperty
 #define gluBeginPolygon mgluBeginPolygon
-#define gluEndPolygon mgluEndPolygon
 #define gluNextContour mgluNextContour
-#define gluTessVertex mgluTessVertex
+#define gluEndPolygon mgluEndPolygon
 #define gluGetString mgluGetString
 
 #endif
index d1e489c19994aee87de061bb864e0d625b89c06d..016bb580ae3f2247919f3b097d0df8940ec6a2c7 100644 (file)
@@ -29,7 +29,7 @@ INCDIR = ../include
 LIBDIR = ../lib
 
 SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \
-       project.c quadric.c tess.c tesselat.c polytest.c
+       project.c quadric.c tess.c tess_fist.c tess_hash.c tess_heap.c
 
 OBJECTS = $(SOURCES:.c=.o)
 
index d664534491d21aaf2ee35131d883827b56ccb489..4584c3201b8bdcc5f2417ff3ff6e43e4127e8dae 100644 (file)
 # Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 
-# $Id: Makefile.BeOS-R4,v 1.1 1999/08/19 00:55:42 jtg Exp $
+# $Id: Makefile.BeOS-R4,v 1.2 1999/09/10 02:03:31 gareth Exp $
 
 # $Log: Makefile.BeOS-R4,v $
-# Revision 1.1  1999/08/19 00:55:42  jtg
-# Initial revision
+# Revision 1.2  1999/09/10 02:03:31  gareth
+# Added GLU 1.3 tessellation (except winding rule code).
+#
+# Revision 1.1.1.1  1999/08/19 00:55:42  jtg
+# Imported sources
 #
 # Revision 1.2  1999/02/02 04:44:40  brianp
 # fixed some problems
@@ -42,7 +45,7 @@ INCDIR = ../include
 LIBDIR = ../lib
 
 SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \
-       project.c quadric.c tess.c tesselat.c polytest.c
+       project.c quadric.c tess.c tess_fist.c tess_hash.c tess_heap.c
 
 OBJECTS = $(SOURCES:.c=.o)
 
index c155aea9a557e84816320d7d6c666552c0b853ee..2b123810a57a85d27cb154438e54f106de2455ce 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile.X11,v 1.1 1999/08/19 00:55:42 jtg Exp $
+# $Id: Makefile.X11,v 1.2 1999/09/10 02:03:31 gareth Exp $
 
 # Mesa 3-D graphics library
 # Version:  3.1
@@ -15,7 +15,7 @@ INCDIR = ../include
 LIBDIR = ../lib
 
 SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \
-       project.c quadric.c tess.c tesselat.c polytest.c
+       project.c quadric.c tess.c tess_fist.c tess_hash.c tess_heap.c
 
 OBJECTS = $(SOURCES:.c=.o)
 
index 8b1c4449ff179b9f4de0eadfa18792b4c437a18d..e61782b65a0e00dd95ae9fac80e0091a9bdffab3 100644 (file)
@@ -45,10 +45,17 @@ EXPORTS
     gluPwlCurve\r
     gluNurbsCallback\r
     gluNewTess\r
-    gluTessCallback\r
     gluDeleteTess\r
+    gluTessBeginPolygon\r
+    gluTessBeginContour\r
+    gluTessVertex\r
+    gluTessEndContour\r
+    gluTessEndPolygon\r
+    gluTessProperty\r
+    gluTessNormal\r
+    gluTessCallback\r
+    gluGetTessProperty\r
     gluBeginPolygon\r
-    gluEndPolygon\r
     gluNextContour\r
-    gluTessVertex\r
+    gluEndPolygon\r
     gluGetString\r
index b660f6914de951426d3560e0c5be4440912cbce5..bcce68ff94e0539480a6dc57577e6ad050cbdf9b 100644 (file)
@@ -15,10 +15,11 @@ LIBDIR = [-.lib]
 CFLAGS = /include=$(INCDIR)/define=(FBIND=1)
 
 SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \
-       project.c quadric.c tess.c tesselat.c polytest.c
+       project.c quadric.c tess.c tess_fist.c tess_hash.c tess_heap.c
 
 OBJECTS =glu.obj,mipmap.obj,nurbs.obj,nurbscrv.obj,nurbssrf.obj,nurbsutl.obj,\
-       project.obj,quadric.obj,tess.obj,tesselat.obj,polytest.obj
+       project.obj,quadric.obj,tess.obj,tess_fist.obj,tess_hash.obj,\
+       tess_heap.obj
 
 
 
index 2cceb8b743e523bb0e28b2946337808825af7450..5569ca9d49ca14d591a87c94e59c2b0b4e166777 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: glu.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+/* $Id: glu.c,v 1.2 1999/09/10 02:03:31 gareth Exp $ */
 
 /*
  * Mesa 3-D graphics library
 
 /*
  * $Log: glu.c,v $
- * Revision 1.1  1999/08/19 00:55:42  jtg
- * Initial revision
+ * Revision 1.2  1999/09/10 02:03:31  gareth
+ * Added GLU 1.3 tessellation (except winding rule code).
+ *
+ * Revision 1.1.1.1  1999/08/19 00:55:42  jtg
+ * Imported sources
  *
  * Revision 1.13  1999/03/31 19:07:28  brianp
  * added GL_EXT_abgr to extensions
@@ -220,8 +223,7 @@ const GLubyte* GLAPIENTRY gluErrorString( GLenum errorCode )
       "misoriented or self-intersecting loops",
       "coincident vertices",
       "colinear vertices",
-      "intersecting edges",
-      "not coplanar contours"
+      "intersecting edges"
    };
    static char *nurbs_error[] = {
       "spline order un-supported",
@@ -301,7 +303,7 @@ const GLubyte* GLAPIENTRY gluErrorString( GLenum errorCode )
    else if (errorCode==GLU_INCOMPATIBLE_GL_VERSION) {
       return (GLubyte *) "incompatible GL version";
    }
-   else if (errorCode>=GLU_TESS_ERROR1 && errorCode<=GLU_TESS_ERROR9) {
+   else if (errorCode>=GLU_TESS_ERROR1 && errorCode<=GLU_TESS_ERROR8) {
       return (GLubyte *) tess_error[errorCode-GLU_TESS_ERROR1];
    }
    else if (errorCode>=GLU_NURBS_ERROR1 && errorCode<=GLU_NURBS_ERROR37) {
index 372e3fff1e9ac1f6a4498ca8ecf2eadc1855e174..37e9eb2b920173d354fc04810d559d95cae7ef44 100644 (file)
@@ -9,5 +9,6 @@ nurbsutl.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h nurbs.h
 project.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h
 quadric.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h
 tess.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h
-tesselat.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h
-polytest.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h
+tess_fist.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h
+tess_hash.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h
+tess_heap.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h
diff --git a/src/glu/mesa/polytest.c b/src/glu/mesa/polytest.c
deleted file mode 100644 (file)
index 9b42c63..0000000
+++ /dev/null
@@ -1,1049 +0,0 @@
-/* $Id: polytest.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
-
-/*
- * Mesa 3-D graphics library
- * Version:  2.4
- * Copyright (C) 1995-1997  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: polytest.c,v $
- * Revision 1.1  1999/08/19 00:55:42  jtg
- * Initial revision
- *
- * Revision 1.7  1999/06/08 00:44:51  brianp
- * OpenStep updates (pete@ohm.york.ac.uk)
- *
- * Revision 1.6  1998/07/26 02:08:52  brianp
- * updated for Windows compilation per Ted Jump
- *
- * Revision 1.5  1997/10/29 02:02:20  brianp
- * various MS Windows compiler changes (David Bucciarelli, v20 3dfx driver)
- *
- * Revision 1.4  1997/07/24 01:28:44  brianp
- * changed precompiled header symbol from PCH to PC_HEADER
- *
- * Revision 1.3  1997/05/28 02:29:38  brianp
- * added support for precompiled headers (PCH), inserted APIENTRY keyword
- *
- * Revision 1.2  1997/05/08 01:53:21  brianp
- * fixed memory leak in free_current_polygon() reported by Randy Frank
- *
- * 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 "gluP.h"
-#include "tess.h"
-#endif
-
-
-
-static GLenum store_polygon_as_contour(GLUtriangulatorObj *);
-static void free_current_polygon(tess_polygon *);
-static void prepare_projection_info(GLUtriangulatorObj *);
-static GLdouble twice_the_polygon_area(tess_vertex *,tess_vertex *);
-static GLenum verify_edge_vertex_intersections(GLUtriangulatorObj *);
-void tess_find_contour_hierarchies(GLUtriangulatorObj *);
-static GLenum test_for_overlapping_contours(GLUtriangulatorObj *);
-static GLenum contours_overlap(tess_contour *, tess_polygon *);
-static GLenum is_contour_contained_in(tess_contour *,tess_contour *);
-static void add_new_exterior(GLUtriangulatorObj *,tess_contour *);
-static void add_new_interior(GLUtriangulatorObj *,tess_contour *,
-       tess_contour *);
-static void add_interior_with_hierarchy_check(GLUtriangulatorObj *,
-       tess_contour *,tess_contour *);
-static void reverse_hierarchy_and_add_exterior(GLUtriangulatorObj *,
-       tess_contour *,tess_contour *);
-static GLboolean point_in_polygon(tess_contour *,GLdouble,GLdouble);
-static void shift_interior_to_exterior(GLUtriangulatorObj *,tess_contour *);
-static void add_exterior_with_check(GLUtriangulatorObj *,tess_contour *,
-       tess_contour *);
-static GLenum cut_out_hole(GLUtriangulatorObj *,tess_contour *,
-       tess_contour *);
-static GLenum merge_hole_with_contour(GLUtriangulatorObj *,
-       tess_contour *,tess_contour *,tess_vertex *,
-       tess_vertex *);
-
-static GLenum
-find_normal(GLUtriangulatorObj *tobj)
-{
-       tess_polygon *polygon=tobj->current_polygon;
-       tess_vertex *va,*vb,*vc;
-       GLdouble A,B,C;
-       GLdouble A0,A1,A2,B0,B1,B2;
-
-       va=polygon->vertices;
-       vb=va->next;
-       A0=vb->location[0]-va->location[0];
-       A1=vb->location[1]-va->location[1];
-       A2=vb->location[2]-va->location[2];
-       for(vc=vb->next;vc!=va;vc=vc->next)
-       {
-               B0=vc->location[0]-va->location[0];
-               B1=vc->location[1]-va->location[1];
-               B2=vc->location[2]-va->location[2];
-               A=A1*B2-A2*B1;
-               B=A2*B0-A0*B2;
-               C=A0*B1-A1*B0;
-               if(fabs(A)>EPSILON || fabs(B)>EPSILON || fabs(C)>EPSILON)
-               {
-                       polygon->A=A;
-                       polygon->B=B;
-                       polygon->C=C;
-                       polygon->D= -A*va->location[0]-B*va->location[1]-C*va->location[2];
-                       return GLU_NO_ERROR;
-               }
-       }
-       tess_call_user_error(tobj,GLU_TESS_ERROR7);
-       return GLU_ERROR;
-}
-
-void
-tess_test_polygon( GLUtriangulatorObj *tobj )
-{
-       tess_polygon *polygon=tobj->current_polygon;
-
-       /* any vertices defined? */
-       if(polygon->vertex_cnt<3)
-       {
-               free_current_polygon(polygon);
-               return;
-       }
-       /* wrap pointers */
-       polygon->last_vertex->next=polygon->vertices;
-       polygon->vertices->previous=polygon->last_vertex;
-       /* determine the normal */
-       if(find_normal(tobj)==GLU_ERROR)
-               return;
-       /* compare the normals of previously defined contours and this one */
-       /* first contour define ? */
-       if(tobj->contours==NULL)
-       {
-               tobj->A=polygon->A;
-               tobj->B=polygon->B;
-               tobj->C=polygon->C;
-               tobj->D=polygon->D;
-               /* determine the best projection to use */
-               if(fabs(polygon->A) > fabs(polygon->B))
-                       if(fabs(polygon->A) > fabs(polygon->C))
-                               tobj->projection=OYZ;
-                       else
-                               tobj->projection=OXY;
-               else
-                       if(fabs(polygon->B) > fabs(polygon->C))
-                               tobj->projection=OXZ;
-                       else
-                               tobj->projection=OXY;
-       }
-       else
-       {
-               GLdouble a[3],b[3];
-               tess_vertex *vertex=polygon->vertices;
-
-               a[0]=tobj->A;
-               a[1]=tobj->B;
-               a[2]=tobj->C;
-               b[0]=polygon->A;
-               b[1]=polygon->B;
-               b[2]=polygon->C;
-
-               /* compare the normals */
-               if( fabs(a[1]*b[2]-a[2]*b[1]) > EPSILON ||
-                       fabs(a[2]*b[0]-a[0]*b[2]) > EPSILON ||
-                       fabs(a[0]*b[1]-a[1]*b[0]) > EPSILON)
-               {
-                       /* not coplanar */
-                       tess_call_user_error(tobj,GLU_TESS_ERROR9);
-                       return;
-               }
-               /* the normals are parallel - test for plane equation */
-               if(fabs(a[0]*vertex->location[0]+a[1]*vertex->location[1]+
-                       a[2]*vertex->location[2]+tobj->D) > EPSILON)
-               {
-                       /* not the same plane */
-                       tess_call_user_error(tobj,GLU_TESS_ERROR9);
-                       return;
-               }
-       }
-       prepare_projection_info(tobj);
-       if(verify_edge_vertex_intersections(tobj)==GLU_ERROR)
-               return;
-       if(test_for_overlapping_contours(tobj)==GLU_ERROR)
-               return;
-       if(store_polygon_as_contour(tobj)==GLU_ERROR)
-               return;
-}
-
-static GLenum test_for_overlapping_contours(GLUtriangulatorObj *tobj)
-{
-       tess_contour *contour;
-       tess_polygon *polygon;
-
-       polygon=tobj->current_polygon;
-       for(contour=tobj->contours;contour!=NULL;contour=contour->next)
-               if(contours_overlap(contour,polygon)!=GLU_NO_ERROR)
-               {
-                       tess_call_user_error(tobj,GLU_TESS_ERROR5);
-                       return GLU_ERROR;
-               }
-       return GLU_NO_ERROR;
-}
-
-static GLenum store_polygon_as_contour(GLUtriangulatorObj *tobj)
-{
-       tess_polygon *polygon=tobj->current_polygon;
-       tess_contour *contour=tobj->contours;
-
-       /* the first contour defined */
-       if(contour==NULL)
-       {
-               if((contour=(tess_contour *)malloc(
-                       sizeof(tess_contour)))==NULL)
-               {
-                       tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
-                       free_current_polygon(polygon);
-                       return GLU_ERROR;
-               }
-               tobj->contours=tobj->last_contour=contour;
-               contour->next=contour->previous=NULL;
-       }
-       else
-       {
-               if((contour=(tess_contour *)malloc(
-                       sizeof(tess_contour)))==NULL)
-               {
-                       tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
-                       free_current_polygon(polygon);
-                       return GLU_ERROR;
-               }
-               contour->previous=tobj->last_contour;
-               tobj->last_contour->next=contour;
-               tobj->last_contour=contour;
-               contour->next=NULL;
-       }
-       /* mark all vertices in new contour as not special */
-       /* and all are boundary edges */
-       {
-               tess_vertex *vertex;
-               GLuint vertex_cnt,i;
-
-               for(vertex=polygon->vertices , i=0 , vertex_cnt=polygon->vertex_cnt;
-                       i<vertex_cnt;
-                       vertex=vertex->next , i++)
-               {
-                       vertex->shadow_vertex=NULL;
-                       vertex->edge_flag=GL_TRUE;
-               }
-       }
-       contour->vertex_cnt=polygon->vertex_cnt;
-       contour->area=polygon->area;
-       contour->orientation=polygon->orientation;
-       contour->type=GLU_UNKNOWN;
-       contour->vertices=polygon->vertices;
-       contour->last_vertex=polygon->last_vertex;
-       polygon->vertices=polygon->last_vertex=NULL;
-       polygon->vertex_cnt=0;
-       ++(tobj->contour_cnt);
-       return GLU_NO_ERROR;
-}
-
-static void free_current_polygon(tess_polygon *polygon)
-{
-       tess_vertex *vertex,*vertex_tmp;
-       GLuint  i;
-
-       /* free current_polygon structures */
-       for(vertex=polygon->vertices,i=0;i<polygon->vertex_cnt;i++)
-       {
-               vertex_tmp=vertex->next;
-               free(vertex);
-               vertex=vertex_tmp;
-       }
-       polygon->vertices=polygon->last_vertex=NULL;
-       polygon->vertex_cnt=0;
-}
-
-static void prepare_projection_info(GLUtriangulatorObj *tobj)
-{
-       tess_polygon *polygon=tobj->current_polygon;
-       tess_vertex *vertex,*last_vertex_ptr;
-       GLdouble area;
-
-       last_vertex_ptr=polygon->last_vertex;
-       switch(tobj->projection)
-       {
-               case OXY:
-                       for(vertex=polygon->vertices;vertex!=last_vertex_ptr;
-                               vertex=vertex->next)
-                       {
-                               vertex->x=vertex->location[0];
-                               vertex->y=vertex->location[1];
-                       }
-                       last_vertex_ptr->x=last_vertex_ptr->location[0];
-                       last_vertex_ptr->y=last_vertex_ptr->location[1];
-                       break;
-               case OXZ:
-                       for(vertex=polygon->vertices;vertex!=last_vertex_ptr;
-                               vertex=vertex->next)
-                       {
-                               vertex->x=vertex->location[0];
-                               vertex->y=vertex->location[2];
-                       }
-                       last_vertex_ptr->x=last_vertex_ptr->location[0];
-                       last_vertex_ptr->y=last_vertex_ptr->location[2];
-                       break;
-               case OYZ:
-                       for(vertex=polygon->vertices;vertex!=last_vertex_ptr;
-                               vertex=vertex->next)
-                       {
-                               vertex->x=vertex->location[1];
-                               vertex->y=vertex->location[2];
-                       }
-                       last_vertex_ptr->x=last_vertex_ptr->location[1];
-                       last_vertex_ptr->y=last_vertex_ptr->location[2];
-                       break;
-       }
-       area=twice_the_polygon_area(polygon->vertices,polygon->last_vertex);
-       if(area >= 0.0)
-       {
-               polygon->orientation=GLU_CCW;
-               polygon->area=area;
-       }
-       else
-       {
-               polygon->orientation=GLU_CW;
-               polygon->area= -area;
-       }
-}
-
-static GLdouble twice_the_polygon_area(tess_vertex *vertex,
-       tess_vertex *last_vertex)
-{
-       tess_vertex *next;
-       GLdouble area,x,y;
-
-       area=0.0;
-       x=vertex->x;
-       y=vertex->y;
-       vertex=vertex->next;
-       for(; vertex!=last_vertex; vertex=vertex->next)
-       {
-               next=vertex->next;
-               area+=(vertex->x - x)*(next->y - y) - (vertex->y - y)*(next->x - x);
-       }
-       return area;
-}
-
-/* test if edges ab and cd intersect */
-/* if not return GLU_NO_ERROR, else if cross return GLU_TESS_ERROR8, */
-/* else if adjacent return GLU_TESS_ERROR4 */
-static GLenum edge_edge_intersect(
-       tess_vertex *a,
-       tess_vertex *b,
-       tess_vertex *c,
-       tess_vertex *d)
-{
-       GLdouble denom,r,s;
-       GLdouble xba,ydc,yba,xdc,yac,xac;
-
-       xba=b->x - a->x;
-       yba=b->y - a->y;
-       xdc=d->x - c->x;
-       ydc=d->y - c->y;
-       xac=a->x - c->x;
-       yac=a->y - c->y;
-       denom= xba*ydc - yba*xdc;
-       r = yac*xdc - xac*ydc;
-       /* parallel? */
-       if(fabs(denom) < EPSILON)
-       {
-               if(fabs(r) < EPSILON)
-               {
-                       /* colinear */
-                       if(fabs(xba) < EPSILON)
-                       {
-                               /* compare the Y coordinate */
-                               if(yba > 0.0)
-                               {
-                                       if((fabs(a->y - c->y)<EPSILON && fabs(c->y - b->y)<EPSILON)
-                                               ||
-                                               (fabs(a->y - d->y)<EPSILON && fabs(d->y - b->y)<EPSILON))
-                                       return GLU_TESS_ERROR4;
-
-                               }
-                               else
-                               {
-                                       if((fabs(b->y - c->y)<EPSILON && fabs(c->y - a->y)<EPSILON)
-                                               ||
-                                               (fabs(b->y - d->y)<EPSILON && fabs(d->y - a->y)<EPSILON))
-                                       return GLU_TESS_ERROR4;
-                               }
-                       }
-                       else
-                       {
-                               /* compare the X coordinate */
-                               if(xba > 0.0)
-                               {
-                                       if((fabs(a->x - c->x)<EPSILON && fabs(c->x - b->x)<EPSILON)
-                                               ||
-                                               (fabs(a->x - d->x)<EPSILON && fabs(d->x - b->x)<EPSILON))
-                                       return GLU_TESS_ERROR4;
-                               }
-                               else
-                               {
-                                       if((fabs(b->x - c->x)<EPSILON && fabs(c->x - a->x)<EPSILON)
-                                               ||
-                                               (fabs(b->x - d->x)<EPSILON && fabs(d->x - a->x)<EPSILON))
-                                       return GLU_TESS_ERROR4;
-                               }
-                       }
-               }
-               return GLU_NO_ERROR;
-       }
-       r /= denom;
-       s = (yac*xba - xac*yba) / denom;
-       /* test if one vertex lies on other edge */
-       if(((fabs(r) < EPSILON || (r < 1.0+EPSILON && r > 1.0-EPSILON)) &&
-               s > -EPSILON && s < 1.0+EPSILON) ||
-               ((fabs(s) < EPSILON || (s < 1.0+EPSILON && s > 1.0-EPSILON)) &&
-               r > -EPSILON && r < 1.0+EPSILON))
-       {
-               return GLU_TESS_ERROR4;
-       }
-       /* test for crossing */
-       if(r > -EPSILON && r < 1.0+EPSILON &&
-               s > -EPSILON && s < 1.0+EPSILON)
-       {
-               return GLU_TESS_ERROR8;
-       }
-       return GLU_NO_ERROR;
-}
-
-static GLenum verify_edge_vertex_intersections(GLUtriangulatorObj *tobj)
-{
-       tess_polygon *polygon=tobj->current_polygon;
-       tess_vertex *vertex1,*last_vertex,*vertex2;
-       GLenum test;
-
-       last_vertex=polygon->last_vertex;
-       vertex1=last_vertex;
-       for(vertex2=vertex1->next->next;
-               vertex2->next!=last_vertex;
-               vertex2=vertex2->next)
-       {
-               test=edge_edge_intersect(vertex1,vertex1->next,vertex2,
-                       vertex2->next);
-               if(test!=GLU_NO_ERROR)
-               {
-                       tess_call_user_error(tobj,test);
-                       return GLU_ERROR;
-               }
-       }
-       for(vertex1=polygon->vertices;
-               vertex1->next->next!=last_vertex;
-               vertex1=vertex1->next)
-       {
-               for(vertex2=vertex1->next->next;
-                       vertex2!=last_vertex;
-                       vertex2=vertex2->next)
-               {
-                       test=edge_edge_intersect(vertex1,vertex1->next,vertex2,
-                               vertex2->next);
-                       if(test!=GLU_NO_ERROR)
-                       {
-                               tess_call_user_error(tobj,test);
-                               return GLU_ERROR;
-                       }
-               }
-       }
-       return GLU_NO_ERROR;
-}
-
-static int
-#if defined(WIN32) && !defined(OPENSTEP)
-__cdecl
-#endif
-area_compare(const void *a,const void *b)
-{
-       GLdouble area1,area2;
-
-       area1=(*((tess_contour **)a))->area;
-       area2=(*((tess_contour **)b))->area;
-       if(area1 < area2)
-               return 1;
-       if(area1 > area2)
-               return -1;
-       return 0;
-}
-
-void tess_find_contour_hierarchies(GLUtriangulatorObj *tobj)
-{
-       tess_contour **contours; /* dinamic array of pointers */
-       tess_contour *tmp_contour_ptr=tobj->contours;
-       GLuint cnt,i;
-       GLenum result;
-       GLboolean hierarchy_changed;
-
-       /* any contours? */
-       if(tobj->contour_cnt < 2)
-       {
-               tobj->contours->type=GLU_EXTERIOR;
-               return;
-       }
-       if((contours=(tess_contour **)
-               malloc(sizeof(tess_contour *)*(tobj->contour_cnt)))==NULL)
-       {
-               tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
-               return;
-       }
-       for(tmp_contour_ptr=tobj->contours , cnt=0;
-               tmp_contour_ptr!=NULL;
-               tmp_contour_ptr=tmp_contour_ptr->next)
-               contours[cnt++]=tmp_contour_ptr;
-       /* now sort the contours in decreasing area size order */
-       qsort((void *)contours,(size_t)cnt,(size_t)sizeof(tess_contour *),area_compare);
-       /* we leave just the first contour - remove others from list */
-       tobj->contours=contours[0];
-       tobj->contours->next=tobj->contours->previous=NULL;
-       tobj->last_contour=tobj->contours;
-       tobj->contour_cnt=1;
-       /* first contour is the one with greatest area */
-       /* must be EXTERIOR */
-       tobj->contours->type=GLU_EXTERIOR;
-       tmp_contour_ptr=tobj->contours;
-       /* now we play! */
-       for(i=1;i<cnt;i++)
-       {
-               hierarchy_changed=GL_FALSE;
-               for(tmp_contour_ptr=tobj->contours;
-                       tmp_contour_ptr!=NULL;
-                       tmp_contour_ptr=tmp_contour_ptr->next)
-               {
-                       if(tmp_contour_ptr->type==GLU_EXTERIOR)
-                       {
-                               /* check if contour completely contained in EXTERIOR */
-                               result=is_contour_contained_in(tmp_contour_ptr,contours[i]);
-                               switch(result)
-                               {
-                                       case GLU_INTERIOR:
-                                               /* now we have to check if contour is inside interiors */
-                                               /* or not */
-                                               /* any interiors? */
-                                               if(tmp_contour_ptr->next!=NULL &&
-                                                       tmp_contour_ptr->next->type==GLU_INTERIOR)
-                                               {
-                                                       /* for all interior, check if inside any of them */
-                                                       /* if not inside any of interiors, its another */
-                                                       /* interior */
-                                                       /* or it may contain some interiors, then change */
-                                                       /* the contained interiors to exterior ones */
-                                                       add_interior_with_hierarchy_check(tobj,
-                                                               tmp_contour_ptr,contours[i]);
-                                               }
-                                               else
-                                               {
-                                                       /* not in interior, add as new interior contour */
-                                                       add_new_interior(tobj,tmp_contour_ptr,contours[i]);
-                                               }
-                                               hierarchy_changed=GL_TRUE;
-                                               break;
-                                       case GLU_EXTERIOR:
-                                               /* ooops, the marked as EXTERIOR (contours[i]) is */
-                                               /* actually an interior of tmp_contour_ptr */
-                                               /*  reverse the local hierarchy */
-                                               reverse_hierarchy_and_add_exterior(tobj,tmp_contour_ptr,
-                                                       contours[i]);
-                                               hierarchy_changed=GL_TRUE;
-                                               break;
-                                       case GLU_NO_ERROR:
-                                               break;
-                                       default:
-                                               abort();
-                               }
-                       }
-                       if(hierarchy_changed)
-                               break; /* break from for loop */
-               }
-               if(hierarchy_changed==GL_FALSE)
-               {
-                       /* disjoint with all contours, add to contour list */
-                       add_new_exterior(tobj,contours[i]);
-               }
-       }
-       free(contours);
-}
-
-/* returns GLU_INTERIOR if inner is completey enclosed within outer */
-/* returns GLU_EXTERIOR if outer is completely enclosed within inner */
-/* returns GLU_NO_ERROR if contours are disjoint */
-static GLenum is_contour_contained_in(
-       tess_contour *outer,
-       tess_contour *inner)
-{
-       GLenum relation_flag;
-
-       /* set relation_flag to relation of containment of first inner vertex */
-       /* regarding outer contour */
-       if(point_in_polygon(outer,inner->vertices->x,inner->vertices->y))
-               relation_flag=GLU_INTERIOR;
-       else
-               relation_flag=GLU_EXTERIOR;
-       if(relation_flag==GLU_INTERIOR)
-               return GLU_INTERIOR;
-       if(point_in_polygon(inner,outer->vertices->x,outer->vertices->y))
-               return GLU_EXTERIOR;
-       return GLU_NO_ERROR;
-}
-
-static GLboolean point_in_polygon(
-       tess_contour *contour,
-       GLdouble x,
-       GLdouble y)
-{
-       tess_vertex *v1,*v2;
-       GLuint i,vertex_cnt;
-       GLdouble xp1,yp1,xp2,yp2;
-       GLboolean tst;
-
-       tst=GL_FALSE;
-       v1=contour->vertices;
-       v2=contour->vertices->previous;
-       for(i=0 , vertex_cnt=contour->vertex_cnt;
-               i < vertex_cnt;
-               i++)
-       {
-               xp1=v1->x;
-               yp1=v1->y;
-               xp2=v2->x;
-               yp2=v2->y;
-               if ((((yp1<=y) && (y<yp2)) || ((yp2<=y)  && (y<yp1))) &&
-                       (x < (xp2 - xp1) * (y - yp1) /  (yp2 - yp1) + xp1))
-                               tst = (tst==GL_FALSE ? GL_TRUE : GL_FALSE);
-               v2=v1;
-               v1=v1->next;
-       }
-       return tst;
-}
-
-static GLenum contours_overlap(
-       tess_contour *contour,
-       tess_polygon *polygon)
-{
-       tess_vertex *vertex1,*vertex2;
-       GLuint vertex1_cnt,vertex2_cnt,i,j;
-       GLenum test;
-
-       vertex1=contour->vertices;
-       vertex2=polygon->vertices;
-       vertex1_cnt=contour->vertex_cnt;
-       vertex2_cnt=polygon->vertex_cnt;
-       for(i=0; i<vertex1_cnt; vertex1=vertex1->next , i++)
-       {
-               for(j=0; j<vertex2_cnt; vertex2=vertex2->next , j++)
-                       if((test=edge_edge_intersect(vertex1,vertex1->next,vertex2,
-                               vertex2->next))!=GLU_NO_ERROR)
-                               return test;
-       }
-       return GLU_NO_ERROR;
-}
-
-static void add_new_exterior(
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour)
-{
-       contour->type=GLU_EXTERIOR;
-       contour->next=NULL;
-       contour->previous=tobj->last_contour;
-       tobj->last_contour->next=contour;
-       tobj->last_contour=contour;
-}
-
-static void add_new_interior(
-       GLUtriangulatorObj *tobj,
-       tess_contour *outer,
-       tess_contour *contour)
-{
-       contour->type=GLU_INTERIOR;
-       contour->next=outer->next;
-       contour->previous=outer;
-       if(outer->next!=NULL)
-               outer->next->previous=contour;
-       outer->next=contour;
-       if(tobj->last_contour==outer)
-               tobj->last_contour=contour;
-}
-
-static void add_interior_with_hierarchy_check(
-       GLUtriangulatorObj *tobj,
-       tess_contour *outer,
-       tess_contour *contour)
-{
-       tess_contour *ptr;
-
-       /* for all interiors of outer check if they are interior of contour */
-       /* if so, change that interior to exterior and move it of of the */
-       /* interior sequence */
-       if(outer->next!=NULL && outer->next->type==GLU_INTERIOR)
-       {
-               GLenum test;
-
-               for(ptr=outer->next;ptr!=NULL && ptr->type==GLU_INTERIOR;ptr=ptr->next)
-               {
-                       test=is_contour_contained_in(ptr,contour);
-                       switch(test)
-                       {
-                               case GLU_INTERIOR:
-                                       /* contour is contained in one of the interiors */
-                                       /* check if possibly contained in other exteriors */
-                                       /* move ptr to first EXTERIOR */
-                                       for(;ptr!=NULL && ptr->type==GLU_INTERIOR;ptr=ptr->next);
-                                       if(ptr==NULL)
-                                               /* another exterior */
-                                               add_new_exterior(tobj,contour);
-                                       else
-                                               add_exterior_with_check(tobj,ptr,contour);
-                                       return;
-                               case GLU_EXTERIOR:
-                                       /* one of the interiors is contained in the contour */
-                                       /* change it to EXTERIOR, and shift it away from the */
-                                       /* interior sequence */
-                                       shift_interior_to_exterior(tobj,ptr);
-                                       break;
-                               case GLU_NO_ERROR:
-                                       /* disjoint */
-                                       break;
-                               default:
-                                       abort();
-                       }
-               }
-       }
-       /* add contour to the interior sequence */
-       add_new_interior(tobj,outer,contour);
-}
-
-static void reverse_hierarchy_and_add_exterior(
-       GLUtriangulatorObj *tobj,
-       tess_contour *outer,
-       tess_contour *contour)
-{
-       tess_contour *ptr;
-
-       /* reverse INTERIORS to EXTERIORS */
-       /* any INTERIORS? */
-       if(outer->next!=NULL && outer->next->type==GLU_INTERIOR)
-               for(ptr=outer->next;ptr!=NULL && ptr->type==GLU_INTERIOR;ptr=ptr->next)
-                       ptr->type=GLU_EXTERIOR;
-       /* the outer now becomes inner */
-       outer->type=GLU_INTERIOR;
-       /* contour is the EXTERIOR */
-       contour->next=outer;
-       if(tobj->contours==outer)
-       {
-               /* first contour beeing reversed */
-               contour->previous=NULL;
-               tobj->contours=contour;
-       }
-       else
-       {
-               outer->previous->next=contour;
-               contour->previous=outer->previous;
-       }
-       outer->previous=contour;
-}
-
-static void shift_interior_to_exterior(
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour)
-{
-       contour->previous->next=contour->next;
-       if(contour->next!=NULL)
-               contour->next->previous=contour->previous;
-       else
-               tobj->last_contour=contour->previous;
-}
-
-static void add_exterior_with_check(
-       GLUtriangulatorObj *tobj,
-       tess_contour *outer,
-       tess_contour *contour)
-{
-       GLenum test;
-
-       /* this contour might be interior to further exteriors - check */
-       /* if not, just add as a new exterior */
-       for(;outer!=NULL && outer->type==GLU_EXTERIOR;outer=outer->next)
-       {
-               test=is_contour_contained_in(outer,contour);
-               switch(test)
-               {
-                       case GLU_INTERIOR:
-                               /* now we have to check if contour is inside interiors */
-                               /* or not */
-                               /* any interiors? */
-                               if(outer->next!=NULL && outer->next->type==GLU_INTERIOR)
-                               {
-                                       /* for all interior, check if inside any of them */
-                                       /* if not inside any of interiors, its another */
-                                       /* interior */
-                                       /* or it may contain some interiors, then change */
-                                       /* the contained interiors to exterior ones */
-                                       add_interior_with_hierarchy_check(tobj,
-                                               outer,contour);
-                               }
-                               else
-                               {
-                                       /* not in interior, add as new interior contour */
-                                       add_new_interior(tobj,outer,contour);
-                               }
-                               return;
-                       case GLU_NO_ERROR:
-                               /* disjoint */
-                               break;
-                       default:
-                               abort();
-               }
-       }
-       /* add contour to the exterior sequence */
-       add_new_exterior(tobj,contour);
-}
-
-void tess_handle_holes(GLUtriangulatorObj *tobj)
-{
-       tess_contour *contour,*hole;
-       GLenum exterior_orientation;
-
-       /* verify hole orientation */
-       for(contour=tobj->contours;contour!=NULL;)
-       {
-               exterior_orientation=contour->orientation;
-               for(contour=contour->next;
-                       contour!=NULL && contour->type==GLU_INTERIOR;
-                       contour=contour->next)
-               {
-                       if(contour->orientation==exterior_orientation)
-                       {
-                               tess_call_user_error(tobj,GLU_TESS_ERROR5);
-                               return;
-                       }
-               }
-       }
-       /* now cut-out holes */
-       for(contour=tobj->contours;contour!=NULL;)
-       {
-               hole=contour->next;
-               while(hole!=NULL && hole->type==GLU_INTERIOR)
-               {
-                       if(cut_out_hole(tobj,contour,hole)==GLU_ERROR)
-                               return;
-                       hole=contour->next;
-               }
-               contour=contour->next;
-       }
-}
-
-static GLenum cut_out_hole(
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour,
-       tess_contour *hole)
-{
-       tess_contour *tmp_hole;
-       tess_vertex *v1,*v2,*tmp_vertex;
-       GLuint vertex1_cnt,vertex2_cnt,tmp_vertex_cnt;
-       GLuint i,j,k;
-       GLenum test;
-
-       /* find an edge connecting contour and hole not intersecting any other */
-       /* edge belonging to either the contour or any of the other holes */
-       for(v1=contour->vertices , vertex1_cnt=contour->vertex_cnt , i=0;
-               i<vertex1_cnt;
-               i++ , v1=v1->next)
-       {
-               for(v2=hole->vertices , vertex2_cnt=hole->vertex_cnt , j=0;
-                       j<vertex2_cnt;
-                       j++ , v2=v2->next)
-               {
-                       /* does edge (v1,v2) intersect any edge of contour */
-                       for(tmp_vertex=contour->vertices , tmp_vertex_cnt=contour->vertex_cnt ,
-                                       k=0;
-                               k<tmp_vertex_cnt;
-                               tmp_vertex=tmp_vertex->next , k++)
-                       {
-                               /* skip edge tests for edges directly connected */
-                               if(v1==tmp_vertex || v1==tmp_vertex->next)
-                                       continue;
-                               test=edge_edge_intersect(v1,v2,tmp_vertex,tmp_vertex->next);
-                               if(test!=GLU_NO_ERROR)
-                                       break;
-                       }
-                       if(test==GLU_NO_ERROR)
-                       {
-                               /* does edge (v1,v2) intersect any edge of hole */
-                               for(tmp_vertex=hole->vertices ,
-                                               tmp_vertex_cnt=hole->vertex_cnt , k=0;
-                                       k<tmp_vertex_cnt;
-                                       tmp_vertex=tmp_vertex->next , k++)
-                               {
-                                       /* skip edge tests for edges directly connected */
-                                       if(v2==tmp_vertex || v2==tmp_vertex->next)
-                                               continue;
-                                       test=edge_edge_intersect(v1,v2,tmp_vertex,tmp_vertex->next);
-                                       if(test!=GLU_NO_ERROR)
-                                               break;
-                               }
-                               if(test==GLU_NO_ERROR)
-                               {
-                                       /* does edge (v1,v2) intersect any other hole? */
-                                       for(tmp_hole=hole->next;
-                                               tmp_hole!=NULL && tmp_hole->type==GLU_INTERIOR;
-                                               tmp_hole=tmp_hole->next)
-                                       {
-                                               /* does edge (v1,v2) intersect any edge of hole */
-                                               for(tmp_vertex=tmp_hole->vertices ,
-                                                               tmp_vertex_cnt=tmp_hole->vertex_cnt , k=0;
-                                                       k<tmp_vertex_cnt;
-                                                       tmp_vertex=tmp_vertex->next , k++)
-                                               {
-                                                       test=edge_edge_intersect(v1,v2,tmp_vertex,
-                                                               tmp_vertex->next);
-                                                       if(test!=GLU_NO_ERROR)
-                                                               break;
-                                               }
-                                               if(test!=GLU_NO_ERROR)
-                                                       break;
-                                       }
-                               }
-                       }
-                       if(test==GLU_NO_ERROR)
-                       {
-                               /* edge (v1,v2) is good for eliminating the hole */
-                               if(merge_hole_with_contour(tobj,contour,hole,v1,v2)
-                                       ==GLU_NO_ERROR)
-                                       return GLU_NO_ERROR;
-                               else
-                                       return GLU_ERROR;
-                       }
-               }
-       }
-       /* other holes are blocking all possible connections of hole */
-       /* with contour, we shift this hole as the last hole and retry */
-       for(tmp_hole=hole;
-               tmp_hole!=NULL && tmp_hole->type==GLU_INTERIOR;
-               tmp_hole=tmp_hole->next);
-       contour->next=hole->next;
-       hole->next->previous=contour;
-       if(tmp_hole==NULL)
-       {
-               /* last EXTERIOR contour, shift hole as last contour */
-               hole->next=NULL;
-               hole->previous=tobj->last_contour;
-               tobj->last_contour->next=hole;
-               tobj->last_contour=hole;
-       }
-       else
-       {
-               tmp_hole->previous->next=hole;
-               hole->previous=tmp_hole->previous;
-               tmp_hole->previous=hole;
-               hole->next=tmp_hole;
-       }
-       hole=contour->next;
-       /* try once again - recurse */
-       return cut_out_hole(tobj,contour,hole);
-}
-
-static GLenum merge_hole_with_contour(
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour,
-       tess_contour *hole,
-       tess_vertex *v1,
-       tess_vertex *v2)
-{
-       tess_vertex *v1_new,*v2_new;
-
-       /* make copies of v1 and v2, place them respectively after their originals */
-       if((v1_new=(tess_vertex *)malloc(sizeof(tess_vertex)))==NULL)
-       {
-               tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
-               return GLU_ERROR;
-       }
-       if((v2_new=(tess_vertex *)malloc(sizeof(tess_vertex)))==NULL)
-       {
-               tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
-               return GLU_ERROR;
-       }
-       v1_new->edge_flag=GL_TRUE;
-       v1_new->data=v1->data;
-       v1_new->location[0]=v1->location[0];
-       v1_new->location[1]=v1->location[1];
-       v1_new->location[2]=v1->location[2];
-       v1_new->x=v1->x;
-       v1_new->y=v1->y;
-       v1_new->shadow_vertex=v1;
-       v1->shadow_vertex=v1_new;
-       v1_new->next=v1->next;
-       v1_new->previous=v1;
-       v1->next->previous=v1_new;
-       v1->next=v1_new;
-       v2_new->edge_flag=GL_TRUE;
-       v2_new->data=v2->data;
-       v2_new->location[0]=v2->location[0];
-       v2_new->location[1]=v2->location[1];
-       v2_new->location[2]=v2->location[2];
-       v2_new->x=v2->x;
-       v2_new->y=v2->y;
-       v2_new->shadow_vertex=v2;
-       v2->shadow_vertex=v2_new;
-       v2_new->next=v2->next;
-       v2_new->previous=v2;
-       v2->next->previous=v2_new;
-       v2->next=v2_new;
-       /* link together the two lists */
-       v1->next=v2_new;
-       v2_new->previous=v1;
-       v2->next=v1_new;
-       v1_new->previous=v2;
-       /* update the vertex count of the contour */
-       contour->vertex_cnt += hole->vertex_cnt+2;
-       /* remove the INTERIOR contour */
-       contour->next=hole->next;
-       if(hole->next!=NULL)
-               hole->next->previous=contour;
-       free(hole);
-       /* update tobj structure */
-       --(tobj->contour_cnt);
-       if(contour->last_vertex==v1)
-               contour->last_vertex=v1_new;
-       /* mark two vertices with edge_flag */
-       v2->edge_flag=GL_FALSE;
-       v1->edge_flag=GL_FALSE;
-       return GLU_NO_ERROR;
-}
index c773fbaae4b2d3b62ebd82b79e2f69e7d322ab07..c2e0e1cd988d9f8bbb009943bf86a7462a534aba 100644 (file)
-/* $Id: tess.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+/* $Id: tess.c,v 1.2 1999/09/10 02:03:31 gareth 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.
+ * 
+ * Copyright (C) 1999  Brian Paul   All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-
-/*
- * $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
+ * GLU 1.3 Polygon Tessellation by Gareth Hughes <garethh@lucent.com>
  *
- * 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
+ *****************************************************************************/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glu.h>
+
+#include "tess.h"
+#include "tess_macros.h"
+#include "tess_fist.h"
+#if 0
+#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 );
+
+static void delete_current_contour( GLUtesselator *tobj );
+static void delete_all_contours( GLUtesselator *tobj );
+
+#define TESS_CHECK_ERRORS(t)   if ( (t)->error != GLU_NO_ERROR ) goto cleanup
+
+int    tess_debug_level = 0;
+GLdouble origin[3] = { 0.0, 0.0, 0.0 };
+
+
+/*****************************************************************************
  *
- * Revision 1.1  1996/09/27 01:19:39  brianp
- * Initial revision
+ *                     GLU TESSELLATION FUNCTIONS
  *
- */
+ *****************************************************************************/
 
 
-/*
- * This file is part of the polygon tesselation code contributed by
- * Bogdan Sikorski
- */
+/*****************************************************************************
+ * gluNewTess
+ *****************************************************************************/
+GLUtesselator* GLAPIENTRY gluNewTess( void )
+{
+    GLUtesselator *tobj;
 
+    if ( ( tobj = (GLUtesselator *)
+          malloc( sizeof(GLUtesselator) ) ) == NULL )
+    {
+       return NULL;
+    }
 
-#ifdef PC_HEADER
-#include "all.h"
-#else
-#include <math.h>
-#include <stdlib.h>
-#include "tess.h"
-#endif
+    init_callbacks( &tobj->callbacks );
 
+    tobj->boundary_only = GL_FALSE;
+    tobj->winding_rule = GLU_TESS_WINDING_ODD;
+    tobj->tolerance = 0.0;
 
-/*
- * 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
+    tobj->plane.normal[X] = 0.0;
+    tobj->plane.normal[Y] = 0.0;
+    tobj->plane.normal[Z] = 0.0;
+    tobj->plane.dist = 0.0;
 
+    tobj->contour_count = 0;
+    tobj->contours = tobj->last_contour = NULL;
+    tobj->current_contour = NULL;
 
-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 *);
+    CLEAR_BBOX_2DV( tobj->mins, tobj->maxs );
 
-#ifdef __CYGWIN32__
-#define _CALLBACK
-#else
-#define _CALLBACK GLCALLBACK
+    tobj->vertex_count = 0;
+    tobj->sorted_vertices = NULL;
+#if 0
+    tobj->grid = NULL;
 #endif
 
-void init_callbacks(tess_callbacks *callbacks)
+    tobj->error = GLU_NO_ERROR;
+
+    return tobj;
+}
+
+
+/*****************************************************************************
+ * gluDeleteTess
+ *****************************************************************************/
+void GLAPIENTRY gluDeleteTess( GLUtesselator *tobj )
 {
-   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;
+    DEBUGP(2, ("-> gluDeleteTess(tobj: %p)\n", tobj));
+
+    if ( tobj->error == GLU_NO_ERROR && ( tobj->contour_count > 0 ) )
+    {
+       /* Was gluEndContour called? */
+       tess_error_callback( tobj, GLU_TESS_ERROR4, NULL );
+    }
+
+    /* Delete all internal structures */
+    tess_cleanup( tobj );
+    free( tobj );
+
+    DEBUGP(2, ("<- gluDeleteTess()\n\n"));
 }
 
-void tess_call_user_error(GLUtriangulatorObj *tobj, GLenum gluerr)
+
+/*****************************************************************************
+ * gluTessBeginPolygon
+ *****************************************************************************/
+void GLAPIENTRY gluTessBeginPolygon( GLUtesselator *tobj, void *polygon_data )
 {
-   if(tobj->error==GLU_NO_ERROR)
-      tobj->error=gluerr;
-   if(tobj->callbacks.error!=NULL)
-      (tobj->callbacks.error)(gluerr);
+    DEBUGP(2, ("-> 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_ERROR1, NULL );
+
+       tess_cleanup( tobj );
+    }
+
+    DEBUGP(2, ("<- gluTessBeginPolygon(tobj: %p)\n\n", tobj));
 }
 
-GLUtriangulatorObj* GLAPIENTRY gluNewTess( void )
+
+/*****************************************************************************
+ * gluTessBeginContour
+ *****************************************************************************/
+void GLAPIENTRY gluTessBeginContour( GLUtesselator *tobj )
 {
-   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;
+    DEBUGP(2, ("  -> gluTessBeginContour(tobj: %p)\n", tobj));
+    TESS_CHECK_ERRORS( tobj );
+
+    if ( tobj->current_contour != NULL )
+    {
+       tess_error_callback( tobj, GLU_TESS_ERROR2, NULL );
+       return;
+    }
+
+    if ( ( tobj->current_contour =
+          (tess_contour_t *) malloc( sizeof(tess_contour_t) ) ) == NULL )
+    {
+       tess_error_callback( tobj, GLU_OUT_OF_MEMORY, NULL );
+       return;
+    }
+
+    COPY_3V( tobj->plane.normal, tobj->current_contour->plane.normal );
+    tobj->current_contour->plane.dist = tobj->plane.dist;
+
+    tobj->current_contour->vertex_count = 0;
+    tobj->current_contour->vertices =
+       tobj->current_contour->last_vertex = NULL;
+
+    tobj->current_contour->reflex_count = 0;
+    tobj->current_contour->reflex_vertices =
+       tobj->current_contour->last_reflex = NULL;
+
+    tobj->current_contour->orientation = GLU_UNKNOWN;
+    tobj->current_contour->area = 0.0;
+
+    tobj->current_contour->winding = 0;
+    CLEAR_BBOX_2DV( tobj->current_contour->mins,
+                   tobj->current_contour->maxs );
+
+ cleanup:
+    DEBUGP(2, ("  <- gluTessBeginContour(tobj: %p)\n\n", tobj));
+    return;
 }
 
 
-void GLAPIENTRY gluTessCallback( GLUtriangulatorObj *tobj, GLenum which,
-                               void (GLCALLBACK *fn)() )
+/*****************************************************************************
+ * gluTessVertex
+ *****************************************************************************/
+void GLAPIENTRY gluTessVertex( GLUtesselator *tobj, GLdouble coords[3],
+                              void *vertex_data )
 {
-       switch(which)
+    tess_contour_t             *current = tobj->current_contour;
+    tess_vertex_t              *last_vertex;
+
+    DEBUGP(2, ("    -> gluTessVertex(tobj: %p, (%.2f, %.2f, %.2f))\n",
+              tobj, coords[X], coords[Y], coords[Z]));
+    TESS_CHECK_ERRORS( tobj );
+
+    if ( current == NULL ) {
+       tess_error_callback( tobj, GLU_TESS_ERROR2, NULL );
+       return;
+    }
+
+    tobj->vertex_count++;
+
+    last_vertex = current->last_vertex;
+
+    if ( last_vertex == NULL )
+    {
+       if ( ( last_vertex = (tess_vertex_t *)
+              malloc( sizeof(tess_vertex_t) ) ) == NULL )
        {
-               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;
+           tess_error_callback( tobj, GLU_OUT_OF_MEMORY, NULL );
+           return;
        }
-}
 
+       current->vertices = last_vertex;
+       current->last_vertex = last_vertex;
+
+       last_vertex->index = -1;
+       last_vertex->data = vertex_data;
+
+       last_vertex->coords[X] = coords[X];
+       last_vertex->coords[Y] = coords[Y];
+       last_vertex->coords[Z] = coords[Z];
+
+       last_vertex->next = NULL;
+       last_vertex->previous = NULL;
+
+       current->vertex_count++;
+    }
+    else
+    {
+       tess_vertex_t   *vertex;
+
+       if ( ( vertex = (tess_vertex_t *)
+              malloc( sizeof(tess_vertex_t) ) ) == NULL )
+       {
+           tess_error_callback( tobj, GLU_OUT_OF_MEMORY, NULL );
+           return;
+       }
+
+       vertex->index = -1;
+       vertex->data = vertex_data;
+
+       vertex->coords[X] = coords[X];
+       vertex->coords[Y] = coords[Y];
+       vertex->coords[Z] = coords[Z];
+
+       vertex->next = NULL;
+       vertex->previous = last_vertex;
 
+       current->vertex_count++;
+
+       last_vertex->next = vertex;
+       current->last_vertex = vertex;
+    }
+
+    DEBUGP(3, ("\t     vertex: (%.2f, %.2f, %.2f)\n",
+              current->last_vertex->coords[X],
+              current->last_vertex->coords[Y],
+              current->last_vertex->coords[Z]));
+ cleanup:
+    DEBUGP(2, ("    <- gluTessVertex(tobj: %p)\n", tobj));
+    return;
+}
 
-void GLAPIENTRY gluDeleteTess( GLUtriangulatorObj *tobj )
+
+/*****************************************************************************
+ * gluTessEndContour
+ *****************************************************************************/
+void GLAPIENTRY gluTessEndContour( GLUtesselator *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);
+    DEBUGIF(2) fprintf( stderr, "\n" ); DEBUGENDIF;
+    DEBUGP(2, ("  -> gluTessEndContour(tobj: %p)\n", tobj));
+
+    TESS_CHECK_ERRORS( tobj );
+
+    if ( tobj->current_contour == NULL ) {
+       tess_error_callback( tobj, GLU_TESS_ERROR2, NULL );
+       return;
+    }
+
+    if ( tobj->current_contour->vertex_count > 0 )
+    {
+       inspect_current_contour( tobj );
+    }
+
+ cleanup:
+    DEBUGP(2, ("  <- gluTessEndContour(tobj: %p)\n\n", tobj));
+    return;
 }
 
 
-void GLAPIENTRY gluBeginPolygon( GLUtriangulatorObj *tobj )
+/*****************************************************************************
+ * gluTessEndPolygon
+ *****************************************************************************/
+void GLAPIENTRY gluTessEndPolygon( GLUtesselator *tobj )
 {
-/*
-       if(tobj->error!=GLU_NO_ERROR)
-               return;
-*/
-        tobj->error = GLU_NO_ERROR;
-       if(tobj->current_polygon!=NULL)
+    DEBUGP(2, ("-> gluTessEndPolygon(tobj: %p)\n", tobj));
+    TESS_CHECK_ERRORS( tobj );
+
+    /*
+     * Ensure gluTessBeginPolygon was called, otherwise we can't do anything.
+     */
+    if ( tobj->current_contour != NULL ) {
+       tess_error_callback( tobj, GLU_TESS_ERROR2, NULL );
+       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 )
+    {
+       DEBUGP(2, ("  contour count: 0\n"));
+
+       tess_cleanup( tobj );
+       return;
+    }
+
+    /* Wrap the contour list. */
+
+    tobj->last_contour->next = tobj->contours;
+    tobj->contours->previous = tobj->last_contour;
+
+    /* tess_find_contour_hierarchies(tobj); */
+
+    TESS_CHECK_ERRORS( tobj );
+
+    /* tess_handle_holes(tobj); */
+
+    TESS_CHECK_ERRORS( tobj );
+
+    /*
+     * 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 ) ) )
+    {
+       if ( ( tobj->callbacks.edgeFlag == NULL ) &&
+            ( tobj->callbacks.edgeFlagData == NULL ) )
        {
-               /* gluEndPolygon was not called */
-               tess_call_user_error(tobj,GLU_TESS_ERROR1);
-               /* delete all internal structures */
-               delete_contours(tobj);
+           fist_tessellation( 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;
+           fist_tessellation( tobj );
        }
+    }
+
+ cleanup:
+    delete_all_contours( tobj );
+
+    DEBUGP(2, ("<- gluTessEndPolygon(tobj: %p)\n\n", tobj));
 }
 
 
-void GLAPIENTRY gluEndPolygon( GLUtriangulatorObj *tobj )
+/*****************************************************************************
+ * gluTessCallback
+ *****************************************************************************/
+void GLAPIENTRY gluTessCallback( GLUtesselator *tobj, GLenum which,
+                                void (GLCALLBACK *fn)() )
 {
-       /*tess_contour *contour_ptr;*/
+    switch ( which )
+    {
+       /* Register the begin callbacks. */
+    case GLU_TESS_BEGIN:
+       tobj->callbacks.begin = (void (GLCALLBACK*)(GLenum)) fn;
+       break;
+    case GLU_TESS_BEGIN_DATA:
+       tobj->callbacks.beginData = (void (GLCALLBACK*)(GLenum, void *)) fn;
+       break;
+
+       /* Register the edge flag callbacks. */
+    case GLU_TESS_EDGE_FLAG:
+       tobj->callbacks.edgeFlag = (void (GLCALLBACK*)(GLboolean)) fn;
+       break;
+    case GLU_TESS_EDGE_FLAG_DATA:
+       tobj->callbacks.edgeFlagData =
+           (void (GLCALLBACK*)(GLboolean, void *)) fn;
+       break;
+
+       /* Register the vertex callbacks. */
+    case GLU_TESS_VERTEX:
+       tobj->callbacks.vertex = (void (GLCALLBACK*)(void *)) fn;
+       break;
+    case GLU_TESS_VERTEX_DATA:
+       tobj->callbacks.vertexData = (void (GLCALLBACK*)(void *, void *)) fn;
+       break;
+
+       /* Register the end callbacks. */
+    case GLU_TESS_END:
+       tobj->callbacks.end = (void (GLCALLBACK*)(void)) fn;
+       break;
+    case GLU_TESS_END_DATA:
+       tobj->callbacks.endData = (void (GLCALLBACK*)(void *)) fn;
+       break;
+
+       /* Register the error callbacks. */
+    case GLU_TESS_ERROR:
+       tobj->callbacks.error = (void (GLCALLBACK*)(GLenum)) fn;
+       break;
+    case GLU_TESS_ERROR_DATA:
+       tobj->callbacks.errorData = (void (GLCALLBACK*)(GLenum, void *)) fn;
+       break;
+
+       /* Register the combine callbacks. */
+    case GLU_TESS_COMBINE:
+       tobj->callbacks.combine =
+           (void (GLCALLBACK*)(GLdouble[3], void *[4],
+                               GLfloat [4], void **)) fn;
+       break;
+    case GLU_TESS_COMBINE_DATA:
+       tobj->callbacks.combineData =
+           (void (GLCALLBACK*)(GLdouble[3], void *[4], GLfloat [4],
+                               void **, void *)) fn;
+       break;
+
+    default:
+       tobj->error = GLU_INVALID_ENUM;
+       break;
+    }
+}
 
-       /* 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;
+/*****************************************************************************
+ * gluTessProperty
+ *
+ * Set the current value of the given property.
+ *****************************************************************************/
+void GLAPIENTRY gluTessProperty( GLUtesselator *tobj, GLenum which,
+                                GLdouble value )
+{
+    switch ( which )
+    {
+    case GLU_TESS_BOUNDARY_ONLY:
+       tobj->boundary_only = (GLboolean) value;
+       break;
+
+    case GLU_TESS_TOLERANCE:
+       tobj->tolerance = value;
+       break;
+
+    case GLU_TESS_WINDING_RULE:
+       tobj->winding_rule = (GLenum) value;
+       break;
+
+    default:
+       tobj->error = GLU_INVALID_ENUM;
+       break;
+    }
+}
 
-       /* 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;
+/*****************************************************************************
+ * gluGetTessProperty
+ *
+ * Return the current value of the given property.
+ *****************************************************************************/
+void GLAPIENTRY gluGetTessProperty( GLUtesselator *tobj, GLenum which,
+                                   GLdouble *value )
+{
+    switch ( which )
+    {
+    case GLU_TESS_BOUNDARY_ONLY:
+       *value = tobj->boundary_only;
+       break;
+
+    case GLU_TESS_TOLERANCE:
+       *value = tobj->tolerance;
+       break;
+
+    case GLU_TESS_WINDING_RULE:
+       *value = tobj->winding_rule;
+       break;
+
+    default:
+       tobj->error = GLU_INVALID_ENUM;
+       break;
+    }
+}
+
+
+/*****************************************************************************
+ * gluTessNormal
+ *
+ * Set the current tessellation normal.
+ *****************************************************************************/
+void GLAPIENTRY gluTessNormal( GLUtesselator *tobj, GLdouble x,
+                              GLdouble y, GLdouble z )
+{
+    tobj->plane.normal[X] = x;
+    tobj->plane.normal[Y] = y;
+    tobj->plane.normal[Z] = z;
+}
 
-       /* 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);
+
+/*****************************************************************************
+ *
+ *                     OBSOLETE TESSELLATION FUNCTIONS
+ *
+ *****************************************************************************/
+
+void GLAPIENTRY gluBeginPolygon( GLUtesselator *tobj )
+{
+    gluTessBeginPolygon( tobj, NULL );
+    gluTessBeginContour( tobj );
 }
 
+void GLAPIENTRY gluNextContour( GLUtesselator *tobj, GLenum type )
+{
+    gluTessEndContour( tobj );
+    gluTessBeginContour( tobj );
+}
 
-void GLAPIENTRY gluNextContour( GLUtriangulatorObj *tobj, GLenum type )
+void GLAPIENTRY gluEndPolygon( GLUtesselator *tobj )
 {
-       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);
+    gluTessEndContour( tobj );
+    gluTessEndPolygon( tobj );
 }
 
 
-void GLAPIENTRY gluTessVertex( GLUtriangulatorObj *tobj, GLdouble v[3], void *data )
+
+/*****************************************************************************
+ * tess_error_callback
+ *
+ * Internal error handler.  Call the user-registered error callback.
+ *****************************************************************************/
+void tess_error_callback( GLUtesselator *tobj, GLenum errno, void *data )
 {
-       tess_polygon *polygon=tobj->current_polygon;
-       tess_vertex *last_vertex_ptr;
+    if ( tobj->error == GLU_NO_ERROR )
+    {
+       tobj->error = errno;
+    }
+
+    if ( tobj->callbacks.errorData != NULL )
+    {
+       ( tobj->callbacks.errorData )( errno, data );
+    }
+    else if ( tobj->callbacks.error != NULL )
+    {
+       ( tobj->callbacks.error )( errno );
+    }
+}
 
-       if(tobj->error!=GLU_NO_ERROR)
-               return;
-       if(polygon==NULL)
-       {
-               tess_call_user_error(tobj,GLU_TESS_ERROR2);
-               return;
+
+
+/*****************************************************************************
+ *
+ *                             INTERNAL FUNCTIONS
+ *
+ *****************************************************************************/
+
+
+/*****************************************************************************
+ * init_callbacks
+ *****************************************************************************/
+static void init_callbacks( tess_callbacks_t *callbacks )
+{
+    callbacks->begin           = ( void (GLCALLBACK*)(GLenum) ) NULL;
+    callbacks->beginData = ( void (GLCALLBACK*)(GLenum, void *) ) NULL;
+    callbacks->edgeFlag                = ( void (GLCALLBACK*)(GLboolean) ) NULL;
+    callbacks->edgeFlagData    = ( void (GLCALLBACK*)(GLboolean, void *) ) NULL;
+    callbacks->vertex          = ( void (GLCALLBACK*)(void *) ) NULL;
+    callbacks->vertexData      = ( void (GLCALLBACK*)(void *, void *) ) NULL;
+    callbacks->end             = ( void (GLCALLBACK*)(void) ) NULL;
+    callbacks->endData = ( void (GLCALLBACK*)(void *) ) NULL;
+    callbacks->error           = ( void (GLCALLBACK*)(GLenum) ) NULL;
+    callbacks->errorData       = ( void (GLCALLBACK*)(GLenum, void *) ) NULL;
+    callbacks->combine         = ( void (GLCALLBACK*)(GLdouble [3], void *[4],
+                                                      GLfloat [4], void **) ) NULL;
+    callbacks->combineData     = ( void (GLCALLBACK*)(GLdouble [3], void *[4],
+                                                      GLfloat [4], void **,
+                                                      void *) ) NULL;
+}
+
+
+/*****************************************************************************
+ * tess_cleanup
+ *****************************************************************************/
+static void tess_cleanup( GLUtesselator *tobj )
+{
+    DEBUGP(3, ("  -> tess_cleanup(tobj: %p)\n", tobj));
+
+    if ( tobj->current_contour != NULL )
+    {
+       delete_current_contour( tobj );
+    }
+
+    if ( tobj->contours != NULL )
+    {
+       delete_all_contours( tobj );
+    }
+
+    DEBUGP(3, ("  <- tess_cleanup(tobj: %p)\n", tobj));
+}
+
+
+/*****************************************************************************
+ * inspect_current_contour
+ *****************************************************************************/
+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 )
+{
+    tess_contour_t *current = tobj->current_contour;
+
+    DEBUGP(3, ("    -> inspect_current_contour(tobj: %p)\n", tobj));
+
+    if ( current->vertex_count < 3 )
+    {
+       delete_current_contour( tobj );
+       return;
+    }
+
+    current->last_vertex->next = current->vertices;
+    current->vertices->previous = current->last_vertex;
+
+    if ( ( tobj->contours == NULL ) &&
+        ( COMPARE_3DV( current->plane.normal, origin ) ) )
+    {
+       /* We haven't been given a normal, so let's take a guess. */
+       if ( find_normal( tobj ) == GLU_ERROR ) {
+           return;
        }
-       last_vertex_ptr=polygon->last_vertex;
-       if(last_vertex_ptr==NULL)
+       COPY_3V( current->plane.normal, tobj->plane.normal );
+       tobj->plane.dist = current->plane.dist;
+    }
+
+    project_current_contour( tobj );
+
+    if ( save_current_contour( tobj ) == GLU_ERROR ) {
+       return;
+    }
+
+    DEBUGP(3, ("    <- inspect_current_contour(tobj: %p)\n", tobj));
+}
+
+/*****************************************************************************
+ * 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];
+
+    DEBUGP(3, ("      -> 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 ( COMPARE_3DV( va->coords, vb->coords ) && ( vb != va ) ) {
+       vb = vb->next;
+    }
+
+    if ( vb == va ) {
+       tess_error_callback( tobj, GLU_TESS_ERROR7, NULL );
+    }
+
+    SUB_3V( a, vb->coords, va->coords );
+
+    for ( vc = vb->next; vc != va; vc = vc->next )
+    {
+       SUB_3V( b, vc->coords, va->coords );
+
+       CROSS3( c, a, b );
+
+       if ( ( fabs( c[X] ) > EQUAL_EPSILON ) ||
+            ( fabs( c[Y] ) > EQUAL_EPSILON ) ||
+            ( fabs( c[Z] ) > EQUAL_EPSILON ) )
        {
-               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);
+           COPY_3V( contour->plane.normal, c );
+           NORMALIZE_3DV( contour->plane.normal );
+
+           contour->plane.dist = - DOT3( contour->plane.normal, va->coords );
+
+           DEBUGP(3, ("      <- find_normal(tobj: %p) (%.2f, %.2f, %.2f)\n",
+                      tobj, contour->plane.normal[X],
+                      contour->plane.normal[Y], contour->plane.normal[Z]));
+           return GLU_NO_ERROR;
        }
        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;
+           DEBUGP(3, ("        *** skipping colinear points...\n"));
        }
+    }
+    tess_error_callback( tobj, GLU_TESS_ERROR7, NULL );
+
+    DEBUGP(3, ("      <- find_normal(tobj: %p) ERROR\n", tobj));
+    return GLU_ERROR;
 }
 
+/*****************************************************************************
+ * project_current_contour
+ *****************************************************************************/
+static GLdouble                twice_contour_area( tess_vertex_t *vertex,
+                                           tess_vertex_t *last_vertex );
 
-static void delete_contours(GLUtriangulatorObj *tobj)
+static void project_current_contour( GLUtesselator *tobj )
 {
-       tess_polygon *polygon=tobj->current_polygon;
-       tess_contour *contour,*contour_tmp;
-       tess_vertex *vertex,*vertex_tmp;
+    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;
 
-       /* 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;)
+    DEBUGP(3, ("      -> project_current_contour(tobj: %p)\n", tobj));
+
+    if ( current == NULL ) { return; }
+
+    DEBUGP(3, ("           normal: (%.2f, %.2f, %.2f) dist: %.2f n: %u\n",
+              current->plane.normal[X], current->plane.normal[Y],
+              current->plane.normal[Z], current->plane.dist,
+              current->vertex_count));
+
+    /* 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 = DOT3( znormal, zaxis );
+    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 = DOT3( xnormal, zaxis );
+    rotx = acos( dot );
+
+    for ( vertex = current->vertices, i = 0;
+         i < current->vertex_count; vertex = vertex->next, i++ )
+    {
+       tess_plane_t    *plane = &current->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 );
+
+       DEBUGP(3, ("           v %d: (%.2f, %.2f, %.2f) -> (%.2f, %.2f)\n",
+                  i, vertex->coords[X], vertex->coords[Y],
+                  vertex->coords[Z], vertex->v[X], vertex->v[Y]));
+    }
+
+    area = twice_contour_area( current->vertices,
+                              current->last_vertex );
+    if ( area >= 0.0 )
+    {
+       current->orientation = GLU_CCW;
+       current->area = area;
+    }
+    else
+    {
+       current->orientation = GLU_CW;
+       current->area = -area;
+    }
+
+    DEBUGP(3, ("      <- project_current_contour(tobj: %p)\n", tobj));
+}
+
+/*****************************************************************************
+ * twice_contour_area
+ *****************************************************************************/
+static GLdouble twice_contour_area( tess_vertex_t *vertex,
+                                   tess_vertex_t *last_vertex )
+{
+    tess_vertex_t      *next;
+    GLdouble           area, x, y;
+
+    area = 0.0;
+
+    x = vertex->v[X];
+    y = vertex->v[Y];
+
+    vertex = vertex->next;
+
+    while ( vertex != last_vertex )
+    {
+       next = vertex->next;
+       area +=
+           (vertex->v[X] - x) * (next->v[Y] - y) -
+           (vertex->v[Y] - y) * (next->v[X] - x);
+
+       vertex = vertex->next;
+    }
+    return area;
+}
+
+
+/*****************************************************************************
+ * save_current_contour
+ *****************************************************************************/
+static GLenum save_current_contour( GLUtesselator *tobj )
+{
+    tess_contour_t     *current = tobj->current_contour;
+    tess_vertex_t      *vertex;
+    GLuint                     i;
+
+    DEBUGP(3, ("      -> save_current_contour(tobj: %p)\n", tobj));
+
+    if ( current == NULL ) { return GLU_ERROR; }
+
+    if ( tobj->contours == NULL )
+    {
+       tobj->contours = tobj->last_contour = current;
+       current->next = current->previous = NULL;
+    }
+    else
+    {
+       current->previous = tobj->last_contour;
+
+       tobj->last_contour->next = current;
+       tobj->last_contour = current;
+
+       current->next = NULL;
+    }
+
+    for ( vertex = current->vertices, i = 0;
+         i < current->vertex_count; vertex = vertex->next, i++ )
+    {
+       vertex->shadow_vertex = NULL;
+       vertex->edge_flag = GL_TRUE;
+    }
+
+    current->type = GLU_UNKNOWN;
+
+    tobj->contour_count++;
+    tobj->current_contour = NULL;
+
+    DEBUGP(3, ("      <- save_current_contour()\n"));
+    return GLU_NO_ERROR;
+}
+
+/*****************************************************************************
+ * delete_current_contour
+ *****************************************************************************/
+static void delete_current_contour( GLUtesselator *tobj )
+{
+    tess_contour_t     *current = tobj->current_contour;
+    tess_vertex_t      *vertex, *next;
+    GLuint                     i;
+
+    DEBUGP(3, ("  -> delete_current_contour(contour: %p)\n", current));
+
+    if ( current == NULL ) { return; }
+
+    for ( vertex = current->vertices, i = 0; i < current->vertex_count; i++)
+    {
+       next = vertex->next;
+       free( vertex );
+       vertex = next;
+    }
+
+    free( current );
+    tobj->current_contour = NULL;
+
+    DEBUGP(3, ("  <- delete_current_contour()\n"));
+}
+
+/*****************************************************************************
+ * delete_all_contours
+ *****************************************************************************/
+static void delete_all_contours( GLUtesselator *tobj )
+{
+    tess_contour_t     *current = tobj->current_contour, *next_contour;
+    tess_vertex_t      *vertex, *next_vertex;
+    GLuint                     i;
+
+    DEBUGP(3, ("  -> delete_all_contours(tobj: %p)\n", tobj));
+
+    if ( current != NULL )
+    {
+       delete_current_contour( tobj );
+    }
+
+    for ( current = tobj->contours, i = 0; i < tobj->contour_count; i++ )
+    {
+       vertex = current->vertices;
+
+       while ( vertex != current->last_vertex )
        {
-               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;
+           next_vertex = vertex->next;
+           free( vertex );
+           vertex = next_vertex;
        }
-       tobj->contours=tobj->last_contour=NULL;
-       tobj->contour_cnt=0;
+       free( 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 );
+
+    ZERO_3V( tobj->plane.normal );
+    tobj->plane.dist = 0.0;
+
+    DEBUGP(3, ("  <- delete_all_contours(tobj: %p)\n", tobj));
 }
 
 
 
+/*****************************************************************************
+ * Debugging output
+ *****************************************************************************/
+#ifdef _DEBUG
+int vdebugstr( char *format_str, ... )
+{
+    va_list ap;
+    va_start( ap, format_str );
+
+    vfprintf( stderr, format_str, ap );
+    va_end( ap );
+    return 0;
+}
+#endif
index 53d673ccbea5c33379cd6b0ea4bb636b9d391308..fe8296c976cb2f1973ad4e84b53947aaf878d9e3 100644 (file)
-/* $Id: tess.h,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+/* $Id: tess.h,v 1.2 1999/09/10 02:03:31 gareth Exp $ */
 
 /*
  * Mesa 3-D graphics library
  * Version:  3.1
- * Copyright (C) 1995-1998  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.
+ * 
+ * Copyright (C) 1999  Brian Paul   All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-
-/*
- * $Log: tess.h,v $
- * Revision 1.1  1999/08/19 00:55:42  jtg
- * Initial revision
- *
- * Revision 1.5  1999/02/27 13:55:31  brianp
- * fixed BeOS-related GLU typedef problems
- *
- * Revision 1.4  1999/01/03 03:23:15  brianp
- * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
- *
- * Revision 1.3  1997/10/29 02:02:20  brianp
- * various MS Windows compiler changes (David Bucciarelli, v20 3dfx driver)
+/*****************************************************************************
  *
- * Revision 1.2  1997/05/24 13:30:58  brianp
- * added TESS_H multi-inclusion prevention test
+ * GLU 1.3 Polygon Tessellation by Gareth Hughes <garethh@lucent.com>
  *
- * 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
- */
-
+ *****************************************************************************/
 
-#ifndef TESS_H
-#define TESS_H
+#ifndef __GLU_TESS_H__
+#define __GLU_TESS_H__
 
+#include <stdarg.h>
+#include <stdio.h>
 
 #include "gluP.h"
 
-#define EPSILON 1e-06 /* epsilon for double precision compares */
-
-typedef enum
-{
-       OXY,
-       OYZ,
-       OXZ
-} projection_type;
-
-typedef struct callbacks_str
-{
-       void (GLCALLBACK *begin)( GLenum mode );
-       void (GLCALLBACK *edgeFlag)( GLboolean flag );
-       void (GLCALLBACK *vertex)( GLvoid *v );
-       void (GLCALLBACK *end)( void );
-       void (GLCALLBACK *error)( GLenum err );
-} tess_callbacks;
-
-typedef struct vertex_str
-{
-       void                            *data;
-       GLdouble                        location[3];
-       GLdouble                        x,y;
-       GLboolean                       edge_flag;
-       struct vertex_str       *shadow_vertex;
-       struct vertex_str       *next,*previous;
-} tess_vertex;
-
-typedef struct contour_str
-{
-       GLenum                          type;
-       GLuint                          vertex_cnt;
-       GLdouble                        area;
-       GLenum                          orientation;
-       struct vertex_str       *vertices,*last_vertex;
-       struct contour_str      *next,*previous;
-} tess_contour;
+#include "tess_typedefs.h"
+#include "tess_heap.h"
+#if 0
+#include "tess_grid.h"
+#endif
 
-typedef struct polygon_str
-{
-       GLuint                          vertex_cnt;
-       GLdouble                        A,B,C,D;
-       GLdouble                        area;
-       GLenum                          orientation;
-       struct vertex_str       *vertices,*last_vertex;
-} tess_polygon;
+#ifdef __cplusplus
+extern "C" {
+#endif
 
+/*****************************************************************************
+ * The GLUtesselator structure:
+ *****************************************************************************/
 struct GLUtesselator
 {
-       tess_contour            *contours,*last_contour;
-       GLuint                          contour_cnt;
-       tess_callbacks          callbacks;
-       tess_polygon            *current_polygon;
-       GLenum                          error;
-       GLdouble                        A,B,C,D;
-       projection_type         projection;
+    tess_callbacks_t   callbacks;
+    GLboolean          boundary_only;
+    GLenum             winding_rule;
+    GLdouble           tolerance;
+    tess_plane_t       plane;
+    GLuint             contour_count;
+    tess_contour_t     *contours, *last_contour;
+    tess_contour_t     *current_contour;
+    GLdouble           mins[2], maxs[2];
+    GLuint             vertex_count;
+    tess_vertex_t      **sorted_vertices;
+#if 0
+    tess_grid_t                *grid;                  /* Not currently used... */
+#endif
+    heap_t             *heap;
+    GLenum             error;
 };
 
 
-extern void tess_call_user_error(GLUtriangulatorObj *,GLenum);
-
+/*****************************************************************************
+ * Tessellation error handler:
+ *****************************************************************************/
+extern void tess_error_callback( GLUtesselator *, GLenum, void * );
+
+
+/*****************************************************************************
+ * Debugging output:  (to be removed...)
+ *****************************************************************************/
+extern int     tess_debug_level;
+int vdebugstr( char *format_str, ... );
+
+#ifdef _DEBUG
+#define DEBUGP(level, body)                                            \
+    do {                                                               \
+       if ( tess_debug_level >= level ) {                              \
+           vdebugstr( "%11.11s:%-5d ", __FILE__, __LINE__, level );    \
+           vdebugstr body;                                             \
+           fflush ( stderr );                                          \
+       }                                                               \
+    } while ( 0 )
+#define DEBUGIF(level)          do { if ( tess_debug_level >= level ) {
+#define DEBUGENDIF              } } while ( 0 )
+#else
+#define DEBUGP(level, body)
+#define DEBUGIF(level)         while(0) {
+#define DEBUGENDIF             }
+#endif
 
+#ifdef __cplusplus
+}
 #endif
+
+#endif // __GLU_TESS_H__
diff --git a/src/glu/mesa/tesselat.c b/src/glu/mesa/tesselat.c
deleted file mode 100644 (file)
index 1e424c1..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-/* $Id: tesselat.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
-
-/*
- * Mesa 3-D graphics library
- * Version:  2.4
- * Copyright (C) 1995-1997  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: tesselat.c,v $
- * Revision 1.1  1999/08/19 00:55:42  jtg
- * Initial revision
- *
- * 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  1997/02/17 17:24:58  brianp
- * more tesselation changes (Randy Frank)
- *
- * Revision 1.2  1997/02/13 18:31:57  brianp
- * fixed some numerical precision problems (Randy Frank)
- *
- * 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 <stdlib.h>
-#include <math.h>
-#include "tess.h"
-#endif
-
-
-
-static GLboolean edge_flag;
-
-static void emit_triangle(GLUtriangulatorObj *, tess_vertex *,
-       tess_vertex *,tess_vertex *);
-
-static void emit_triangle_with_edge_flag(GLUtriangulatorObj *,
-        tess_vertex *,GLboolean,tess_vertex *,GLboolean,
-        tess_vertex *,GLboolean);
-
-static GLdouble twice_the_triangle_area(
-       tess_vertex *va,
-       tess_vertex *vb,
-       tess_vertex *vc)
-{
-       return   (vb->x - va->x)*(vc->y - va->y) - (vb->y - va->y)*(vc->x - va->x);
-}
-
-static GLboolean left(
-       GLdouble A,
-       GLdouble B,
-       GLdouble C,
-       GLdouble x,
-       GLdouble y)
-{
-       if(A*x+B*y+C > -EPSILON)
-               return GL_TRUE;
-       else
-               return GL_FALSE;
-}
-
-static GLboolean right(
-       GLdouble A,
-       GLdouble B,
-       GLdouble C,
-       GLdouble x,
-       GLdouble y)
-{
-       if(A*x+B*y+C < EPSILON)
-               return GL_TRUE;
-       else
-               return GL_FALSE;
-}
-
-static GLint convex_ccw(
-       tess_vertex *va,
-       tess_vertex *vb,
-       tess_vertex *vc,
-       GLUtriangulatorObj *tobj)
-{
-       GLdouble        d;
-
-       d = twice_the_triangle_area(va,vb,vc);
-
-       if (d > EPSILON ) {
-               return 1;
-       } else if (d < -EPSILON ) {
-               return 0;
-       } else {
-               return -1;
-       }
-}
-
-static GLint convex_cw(
-       tess_vertex *va,
-       tess_vertex *vb,
-       tess_vertex *vc,
-       GLUtriangulatorObj *tobj)
-{
-       GLdouble        d;
-
-       d = twice_the_triangle_area(va,vb,vc);
-
-       if (d < -EPSILON ) {
-               return 1;
-       } else if (d > EPSILON ) {
-               return 0;
-       } else {
-               return -1;
-       }
-}
-
-static GLboolean diagonal_ccw(
-       tess_vertex *va,
-       tess_vertex *vb,
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour)
-{
-       tess_vertex *vc=va->next , *vertex , *shadow_vertex;
-       struct
-       {
-               GLdouble A,B,C;
-       } ac,cb,ba;
-       GLdouble x,y;
-
-       GLint    res = convex_ccw(va,vc,vb,tobj);
-       if (res == 0) return GL_FALSE;
-       if (res == -1) return GL_TRUE;
-
-       ba.A=vb->y - va->y;
-       ba.B=va->x - vb->x;
-       ba.C= -ba.A*va->x - ba.B*va->y;
-       ac.A=va->y - vc->y;
-       ac.B=vc->x - va->x;
-       ac.C= -ac.A*vc->x - ac.B*vc->y;
-       cb.A=vc->y - vb->y;
-       cb.B=vb->x - vc->x;
-       cb.C= -cb.A*vb->x - cb.B*vb->y;
-       for(vertex=vb->next;vertex!=va;vertex=vertex->next)
-       {
-               shadow_vertex=vertex->shadow_vertex;
-               if(shadow_vertex!=NULL && 
-                       (shadow_vertex==va || shadow_vertex==vb || shadow_vertex==vc))
-                       continue;
-               x=vertex->x;
-               y=vertex->y;
-               if(left(ba.A,ba.B,ba.C,x,y) &&
-                       left(ac.A,ac.B,ac.C,x,y) &&
-                       left(cb.A,cb.B,cb.C,x,y))
-                       return GL_FALSE;
-       }
-       return GL_TRUE;
-}
-
-static GLboolean diagonal_cw(
-       tess_vertex *va,
-       tess_vertex *vb,
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour)
-{
-       tess_vertex *vc=va->next , *vertex , *shadow_vertex;
-       struct
-       {
-               GLdouble A,B,C;
-       } ac,cb,ba;
-       GLdouble x,y;
-
-       GLint    res = convex_cw(va,vc,vb,tobj);
-       if (res == 0) return GL_FALSE;
-       if (res == -1) return GL_TRUE;
-
-       ba.A=vb->y - va->y;
-       ba.B=va->x - vb->x;
-       ba.C= -ba.A*va->x - ba.B*va->y;
-       ac.A=va->y - vc->y;
-       ac.B=vc->x - va->x;
-       ac.C= -ac.A*vc->x - ac.B*vc->y;
-       cb.A=vc->y - vb->y;
-       cb.B=vb->x - vc->x;
-       cb.C= -cb.A*vb->x - cb.B*vb->y;
-       for(vertex=vb->next;vertex!=va;vertex=vertex->next)
-       {
-               shadow_vertex=vertex->shadow_vertex;
-               if(shadow_vertex!=NULL && 
-                       (shadow_vertex==va || shadow_vertex==vb || shadow_vertex==vc))
-                       continue;
-               x=vertex->x;
-               y=vertex->y;
-               if(right(ba.A,ba.B,ba.C,x,y) &&
-                       right(ac.A,ac.B,ac.C,x,y) &&
-                       right(cb.A,cb.B,cb.C,x,y))
-                       return GL_FALSE;
-       }
-       return GL_TRUE;
-}
-
-static void clip_ear(
-       GLUtriangulatorObj *tobj,
-       tess_vertex *v,
-       tess_contour *contour)
-{
-       emit_triangle(tobj,v->previous,v,v->next);
-       /* the first in the list */
-       if(contour->vertices==v)
-       {
-               contour->vertices=v->next;
-               contour->last_vertex->next=v->next;
-               v->next->previous=contour->last_vertex;
-       }
-       else
-       /* the last ? */
-       if(contour->last_vertex==v)
-       {
-               contour->vertices->previous=v->previous;
-               v->previous->next=v->next;
-               contour->last_vertex=v->previous;
-       }
-       else
-       {
-               v->next->previous=v->previous;
-               v->previous->next=v->next;
-       }
-       free(v);
-       --(contour->vertex_cnt);
-}
-
-static void clip_ear_with_edge_flag(
-       GLUtriangulatorObj *tobj,
-       tess_vertex *v,
-       tess_contour *contour)
-{
-       emit_triangle_with_edge_flag(tobj,v->previous,v->previous->edge_flag,
-               v,v->edge_flag,v->next,GL_FALSE);
-       v->previous->edge_flag=GL_FALSE;
-       /* the first in the list */
-       if(contour->vertices==v)
-       {
-               contour->vertices=v->next;
-               contour->last_vertex->next=v->next;
-               v->next->previous=contour->last_vertex;
-       }
-       else
-       /* the last ? */
-       if(contour->last_vertex==v)
-       {
-               contour->vertices->previous=v->previous;
-               v->previous->next=v->next;
-               contour->last_vertex=v->previous;
-       }
-       else
-       {
-               v->next->previous=v->previous;
-               v->previous->next=v->next;
-       }
-       free(v);
-       --(contour->vertex_cnt);
-}
-
-static void triangulate_ccw(
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour)
-{
-       tess_vertex *vertex;
-       GLuint vertex_cnt=contour->vertex_cnt;
-
-       while(vertex_cnt > 3)
-       {
-               vertex=contour->vertices;
-               while(diagonal_ccw(vertex,vertex->next->next,tobj,contour)==GL_FALSE &&
-                       tobj->error==GLU_NO_ERROR)
-                       vertex=vertex->next;
-               if(tobj->error!=GLU_NO_ERROR)
-                       return;
-               clip_ear(tobj,vertex->next,contour);
-               --vertex_cnt;
-       }
-}
-
-static void triangulate_cw(
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour)
-{
-       tess_vertex *vertex;
-       GLuint vertex_cnt=contour->vertex_cnt;
-
-       while(vertex_cnt > 3)
-       {
-               vertex=contour->vertices;
-               while(diagonal_cw(vertex,vertex->next->next,tobj,contour)==GL_FALSE &&
-                       tobj->error==GLU_NO_ERROR)
-                       vertex=vertex->next;
-               if(tobj->error!=GLU_NO_ERROR)
-                       return;
-               clip_ear(tobj,vertex->next,contour);
-               --vertex_cnt;
-       }
-}
-
-static void triangulate_ccw_with_edge_flag(
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour)
-{
-       tess_vertex *vertex;
-       GLuint vertex_cnt=contour->vertex_cnt;
-
-       while(vertex_cnt > 3)
-       {
-               vertex=contour->vertices;
-               while(diagonal_ccw(vertex,vertex->next->next,tobj,contour)==GL_FALSE &&
-                       tobj->error==GLU_NO_ERROR)
-                       vertex=vertex->next;
-               if(tobj->error!=GLU_NO_ERROR)
-                       return;
-               clip_ear_with_edge_flag(tobj,vertex->next,contour);
-               --vertex_cnt;
-       }
-}
-
-static void triangulate_cw_with_edge_flag(
-       GLUtriangulatorObj *tobj,
-       tess_contour *contour)
-{
-       tess_vertex *vertex;
-       GLuint vertex_cnt=contour->vertex_cnt;
-
-       while(vertex_cnt > 3)
-       {
-               vertex=contour->vertices;
-               while(diagonal_cw(vertex,vertex->next->next,tobj,contour)==GL_FALSE &&
-                       tobj->error==GLU_NO_ERROR)
-                       vertex=vertex->next;
-               if(tobj->error!=GLU_NO_ERROR)
-                       return;
-               clip_ear_with_edge_flag(tobj,vertex->next,contour);
-               --vertex_cnt;
-       }
-}
-
-void tess_tesselate(GLUtriangulatorObj *tobj)
-{
-       tess_contour *contour;
-
-       for(contour=tobj->contours;contour!=NULL;contour=contour->next)
-       {
-               if(contour->orientation==GLU_CCW) {
-                       triangulate_ccw(tobj,contour);
-               } else {
-                       triangulate_cw(tobj,contour);
-               }
-               if(tobj->error!=GLU_NO_ERROR)
-                       return;
-
-               /* emit the last triangle */
-               emit_triangle(tobj,contour->vertices,contour->vertices->next,
-                       contour->vertices->next->next);
-       }
-}
-
-void tess_tesselate_with_edge_flag(GLUtriangulatorObj *tobj)
-{
-       tess_contour *contour;
-
-       edge_flag=GL_TRUE;
-       /* first callback with edgeFlag set to GL_TRUE */
-       (tobj->callbacks.edgeFlag)(GL_TRUE);
-
-       for(contour=tobj->contours;contour!=NULL;contour=contour->next)
-       {
-               if(contour->orientation==GLU_CCW)
-                       triangulate_ccw_with_edge_flag(tobj,contour);
-               else
-                       triangulate_cw_with_edge_flag(tobj,contour);
-               if(tobj->error!=GLU_NO_ERROR)
-                       return;
-               /* emit the last triangle */
-               emit_triangle_with_edge_flag(tobj,contour->vertices,
-                       contour->vertices->edge_flag,contour->vertices->next,
-                       contour->vertices->next->edge_flag,contour->vertices->next->next,
-                       contour->vertices->next->next->edge_flag);
-       }
-}
-
-static void emit_triangle(
-       GLUtriangulatorObj *tobj,
-       tess_vertex *v1,
-       tess_vertex *v2,
-       tess_vertex *v3)
-{
-       (tobj->callbacks.begin)(GL_TRIANGLES);
-       (tobj->callbacks.vertex)(v1->data);
-       (tobj->callbacks.vertex)(v2->data);
-       (tobj->callbacks.vertex)(v3->data);
-       (tobj->callbacks.end)();
-}
-
-static void emit_triangle_with_edge_flag(
-       GLUtriangulatorObj *tobj,
-       tess_vertex *v1,
-       GLboolean edge_flag1,
-       tess_vertex *v2,
-       GLboolean edge_flag2,
-       tess_vertex *v3,
-       GLboolean edge_flag3)
-{
-       (tobj->callbacks.begin)(GL_TRIANGLES);
-       if(edge_flag1!=edge_flag)
-       {
-               edge_flag = (edge_flag==GL_TRUE ? GL_FALSE : GL_TRUE);
-               (tobj->callbacks.edgeFlag)(edge_flag);
-       }
-       (tobj->callbacks.vertex)(v1->data);
-       if(edge_flag2!=edge_flag)
-       {
-               edge_flag = (edge_flag==GL_TRUE ? GL_FALSE : GL_TRUE);
-               (tobj->callbacks.edgeFlag)(edge_flag);
-       }
-       (tobj->callbacks.vertex)(v2->data);
-       if(edge_flag3!=edge_flag)
-       {
-               edge_flag = (edge_flag==GL_TRUE ? GL_FALSE : GL_TRUE);
-               (tobj->callbacks.edgeFlag)(edge_flag);
-       }
-       (tobj->callbacks.vertex)(v3->data);
-       (tobj->callbacks.end)();
-}