summaryrefslogtreecommitdiffstats
path: root/src/glu
diff options
context:
space:
mode:
Diffstat (limited to 'src/glu')
-rw-r--r--src/glu/mesa/Makefile.BeOS73
-rw-r--r--src/glu/mesa/Makefile.BeOS-R485
-rw-r--r--src/glu/mesa/Makefile.X1157
-rw-r--r--src/glu/mesa/MesaGLU.def54
-rw-r--r--src/glu/mesa/README1195
-rw-r--r--src/glu/mesa/README243
-rw-r--r--src/glu/mesa/all.h69
-rw-r--r--src/glu/mesa/descrip.mms62
-rw-r--r--src/glu/mesa/glu.c335
-rw-r--r--src/glu/mesa/gluP.h83
-rw-r--r--src/glu/mesa/mipmap.c790
-rw-r--r--src/glu/mesa/mms_depend13
-rw-r--r--src/glu/mesa/nurbs.c715
-rw-r--r--src/glu/mesa/nurbs.h252
-rw-r--r--src/glu/mesa/nurbscrv.c500
-rw-r--r--src/glu/mesa/nurbssrf.c1422
-rw-r--r--src/glu/mesa/nurbsutl.c1403
-rw-r--r--src/glu/mesa/polytest.c1049
-rw-r--r--src/glu/mesa/project.c318
-rw-r--r--src/glu/mesa/quadric.c858
-rw-r--r--src/glu/mesa/tess.c369
-rw-r--r--src/glu/mesa/tess.h121
-rw-r--r--src/glu/mesa/tesselat.c456
23 files changed, 9322 insertions, 0 deletions
diff --git a/src/glu/mesa/Makefile.BeOS b/src/glu/mesa/Makefile.BeOS
new file mode 100644
index 00000000000..d1e489c1999
--- /dev/null
+++ b/src/glu/mesa/Makefile.BeOS
@@ -0,0 +1,73 @@
+# Makefile for GLU for BeOS contributed by
+# Tinic Uro <[email protected]>
+
+# Mesa 3-D graphics library
+# Version: 2.6
+# 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.
+
+
+
+##### MACROS #####
+
+VPATH = RCS
+
+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
+
+OBJECTS = $(SOURCES:.c=.o)
+
+
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c -i . -i- -i $(INCDIR) $(CFLAGS) $<
+
+
+
+##### TARGETS #####
+
+default:
+ @echo "Specify a target configuration"
+
+clean:
+ -rm *.o *~
+
+targets: $(LIBDIR)/$(GLU_LIB)
+
+# Make the library:
+$(LIBDIR)/$(GLU_LIB): $(OBJECTS)
+ $(MAKELIB) $(GLU_LIB) 2 6 $(OBJECTS)
+# $(RANLIB) $(GLU_LIB)
+ mv $(GLU_LIB)* $(LIBDIR)
+
+include ../Make-config
+
+include depend
+
+
+
+#
+# Run 'make depend' to update the dependencies if you change what's included
+# by any source file.
+#
+depend: $(SOURCES)
+ makedepend -fdepend -Y -I../include $(SOURCES)
+
diff --git a/src/glu/mesa/Makefile.BeOS-R4 b/src/glu/mesa/Makefile.BeOS-R4
new file mode 100644
index 00000000000..d664534491d
--- /dev/null
+++ b/src/glu/mesa/Makefile.BeOS-R4
@@ -0,0 +1,85 @@
+# Makefile for GLU for BeOS R4
+
+# 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.
+
+
+# $Id: Makefile.BeOS-R4,v 1.1 1999/08/19 00:55:42 jtg Exp $
+
+# $Log: Makefile.BeOS-R4,v $
+# Revision 1.1 1999/08/19 00:55:42 jtg
+# Initial revision
+#
+# Revision 1.2 1999/02/02 04:44:40 brianp
+# fixed some problems
+#
+# Revision 1.1 1999/01/19 04:10:02 brianp
+# Initial revision
+#
+
+
+
+##### MACROS #####
+
+VPATH = RCS
+
+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
+
+OBJECTS = $(SOURCES:.c=.o)
+
+
+
+##### TARGETS #####
+
+default:
+ @echo "Specify a target configuration"
+
+clean:
+ -rm *.o *~
+
+targets: $(LIBDIR)/$(GLU_LIB)
+
+# Make the library:
+$(LIBDIR)/$(GLU_LIB): $(OBJECTS)
+ $(MAKELIB) $(GLU_LIB) $(MAJOR) $(MINOR) -L$(LIBDIR) -lMesaGL $(OBJECTS)
+ mv $(GLU_LIB)* $(LIBDIR)
+
+include ../Make-config
+
+include depend
+
+
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c -I. -I../ -I$(INCDIR) $(CFLAGS) $<
+
+
+
+#
+# Run 'make depend' to update the dependencies if you change what's included
+# by any source file.
+#
+depend: $(SOURCES)
+ makedepend -fdepend -Y -I../include $(SOURCES)
+
diff --git a/src/glu/mesa/Makefile.X11 b/src/glu/mesa/Makefile.X11
new file mode 100644
index 00000000000..c155aea9a55
--- /dev/null
+++ b/src/glu/mesa/Makefile.X11
@@ -0,0 +1,57 @@
+# $Id: Makefile.X11,v 1.1 1999/08/19 00:55:42 jtg Exp $
+
+# Mesa 3-D graphics library
+# Version: 3.1
+# Copyright (C) 1995-1999 Brian Paul
+
+# Makefile for GLU library
+
+
+##### MACROS #####
+
+VPATH = RCS
+
+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
+
+OBJECTS = $(SOURCES:.c=.o)
+
+
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c -I$(INCDIR) $(CFLAGS) $<
+
+
+
+##### TARGETS #####
+
+default:
+ @echo "Specify a target configuration"
+
+clean:
+ -rm *.o *~
+
+targets: $(LIBDIR)/$(GLU_LIB)
+
+# Make the library:
+$(LIBDIR)/$(GLU_LIB): $(OBJECTS)
+ $(MAKELIB) $(GLU_LIB) $(MAJOR) $(MINOR) $(OBJECTS)
+ mv $(GLU_LIB)* $(LIBDIR)
+
+include ../Make-config
+
+include depend
+
+
+
+#
+# Run 'make depend' to update the dependencies if you change what's included
+# by any source file.
+#
+dep: $(SOURCES)
+ makedepend -fdepend -Y -I../include $(SOURCES)
diff --git a/src/glu/mesa/MesaGLU.def b/src/glu/mesa/MesaGLU.def
new file mode 100644
index 00000000000..8b1c4449ff1
--- /dev/null
+++ b/src/glu/mesa/MesaGLU.def
@@ -0,0 +1,54 @@
+LIBRARY MESAGLU
+DESCRIPTION 'GLU for Windows Mesa'
+EXETYPE WINDOWS
+CODE MOVEABLE DISCARDABLE
+DATA MOVEABLE SINGLE
+HEAPSIZE 256000
+
+STACKSIZE 4096
+
+EXPORTS
+ gluLookAt
+ gluOrtho2D
+ gluPerspective
+ gluPickMatrix
+ gluProject
+ gluUnProject
+ gluErrorString
+ gluScaleImage
+ gluBuild1DMipmaps
+ gluBuild2DMipmaps
+ gluNewQuadric
+ gluDeleteQuadric
+ gluQuadricDrawStyle
+ gluQuadricOrientation
+ gluQuadricNormals
+ gluQuadricTexture
+ gluQuadricCallback
+ gluCylinder
+ gluSphere
+ gluDisk
+ gluPartialDisk
+ gluNewNurbsRenderer
+ gluDeleteNurbsRenderer
+ gluLoadSamplingMatrices
+ gluNurbsProperty
+ gluGetNurbsProperty
+ gluBeginCurve
+ gluEndCurve
+ gluNurbsCurve
+ gluBeginSurface
+ gluEndSurface
+ gluNurbsSurface
+ gluBeginTrim
+ gluEndTrim
+ gluPwlCurve
+ gluNurbsCallback
+ gluNewTess
+ gluTessCallback
+ gluDeleteTess
+ gluBeginPolygon
+ gluEndPolygon
+ gluNextContour
+ gluTessVertex
+ gluGetString
diff --git a/src/glu/mesa/README1 b/src/glu/mesa/README1
new file mode 100644
index 00000000000..75968572ff6
--- /dev/null
+++ b/src/glu/mesa/README1
@@ -0,0 +1,195 @@
+
+Notes on the GLU polygon tesselation facility implemented by Bogdan Sikorski...
+
+
+
+The tesselation module is provided under the same terms as the Mesa
+package.
+
+This is the first release of polygon tesselation code for Mesa.
+It was written during my very little free time, so lets name it:
+"its not perfect". If someone hates pointers, don't look at the code.
+I preffer dynamic allocation versus static. But _all_ ideas, suggestions,
+bug reports and fixes are welcome (if You want, also flames). I am aware
+that many things could have been written using better techniques, but time
+that I could devote to this library was very limited. It is not well commented,
+excuse me. Also I am thinking of continuing working on this code to improve,
+fix and polish it. And make it as compliant as possible to the OpenGL, so
+software ports from OpenGL to Mesa will work correctly. If You know of any
+differences in behaviour, expected input/output between Mesa tesselation library
+and OpenGL, please send me a note. I explain later on why I am not
+confident with this code.
+
+I tried to be fully compliant with the OpenGL routines. By "tried" I mean that
+up to my knowledge it behaves as OpenGL tesselation routines. Just recently
+I began to experiment with OpenGL (actually only Mesa), and also have
+no access to any machine providing official implementation of OpenGL,
+nor access to books (particulary Addison-Wesley publications). Thus my
+knowledge on how the original tesselation code works, what kind of data
+it expects etc. is based _only_ on the publicly available documentation
+provided by SGI. Namely:
+
+* "The OpenGL Graphics System Utility Library" by K.P.Smith
+ (Silicon Graphics, 1992)
+* "The OpenGL Graphics Interface" by M.Segal and K.Akeley
+ (Silicon Graphics, 19??)
+* "OpenGL and X, Part 1: Introduction" by M.J.Kilgard
+ (Silicon Graphics, 1994)
+* "OpenGL and X, Part 2: Using OpenGL with Xlib" by M.J.Kilgard
+ (Silicon Graphics, 1994)
+* "OpenGL Graphics with the X Window System" by P.Karlton
+ (Silicon Graphics, 1993)
+* Online Docs - Appendix C of OpenGL Programming Guide, Polygon Tesselation
+ (partial text cut and sent by e-mail)
+
+
+The tesselation routines use slightly different prototypes than the ones
+specified in the mentioned above publications. The _only_ differences are
+the enumeration types which are not GLenum, but are GLUenum. So the
+implemented routines have following prototypes:
+
+GLUtringulatorObj *gluNewTess(void);
+
+void gluTessCallback(GLUtriangulatorObj *,GLUenum,void (*)());
+ ^^^^^^^
+void gluBeginPolygon(GLUtriangulatorObj *);
+
+void gluTessVertex(GLUtriangulatorObj *,GLdouble [3],void *);
+
+void gluNextContour(GLUtriangulatorObj *,GLUenum);
+ ^^^^^^^
+void gluEndPolygon(GLUtriangulatorObj *);
+
+const GLubyte *gluErrorString(GLUenum);
+ ^^^^^^^
+ prototypes for callback functions:
+
+void <begin>(GLUenum);
+ ^^^^^^^
+void <edgeFlag>(GLboolean);
+void <vertex>(void *);
+void <end>(void);
+void <error>(GLUenum);
+ ^^^^^^^
+
+The begin callback will be called only with GLU_TRIANGLES. No support
+for traingle fans or strips yet.
+
+In case of errors an internal error variable is set to the appropiate
+error enum values (GLU_TESS_ERROR?). Initially it is set to GLU_NO_ERROR.
+The OpenGL library provides 8 error conditions, the tesselation code
+of Mesa provides 9. They are:
+
+GLU_TESS_ERROR1: missing gluEndPolygon /* same as OpenGL */
+GLU_TESS_ERROR2: missing gluBeginPolygon /* same as OpenGL */
+GLU_TESS_ERROR3: misoriented contour /* not used in Mesa
+ in OpenGL is bad orientation or intersecting edges */
+GLU_TESS_ERROR4: vertex/edge intersection /* same as OpenGL */
+GLU_TESS_ERROR5: misoriented or self-intersecting loops /* same as OpenGL */
+GLU_TESS_ERROR6: coincident vertices /* same as OpenGL */
+GLU_TESS_ERROR7: colinear vertices /* OpenGL's illegal data */
+GLU_TESS_ERROR8: intersecting edges /* same as OpenGL */
+GLU_TESS_ERROR9: not coplanar contours /* new for Mesa */
+
+The Mesa tesselation code ignores all data and calls after detecting an error
+codition. This means that a _new_ tesselation object must be used for further
+triangulations. Maybe this is too restrictive, and will be lifted in
+future versions.
+
+The tesselation code completely ignores the type parameter passed in
+gluNextContour. It also doesn't check if the passed parameter is a legal
+enum value - ignores silently (maybe at least this should be checked).
+The reason I chose this behaviour is based on what I read in the
+beforementioned documents. I cite:
+
+"....
+void gluNextContour(GLUtriangulatorObj *tessobj, GLenum type);
+
+Marks the beginning of the next contour when multiple contours make up the
+boundary of the polygon to be tessellated. type can be GLU_EXTERIOR,
+GLU_INTERIOR, GLU_CCW, GLU_CW, or GLU_UNKNOWN. These serve only as
+to the tessellation. If you get them right, the tessellation might
+go faster. If you get them wrong, they're ignored, and the tesselation still
+works.
+....."
+
+I hope You agree with me that my decision was correct. Mesa tesselation
+_always_ checks by itself the interrelations between contours. Just as if
+all contours were specified with the type GLU_UNKNOWN.
+
+One of OpenGL's policy is not to check all error conditions - rely sometimes
+that the user "got things right". This is justified, since exhausting
+error checking is timeconsuming, and would significantly slow down
+a correct application. The Mesa tesselation code assumes only _one_ condition
+when triangulating - all vertices in a contour are planar. This is _not_
+checked for correctness. Trying to tesselate such objects will lead to
+unpredictable output.
+
+And now we arrive to the moment where I would like to list the required
+(but checked for) conditions for triangulation, as well as summarize the
+library:
+
+* all contours in a single tesselation cycle _must_ be coplanar - if not
+ an error is raised (and if provided a call to the error callback
+ is made)
+* the contours can be passed in _any_ order, exteriors and holes can be
+ intermixed within a tesselation cycle and the correct hierarchy
+ will be determined by the library; thus specifying first holes then
+ exteriors, then holes within holes form a valid input.
+* a hole within a hole is consider to be a yet another exterior contour
+* multiple exterior contours (polygons) can be tesselated in one cycle;
+ _but_ this significantly degrades performance since many tests will be
+ performed for every contour pair; if You want triangulation to be fast
+ tesselate a single polygon (with possible holes) one at a time.
+* orientation of exterior contours is arbitray, but if it has holes,
+ all interior holes of this particular exterior contour _must_ have an
+ opposite orientation.
+* the output triangles have the same orientation as the exterior contour
+ that forms them
+* each triangle is "enclosed" within the begin and end callbacks;
+ this is not efficent, but was made on purpose; so if triangulation
+ results in 2 triangles the following callbacks will be made in such
+ order:
+ <begin>(GLU_TRAINGLES)
+ <vertex>(...) /* 3 vertices of first triangle */
+ <vertex>(...)
+ <vertex>(...)
+ <end>()
+ <begin>(GLU_TRAINGLES)
+ <vertex>(...) /* 3 vertices of second triangle */
+ <vertex>(...)
+ <vertex>(...)
+ <end>()
+ Of course only when begin, vertex, and end callback were provided,
+ otherwise no output is done (actually tesselation does not take place).
+* You will notice that some output traingles are very "thin"; there
+ exist possible several ways to traingulate a polygon, but "smart" code
+ avoiding such cases would require time to write, and will impact on
+ execution speed.
+* like OpenGL, no new vertices are introduced during triangulation
+* if the edgeflag callback is provided it will be called whenever
+ the just-about-to be output vertex begins a different type of edge
+ than the previous vertices; always before the first output a call
+ is made with GL_TRUE, to allow synchronization.
+* all intermediate computations are done using GLdouble type, and comparisons
+ are biased with a precision value (EPSILON defined in tess.h)
+* the point_in_poly function is my adaptation of code from the
+ comp.graphics.alg newsgroup FAQ (originally written by Mr. Wm. Randolph
+ Franklin, modified by Scott Anguish).
+* the edge_edge_intersect test is also an adopted code from comp.graphics.alg
+ newsgroup FAQ
+* the general idea for traingulation used in this library is described in
+ the book "Computational Geometry in C" by Joseph O'Rourke.
+
+
+Excuse my English, its not my mother tongue. I should be available for some
+time uner the following e-mail address. But For how long I am not certain.
+Once I am settled in my new place, I'll post on the Mesa mailing list
+my new address.
+
+(PS: today is my last day of work here, I'm changing my job).
+
+Bogdan. ( [email protected] )
+
+Apr 28, 1995.
+
diff --git a/src/glu/mesa/README2 b/src/glu/mesa/README2
new file mode 100644
index 00000000000..3c9959179b0
--- /dev/null
+++ b/src/glu/mesa/README2
@@ -0,0 +1,43 @@
+The current NURBS implementation has no trimming facilities yet.
+
+The code is not well commented.
+
+1) Normal calculus fails for special cases of NURBS (independent
+ of the NURBS modules)
+ Those cases arise when for u or v, some control points
+ for a fixed value of that parameter form the same point.
+ Imagine a Bezier patch degenerated into a "triangle".
+
+ v ^ 0,1,2 order=3
+ | *
+ |
+ | 3* 4* 5*
+ |
+ | 6* 7* 8*
+ |
+ |
+ +------------------------> u
+
+ The calculus of du derivative at triple point (0,1 and 2) will fail.
+ As a result, the normal vector will be 0.
+ The eval2.c code has to be changed to handle the above situation.
+
+2) Adjacent NURBS surfaces ("sharing" the same control points along
+ the "joining" edge) will be sampled with the same factor.
+ This prevents the formation of "cracks".
+ When the control polygon of the "shared" edge is not the same,
+ cracks might appear.
+
+The sampling tolerance is sometimes not respected!
+A NURBS object is broken into Bezier curves/surfaces. If one of such
+Bezier objects has a local high curvature with other portions of it
+relatively flat then the high curvature part will be sampled more dense that
+its flatter regions.
+The flat regions might be tesselated into quads having sides of length
+greater than the current sampling tolernace setting.
+I believe such behaviour is acceptable, though not along the concept of
+sampling tolerance.
+
+February 20, 1996.
+
+Bogdan.
diff --git a/src/glu/mesa/all.h b/src/glu/mesa/all.h
new file mode 100644
index 00000000000..3712ca884ab
--- /dev/null
+++ b/src/glu/mesa/all.h
@@ -0,0 +1,69 @@
+/* $Id: all.h,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 2.3
+ * 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: all.h,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.2 1997/11/20 00:28:20 brianp
+ * changed PCH to PC_HEADER
+ *
+ * Revision 1.1 1997/05/28 02:29:14 brianp
+ * Initial revision
+ *
+ */
+
+
+/*
+ * This file includes all .h files needed for the GLU source code for
+ * the purpose of precompiled headers.
+ *
+ * If the preprocessor symbol PCH is defined at compile time then each
+ * of the .c files will #include "all.h" only, instead of a bunch of
+ * individual .h files.
+ */
+
+
+#ifndef GLU_ALL_H
+#define GLU_ALL_H
+
+
+#ifndef PC_HEADER
+ This is an error. all.h should be included only if PCH is defined.
+#endif
+
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "GL/gl.h"
+#include "GL/glu.h"
+#include "gluP.h"
+#include "nurbs.h"
+#include "tess.h"
+
+
+#endif /*GLU_ALL_H*/
diff --git a/src/glu/mesa/descrip.mms b/src/glu/mesa/descrip.mms
new file mode 100644
index 00000000000..b660f6914de
--- /dev/null
+++ b/src/glu/mesa/descrip.mms
@@ -0,0 +1,62 @@
+# Makefile for GLU for VMS
+# contributed by Jouk Jansen [email protected]
+
+.first
+ define gl [-.include.gl]
+
+.include [-]mms-config.
+
+##### MACROS #####
+
+VPATH = RCS
+
+INCDIR = $disk2:[-.include]
+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
+
+OBJECTS =glu.obj,mipmap.obj,nurbs.obj,nurbscrv.obj,nurbssrf.obj,nurbsutl.obj,\
+ project.obj,quadric.obj,tess.obj,tesselat.obj,polytest.obj
+
+
+
+##### RULES #####
+
+VERSION=MesaGlu V3.1
+
+##### TARGETS #####
+
+# Make the library:
+$(LIBDIR)$(GLU_LIB) : $(OBJECTS)
+.ifdef SHARE
+ @ WRITE_ SYS$OUTPUT " generating mesagl1.opt"
+ @ OPEN_/WRITE FILE mesagl1.opt
+ @ WRITE_ FILE "!"
+ @ WRITE_ FILE "! mesagl1.opt generated by DESCRIP.$(MMS_EXT)"
+ @ WRITE_ FILE "!"
+ @ WRITE_ FILE "IDENTIFICATION=""$(VERSION)"""
+ @ WRITE_ FILE "GSMATCH=LEQUAL,3,1
+ @ WRITE_ FILE "$(OBJECTS)"
+ @ WRITE_ FILE "[-.lib]libmesagl.exe/SHARE"
+ @ WRITE_ FILE "SYS$SHARE:DECW$XEXTLIBSHR/SHARE"
+ @ WRITE_ FILE "SYS$SHARE:DECW$XLIBSHR/SHARE"
+ @ CLOSE_ FILE
+ @ WRITE_ SYS$OUTPUT " generating mesagl.map ..."
+ @ LINK_/NODEB/NOSHARE/NOEXE/MAP=mesagl.map/FULL mesagl1.opt/OPT
+ @ WRITE_ SYS$OUTPUT " analyzing mesagl.map ..."
+ @ @[-.vms]ANALYZE_MAP.COM mesagl.map mesagl.opt
+ @ WRITE_ SYS$OUTPUT " linking $(GLU_LIB) ..."
+ @ LINK_/noinform/NODEB/SHARE=$(GLU_LIB)/MAP=mesagl.map/FULL mesagl1.opt/opt,mesagl.opt/opt
+.else
+ @ $(MAKELIB) $(GLU_LIB) $(OBJECTS)
+.endif
+ @ rename $(GLU_LIB)* $(LIBDIR)
+
+clean :
+ delete *.obj;*
+ purge
+
+include mms_depend.
+
diff --git a/src/glu/mesa/glu.c b/src/glu/mesa/glu.c
new file mode 100644
index 00000000000..2cceb8b743e
--- /dev/null
+++ b/src/glu/mesa/glu.c
@@ -0,0 +1,335 @@
+/* $Id: glu.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ * Copyright (C) 1995-1999 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: glu.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.13 1999/03/31 19:07:28 brianp
+ * added GL_EXT_abgr to extensions
+ *
+ * Revision 1.12 1999/02/06 06:12:41 brianp
+ * updated version string to 3.1
+ *
+ * Revision 1.11 1999/01/03 03:23:15 brianp
+ * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
+ *
+ * Revision 1.10 1998/04/22 00:35:50 brianp
+ * changed version to 3.0
+ *
+ * Revision 1.9 1997/12/09 03:03:32 brianp
+ * changed version to 2.6
+ *
+ * Revision 1.8 1997/10/04 01:30:20 brianp
+ * changed version to 2.5
+ *
+ * Revision 1.7 1997/08/13 01:25:21 brianp
+ * changed version string to 2.4
+ *
+ * Revision 1.6 1997/07/24 01:28:44 brianp
+ * changed precompiled header symbol from PCH to PC_HEADER
+ *
+ * Revision 1.5 1997/07/13 22:59:11 brianp
+ * added const to viewport parameter of gluPickMatrix()
+ *
+ * Revision 1.4 1997/05/28 02:29:38 brianp
+ * added support for precompiled headers (PCH), inserted APIENTRY keyword
+ *
+ * Revision 1.3 1997/04/12 16:19:02 brianp
+ * changed version to 2.3
+ *
+ * Revision 1.2 1997/03/11 00:58:34 brianp
+ * changed version to 2.2
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "gluP.h"
+#endif
+
+
+/*
+ * Miscellaneous utility functions
+ */
+
+
+#ifndef M_PI
+#define M_PI 3.1415926536
+#endif
+#define EPS 0.00001
+
+
+
+
+void GLAPIENTRY gluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez,
+ GLdouble centerx, GLdouble centery, GLdouble centerz,
+ GLdouble upx, GLdouble upy, GLdouble upz )
+{
+ GLdouble m[16];
+ GLdouble x[3], y[3], z[3];
+ GLdouble mag;
+
+ /* Make rotation matrix */
+
+ /* Z vector */
+ z[0] = eyex - centerx;
+ z[1] = eyey - centery;
+ z[2] = eyez - centerz;
+ mag = sqrt( z[0]*z[0] + z[1]*z[1] + z[2]*z[2] );
+ if (mag) { /* mpichler, 19950515 */
+ z[0] /= mag;
+ z[1] /= mag;
+ z[2] /= mag;
+ }
+
+ /* Y vector */
+ y[0] = upx;
+ y[1] = upy;
+ y[2] = upz;
+
+ /* X vector = Y cross Z */
+ x[0] = y[1]*z[2] - y[2]*z[1];
+ x[1] = -y[0]*z[2] + y[2]*z[0];
+ x[2] = y[0]*z[1] - y[1]*z[0];
+
+ /* Recompute Y = Z cross X */
+ y[0] = z[1]*x[2] - z[2]*x[1];
+ y[1] = -z[0]*x[2] + z[2]*x[0];
+ y[2] = z[0]*x[1] - z[1]*x[0];
+
+ /* mpichler, 19950515 */
+ /* cross product gives area of parallelogram, which is < 1.0 for
+ * non-perpendicular unit-length vectors; so normalize x, y here
+ */
+
+ mag = sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] );
+ if (mag) {
+ x[0] /= mag;
+ x[1] /= mag;
+ x[2] /= mag;
+ }
+
+ mag = sqrt( y[0]*y[0] + y[1]*y[1] + y[2]*y[2] );
+ if (mag) {
+ y[0] /= mag;
+ y[1] /= mag;
+ y[2] /= mag;
+ }
+
+#define M(row,col) m[col*4+row]
+ M(0,0) = x[0]; M(0,1) = x[1]; M(0,2) = x[2]; M(0,3) = 0.0;
+ M(1,0) = y[0]; M(1,1) = y[1]; M(1,2) = y[2]; M(1,3) = 0.0;
+ M(2,0) = z[0]; M(2,1) = z[1]; M(2,2) = z[2]; M(2,3) = 0.0;
+ M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
+#undef M
+ glMultMatrixd( m );
+
+ /* Translate Eye to Origin */
+ glTranslated( -eyex, -eyey, -eyez );
+
+}
+
+
+
+void GLAPIENTRY gluOrtho2D( GLdouble left, GLdouble right,
+ GLdouble bottom, GLdouble top )
+{
+ glOrtho( left, right, bottom, top, -1.0, 1.0 );
+}
+
+
+
+void GLAPIENTRY gluPerspective( GLdouble fovy, GLdouble aspect,
+ GLdouble zNear, GLdouble zFar )
+{
+ GLdouble xmin, xmax, ymin, ymax;
+
+ ymax = zNear * tan( fovy * M_PI / 360.0 );
+ ymin = -ymax;
+
+ xmin = ymin * aspect;
+ xmax = ymax * aspect;
+
+ glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
+}
+
+
+
+void GLAPIENTRY gluPickMatrix( GLdouble x, GLdouble y,
+ GLdouble width, GLdouble height,
+ const GLint viewport[4] )
+{
+ GLfloat m[16];
+ GLfloat sx, sy;
+ GLfloat tx, ty;
+
+ sx = viewport[2] / width;
+ sy = viewport[3] / height;
+ tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
+ ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
+
+#define M(row,col) m[col*4+row]
+ M(0,0) = sx; M(0,1) = 0.0; M(0,2) = 0.0; M(0,3) = tx;
+ M(1,0) = 0.0; M(1,1) = sy; M(1,2) = 0.0; M(1,3) = ty;
+ M(2,0) = 0.0; M(2,1) = 0.0; M(2,2) = 1.0; M(2,3) = 0.0;
+ M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
+#undef M
+
+ glMultMatrixf( m );
+}
+
+
+
+const GLubyte* GLAPIENTRY gluErrorString( GLenum errorCode )
+{
+ static char *tess_error[] = {
+ "missing gluEndPolygon",
+ "missing gluBeginPolygon",
+ "misoriented contour",
+ "vertex/edge intersection",
+ "misoriented or self-intersecting loops",
+ "coincident vertices",
+ "colinear vertices",
+ "intersecting edges",
+ "not coplanar contours"
+ };
+ static char *nurbs_error[] = {
+ "spline order un-supported",
+ "too few knots",
+ "valid knot range is empty",
+ "decreasing knot sequence knot",
+ "knot multiplicity greater than order of spline",
+ "endcurve() must follow bgncurve()",
+ "bgncurve() must precede endcurve()",
+ "missing or extra geometric data",
+ "can't draw pwlcurves",
+ "missing bgncurve()",
+ "missing bgnsurface()",
+ "endtrim() must precede endsurface()",
+ "bgnsurface() must precede endsurface()",
+ "curve of improper type passed as trim curve",
+ "bgnsurface() must precede bgntrim()",
+ "endtrim() must follow bgntrim()",
+ "bgntrim() must precede endtrim()",
+ "invalid or missing trim curve",
+ "bgntrim() must precede pwlcurve()",
+ "pwlcurve referenced twice",
+ "pwlcurve and nurbscurve mixed",
+ "improper usage of trim data type",
+ "nurbscurve referenced twice",
+ "nurbscurve and pwlcurve mixed",
+ "nurbssurface referenced twice",
+ "invalid property",
+ "endsurface() must follow bgnsurface()",
+ "misoriented trim curves",
+ "intersecting trim curves",
+ "UNUSED",
+ "unconnected trim curves",
+ "unknown knot error",
+ "negative vertex count encountered",
+ "negative byte-stride encounteed",
+ "unknown type descriptor",
+ "null control array or knot vector",
+ "duplicate point on pwlcurve"
+ };
+
+ /* GL Errors */
+ if (errorCode==GL_NO_ERROR) {
+ return (GLubyte *) "no error";
+ }
+ else if (errorCode==GL_INVALID_VALUE) {
+ return (GLubyte *) "invalid value";
+ }
+ else if (errorCode==GL_INVALID_ENUM) {
+ return (GLubyte *) "invalid enum";
+ }
+ else if (errorCode==GL_INVALID_OPERATION) {
+ return (GLubyte *) "invalid operation";
+ }
+ else if (errorCode==GL_STACK_OVERFLOW) {
+ return (GLubyte *) "stack overflow";
+ }
+ else if (errorCode==GL_STACK_UNDERFLOW) {
+ return (GLubyte *) "stack underflow";
+ }
+ else if (errorCode==GL_OUT_OF_MEMORY) {
+ return (GLubyte *) "out of memory";
+ }
+ /* GLU Errors */
+ else if (errorCode==GLU_NO_ERROR) {
+ return (GLubyte *) "no error";
+ }
+ else if (errorCode==GLU_INVALID_ENUM) {
+ return (GLubyte *) "invalid enum";
+ }
+ else if (errorCode==GLU_INVALID_VALUE) {
+ return (GLubyte *) "invalid value";
+ }
+ else if (errorCode==GLU_OUT_OF_MEMORY) {
+ return (GLubyte *) "out of memory";
+ }
+ else if (errorCode==GLU_INCOMPATIBLE_GL_VERSION) {
+ return (GLubyte *) "incompatible GL version";
+ }
+ else if (errorCode>=GLU_TESS_ERROR1 && errorCode<=GLU_TESS_ERROR9) {
+ return (GLubyte *) tess_error[errorCode-GLU_TESS_ERROR1];
+ }
+ else if (errorCode>=GLU_NURBS_ERROR1 && errorCode<=GLU_NURBS_ERROR37) {
+ return (GLubyte *) nurbs_error[errorCode-GLU_NURBS_ERROR1];
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+
+/*
+ * New in GLU 1.1
+ */
+
+const GLubyte* GLAPIENTRY gluGetString( GLenum name )
+{
+ static char *extensions = "GL_EXT_abgr";
+ static char *version = "1.1 Mesa 3.1";
+
+ switch (name) {
+ case GLU_EXTENSIONS:
+ return (GLubyte *) extensions;
+ case GLU_VERSION:
+ return (GLubyte *) version;
+ default:
+ return NULL;
+ }
+}
+
diff --git a/src/glu/mesa/gluP.h b/src/glu/mesa/gluP.h
new file mode 100644
index 00000000000..1d036eeb5ea
--- /dev/null
+++ b/src/glu/mesa/gluP.h
@@ -0,0 +1,83 @@
+/* $Id: gluP.h,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ * Copyright (C) 1995-1999 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: gluP.h,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.4 1999/01/03 03:23:15 brianp
+ * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
+ *
+ * Revision 1.3 1997/08/01 22:25:27 brianp
+ * check for Cygnus Win32 (Stephen Rehel)
+ *
+ * Revision 1.2 1997/05/27 02:59:46 brianp
+ * added defines for APIENTRY and CALLBACK if not compiling on Win32
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+
+/*
+ * This file allows the GLU code to be compiled either with the Mesa
+ * headers or with the real OpenGL headers.
+ */
+
+
+#ifndef GLUP_H
+#define GLUP_H
+
+
+#include "GL/gl.h"
+#include "GL/glu.h"
+
+
+#ifndef MESA
+ /* If we're using the real OpenGL header files... */
+# define GLU_TESS_ERROR9 100159
+#endif
+
+
+#define GLU_NO_ERROR GL_NO_ERROR
+
+
+/* for Sun: */
+#ifdef SUNOS4
+#define MEMCPY( DST, SRC, BYTES) \
+ memcpy( (char *) (DST), (char *) (SRC), (int) (BYTES) )
+#else
+#define MEMCPY( DST, SRC, BYTES) \
+ memcpy( (void *) (DST), (void *) (SRC), (size_t) (BYTES) )
+#endif
+
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+
+#endif
diff --git a/src/glu/mesa/mipmap.c b/src/glu/mesa/mipmap.c
new file mode 100644
index 00000000000..24af0ba33c0
--- /dev/null
+++ b/src/glu/mesa/mipmap.c
@@ -0,0 +1,790 @@
+/* $Id: mipmap.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ * Copyright (C) 1995-1999 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: mipmap.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.13 1999/03/05 17:49:06 brianp
+ * added support for GL_EXT_abgr ([email protected])
+ *
+ * Revision 1.12 1999/01/03 03:23:15 brianp
+ * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
+ *
+ * Revision 1.11 1998/09/18 02:44:03 brianp
+ * further changes to gluScaleImage() per Randy Frank
+ *
+ * Revision 1.10 1998/09/17 03:20:26 brianp
+ * fixed another bug in gluScaleImage() per Sven Panne
+ *
+ * Revision 1.9 1998/07/31 03:06:20 brianp
+ * tweaked the gluScaleImage() function per Randy Frank
+ *
+ * Revision 1.8 1998/07/08 01:02:53 brianp
+ * if gluBuildxDMipmaps() width or height <= 0 return GLU_INVALID_VALUE
+ *
+ * Revision 1.7 1998/07/01 00:18:02 brianp
+ * if gluBuildxDMipmaps() width or height <= 0 just return 0
+ *
+ * Revision 1.6 1998/06/01 01:06:41 brianp
+ * small update for Next/OpenStep from Alexander Mai
+ *
+ * Revision 1.5 1997/07/24 01:28:44 brianp
+ * changed precompiled header symbol from PCH to PC_HEADER
+ *
+ * Revision 1.4 1997/06/23 00:22:56 brianp
+ * added dummy() call to work around an MSVC 4.1 bug
+ *
+ * Revision 1.3 1997/05/28 02:29:38 brianp
+ * added support for precompiled headers (PCH), inserted APIENTRY keyword
+ *
+ * Revision 1.2 1997/05/24 13:32:25 brianp
+ * undef EPSILON in case it's already defined
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "gluP.h"
+#endif
+
+
+/*
+ * Compute ceiling of integer quotient of A divided by B:
+ */
+#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
+
+
+
+#ifdef EPSILON
+#undef EPSILON
+#endif
+#define EPSILON 0.001
+
+
+/* To work around optimizer bug in MSVC4.1 */
+#if defined(__WIN32__) && !defined(OPENSTEP)
+void dummy(GLuint j, GLuint k){
+}
+#else
+#define dummy(J, K)
+#endif
+
+
+GLint GLAPIENTRY gluScaleImage( GLenum format,
+ GLint widthin, GLint heightin,
+ GLenum typein, const void *datain,
+ GLint widthout, GLint heightout,
+ GLenum typeout, void *dataout )
+{
+ GLint components, i, j, k;
+ GLfloat *tempin, *tempout;
+ GLfloat sx, sy;
+ GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
+ GLint packrowlength, packalignment, packskiprows, packskippixels;
+ GLint sizein, sizeout;
+ GLint rowstride, rowlen;
+
+
+ /* Determine number of components per pixel */
+ switch (format) {
+ case GL_COLOR_INDEX:
+ case GL_STENCIL_INDEX:
+ case GL_DEPTH_COMPONENT:
+ case GL_RED:
+ case GL_GREEN:
+ case GL_BLUE:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ components = 1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ components = 2;
+ break;
+ case GL_RGB:
+ components = 3;
+ break;
+ case GL_RGBA:
+#ifdef GL_EXT_abgr
+ case GL_ABGR_EXT:
+#endif
+ components = 4;
+ break;
+ default:
+ return GLU_INVALID_ENUM;
+ }
+
+ /* Determine bytes per input datum */
+ switch (typein) {
+ case GL_UNSIGNED_BYTE: sizein = sizeof(GLubyte); break;
+ case GL_BYTE: sizein = sizeof(GLbyte); break;
+ case GL_UNSIGNED_SHORT: sizein = sizeof(GLushort); break;
+ case GL_SHORT: sizein = sizeof(GLshort); break;
+ case GL_UNSIGNED_INT: sizein = sizeof(GLuint); break;
+ case GL_INT: sizein = sizeof(GLint); break;
+ case GL_FLOAT: sizein = sizeof(GLfloat); break;
+ case GL_BITMAP:
+ /* not implemented yet */
+ default:
+ return GL_INVALID_ENUM;
+ }
+
+ /* Determine bytes per output datum */
+ switch (typeout) {
+ case GL_UNSIGNED_BYTE: sizeout = sizeof(GLubyte); break;
+ case GL_BYTE: sizeout = sizeof(GLbyte); break;
+ case GL_UNSIGNED_SHORT: sizeout = sizeof(GLushort); break;
+ case GL_SHORT: sizeout = sizeof(GLshort); break;
+ case GL_UNSIGNED_INT: sizeout = sizeof(GLuint); break;
+ case GL_INT: sizeout = sizeof(GLint); break;
+ case GL_FLOAT: sizeout = sizeof(GLfloat); break;
+ case GL_BITMAP:
+ /* not implemented yet */
+ default:
+ return GL_INVALID_ENUM;
+ }
+
+ /* Get glPixelStore state */
+ glGetIntegerv( GL_UNPACK_ROW_LENGTH, &unpackrowlength );
+ glGetIntegerv( GL_UNPACK_ALIGNMENT, &unpackalignment );
+ glGetIntegerv( GL_UNPACK_SKIP_ROWS, &unpackskiprows );
+ glGetIntegerv( GL_UNPACK_SKIP_PIXELS, &unpackskippixels );
+ glGetIntegerv( GL_PACK_ROW_LENGTH, &packrowlength );
+ glGetIntegerv( GL_PACK_ALIGNMENT, &packalignment );
+ glGetIntegerv( GL_PACK_SKIP_ROWS, &packskiprows );
+ glGetIntegerv( GL_PACK_SKIP_PIXELS, &packskippixels );
+
+ /* Allocate storage for intermediate images */
+ tempin = (GLfloat *) malloc( widthin * heightin
+ * components * sizeof(GLfloat) );
+ if (!tempin) {
+ return GLU_OUT_OF_MEMORY;
+ }
+ tempout = (GLfloat *) malloc( widthout * heightout
+ * components * sizeof(GLfloat) );
+ if (!tempout) {
+ free( tempin );
+ return GLU_OUT_OF_MEMORY;
+ }
+
+
+ /*
+ * Unpack the pixel data and convert to floating point
+ */
+
+ if (unpackrowlength>0) {
+ rowlen = unpackrowlength;
+ }
+ else {
+ rowlen = widthin;
+ }
+ if (sizein >= unpackalignment) {
+ rowstride = components * rowlen;
+ }
+ else {
+ rowstride = unpackalignment/sizein
+ * CEILING( components * rowlen * sizein, unpackalignment );
+ }
+
+ switch (typein) {
+ case GL_UNSIGNED_BYTE:
+ k = 0;
+ for (i=0;i<heightin;i++) {
+ GLubyte *ubptr = (GLubyte *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride
+ + unpackskippixels * components;
+ for (j=0;j<widthin*components;j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) *ubptr++;
+ }
+ }
+ break;
+ case GL_BYTE:
+ k = 0;
+ for (i=0;i<heightin;i++) {
+ GLbyte *bptr = (GLbyte *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride
+ + unpackskippixels * components;
+ for (j=0;j<widthin*components;j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) *bptr++;
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ k = 0;
+ for (i=0;i<heightin;i++) {
+ GLushort *usptr = (GLushort *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride
+ + unpackskippixels * components;
+ for (j=0;j<widthin*components;j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) *usptr++;
+ }
+ }
+ break;
+ case GL_SHORT:
+ k = 0;
+ for (i=0;i<heightin;i++) {
+ GLshort *sptr = (GLshort *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride
+ + unpackskippixels * components;
+ for (j=0;j<widthin*components;j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) *sptr++;
+ }
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ k = 0;
+ for (i=0;i<heightin;i++) {
+ GLuint *uiptr = (GLuint *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride
+ + unpackskippixels * components;
+ for (j=0;j<widthin*components;j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) *uiptr++;
+ }
+ }
+ break;
+ case GL_INT:
+ k = 0;
+ for (i=0;i<heightin;i++) {
+ GLint *iptr = (GLint *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride
+ + unpackskippixels * components;
+ for (j=0;j<widthin*components;j++) {
+ dummy(j, k);
+ tempin[k++] = (GLfloat) *iptr++;
+ }
+ }
+ break;
+ case GL_FLOAT:
+ k = 0;
+ for (i=0;i<heightin;i++) {
+ GLfloat *fptr = (GLfloat *) datain
+ + i * rowstride
+ + unpackskiprows * rowstride
+ + unpackskippixels * components;
+ for (j=0;j<widthin*components;j++) {
+ dummy(j, k);
+ tempin[k++] = *fptr++;
+ }
+ }
+ break;
+ default:
+ return GLU_INVALID_ENUM;
+ }
+
+
+ /*
+ * Scale the image!
+ */
+
+ if (widthout > 1)
+ sx = (GLfloat) (widthin-1) / (GLfloat) (widthout-1);
+ else
+ sx = (GLfloat) (widthin-1);
+ if (heightout > 1)
+ sy = (GLfloat) (heightin-1) / (GLfloat) (heightout-1);
+ else
+ sy = (GLfloat) (heightin-1);
+
+/*#define POINT_SAMPLE*/
+#ifdef POINT_SAMPLE
+ for (i=0;i<heightout;i++) {
+ GLint ii = i * sy;
+ for (j=0;j<widthout;j++) {
+ GLint jj = j * sx;
+
+ GLfloat *src = tempin + (ii * widthin + jj) * components;
+ GLfloat *dst = tempout + (i * widthout + j) * components;
+
+ for (k=0;k<components;k++) {
+ *dst++ = *src++;
+ }
+ }
+ }
+#else
+ if (sx<1.0 && sy<1.0) {
+ /* magnify both width and height: use weighted sample of 4 pixels */
+ GLint i0, i1, j0, j1;
+ GLfloat alpha, beta;
+ GLfloat *src00, *src01, *src10, *src11;
+ GLfloat s1, s2;
+ GLfloat *dst;
+
+ for (i=0;i<heightout;i++) {
+ i0 = i * sy;
+ i1 = i0 + 1;
+ if (i1 >= heightin) i1 = heightin-1;
+/* i1 = (i+1) * sy - EPSILON;*/
+ alpha = i*sy - i0;
+ for (j=0;j<widthout;j++) {
+ j0 = j * sx;
+ j1 = j0 + 1;
+ if (j1 >= widthin) j1 = widthin-1;
+/* j1 = (j+1) * sx - EPSILON; */
+ beta = j*sx - j0;
+
+ /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
+ src00 = tempin + (i0 * widthin + j0) * components;
+ src01 = tempin + (i0 * widthin + j1) * components;
+ src10 = tempin + (i1 * widthin + j0) * components;
+ src11 = tempin + (i1 * widthin + j1) * components;
+
+ dst = tempout + (i * widthout + j) * components;
+
+ for (k=0;k<components;k++) {
+ s1 = *src00++ * (1.0-beta) + *src01++ * beta;
+ s2 = *src10++ * (1.0-beta) + *src11++ * beta;
+ *dst++ = s1 * (1.0-alpha) + s2 * alpha;
+ }
+ }
+ }
+ }
+ else {
+ /* shrink width and/or height: use an unweighted box filter */
+ GLint i0, i1;
+ GLint j0, j1;
+ GLint ii, jj;
+ GLfloat sum, *dst;
+
+ for (i=0;i<heightout;i++) {
+ i0 = i * sy;
+ i1 = i0 + 1;
+ if (i1 >= heightin) i1 = heightin-1;
+/* i1 = (i+1) * sy - EPSILON; */
+ for (j=0;j<widthout;j++) {
+ j0 = j * sx;
+ j1 = j0 + 1;
+ if (j1 >= widthin) j1 = widthin-1;
+/* j1 = (j+1) * sx - EPSILON; */
+
+ dst = tempout + (i * widthout + j) * components;
+
+ /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
+ for (k=0;k<components;k++) {
+ sum = 0.0;
+ for (ii=i0;ii<=i1;ii++) {
+ for (jj=j0;jj<=j1;jj++) {
+ sum += *(tempin + (ii * widthin + jj) * components + k);
+ }
+ }
+ sum /= (j1-j0+1) * (i1-i0+1);
+ *dst++ = sum;
+ }
+ }
+ }
+ }
+#endif
+
+
+ /*
+ * Return output image
+ */
+
+ if (packrowlength>0) {
+ rowlen = packrowlength;
+ }
+ else {
+ rowlen = widthout;
+ }
+ if (sizeout >= packalignment) {
+ rowstride = components * rowlen;
+ }
+ else {
+ rowstride = packalignment/sizeout
+ * CEILING( components * rowlen * sizeout, packalignment );
+ }
+
+ switch (typeout) {
+ case GL_UNSIGNED_BYTE:
+ k = 0;
+ for (i=0;i<heightout;i++) {
+ GLubyte *ubptr = (GLubyte *) dataout
+ + i * rowstride
+ + packskiprows * rowstride
+ + packskippixels * components;
+ for (j=0;j<widthout*components;j++) {
+ dummy(j, k+i);
+ *ubptr++ = (GLubyte) tempout[k++];
+ }
+ }
+ break;
+ case GL_BYTE:
+ k = 0;
+ for (i=0;i<heightout;i++) {
+ GLbyte *bptr = (GLbyte *) dataout
+ + i * rowstride
+ + packskiprows * rowstride
+ + packskippixels * components;
+ for (j=0;j<widthout*components;j++) {
+ dummy(j, k+i);
+ *bptr++ = (GLbyte) tempout[k++];
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ k = 0;
+ for (i=0;i<heightout;i++) {
+ GLushort *usptr = (GLushort *) dataout
+ + i * rowstride
+ + packskiprows * rowstride
+ + packskippixels * components;
+ for (j=0;j<widthout*components;j++) {
+ dummy(j, k+i);
+ *usptr++ = (GLushort) tempout[k++];
+ }
+ }
+ break;
+ case GL_SHORT:
+ k = 0;
+ for (i=0;i<heightout;i++) {
+ GLshort *sptr = (GLshort *) dataout
+ + i * rowstride
+ + packskiprows * rowstride
+ + packskippixels * components;
+ for (j=0;j<widthout*components;j++) {
+ dummy(j, k+i);
+ *sptr++ = (GLshort) tempout[k++];
+ }
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ k = 0;
+ for (i=0;i<heightout;i++) {
+ GLuint *uiptr = (GLuint *) dataout
+ + i * rowstride
+ + packskiprows * rowstride
+ + packskippixels * components;
+ for (j=0;j<widthout*components;j++) {
+ dummy(j, k+i);
+ *uiptr++ = (GLuint) tempout[k++];
+ }
+ }
+ break;
+ case GL_INT:
+ k = 0;
+ for (i=0;i<heightout;i++) {
+ GLint *iptr = (GLint *) dataout
+ + i * rowstride
+ + packskiprows * rowstride
+ + packskippixels * components;
+ for (j=0;j<widthout*components;j++) {
+ dummy(j, k+i);
+ *iptr++ = (GLint) tempout[k++];
+ }
+ }
+ break;
+ case GL_FLOAT:
+ k = 0;
+ for (i=0;i<heightout;i++) {
+ GLfloat *fptr = (GLfloat *) dataout
+ + i * rowstride
+ + packskiprows * rowstride
+ + packskippixels * components;
+ for (j=0;j<widthout*components;j++) {
+ dummy(j, k+i);
+ *fptr++ = tempout[k++];
+ }
+ }
+ break;
+ default:
+ return GLU_INVALID_ENUM;
+ }
+
+
+ /* free temporary image storage */
+ free( tempin );
+ free( tempout );
+
+ return 0;
+}
+
+
+
+/*
+ * Return the largest k such that 2^k <= n.
+ */
+static GLint ilog2( GLint n )
+{
+ GLint k;
+
+ if (n<=0) return 0;
+ for (k=0; n>>=1; k++) ;
+ return k;
+}
+
+
+
+/*
+ * Find the value nearest to n which is also a power of two.
+ */
+static GLint round2( GLint n )
+{
+ GLint m;
+
+ for (m=1; m<n; m*=2)
+ ;
+
+ /* m>=n */
+ if (m-n <= n-m/2) {
+ return m;
+ }
+ else {
+ return m/2;
+ }
+}
+
+
+/*
+ * Given an pixel format and datatype, return the number of bytes to
+ * store one pixel.
+ */
+static GLint bytes_per_pixel( GLenum format, GLenum type )
+{
+ GLint n, m;
+
+ switch (format) {
+ case GL_COLOR_INDEX:
+ case GL_STENCIL_INDEX:
+ case GL_DEPTH_COMPONENT:
+ case GL_RED:
+ case GL_GREEN:
+ case GL_BLUE:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ n = 1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ n = 2;
+ break;
+ case GL_RGB:
+ n = 3;
+ break;
+ case GL_RGBA:
+#ifdef GL_EXT_abgr
+ case GL_ABGR_EXT:
+#endif
+ n = 4;
+ break;
+ default:
+ n = 0;
+ }
+
+ switch (type) {
+ case GL_UNSIGNED_BYTE: m = sizeof(GLubyte); break;
+ case GL_BYTE: m = sizeof(GLbyte); break;
+ case GL_BITMAP: m = 1; break;
+ case GL_UNSIGNED_SHORT: m = sizeof(GLushort); break;
+ case GL_SHORT: m = sizeof(GLshort); break;
+ case GL_UNSIGNED_INT: m = sizeof(GLuint); break;
+ case GL_INT: m = sizeof(GLint); break;
+ case GL_FLOAT: m = sizeof(GLfloat); break;
+ default: m = 0;
+ }
+
+ return n * m;
+}
+
+
+
+/*
+ * WARNING: This function isn't finished and has never been tested!!!!
+ */
+GLint GLAPIENTRY gluBuild1DMipmaps( GLenum target, GLint components,
+ GLint width, GLenum format,
+ GLenum type, const void *data )
+{
+ GLubyte *texture;
+ GLint levels, max_levels;
+ GLint new_width, max_width;
+ GLint i, j, k, l;
+
+ if (width < 1)
+ return GLU_INVALID_VALUE;
+
+ glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_width );
+ max_levels = ilog2( max_width ) + 1;
+
+ /* Compute how many mipmap images to make */
+ levels = ilog2( width ) + 1;
+ if (levels>max_levels) {
+ levels = max_levels;
+ }
+
+ new_width = 1 << (levels-1);
+
+ texture = (GLubyte *) malloc( new_width * components );
+ if (!texture) {
+ return GLU_OUT_OF_MEMORY;
+ }
+
+ if (width != new_width) {
+ /* initial rescaling */
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ {
+ GLubyte *ub_data = (GLubyte *) data;
+ for (i=0;i<new_width;i++) {
+ j = i * width / new_width;
+ for (k=0;k<components;k++) {
+ texture[i*components+k] = ub_data[j*components+k];
+ }
+ }
+ }
+ break;
+ default:
+ /* Not implemented */
+ return GLU_ERROR;
+ }
+ }
+
+ /* generate and load mipmap images */
+ for (l=0;l<levels;l++) {
+ glTexImage1D( GL_TEXTURE_1D, l, components, new_width, 0,
+ format, GL_UNSIGNED_BYTE, texture );
+
+ /* Scale image down to 1/2 size */
+ new_width = new_width / 2;
+ for (i=0;i<new_width;i++) {
+ for (k=0;k<components;k++) {
+ GLint sample1, sample2;
+ sample1 = (GLint) texture[i*2*components+k];
+ sample2 = (GLint) texture[(i*2+1)*components+k];
+ texture[i*components+k] = (GLubyte) ((sample1 + sample2) / 2);
+ }
+ }
+ }
+
+ free( texture );
+
+ /* make sure remaining mipmap levels are removed */
+ for (l=levels;l<max_levels;l++) {
+ glTexImage1D( GL_TEXTURE_1D, l, components, 0, 0,
+ format, GL_UNSIGNED_BYTE, NULL );
+ }
+
+ return 0;
+}
+
+
+
+GLint GLAPIENTRY gluBuild2DMipmaps( GLenum target, GLint components,
+ GLint width, GLint height, GLenum format,
+ GLenum type, const void *data )
+{
+ GLint w, h, maxsize;
+ void *image, *newimage;
+ GLint neww, newh, level, bpp;
+ int error;
+
+ if (width < 1 || height < 1)
+ return GLU_INVALID_VALUE;
+
+ glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxsize );
+
+ w = round2( width );
+ if (w>maxsize) {
+ w = maxsize;
+ }
+ h = round2( height );
+ if (h>maxsize) {
+ h = maxsize;
+ }
+
+ bpp = bytes_per_pixel( format, type );
+ if (bpp==0) {
+ /* probably a bad format or type enum */
+ return GLU_INVALID_ENUM;
+ }
+
+ if (w!=width || h!=height) {
+ /* must rescale image to get "top" mipmap texture image */
+ image = malloc( (w+4) * h * bpp );
+ if (!image) {
+ return GLU_OUT_OF_MEMORY;
+ }
+ error = gluScaleImage( format, width, height, type, data,
+ w, h, type, image );
+ if (error) {
+ return error;
+ }
+ }
+ else {
+ image = (void *) data;
+ }
+
+ level = 0;
+ while (1) {
+ glTexImage2D( target, level, components, w, h, 0, format, type, image );
+
+ if (w==1 && h==1) break;
+
+ neww = (w<2) ? 1 : w/2;
+ newh = (h<2) ? 1 : h/2;
+ newimage = malloc( (neww+4) * newh * bpp );
+ if (!newimage) {
+ return GLU_OUT_OF_MEMORY;
+ }
+
+ error = gluScaleImage( format, w, h, type, image,
+ neww, newh, type, newimage );
+ if (error) {
+ return error;
+ }
+
+ if (image!=data) {
+ free( image );
+ }
+ image = newimage;
+
+ w = neww;
+ h = newh;
+ level++;
+ }
+
+ if (image!=data) {
+ free( image );
+ }
+
+ return 0;
+}
+
diff --git a/src/glu/mesa/mms_depend b/src/glu/mesa/mms_depend
new file mode 100644
index 00000000000..372e3fff1e9
--- /dev/null
+++ b/src/glu/mesa/mms_depend
@@ -0,0 +1,13 @@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+glu.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h
+mipmap.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h
+nurbs.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h nurbs.h
+nurbscrv.obj : nurbs.h gluP.h [-.include.gl]gl.h [-.include.gl]glu.h
+nurbssrf.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h nurbs.h
+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
diff --git a/src/glu/mesa/nurbs.c b/src/glu/mesa/nurbs.c
new file mode 100644
index 00000000000..65bc6f8acb7
--- /dev/null
+++ b/src/glu/mesa/nurbs.c
@@ -0,0 +1,715 @@
+/* $Id: nurbs.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ * Copyright (C) 1995-1999 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: nurbs.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.14 1999/01/03 03:23:15 brianp
+ * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
+ *
+ * Revision 1.13 1998/06/01 01:07:49 brianp
+ * small update for Next/OpenStep from Alexander Mai
+ *
+ * Revision 1.12 1998/03/15 18:14:30 brianp
+ * fixed a compiler cast warning
+ *
+ * Revision 1.11 1998/02/07 14:29:11 brianp
+ * fixed casting problem in gluNurbsCallback, again
+ *
+ * Revision 1.10 1998/02/04 00:21:20 brianp
+ * fixed cygnus compilation problem (Stephane Rehel)
+ *
+ * Revision 1.9 1998/01/16 03:35:26 brianp
+ * fixed Windows compilation warnings (Theodore Jump)
+ *
+ * Revision 1.8 1997/09/17 01:51:48 brianp
+ * changed glu*Callback() functions to match prototype in glu.h
+ *
+ * Revision 1.7 1997/07/24 01:28:44 brianp
+ * changed precompiled header symbol from PCH to PC_HEADER
+ *
+ * Revision 1.6 1997/07/24 01:26:31 brianp
+ * added CALLBACK keyword to gluNurbsCallback()
+ *
+ * Revision 1.5 1997/05/28 02:29:38 brianp
+ * added support for precompiled headers (PCH), inserted APIENTRY keyword
+ *
+ * Revision 1.4 1997/05/27 03:17:22 brianp
+ * minor clean-up
+ *
+ * Revision 1.3 1997/05/27 03:00:16 brianp
+ * incorporated Bogdan's new NURBS code
+ *
+ * Revision 1.2 1996/09/27 23:11:23 brianp
+ * ifdef'd out unimplemented trimmed nurbs code
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+/*
+ * NURBS implementation written by Bogdan Sikorski ([email protected])
+ * See README2 for more info.
+ */
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include "gluP.h"
+#include "nurbs.h"
+#endif
+
+
+void
+call_user_error( GLUnurbsObj *nobj, GLenum error )
+{
+ nobj->error=error;
+ if(nobj->error_callback != NULL) {
+ (*(nobj->error_callback))(error);
+ }
+ else {
+ printf("NURBS error %d %s\n", error, (char *) gluErrorString(error) );
+ }
+}
+
+
+
+GLUnurbsObj * GLAPIENTRY gluNewNurbsRenderer( void )
+{
+ GLUnurbsObj *n;
+ GLfloat tmp_viewport[4];
+ GLint i,j;
+
+ n = (GLUnurbsObj *) malloc( sizeof(GLUnurbsObj) );
+ if (n) {
+ /* init */
+ n->culling=GL_FALSE;
+ n->nurbs_type=GLU_NURBS_NONE;
+ n->error=GLU_NO_ERROR;
+ n->error_callback=NULL;
+ n->auto_load_matrix=GL_TRUE;
+ n->sampling_tolerance=50.0;
+ n->parametric_tolerance=0.5;
+ n->u_step = n->v_step = 100;
+ n->sampling_method = GLU_PATH_LENGTH;
+ n->display_mode=GLU_FILL;
+ /* in case the user doesn't supply the sampling matrices */
+ /* set projection and modelview to identity */
+ for(i=0;i<4;i++)
+ for(j=0;j<4;j++)
+ if(i==j)
+ {
+ n->sampling_matrices.model[i*4+j]=1.0;
+ n->sampling_matrices.proj[i*4+j]=1.0;
+ }
+ else
+ {
+ n->sampling_matrices.model[i*4+j]=0.0;
+ n->sampling_matrices.proj[i*4+j]=0.0;
+ }
+ /* and set the viewport sampling matrix to current ciewport */
+ glGetFloatv(GL_VIEWPORT,tmp_viewport);
+ for(i=0;i<4;i++)
+ n->sampling_matrices.viewport[i]=tmp_viewport[i];
+ n->trim=NULL;
+ }
+ return n;
+}
+
+
+
+void GLAPIENTRY gluDeleteNurbsRenderer( GLUnurbsObj *nobj )
+{
+ if (nobj) {
+ free( nobj );
+ }
+}
+
+
+
+void GLAPIENTRY gluLoadSamplingMatrices( GLUnurbsObj *nobj,
+ const GLfloat modelMatrix[16],
+ const GLfloat projMatrix[16],
+ const GLint viewport[4] )
+{
+ GLint i;
+
+ for(i=0;i<16;i++)
+ {
+ nobj->sampling_matrices.model[i]=modelMatrix[i];
+ nobj->sampling_matrices.proj[i]=projMatrix[i];
+ }
+ for(i=0;i<4;i++)
+ nobj->sampling_matrices.viewport[i]=viewport[i];
+}
+
+
+void GLAPIENTRY gluNurbsProperty( GLUnurbsObj *nobj, GLenum property, GLfloat value )
+{
+ GLenum val;
+
+ switch (property) {
+ case GLU_SAMPLING_TOLERANCE:
+ if(value <= 0.0)
+ {
+ call_user_error(nobj,GLU_INVALID_VALUE);
+ return;
+ }
+ nobj->sampling_tolerance=value;
+ break;
+ case GLU_PARAMETRIC_TOLERANCE:
+ if(value <= 0.0)
+ {
+ call_user_error(nobj,GLU_INVALID_VALUE);
+ return;
+ }
+ nobj->parametric_tolerance=value;
+ break;
+ case GLU_U_STEP:
+ if(value <= 0.0)
+ {
+ call_user_error(nobj,GLU_INVALID_VALUE);
+ return;
+ }
+ nobj->u_step=(GLint)value;
+ break;
+ case GLU_V_STEP:
+ if(value <= 0.0)
+ {
+ call_user_error(nobj,GLU_INVALID_VALUE);
+ return;
+ }
+ nobj->v_step=(GLint)value;
+ break;
+ case GLU_SAMPLING_METHOD:
+ val = (GLenum)value;
+ if(val!=GLU_PATH_LENGTH && val!=GLU_PARAMETRIC_ERROR && val!=GLU_DOMAIN_DISTANCE)
+ {
+ call_user_error(nobj,GLU_INVALID_ENUM);
+ return;
+ }
+ nobj->sampling_method=val;
+ break;
+ case GLU_DISPLAY_MODE:
+ val=(GLenum)value;
+ if(val!=GLU_FILL && val!=GLU_OUTLINE_POLYGON && val!=GLU_OUTLINE_PATCH)
+ {
+ call_user_error(nobj,GLU_INVALID_ENUM);
+ return;
+ }
+ if(nobj->nurbs_type==GLU_NURBS_CURVE)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR26);
+ return;
+ }
+ nobj->display_mode=val;
+if(val==GLU_OUTLINE_PATCH)
+ fprintf(stderr,"NURBS, for the moment, can display only in POLYGON mode\n");
+ break;
+ case GLU_CULLING:
+ val=(GLenum)value;
+ if(val!=GL_TRUE && val!=GL_FALSE)
+ {
+ call_user_error(nobj,GLU_INVALID_ENUM);
+ return;
+ }
+ nobj->culling = (GLboolean) value;
+ break;
+ case GLU_AUTO_LOAD_MATRIX:
+ val=(GLenum)value;
+ if(val!=GL_TRUE && val!=GL_FALSE)
+ {
+ call_user_error(nobj,GLU_INVALID_ENUM);
+ return;
+ }
+ nobj->auto_load_matrix = (GLboolean) value;
+ break;
+ default:
+ call_user_error(nobj,GLU_NURBS_ERROR26);
+ }
+}
+
+
+void GLAPIENTRY gluGetNurbsProperty( GLUnurbsObj *nobj, GLenum property, GLfloat *value )
+{
+ switch (property) {
+ case GLU_SAMPLING_TOLERANCE:
+ *value = nobj->sampling_tolerance;
+ break;
+ case GLU_DISPLAY_MODE:
+ *value = (GLfloat) (GLint) nobj->display_mode;
+ break;
+ case GLU_CULLING:
+ *value = nobj->culling ? 1.0 : 0.0;
+ break;
+ case GLU_AUTO_LOAD_MATRIX:
+ *value = nobj->auto_load_matrix ? 1.0 : 0.0;
+ break;
+ default:
+ call_user_error(nobj,GLU_INVALID_ENUM);
+ }
+}
+
+
+
+void GLAPIENTRY gluBeginCurve( GLUnurbsObj *nobj )
+{
+ if(nobj->nurbs_type==GLU_NURBS_CURVE)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR6);
+ return;
+ }
+ nobj->nurbs_type=GLU_NURBS_CURVE;
+ nobj->curve.geom.type=GLU_INVALID_ENUM;
+ nobj->curve.color.type=GLU_INVALID_ENUM;
+ nobj->curve.texture.type=GLU_INVALID_ENUM;
+ nobj->curve.normal.type=GLU_INVALID_ENUM;
+}
+
+
+void GLAPIENTRY gluEndCurve( GLUnurbsObj * nobj )
+{
+ if(nobj->nurbs_type==GLU_NURBS_NONE)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR7);
+ return;
+ }
+ if(nobj->curve.geom.type==GLU_INVALID_ENUM)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR8);
+ nobj->nurbs_type=GLU_NURBS_NONE;
+ return;
+ }
+ glPushAttrib( (GLbitfield) (GL_EVAL_BIT | GL_ENABLE_BIT) );
+ glDisable(GL_MAP1_VERTEX_3);
+ glDisable(GL_MAP1_VERTEX_4);
+ glDisable(GL_MAP1_INDEX);
+ glDisable(GL_MAP1_COLOR_4);
+ glDisable(GL_MAP1_NORMAL);
+ glDisable(GL_MAP1_TEXTURE_COORD_1);
+ glDisable(GL_MAP1_TEXTURE_COORD_2);
+ glDisable(GL_MAP1_TEXTURE_COORD_3);
+ glDisable(GL_MAP1_TEXTURE_COORD_4);
+ glDisable(GL_MAP2_VERTEX_3);
+ glDisable(GL_MAP2_VERTEX_4);
+ glDisable(GL_MAP2_INDEX);
+ glDisable(GL_MAP2_COLOR_4);
+ glDisable(GL_MAP2_NORMAL);
+ glDisable(GL_MAP2_TEXTURE_COORD_1);
+ glDisable(GL_MAP2_TEXTURE_COORD_2);
+ glDisable(GL_MAP2_TEXTURE_COORD_3);
+ glDisable(GL_MAP2_TEXTURE_COORD_4);
+ do_nurbs_curve(nobj);
+ glPopAttrib();
+ nobj->nurbs_type=GLU_NURBS_NONE;
+}
+
+
+void GLAPIENTRY gluNurbsCurve( GLUnurbsObj *nobj, GLint nknots, GLfloat *knot,
+ GLint stride, GLfloat *ctlarray, GLint order, GLenum type )
+{
+ if(nobj->nurbs_type==GLU_NURBS_TRIM)
+ {
+#if 0
+/* TODO: NOT IMPLEMENTED YET */
+ nurbs_trim *ptr1;
+ trim_list *ptr2;
+
+ if(type!=GLU_MAP1_TRIM_2 && type!=GLU_MAP1_TRIM_3)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR14);
+ return;
+ }
+ for(ptr1=nobj->trim;ptr1->next;ptr1=ptr1->next);
+ if(ptr1->trim_loop)
+ {
+ for(ptr2=ptr1->trim_loop;ptr2->next;ptr2=ptr2->next);
+ if((ptr2->next=(trim_list *)malloc(sizeof(trim_list)))==NULL)
+ {
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ ptr2=ptr2->next;
+ }
+ else
+ {
+ if((ptr2=(trim_list *)malloc(sizeof(trim_list)))==NULL)
+ {
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ ptr1->trim_loop=ptr2;
+ }
+ ptr2->trim_type=GLU_TRIM_NURBS;
+ ptr2->curve.nurbs_curve.knot_count=nknots;
+ ptr2->curve.nurbs_curve.knot=knot;
+ ptr2->curve.nurbs_curve.stride=stride;
+ ptr2->curve.nurbs_curve.ctrlarray=ctlarray;
+ ptr2->curve.nurbs_curve.order=order;
+ ptr2->curve.nurbs_curve.dim= (type==GLU_MAP1_TRIM_2 ? 2 : 3 );
+ ptr2->curve.nurbs_curve.type=type;
+ ptr2->next=NULL;
+#endif
+ }
+ else
+ {
+ if(type==GLU_MAP1_TRIM_2 || type==GLU_MAP1_TRIM_3)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR22);
+ return;
+ }
+ if(nobj->nurbs_type!=GLU_NURBS_CURVE)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR10);
+ return;
+ }
+ switch(type)
+ {
+ case GL_MAP1_VERTEX_3:
+ case GL_MAP1_VERTEX_4:
+ if(nobj->curve.geom.type!=GLU_INVALID_ENUM)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR8);
+ return;
+ }
+ nobj->curve.geom.type=type;
+ nobj->curve.geom.knot_count=nknots;
+ nobj->curve.geom.knot=knot;
+ nobj->curve.geom.stride=stride;
+ nobj->curve.geom.ctrlarray=ctlarray;
+ nobj->curve.geom.order=order;
+ break;
+ case GL_MAP1_INDEX:
+ case GL_MAP1_COLOR_4:
+ nobj->curve.color.type=type;
+ nobj->curve.color.knot_count=nknots;
+ nobj->curve.color.knot=knot;
+ nobj->curve.color.stride=stride;
+ nobj->curve.color.ctrlarray=ctlarray;
+ nobj->curve.color.order=order;
+ break;
+ case GL_MAP1_NORMAL:
+ nobj->curve.normal.type=type;
+ nobj->curve.normal.knot_count=nknots;
+ nobj->curve.normal.knot=knot;
+ nobj->curve.normal.stride=stride;
+ nobj->curve.normal.ctrlarray=ctlarray;
+ nobj->curve.normal.order=order;
+ break;
+ case GL_MAP1_TEXTURE_COORD_1:
+ case GL_MAP1_TEXTURE_COORD_2:
+ case GL_MAP1_TEXTURE_COORD_3:
+ case GL_MAP1_TEXTURE_COORD_4:
+ nobj->curve.texture.type=type;
+ nobj->curve.texture.knot_count=nknots;
+ nobj->curve.texture.knot=knot;
+ nobj->curve.texture.stride=stride;
+ nobj->curve.texture.ctrlarray=ctlarray;
+ nobj->curve.texture.order=order;
+ break;
+ default:
+ call_user_error(nobj,GLU_INVALID_ENUM);
+ }
+ }
+}
+
+
+void GLAPIENTRY gluBeginSurface( GLUnurbsObj *nobj )
+{
+ switch(nobj->nurbs_type)
+ {
+ case GLU_NURBS_NONE:
+ nobj->nurbs_type=GLU_NURBS_SURFACE;
+ nobj->surface.geom.type=GLU_INVALID_ENUM;
+ nobj->surface.color.type=GLU_INVALID_ENUM;
+ nobj->surface.texture.type=GLU_INVALID_ENUM;
+ nobj->surface.normal.type=GLU_INVALID_ENUM;
+ break;
+ case GLU_NURBS_TRIM:
+ call_user_error(nobj,GLU_NURBS_ERROR16);
+ break;
+ case GLU_NURBS_SURFACE:
+ case GLU_NURBS_NO_TRIM:
+ case GLU_NURBS_TRIM_DONE:
+ call_user_error(nobj,GLU_NURBS_ERROR27);
+ break;
+ case GLU_NURBS_CURVE:
+ call_user_error(nobj,GLU_NURBS_ERROR6);
+ break;
+ }
+}
+
+
+void GLAPIENTRY gluEndSurface( GLUnurbsObj * nobj )
+{
+ switch(nobj->nurbs_type)
+ {
+ case GLU_NURBS_NONE:
+ call_user_error(nobj,GLU_NURBS_ERROR13);
+ break;
+ case GLU_NURBS_TRIM:
+ call_user_error(nobj,GLU_NURBS_ERROR12);
+ break;
+ case GLU_NURBS_TRIM_DONE:
+/* if(nobj->trim->trim_loop==NULL)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR18);
+ return;
+ }*/
+ /* no break - fallthrough */
+ case GLU_NURBS_NO_TRIM:
+ glPushAttrib( (GLbitfield)
+ (GL_EVAL_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT) );
+ glDisable(GL_MAP2_VERTEX_3);
+ glDisable(GL_MAP2_VERTEX_4);
+ glDisable(GL_MAP2_INDEX);
+ glDisable(GL_MAP2_COLOR_4);
+ glDisable(GL_MAP2_NORMAL);
+ glDisable(GL_MAP2_TEXTURE_COORD_1);
+ glDisable(GL_MAP2_TEXTURE_COORD_2);
+ glDisable(GL_MAP2_TEXTURE_COORD_3);
+ glDisable(GL_MAP2_TEXTURE_COORD_4);
+/* glDisable(GL_MAP1_VERTEX_3);
+ glDisable(GL_MAP1_VERTEX_4);
+ glDisable(GL_MAP1_INDEX);
+ glDisable(GL_MAP1_COLOR_4);
+ glDisable(GL_MAP1_NORMAL);
+ glDisable(GL_MAP1_TEXTURE_COORD_1);
+ glDisable(GL_MAP1_TEXTURE_COORD_2);
+ glDisable(GL_MAP1_TEXTURE_COORD_3);
+ glDisable(GL_MAP1_TEXTURE_COORD_4);*/
+ do_nurbs_surface(nobj);
+ glPopAttrib();
+ break;
+ default:
+ call_user_error(nobj,GLU_NURBS_ERROR8);
+ }
+ nobj->nurbs_type=GLU_NURBS_NONE;
+}
+
+
+void GLAPIENTRY gluNurbsSurface( GLUnurbsObj *nobj,
+ GLint sknot_count, GLfloat *sknot,
+ GLint tknot_count, GLfloat *tknot,
+ GLint s_stride, GLint t_stride,
+ GLfloat *ctrlarray,
+ GLint sorder, GLint torder,
+ GLenum type )
+{
+ if(nobj->nurbs_type==GLU_NURBS_NO_TRIM || nobj->nurbs_type==GLU_NURBS_TRIM ||
+ nobj->nurbs_type==GLU_NURBS_TRIM_DONE)
+ {
+ if(type==GL_MAP2_VERTEX_3 || type==GL_MAP2_VERTEX_4)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR8);
+ return;
+ }
+ }
+ else
+ if(nobj->nurbs_type!=GLU_NURBS_SURFACE)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR11);
+ return;
+ }
+ switch(type)
+ {
+ case GL_MAP2_VERTEX_3:
+ case GL_MAP2_VERTEX_4:
+ nobj->surface.geom.sknot_count=sknot_count;
+ nobj->surface.geom.sknot=sknot;
+ nobj->surface.geom.tknot_count=tknot_count;
+ nobj->surface.geom.tknot=tknot;
+ nobj->surface.geom.s_stride=s_stride;
+ nobj->surface.geom.t_stride=t_stride;
+ nobj->surface.geom.ctrlarray=ctrlarray;
+ nobj->surface.geom.sorder=sorder;
+ nobj->surface.geom.torder=torder;
+ nobj->surface.geom.type=type;
+ nobj->nurbs_type=GLU_NURBS_NO_TRIM;
+ break;
+ case GL_MAP2_INDEX:
+ case GL_MAP2_COLOR_4:
+ nobj->surface.color.sknot_count=sknot_count;
+ nobj->surface.color.sknot=sknot;
+ nobj->surface.color.tknot_count=tknot_count;
+ nobj->surface.color.tknot=tknot;
+ nobj->surface.color.s_stride=s_stride;
+ nobj->surface.color.t_stride=t_stride;
+ nobj->surface.color.ctrlarray=ctrlarray;
+ nobj->surface.color.sorder=sorder;
+ nobj->surface.color.torder=torder;
+ nobj->surface.color.type=type;
+ break;
+ case GL_MAP2_NORMAL:
+ nobj->surface.normal.sknot_count=sknot_count;
+ nobj->surface.normal.sknot=sknot;
+ nobj->surface.normal.tknot_count=tknot_count;
+ nobj->surface.normal.tknot=tknot;
+ nobj->surface.normal.s_stride=s_stride;
+ nobj->surface.normal.t_stride=t_stride;
+ nobj->surface.normal.ctrlarray=ctrlarray;
+ nobj->surface.normal.sorder=sorder;
+ nobj->surface.normal.torder=torder;
+ nobj->surface.normal.type=type;
+ break;
+ case GL_MAP2_TEXTURE_COORD_1:
+ case GL_MAP2_TEXTURE_COORD_2:
+ case GL_MAP2_TEXTURE_COORD_3:
+ case GL_MAP2_TEXTURE_COORD_4:
+ nobj->surface.texture.sknot_count=sknot_count;
+ nobj->surface.texture.sknot=sknot;
+ nobj->surface.texture.tknot_count=tknot_count;
+ nobj->surface.texture.tknot=tknot;
+ nobj->surface.texture.s_stride=s_stride;
+ nobj->surface.texture.t_stride=t_stride;
+ nobj->surface.texture.ctrlarray=ctrlarray;
+ nobj->surface.texture.sorder=sorder;
+ nobj->surface.texture.torder=torder;
+ nobj->surface.texture.type=type;
+ break;
+ default:
+ call_user_error(nobj,GLU_INVALID_ENUM);
+ }
+}
+
+
+void GLAPIENTRY
+gluNurbsCallback( GLUnurbsObj *nobj, GLenum which, void (GLCALLBACK *fn)())
+{
+#if defined(__CYGWIN32__) || defined(OPENSTEP)
+ nobj->error_callback = (void(*)(GLenum))fn;
+#else
+ nobj->error_callback = (void(GLCALLBACK*)(GLenum))fn;
+#endif
+
+ if(which!=GLU_ERROR)
+ call_user_error(nobj,GLU_INVALID_ENUM);
+}
+
+void GLAPIENTRY
+gluBeginTrim( GLUnurbsObj *nobj )
+{
+#if 0
+ nurbs_trim *ptr;
+#endif
+
+ if(nobj->nurbs_type!=GLU_NURBS_TRIM_DONE)
+ if(nobj->nurbs_type!=GLU_NURBS_NO_TRIM)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR15);
+ return;
+ }
+ nobj->nurbs_type=GLU_NURBS_TRIM;
+fprintf(stderr,"NURBS - trimming not supported yet\n");
+#if 0
+ if((ptr=(nurbs_trim *)malloc(sizeof(nurbs_trim)))==NULL)
+ {
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ if(nobj->trim)
+ {
+ nurbs_trim *tmp_ptr;
+
+ for(tmp_ptr=nobj->trim;tmp_ptr->next;tmp_ptr=tmp_ptr->next);
+ tmp_ptr->next=ptr;
+ }
+ else
+ nobj->trim=ptr;
+ ptr->trim_loop=NULL;
+ ptr->segments=NULL;
+ ptr->next=NULL;
+#endif
+}
+
+void GLAPIENTRY
+gluPwlCurve( GLUnurbsObj *nobj, GLint count, GLfloat *array, GLint stride,
+ GLenum type)
+{
+#if 0
+ nurbs_trim *ptr1;
+ trim_list *ptr2;
+#endif
+ if(nobj->nurbs_type==GLU_NURBS_CURVE)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR9);
+ return;
+ }
+ if(nobj->nurbs_type==GLU_NURBS_NONE)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR19);
+ return;
+ }
+ if(type!=GLU_MAP1_TRIM_2 && type!=GLU_MAP1_TRIM_3)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR14);
+ return;
+ }
+#if 0
+ for(ptr1=nobj->trim;ptr1->next;ptr1=ptr1->next);
+ if(ptr1->trim_loop)
+ {
+ for(ptr2=ptr1->trim_loop;ptr2->next;ptr2=ptr2->next);
+ if((ptr2->next=(trim_list *)malloc(sizeof(trim_list)))==NULL)
+ {
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ ptr2=ptr2->next;
+ }
+ else
+ {
+ if((ptr2=(trim_list *)malloc(sizeof(trim_list)))==NULL)
+ {
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ ptr1->trim_loop=ptr2;
+ }
+ ptr2->trim_type=GLU_TRIM_PWL;
+ ptr2->curve.pwl_curve.pt_count=count;
+ ptr2->curve.pwl_curve.ctrlarray=array;
+ ptr2->curve.pwl_curve.stride=stride;
+ ptr2->curve.pwl_curve.dim= (type==GLU_MAP1_TRIM_2 ? 2 : 3 );
+ ptr2->curve.pwl_curve.type=type;
+ ptr2->next=NULL;
+#endif
+}
+
+void GLAPIENTRY
+gluEndTrim( GLUnurbsObj *nobj )
+{
+ if(nobj->nurbs_type!=GLU_NURBS_TRIM)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR17);
+ return;
+ }
+ nobj->nurbs_type=GLU_NURBS_TRIM_DONE;
+}
+
diff --git a/src/glu/mesa/nurbs.h b/src/glu/mesa/nurbs.h
new file mode 100644
index 00000000000..fc2b4f7d557
--- /dev/null
+++ b/src/glu/mesa/nurbs.h
@@ -0,0 +1,252 @@
+/* $Id: nurbs.h,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ * Copyright (C) 1995-1999 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: nurbs.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/05/27 03:18:23 brianp
+ * minor clean-up
+ *
+ * Revision 1.2 1997/05/27 03:00:16 brianp
+ * incorporated Bogdan's new NURBS code
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+/*
+ * NURBS implementation written by Bogdan Sikorski ([email protected])
+ * See README2 for more info.
+ */
+
+
+#ifndef NURBS_H
+#define NURBS_H
+
+
+#define EPSILON 1e-06 /* epsilon for double precision compares */
+
+typedef enum
+{
+ GLU_NURBS_CURVE, GLU_NURBS_SURFACE, GLU_NURBS_TRIM, GLU_NURBS_NO_TRIM,
+ GLU_NURBS_TRIM_DONE, GLU_NURBS_NONE
+} GLU_nurbs_enum;
+
+typedef enum
+{
+ GLU_TRIM_NURBS, GLU_TRIM_PWL
+} GLU_trim_enum;
+
+typedef struct
+{
+ GLint sknot_count;
+ GLfloat *sknot;
+ GLint tknot_count;
+ GLfloat *tknot;
+ GLint s_stride;
+ GLint t_stride;
+ GLfloat *ctrlarray;
+ GLint sorder;
+ GLint torder;
+ GLint dim;
+ GLenum type;
+} surface_attribs;
+
+typedef struct
+{
+ surface_attribs geom;
+ surface_attribs color;
+ surface_attribs texture;
+ surface_attribs normal;
+} nurbs_surface;
+
+typedef struct
+{
+ GLint knot_count;
+ GLfloat *knot;
+ GLint stride;
+ GLfloat *ctrlarray;
+ GLint order;
+ GLint dim;
+ GLenum type;
+} curve_attribs;
+
+typedef struct
+{
+ GLint pt_count;
+ GLfloat *ctrlarray;
+ GLint stride;
+ GLint dim;
+ GLenum type;
+} pwl_curve_attribs;
+
+typedef struct
+{
+ curve_attribs geom;
+ curve_attribs color;
+ curve_attribs texture;
+ curve_attribs normal;
+} nurbs_curve;
+
+typedef struct trim_list_str
+{
+ GLU_trim_enum trim_type;
+ union
+ {
+ pwl_curve_attribs pwl_curve;
+ curve_attribs nurbs_curve;
+ } curve;
+ struct trim_list_str *next;
+} trim_list;
+
+typedef struct seg_trim_str
+{
+ GLfloat *points;
+ GLint pt_cnt,seg_array_len;
+ struct seg_trim_str *next;
+} trim_segments;
+
+typedef struct nurbs_trim_str
+{
+ trim_list *trim_loop;
+ trim_segments *segments;
+ struct nurbs_trim_str *next;
+} nurbs_trim;
+
+typedef struct
+{
+ GLfloat model[16],proj[16],viewport[4];
+} culling_and_sampling_str;
+
+struct GLUnurbs {
+ GLboolean culling;
+ GLenum error;
+ void (GLCALLBACK *error_callback)( GLenum err );
+ GLenum display_mode;
+ GLU_nurbs_enum nurbs_type;
+ GLboolean auto_load_matrix;
+ culling_and_sampling_str
+ sampling_matrices;
+ GLenum sampling_method;
+ GLfloat sampling_tolerance;
+ GLfloat parametric_tolerance;
+ GLint u_step, v_step;
+ nurbs_surface surface;
+ nurbs_curve curve;
+ nurbs_trim *trim;
+};
+
+typedef struct
+{
+ GLfloat *knot;
+ GLint nknots;
+ GLfloat *unified_knot;
+ GLint unified_nknots;
+ GLint order;
+ GLint t_min,t_max;
+ GLint delta_nknots;
+ GLboolean open_at_begin,open_at_end;
+ GLfloat *new_knot;
+ GLfloat *alpha;
+} knot_str_type;
+
+typedef struct
+{
+ GLfloat *geom_ctrl;
+ GLint geom_s_stride,geom_t_stride;
+ GLfloat **geom_offsets;
+ GLint geom_s_pt_cnt,geom_t_pt_cnt;
+ GLfloat *color_ctrl;
+ GLint color_s_stride,color_t_stride;
+ GLfloat **color_offsets;
+ GLint color_s_pt_cnt,color_t_pt_cnt;
+ GLfloat *normal_ctrl;
+ GLint normal_s_stride,normal_t_stride;
+ GLfloat **normal_offsets;
+ GLint normal_s_pt_cnt,normal_t_pt_cnt;
+ GLfloat *texture_ctrl;
+ GLint texture_s_stride,texture_t_stride;
+ GLfloat **texture_offsets;
+ GLint texture_s_pt_cnt,texture_t_pt_cnt;
+ GLint s_bezier_cnt,t_bezier_cnt;
+} new_ctrl_type;
+
+extern void call_user_error( GLUnurbsObj *nobj, GLenum error );
+
+extern GLenum test_knot(GLint nknots, GLfloat *knot, GLint order);
+
+extern GLenum explode_knot(knot_str_type *the_knot);
+
+extern GLenum calc_alphas(knot_str_type *the_knot);
+
+extern GLenum calc_new_ctrl_pts(GLfloat *ctrl,GLint stride,knot_str_type *the_knot,
+ GLint dim,GLfloat **new_ctrl,GLint *ncontrol);
+
+extern GLenum glu_do_sampling_crv(GLUnurbsObj *nobj, GLfloat *new_ctrl,GLint n_ctrl,
+ GLint order,GLint dim,GLint **factors);
+
+extern GLenum glu_do_sampling_3D(GLUnurbsObj *nobj, new_ctrl_type *new_ctrl,
+ int **sfactors, GLint **tfactors);
+
+extern GLenum glu_do_sampling_uv(GLUnurbsObj *nobj, new_ctrl_type *new_ctrl,
+ int **sfactors, GLint **tfactors);
+
+extern GLenum glu_do_sampling_param_3D(GLUnurbsObj *nobj, new_ctrl_type *new_ctrl,
+ int **sfactors, GLint **tfactors);
+
+extern GLboolean fine_culling_test_2D(GLUnurbsObj *nobj, GLfloat *ctrl, GLint n_ctrl,
+ GLint stride, GLint dim);
+
+extern GLboolean fine_culling_test_3D(GLUnurbsObj *nobj, GLfloat *ctrl,
+ GLint s_n_ctrl, GLint t_n_ctrl, GLint s_stride, GLint t_stride, GLint dim);
+
+extern void do_nurbs_curve( GLUnurbsObj *nobj);
+
+extern void do_nurbs_surface( GLUnurbsObj *nobj);
+
+extern GLenum patch_trimming(GLUnurbsObj *nobj,new_ctrl_type *new_ctrl,
+ GLint *sfactors, GLint *tfactors);
+
+extern void collect_unified_knot(knot_str_type *dest, knot_str_type *src,
+ GLfloat maximal_min_knot, GLfloat minimal_max_knot);
+
+extern GLenum select_knot_working_range(GLUnurbsObj *nobj,knot_str_type *geom_knot,
+ knot_str_type *color_knot, knot_str_type *normal_knot,
+ knot_str_type *texture_knot);
+
+extern void free_unified_knots(knot_str_type *geom_knot, knot_str_type *color_knot,
+ knot_str_type *normal_knot, knot_str_type *texture_knot);
+
+
+
+#endif
diff --git a/src/glu/mesa/nurbscrv.c b/src/glu/mesa/nurbscrv.c
new file mode 100644
index 00000000000..022818b73ca
--- /dev/null
+++ b/src/glu/mesa/nurbscrv.c
@@ -0,0 +1,500 @@
+/* $Id: nurbscrv.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: nurbscrv.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.6 1997/07/24 01:28:44 brianp
+ * changed precompiled header symbol from PCH to PC_HEADER
+ *
+ * Revision 1.5 1997/05/28 02:29:38 brianp
+ * added support for precompiled headers (PCH), inserted APIENTRY keyword
+ *
+ * Revision 1.4 1997/05/27 03:21:22 brianp
+ * minor clean-up
+ *
+ * Revision 1.3 1997/05/27 03:00:16 brianp
+ * incorporated Bogdan's new NURBS code
+ *
+ * Revision 1.2 1996/09/27 23:12:22 brianp
+ * added return 0 to get_surface_dim() to silence warning
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+/*
+ * NURBS implementation written by Bogdan Sikorski ([email protected])
+ * See README2 for more info.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdlib.h>
+#include "gluP.h"
+#include "nurbs.h"
+#endif
+
+
+static int
+get_curve_dim(GLenum type)
+{
+ switch(type)
+ {
+ case GL_MAP1_VERTEX_3: return 3;
+ case GL_MAP1_VERTEX_4: return 4;
+ case GL_MAP1_INDEX: return 1;
+ case GL_MAP1_COLOR_4: return 4;
+ case GL_MAP1_NORMAL: return 3;
+ case GL_MAP1_TEXTURE_COORD_1: return 1;
+ case GL_MAP1_TEXTURE_COORD_2: return 2;
+ case GL_MAP1_TEXTURE_COORD_3: return 3;
+ case GL_MAP1_TEXTURE_COORD_4: return 4;
+ default: abort(); /* TODO: is this OK? */
+ }
+ return 0; /*never get here*/
+}
+
+static GLenum
+test_nurbs_curve(GLUnurbsObj *nobj, curve_attribs *attribs)
+{
+ GLenum err;
+ GLint tmp_int;
+
+ if(attribs->order < 0)
+ {
+ call_user_error(nobj,GLU_INVALID_VALUE);
+ return GLU_ERROR;
+ }
+ glGetIntegerv(GL_MAX_EVAL_ORDER,&tmp_int);
+ if(attribs->order > tmp_int || attribs->order < 2)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR1);
+ return GLU_ERROR;
+ }
+ if(attribs->knot_count < attribs->order +2)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR2);
+ return GLU_ERROR;
+ }
+ if(attribs->stride < 0)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR34);
+ return GLU_ERROR;
+ }
+ if(attribs->knot==NULL || attribs->ctrlarray==NULL)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR36);
+ return GLU_ERROR;
+ }
+ if((err=test_knot(attribs->knot_count,attribs->knot,attribs->order))
+ !=GLU_NO_ERROR)
+ {
+ call_user_error(nobj,err);
+ return GLU_ERROR;
+ }
+ return GLU_NO_ERROR;
+}
+
+static GLenum
+test_nurbs_curves(GLUnurbsObj *nobj)
+{
+ /* test the geometric data */
+ if(test_nurbs_curve(nobj,&(nobj->curve.geom))!=GLU_NO_ERROR)
+ return GLU_ERROR;
+ /* now test the attributive data */
+ /* color */
+ if(nobj->curve.color.type!=GLU_INVALID_ENUM)
+ if(test_nurbs_curve(nobj,&(nobj->curve.color))!=GLU_NO_ERROR)
+ return GLU_ERROR;
+ /* normal */
+ if(nobj->curve.normal.type!=GLU_INVALID_ENUM)
+ if(test_nurbs_curve(nobj,&(nobj->curve.normal))!=GLU_NO_ERROR)
+ return GLU_ERROR;
+ /* texture */
+ if(nobj->curve.texture.type!=GLU_INVALID_ENUM)
+ if(test_nurbs_curve(nobj,&(nobj->curve.texture))!=GLU_NO_ERROR)
+ return GLU_ERROR;
+ return GLU_NO_ERROR;
+}
+
+/* prepare the knot information structures */
+static GLenum
+fill_knot_structures(GLUnurbsObj *nobj,knot_str_type *geom_knot,
+ knot_str_type *color_knot, knot_str_type *normal_knot,
+ knot_str_type *texture_knot)
+{
+ GLint order;
+ GLfloat *knot;
+ GLint nknots;
+ GLint t_min,t_max;
+
+ geom_knot->unified_knot=NULL;
+ knot=geom_knot->knot=nobj->curve.geom.knot;
+ nknots=geom_knot->nknots=nobj->curve.geom.knot_count;
+ order=geom_knot->order=nobj->curve.geom.order;
+ geom_knot->delta_nknots=0;
+ t_min=geom_knot->t_min=order-1;
+ t_max=geom_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ geom_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ geom_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ geom_knot->open_at_end=GL_TRUE;
+ }
+ else
+ geom_knot->open_at_end=GL_FALSE;
+ if(nobj->curve.color.type!=GLU_INVALID_ENUM)
+ {
+ color_knot->unified_knot=(GLfloat *)1;
+ knot=color_knot->knot=nobj->curve.color.knot;
+ nknots=color_knot->nknots=nobj->curve.color.knot_count;
+ order=color_knot->order=nobj->curve.color.order;
+ color_knot->delta_nknots=0;
+ t_min=color_knot->t_min=order-1;
+ t_max=color_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ color_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ color_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ color_knot->open_at_end=GL_TRUE;
+ }
+ else
+ color_knot->open_at_end=GL_FALSE;
+ }
+ else
+ color_knot->unified_knot=NULL;
+ if(nobj->curve.normal.type!=GLU_INVALID_ENUM)
+ {
+ normal_knot->unified_knot=(GLfloat *)1;
+ knot=normal_knot->knot=nobj->curve.normal.knot;
+ nknots=normal_knot->nknots=nobj->curve.normal.knot_count;
+ order=normal_knot->order=nobj->curve.normal.order;
+ normal_knot->delta_nknots=0;
+ t_min=normal_knot->t_min=order-1;
+ t_max=normal_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ normal_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ normal_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ normal_knot->open_at_end=GL_TRUE;
+ }
+ else
+ normal_knot->open_at_end=GL_FALSE;
+ }
+ else
+ normal_knot->unified_knot=NULL;
+ if(nobj->curve.texture.type!=GLU_INVALID_ENUM)
+ {
+ texture_knot->unified_knot=(GLfloat *)1;
+ knot=texture_knot->knot=nobj->curve.texture.knot;
+ nknots=texture_knot->nknots=nobj->curve.texture.knot_count;
+ order=texture_knot->order=nobj->curve.texture.order;
+ texture_knot->delta_nknots=0;
+ t_min=texture_knot->t_min=order-1;
+ t_max=texture_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ texture_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ texture_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ texture_knot->open_at_end=GL_TRUE;
+ }
+ else
+ texture_knot->open_at_end=GL_FALSE;
+ }
+ else
+ texture_knot->unified_knot=NULL;
+ return GLU_NO_ERROR;
+}
+
+/* covert the NURBS curve into a series of adjacent Bezier curves */
+static GLenum
+convert_curve(knot_str_type *the_knot, curve_attribs *attrib,
+ GLfloat **new_ctrl,GLint *ncontrol)
+{
+ GLenum err;
+
+ if((err=explode_knot(the_knot))!=GLU_NO_ERROR)
+ {
+ if(the_knot->unified_knot)
+ {
+ free(the_knot->unified_knot);
+ the_knot->unified_knot=NULL;
+ }
+ return err;
+ }
+ if(the_knot->unified_knot)
+ {
+ free(the_knot->unified_knot);
+ the_knot->unified_knot=NULL;
+ }
+ if((err=calc_alphas(the_knot))!=GLU_NO_ERROR)
+ {
+ free(the_knot->new_knot);
+ return err;
+ }
+ free(the_knot->new_knot);
+ if((err=calc_new_ctrl_pts(attrib->ctrlarray,attrib->stride,the_knot,
+ attrib->dim,new_ctrl,ncontrol))
+ !=GLU_NO_ERROR)
+ {
+ free(the_knot->alpha);
+ return err;
+ }
+ free(the_knot->alpha);
+ return GLU_NO_ERROR;
+}
+
+/* covert curves - geometry and possible attribute ones into equivalent */
+/* sequence of adjacent Bezier curves */
+static GLenum
+convert_curves(GLUnurbsObj *nobj, GLfloat **new_geom_ctrl,
+ GLint *ncontrol, GLfloat **new_color_ctrl, GLfloat **new_normal_ctrl,
+ GLfloat **new_texture_ctrl)
+{
+ knot_str_type geom_knot,color_knot,normal_knot,texture_knot;
+ GLint junk;
+ GLenum err;
+
+ *new_color_ctrl=*new_normal_ctrl=*new_texture_ctrl=NULL;
+
+ if(fill_knot_structures(nobj,&geom_knot,&color_knot,&normal_knot,
+ &texture_knot)!=GLU_NO_ERROR)
+ return GLU_ERROR;
+
+ /* unify knots - all knots should have the same number of working */
+ /* ranges */
+ if((err=select_knot_working_range(nobj,&geom_knot,&color_knot,&normal_knot,
+ &texture_knot))!=GLU_NO_ERROR)
+ {
+ return err;
+ }
+ /* convert the geometry curve */
+ nobj->curve.geom.dim=get_curve_dim(nobj->curve.geom.type);
+ if((err=convert_curve(&geom_knot,&(nobj->curve.geom),new_geom_ctrl,
+ ncontrol))!=GLU_NO_ERROR)
+ {
+ free_unified_knots(&geom_knot,&color_knot,&normal_knot,&texture_knot);
+ call_user_error(nobj,err);
+ return err;
+ }
+ /* if additional attributive curves are given convert them as well */
+ if(color_knot.unified_knot)
+ {
+ nobj->curve.color.dim=get_curve_dim(nobj->curve.color.type);
+ if((err=convert_curve(&color_knot,&(nobj->curve.color),
+ new_color_ctrl,&junk))!=GLU_NO_ERROR)
+ {
+ free_unified_knots(&geom_knot,&color_knot,&normal_knot,&texture_knot);
+ free(*new_geom_ctrl);
+ call_user_error(nobj,err);
+ return err;
+ }
+ }
+ if(normal_knot.unified_knot)
+ {
+ nobj->curve.normal.dim=get_curve_dim(nobj->curve.normal.type);
+ if((err=convert_curve(&normal_knot,&(nobj->curve.normal),
+ new_normal_ctrl,&junk))!=GLU_NO_ERROR)
+ {
+ free_unified_knots(&geom_knot,&color_knot,&normal_knot,&texture_knot);
+ free(*new_geom_ctrl);
+ if(*new_color_ctrl)
+ free(*new_color_ctrl);
+ call_user_error(nobj,err);
+ return err;
+ }
+ }
+ if(texture_knot.unified_knot)
+ {
+ nobj->curve.texture.dim=get_curve_dim(nobj->curve.texture.type);
+ if((err=convert_curve(&texture_knot,&(nobj->curve.texture),
+ new_texture_ctrl,&junk))!=GLU_NO_ERROR)
+ {
+ free_unified_knots(&geom_knot,&color_knot,&normal_knot,&texture_knot);
+ free(*new_geom_ctrl);
+ if(*new_color_ctrl)
+ free(*new_color_ctrl);
+ if(*new_normal_ctrl)
+ free(*new_normal_ctrl);
+ call_user_error(nobj,err);
+ return err;
+ }
+ }
+ return GLU_NO_ERROR;
+}
+
+/* main NURBS curve procedure */
+void do_nurbs_curve( GLUnurbsObj *nobj)
+{
+ GLint geom_order,color_order=0,normal_order=0,texture_order=0;
+ GLenum geom_type;
+ GLint n_ctrl;
+ GLfloat *new_geom_ctrl,*new_color_ctrl,*new_normal_ctrl,*new_texture_ctrl;
+ GLfloat *geom_ctrl,*color_ctrl,*normal_ctrl,*texture_ctrl;
+ GLint *factors;
+ GLint i,j;
+ GLint geom_dim,color_dim=0,normal_dim=0,texture_dim=0;
+
+ /* test the user supplied data */
+ if(test_nurbs_curves(nobj)!=GLU_NO_ERROR)
+ return;
+
+ if(convert_curves(nobj,&new_geom_ctrl,&n_ctrl,&new_color_ctrl,
+ &new_normal_ctrl,&new_texture_ctrl)!=GLU_NO_ERROR)
+ return;
+
+ geom_order=nobj->curve.geom.order;
+ geom_type=nobj->curve.geom.type;
+ geom_dim=nobj->curve.geom.dim;
+
+ if(glu_do_sampling_crv(nobj,new_geom_ctrl,n_ctrl,geom_order,geom_dim,
+ &factors)
+ !=GLU_NO_ERROR)
+ {
+ free(new_geom_ctrl);
+ if(new_color_ctrl)
+ free(new_color_ctrl);
+ if(new_normal_ctrl)
+ free(new_normal_ctrl);
+ if(new_texture_ctrl)
+ free(new_texture_ctrl);
+ return;
+ }
+ glEnable(geom_type);
+ if(new_color_ctrl)
+ {
+ glEnable(nobj->curve.color.type);
+ color_dim=nobj->curve.color.dim;
+ color_ctrl=new_color_ctrl;
+ color_order=nobj->curve.color.order;
+ }
+ if(new_normal_ctrl)
+ {
+ glEnable(nobj->curve.normal.type);
+ normal_dim=nobj->curve.normal.dim;
+ normal_ctrl=new_normal_ctrl;
+ normal_order=nobj->curve.normal.order;
+ }
+ if(new_texture_ctrl)
+ {
+ glEnable(nobj->curve.texture.type);
+ texture_dim=nobj->curve.texture.dim;
+ texture_ctrl=new_texture_ctrl;
+ texture_order=nobj->curve.texture.order;
+ }
+ for(i=0 , j=0, geom_ctrl=new_geom_ctrl;
+ i<n_ctrl;
+ i+=geom_order , j++ , geom_ctrl+=geom_order*geom_dim)
+ {
+ if(fine_culling_test_2D(nobj,geom_ctrl,geom_order,geom_dim,geom_dim))
+ {
+ color_ctrl+=color_order*color_dim;
+ normal_ctrl+=normal_order*normal_dim;
+ texture_ctrl+=texture_order*texture_dim;
+ continue;
+ }
+ glMap1f(geom_type, 0.0, 1.0, geom_dim, geom_order, geom_ctrl);
+ if(new_color_ctrl)
+ {
+ glMap1f(nobj->curve.color.type, 0.0, 1.0, color_dim,
+ color_order,color_ctrl);
+ color_ctrl+=color_order*color_dim;
+ }
+ if(new_normal_ctrl)
+ {
+ glMap1f(nobj->curve.normal.type, 0.0, 1.0, normal_dim,
+ normal_order,normal_ctrl);
+ normal_ctrl+=normal_order*normal_dim;
+ }
+ if(new_texture_ctrl)
+ {
+ glMap1f(nobj->curve.texture.type, 0.0, 1.0, texture_dim,
+ texture_order,texture_ctrl);
+ texture_ctrl+=texture_order*texture_dim;
+ }
+ glMapGrid1f(factors[j],0.0,1.0);
+ glEvalMesh1(GL_LINE,0,factors[j]);
+ }
+ free(new_geom_ctrl);
+ free(factors);
+ if(new_color_ctrl)
+ free(new_color_ctrl);
+ if(new_normal_ctrl)
+ free(new_normal_ctrl);
+ if(new_texture_ctrl)
+ free(new_texture_ctrl);
+}
+
+
diff --git a/src/glu/mesa/nurbssrf.c b/src/glu/mesa/nurbssrf.c
new file mode 100644
index 00000000000..57eb9569862
--- /dev/null
+++ b/src/glu/mesa/nurbssrf.c
@@ -0,0 +1,1422 @@
+/* $Id: nurbssrf.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: nurbssrf.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.7 1997/07/24 01:28:44 brianp
+ * changed precompiled header symbol from PCH to PC_HEADER
+ *
+ * Revision 1.6 1997/06/23 00:22:07 brianp
+ * include <string.h>
+ *
+ * Revision 1.5 1997/05/28 02:29:38 brianp
+ * added support for precompiled headers (PCH), inserted APIENTRY keyword
+ *
+ * Revision 1.4 1997/05/27 03:20:35 brianp
+ * minor clean-up
+ *
+ * Revision 1.3 1997/05/27 03:00:16 brianp
+ * incorporated Bogdan's new NURBS code
+ *
+ * Revision 1.2 1996/09/27 23:13:02 brianp
+ * added return 0 to get_surface_dim() to silence warning
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+/*
+ * NURBS implementation written by Bogdan Sikorski ([email protected])
+ * See README2 for more info.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gluP.h"
+#include "nurbs.h"
+#endif
+
+
+static int
+get_surface_dim(GLenum type)
+{
+ switch(type)
+ {
+ case GL_MAP2_VERTEX_3: return 3;
+ case GL_MAP2_VERTEX_4: return 4;
+ case GL_MAP2_INDEX: return 1;
+ case GL_MAP2_COLOR_4: return 4;
+ case GL_MAP2_NORMAL: return 3;
+ case GL_MAP2_TEXTURE_COORD_1: return 1;
+ case GL_MAP2_TEXTURE_COORD_2: return 2;
+ case GL_MAP2_TEXTURE_COORD_3: return 3;
+ case GL_MAP2_TEXTURE_COORD_4: return 4;
+ default: abort(); /* TODO: is this OK? */
+ }
+ return 0; /*never get here*/
+}
+
+static GLenum
+test_nurbs_surface(GLUnurbsObj *nobj, surface_attribs *attrib)
+{
+ GLenum err;
+ GLint tmp_int;
+
+ if(attrib->sorder < 0 || attrib->torder < 0)
+ {
+ call_user_error(nobj,GLU_INVALID_VALUE);
+ return GLU_ERROR;
+ }
+ glGetIntegerv(GL_MAX_EVAL_ORDER,&tmp_int);
+ if(attrib->sorder > tmp_int || attrib->sorder < 2)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR1);
+ return GLU_ERROR;
+ }
+ if(attrib->torder > tmp_int || attrib->torder < 2)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR1);
+ return GLU_ERROR;
+ }
+ if(attrib->sknot_count < attrib->sorder +2)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR2);
+ return GLU_ERROR;
+ }
+ if(attrib->tknot_count < attrib->torder +2)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR2);
+ return GLU_ERROR;
+ }
+ if(attrib->s_stride < 0 || attrib->t_stride < 0)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR34);
+ return GLU_ERROR;
+ }
+ if(attrib->sknot==NULL || attrib->tknot==NULL || attrib->ctrlarray==NULL)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR36);
+ return GLU_ERROR;
+ }
+ if((err=test_knot(attrib->tknot_count,attrib->tknot,attrib->torder))
+ !=GLU_NO_ERROR)
+ {
+ call_user_error(nobj,err);
+ return GLU_ERROR;
+ }
+ if((err=test_knot(attrib->sknot_count,attrib->sknot,attrib->sorder))
+ !=GLU_NO_ERROR)
+ {
+ call_user_error(nobj,err);
+ return GLU_ERROR;
+ }
+ return GLU_NO_ERROR;
+}
+
+static GLenum
+test_nurbs_surfaces(GLUnurbsObj *nobj)
+{
+ /* test the geometric data */
+ if(test_nurbs_surface(nobj,&(nobj->surface.geom))!=GLU_NO_ERROR)
+ return GLU_ERROR;
+ /* now test the attributive data */
+ /* color */
+ if(nobj->surface.color.type!=GLU_INVALID_ENUM)
+ if(test_nurbs_surface(nobj,&(nobj->surface.color))!=GLU_NO_ERROR)
+ return GLU_ERROR;
+ /* normal */
+ if(nobj->surface.normal.type!=GLU_INVALID_ENUM)
+ if(test_nurbs_surface(nobj,&(nobj->surface.normal))!=GLU_NO_ERROR)
+ return GLU_ERROR;
+ /* texture */
+ if(nobj->surface.texture.type!=GLU_INVALID_ENUM)
+ if(test_nurbs_surface(nobj,&(nobj->surface.texture))!=GLU_NO_ERROR)
+ return GLU_ERROR;
+ return GLU_NO_ERROR;
+}
+
+static GLenum
+convert_surf(knot_str_type *s_knot, knot_str_type *t_knot,
+ surface_attribs *attrib, GLfloat **new_ctrl,
+ GLint *s_n_ctrl, GLint *t_n_ctrl)
+{
+ GLfloat **tmp_ctrl;
+ GLfloat *ctrl_offset;
+ GLint tmp_n_control;
+ GLint i,j,t_cnt,s_cnt;
+ GLint tmp_stride;
+ GLint dim;
+ GLenum err;
+
+ /* valid range is empty? */
+ if((s_knot->unified_knot !=NULL && s_knot->unified_nknots==0) ||
+ (t_knot->unified_knot !=NULL && t_knot->unified_nknots==0))
+ {
+ if(s_knot->unified_knot)
+ {
+ free(s_knot->unified_knot);
+ s_knot->unified_knot=NULL;
+ }
+ if(t_knot->unified_knot)
+ {
+ free(t_knot->unified_knot);
+ t_knot->unified_knot=NULL;
+ }
+ *s_n_ctrl=0;
+ *t_n_ctrl=0;
+ return GLU_NO_ERROR;
+ }
+ t_cnt=attrib->tknot_count-attrib->torder;
+ s_cnt=attrib->sknot_count-attrib->sorder;
+ if((tmp_ctrl=(GLfloat **)malloc(sizeof(GLfloat *)*t_cnt))==NULL)
+ return GLU_OUT_OF_MEMORY;
+ if((err=explode_knot(s_knot))!=GLU_NO_ERROR)
+ {
+ free(tmp_ctrl);
+ if(s_knot->unified_knot)
+ {
+ free(s_knot->unified_knot);
+ s_knot->unified_knot=NULL;
+ }
+ return err;
+ }
+ if(s_knot->unified_knot)
+ {
+ free(s_knot->unified_knot);
+ s_knot->unified_knot=NULL;
+ }
+ if((err=calc_alphas(s_knot))!=GLU_NO_ERROR)
+ {
+ free(tmp_ctrl);
+ free(s_knot->new_knot);
+ return err;
+ }
+ free(s_knot->new_knot);
+ ctrl_offset=attrib->ctrlarray;
+ dim=attrib->dim;
+ for(i=0;i<t_cnt;i++)
+ {
+ if((err=calc_new_ctrl_pts(ctrl_offset,attrib->s_stride,s_knot,
+ dim,&(tmp_ctrl[i]),&tmp_n_control))!=GLU_NO_ERROR)
+ {
+ for(--i;i<=0;i--)
+ free(tmp_ctrl[i]);
+ free(tmp_ctrl);
+ free(s_knot->alpha);
+ return err;
+ }
+ ctrl_offset+=attrib->t_stride;
+ }
+ free(s_knot->alpha);
+ tmp_stride=dim*tmp_n_control;
+ if((*new_ctrl=(GLfloat *)malloc(sizeof(GLfloat)*tmp_stride*t_cnt))
+ ==NULL)
+ {
+ for(i=0;i<t_cnt;i++)
+ free(tmp_ctrl[i]);
+ free(tmp_ctrl);
+ return GLU_OUT_OF_MEMORY;
+ }
+ for(i=0;i<tmp_n_control;i++)
+ for(j=0;j<t_cnt;j++)
+ MEMCPY(*new_ctrl+j*dim+i*dim*t_cnt,tmp_ctrl[j]+dim*i,
+ sizeof(GLfloat)*dim);
+ for(i=0;i<t_cnt;i++)
+ free(tmp_ctrl[i]);
+ free(tmp_ctrl);
+ *s_n_ctrl=tmp_n_control;
+
+ if((tmp_ctrl=(GLfloat **)malloc(sizeof(GLfloat *)*(*s_n_ctrl)))==NULL)
+ {
+ return GLU_OUT_OF_MEMORY;
+ }
+ if((err=explode_knot(t_knot))!=GLU_NO_ERROR)
+ {
+ free(tmp_ctrl);
+ if(t_knot->unified_knot)
+ {
+ free(t_knot->unified_knot);
+ t_knot->unified_knot=NULL;
+ }
+ return err;
+ }
+ if(t_knot->unified_knot)
+ {
+ free(t_knot->unified_knot);
+ t_knot->unified_knot=NULL;
+ }
+ if((err=calc_alphas(t_knot))!=GLU_NO_ERROR)
+ {
+ free(tmp_ctrl);
+ free(t_knot->new_knot);
+ return err;
+ }
+ free(t_knot->new_knot);
+ ctrl_offset=*new_ctrl;
+ for(i=0;i<(*s_n_ctrl);i++)
+ {
+ if((err=calc_new_ctrl_pts(ctrl_offset,dim,t_knot,
+ dim,&(tmp_ctrl[i]),&tmp_n_control))!=GLU_NO_ERROR)
+ {
+ for(--i;i<=0;i--)
+ free(tmp_ctrl[i]);
+ free(tmp_ctrl);
+ free(t_knot->alpha);
+ return err;
+ }
+ ctrl_offset+=dim*t_cnt;
+ }
+ free(t_knot->alpha);
+ free(*new_ctrl);
+ tmp_stride=dim*tmp_n_control;
+ if((*new_ctrl=(GLfloat *)malloc(sizeof(GLfloat)*tmp_stride*(*s_n_ctrl)))
+ ==NULL)
+ {
+ for(i=0;i<(*s_n_ctrl);i++)
+ free(tmp_ctrl[i]);
+ free(tmp_ctrl);
+ return GLU_OUT_OF_MEMORY;
+ }
+ for(i=0;i<(*s_n_ctrl);i++)
+ {
+ MEMCPY(*new_ctrl+i*tmp_stride,tmp_ctrl[i],sizeof(GLfloat)*tmp_stride);
+ free(tmp_ctrl[i]);
+ }
+ free(tmp_ctrl);
+ *t_n_ctrl=tmp_n_control;
+ return GLU_NO_ERROR;
+}
+
+/* prepare the knot information structures */
+static GLenum
+fill_knot_structures(GLUnurbsObj *nobj,
+ knot_str_type *geom_s_knot, knot_str_type *geom_t_knot,
+ knot_str_type *color_s_knot, knot_str_type *color_t_knot,
+ knot_str_type *normal_s_knot, knot_str_type *normal_t_knot,
+ knot_str_type *texture_s_knot, knot_str_type *texture_t_knot)
+{
+ GLint order;
+ GLfloat *knot;
+ GLint nknots;
+ GLint t_min,t_max;
+
+ geom_s_knot->unified_knot=NULL;
+ knot=geom_s_knot->knot=nobj->surface.geom.sknot;
+ nknots=geom_s_knot->nknots=nobj->surface.geom.sknot_count;
+ order=geom_s_knot->order=nobj->surface.geom.sorder;
+ geom_s_knot->delta_nknots=0;
+ t_min=geom_s_knot->t_min=order-1;
+ t_max=geom_s_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ geom_s_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ geom_s_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ geom_s_knot->open_at_end=GL_TRUE;
+ }
+ else
+ geom_s_knot->open_at_end=GL_FALSE;
+ geom_t_knot->unified_knot=NULL;
+ knot=geom_t_knot->knot=nobj->surface.geom.tknot;
+ nknots=geom_t_knot->nknots=nobj->surface.geom.tknot_count;
+ order=geom_t_knot->order=nobj->surface.geom.torder;
+ geom_t_knot->delta_nknots=0;
+ t_min=geom_t_knot->t_min=order-1;
+ t_max=geom_t_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ geom_t_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ geom_t_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ geom_t_knot->open_at_end=GL_TRUE;
+ }
+ else
+ geom_t_knot->open_at_end=GL_FALSE;
+
+ if(nobj->surface.color.type!=GLU_INVALID_ENUM)
+ {
+ color_s_knot->unified_knot=(GLfloat *)1;
+ knot=color_s_knot->knot=nobj->surface.color.sknot;
+ nknots=color_s_knot->nknots=nobj->surface.color.sknot_count;
+ order=color_s_knot->order=nobj->surface.color.sorder;
+ color_s_knot->delta_nknots=0;
+ t_min=color_s_knot->t_min=order-1;
+ t_max=color_s_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ color_s_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ color_s_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ color_s_knot->open_at_end=GL_TRUE;
+ }
+ else
+ color_s_knot->open_at_end=GL_FALSE;
+ color_t_knot->unified_knot=(GLfloat *)1;
+ knot=color_t_knot->knot=nobj->surface.color.tknot;
+ nknots=color_t_knot->nknots=nobj->surface.color.tknot_count;
+ order=color_t_knot->order=nobj->surface.color.torder;
+ color_t_knot->delta_nknots=0;
+ t_min=color_t_knot->t_min=order-1;
+ t_max=color_t_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ color_t_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ color_t_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ color_t_knot->open_at_end=GL_TRUE;
+ }
+ else
+ color_t_knot->open_at_end=GL_FALSE;
+ }
+ else
+ {
+ color_s_knot->unified_knot=NULL;
+ color_t_knot->unified_knot=NULL;
+ }
+
+ if(nobj->surface.normal.type!=GLU_INVALID_ENUM)
+ {
+ normal_s_knot->unified_knot=(GLfloat *)1;
+ knot=normal_s_knot->knot=nobj->surface.normal.sknot;
+ nknots=normal_s_knot->nknots=nobj->surface.normal.sknot_count;
+ order=normal_s_knot->order=nobj->surface.normal.sorder;
+ normal_s_knot->delta_nknots=0;
+ t_min=normal_s_knot->t_min=order-1;
+ t_max=normal_s_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ normal_s_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ normal_s_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ normal_s_knot->open_at_end=GL_TRUE;
+ }
+ else
+ normal_s_knot->open_at_end=GL_FALSE;
+ normal_t_knot->unified_knot=(GLfloat *)1;
+ knot=normal_t_knot->knot=nobj->surface.normal.tknot;
+ nknots=normal_t_knot->nknots=nobj->surface.normal.tknot_count;
+ order=normal_t_knot->order=nobj->surface.normal.torder;
+ normal_t_knot->delta_nknots=0;
+ t_min=normal_t_knot->t_min=order-1;
+ t_max=normal_t_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ normal_t_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ normal_t_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ normal_t_knot->open_at_end=GL_TRUE;
+ }
+ else
+ normal_t_knot->open_at_end=GL_FALSE;
+ }
+ else
+ {
+ normal_s_knot->unified_knot=NULL;
+ normal_t_knot->unified_knot=NULL;
+ }
+
+ if(nobj->surface.texture.type!=GLU_INVALID_ENUM)
+ {
+ texture_s_knot->unified_knot=(GLfloat *)1;
+ knot=texture_s_knot->knot=nobj->surface.texture.sknot;
+ nknots=texture_s_knot->nknots=nobj->surface.texture.sknot_count;
+ order=texture_s_knot->order=nobj->surface.texture.sorder;
+ texture_s_knot->delta_nknots=0;
+ t_min=texture_s_knot->t_min=order-1;
+ t_max=texture_s_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ texture_s_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ texture_s_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ texture_s_knot->open_at_end=GL_TRUE;
+ }
+ else
+ texture_s_knot->open_at_end=GL_FALSE;
+ texture_t_knot->unified_knot=(GLfloat *)1;
+ knot=texture_t_knot->knot=nobj->surface.texture.tknot;
+ nknots=texture_t_knot->nknots=nobj->surface.texture.tknot_count;
+ order=texture_t_knot->order=nobj->surface.texture.torder;
+ texture_t_knot->delta_nknots=0;
+ t_min=texture_t_knot->t_min=order-1;
+ t_max=texture_t_knot->t_max=nknots-order;
+ if(fabs(knot[t_min]-knot[t_max])<EPSILON)
+ {
+ call_user_error(nobj,GLU_NURBS_ERROR3);
+ return GLU_ERROR;
+ }
+ if(fabs(knot[0]-knot[t_min])<EPSILON)
+ {
+ /* knot open at beggining */
+ texture_t_knot->open_at_begin=GL_TRUE;
+ }
+ else
+ texture_t_knot->open_at_begin=GL_FALSE;
+ if(fabs(knot[t_max]-knot[nknots-1])<EPSILON)
+ {
+ /* knot open at end */
+ texture_t_knot->open_at_end=GL_TRUE;
+ }
+ else
+ texture_t_knot->open_at_end=GL_FALSE;
+ }
+ else
+ {
+ texture_s_knot->unified_knot=NULL;
+ texture_t_knot->unified_knot=NULL;
+ }
+ return GLU_NO_ERROR;
+}
+
+void
+free_new_ctrl(new_ctrl_type *p)
+{
+ if(p->geom_ctrl)
+ free(p->geom_ctrl);
+ if(p->geom_offsets)
+ free(p->geom_offsets);
+ if(p->color_ctrl)
+ {
+ free(p->color_ctrl);
+ if(p->color_offsets)
+ free(p->color_offsets);
+ }
+ if(p->normal_ctrl)
+ {
+ free(p->normal_ctrl);
+ if(p->normal_offsets)
+ free(p->normal_offsets);
+ }
+ if(p->texture_ctrl)
+ {
+ free(p->texture_ctrl);
+ if(p->texture_offsets)
+ free(p->texture_offsets);
+ }
+}
+
+/* convert surfaces - geometry and possible attribute ones into equivalent */
+/* sequence of adjacent Bezier patches */
+static GLenum
+convert_surfs(GLUnurbsObj *nobj, new_ctrl_type *new_ctrl)
+{
+ knot_str_type geom_s_knot,color_s_knot,normal_s_knot,texture_s_knot;
+ knot_str_type geom_t_knot,color_t_knot,normal_t_knot,texture_t_knot;
+ GLenum err;
+
+ if((err=fill_knot_structures(nobj,&geom_s_knot,&geom_t_knot,
+ &color_s_knot,&color_t_knot,&normal_s_knot,&normal_t_knot,
+ &texture_s_knot,&texture_t_knot)) !=GLU_NO_ERROR)
+ {
+ return err;
+ }
+ /* unify knots - all knots should have the same working range */
+ if((err=select_knot_working_range(nobj,&geom_s_knot,&color_s_knot,
+ &normal_s_knot,&texture_s_knot)) !=GLU_NO_ERROR)
+ {
+ call_user_error(nobj,err);
+ return err;
+ }
+ if((err=select_knot_working_range(nobj,&geom_t_knot,&color_t_knot,
+ &normal_t_knot,&texture_t_knot)) !=GLU_NO_ERROR)
+ {
+ free_unified_knots(&geom_s_knot,&color_s_knot,&normal_s_knot,
+ &texture_s_knot);
+ call_user_error(nobj,err);
+ return err;
+ }
+
+ /* convert the geometry surface */
+ nobj->surface.geom.dim=get_surface_dim(nobj->surface.geom.type);
+ if((err=convert_surf(&geom_s_knot,&geom_t_knot,&(nobj->surface.geom),
+ &(new_ctrl->geom_ctrl),&(new_ctrl->geom_s_pt_cnt),
+ &(new_ctrl->geom_t_pt_cnt)))!=GLU_NO_ERROR)
+ {
+ free_unified_knots(&geom_s_knot,&color_s_knot,&normal_s_knot,
+ &texture_s_knot);
+ free_unified_knots(&geom_t_knot,&color_t_knot,&normal_t_knot,
+ &texture_t_knot);
+ call_user_error(nobj,err);
+ return err;
+ }
+ /* if additional attributive surfaces are given convert them as well */
+ if(color_s_knot.unified_knot)
+ {
+ nobj->surface.color.dim=get_surface_dim(nobj->surface.color.type);
+ if((err=convert_surf(&color_s_knot,&color_t_knot,&(nobj->surface.color),
+ &(new_ctrl->color_ctrl),&(new_ctrl->color_s_pt_cnt),
+ &(new_ctrl->color_t_pt_cnt)))!=GLU_NO_ERROR)
+ {
+ free_unified_knots(&color_s_knot,&color_s_knot,&normal_s_knot,
+ &texture_s_knot);
+ free_unified_knots(&color_t_knot,&color_t_knot,&normal_t_knot,
+ &texture_t_knot);
+ free_new_ctrl(new_ctrl);
+ call_user_error(nobj,err);
+ return err;
+ }
+ }
+ if(normal_s_knot.unified_knot)
+ {
+ nobj->surface.normal.dim=get_surface_dim(nobj->surface.normal.type);
+ if((err=convert_surf(&normal_s_knot,&normal_t_knot,
+ &(nobj->surface.normal),
+ &(new_ctrl->normal_ctrl),&(new_ctrl->normal_s_pt_cnt),
+ &(new_ctrl->normal_t_pt_cnt)))!=GLU_NO_ERROR)
+ {
+ free_unified_knots(&normal_s_knot,&normal_s_knot,&normal_s_knot,
+ &texture_s_knot);
+ free_unified_knots(&normal_t_knot,&normal_t_knot,&normal_t_knot,
+ &texture_t_knot);
+ free_new_ctrl(new_ctrl);
+ call_user_error(nobj,err);
+ return err;
+ }
+ }
+ if(texture_s_knot.unified_knot)
+ {
+ nobj->surface.texture.dim=get_surface_dim(nobj->surface.texture.type);
+ if((err=convert_surf(&texture_s_knot,&texture_t_knot,
+ &(nobj->surface.texture),
+ &(new_ctrl->texture_ctrl),&(new_ctrl->texture_s_pt_cnt),
+ &(new_ctrl->texture_t_pt_cnt)))!=GLU_NO_ERROR)
+ {
+ free_unified_knots(&texture_s_knot,&texture_s_knot,&texture_s_knot,
+ &texture_s_knot);
+ free_unified_knots(&texture_t_knot,&texture_t_knot,&texture_t_knot,
+ &texture_t_knot);
+ free_new_ctrl(new_ctrl);
+ call_user_error(nobj,err);
+ return err;
+ }
+ }
+ return GLU_NO_ERROR;
+}
+
+/* tesselate the "boundary" Bezier edge strips */
+void
+tesselate_strip_t_line(GLint top_start,GLint top_end,GLint top_z,
+ GLint bottom_start,GLint bottom_end,GLint bottom_z,GLint bottom_domain)
+{
+ GLint top_cnt,bottom_cnt,tri_cnt,k;
+ GLint direction;
+
+ top_cnt=top_end-top_start;
+ direction= (top_cnt>=0 ? 1: -1);
+ bottom_cnt=bottom_end-bottom_start;
+ glBegin(GL_LINES);
+ while(top_cnt)
+ {
+ if(bottom_cnt)
+ tri_cnt=top_cnt/bottom_cnt;
+ else
+ tri_cnt=abs(top_cnt);
+ for(k=0;k<=tri_cnt;k++ , top_start+=direction)
+ {
+ glEvalCoord2f((GLfloat)bottom_z/bottom_domain,
+ (GLfloat)bottom_start/bottom_domain);
+ glEvalPoint2(top_z,top_start);
+ }
+ if(bottom_cnt)
+ {
+ glEvalCoord2f((GLfloat)bottom_z/bottom_domain,
+ (GLfloat)bottom_start/bottom_domain);
+ bottom_start+=direction;
+ top_start-=direction;
+ glEvalCoord2f((GLfloat)bottom_z/bottom_domain,
+ (GLfloat)bottom_start/bottom_domain);
+ glEvalCoord2f((GLfloat)bottom_z/bottom_domain,
+ (GLfloat)bottom_start/bottom_domain);
+ glEvalPoint2(top_z,top_start);
+ }
+ top_cnt-=direction*tri_cnt;
+ bottom_cnt-=direction;
+ }
+ glEnd();
+}
+
+void
+tesselate_strip_t_fill(GLint top_start,GLint top_end,GLint top_z,
+ GLint bottom_start,GLint bottom_end,GLint bottom_z,GLint bottom_domain)
+{
+ GLint top_cnt,bottom_cnt,tri_cnt,k;
+ GLint direction;
+
+ top_cnt=top_end-top_start;
+ direction= (top_cnt>=0 ? 1: -1);
+ bottom_cnt=bottom_end-bottom_start;
+ while(top_cnt)
+ {
+ if(bottom_cnt)
+ tri_cnt=top_cnt/bottom_cnt;
+ else
+ tri_cnt=abs(top_cnt);
+ glBegin(GL_TRIANGLE_FAN);
+ glEvalCoord2f((GLfloat)bottom_z/bottom_domain,
+ (GLfloat)bottom_start/bottom_domain);
+ for(k=0;k<=tri_cnt;k++ , top_start+=direction)
+ glEvalPoint2(top_z,top_start);
+ if(bottom_cnt)
+ {
+ bottom_start+=direction;
+ top_start-=direction;
+ glEvalCoord2f((GLfloat)bottom_z/bottom_domain,
+ (GLfloat)bottom_start/bottom_domain);
+ }
+ glEnd();
+ top_cnt-=direction*tri_cnt;
+ bottom_cnt-=direction;
+ }
+}
+
+void
+tesselate_strip_t(GLenum display_mode, GLint top_start, GLint top_end,
+ GLint top_z, GLint bottom_start, GLint bottom_end, GLint bottom_z,
+ GLint bottom_domain)
+{
+ if(display_mode==GL_FILL)
+ tesselate_strip_t_fill(top_start,top_end,top_z,bottom_start,
+ bottom_end,bottom_z,bottom_domain);
+ else
+ tesselate_strip_t_line(top_start,top_end,top_z,bottom_start,
+ bottom_end,bottom_z,bottom_domain);
+}
+
+
+void
+tesselate_strip_s_fill(GLint top_start, GLint top_end, GLint top_z,
+ GLint bottom_start, GLint bottom_end, GLint bottom_z, GLfloat bottom_domain)
+{
+ GLint top_cnt,bottom_cnt,tri_cnt,k;
+ GLint direction;
+
+ top_cnt=top_end-top_start;
+ direction= (top_cnt>=0 ? 1: -1);
+ bottom_cnt=bottom_end-bottom_start;
+ while(top_cnt)
+ {
+ if(bottom_cnt)
+ tri_cnt=top_cnt/bottom_cnt;
+ else
+ tri_cnt=abs(top_cnt);
+ glBegin(GL_TRIANGLE_FAN);
+ glEvalCoord2f((GLfloat)bottom_start/bottom_domain,
+ (GLfloat)bottom_z/bottom_domain);
+ for(k=0;k<=tri_cnt;k++ , top_start+=direction)
+ glEvalPoint2(top_start,top_z);
+ if(bottom_cnt)
+ {
+ bottom_start+=direction;
+ top_start-=direction;
+ glEvalCoord2f((GLfloat)bottom_start/bottom_domain,
+ (GLfloat)bottom_z/bottom_domain);
+ }
+ glEnd();
+ top_cnt-=direction*tri_cnt;
+ bottom_cnt-=direction;
+ }
+}
+
+void
+tesselate_strip_s_line(GLint top_start, GLint top_end, GLint top_z,
+ GLint bottom_start, GLint bottom_end, GLint bottom_z, GLfloat bottom_domain)
+{
+ GLint top_cnt,bottom_cnt,tri_cnt,k;
+ GLint direction;
+
+ top_cnt=top_end-top_start;
+ direction= (top_cnt>=0 ? 1: -1);
+ bottom_cnt=bottom_end-bottom_start;
+ glBegin(GL_LINES);
+ while(top_cnt)
+ {
+ if(bottom_cnt)
+ tri_cnt=top_cnt/bottom_cnt;
+ else
+ tri_cnt=abs(top_cnt);
+ for(k=0;k<=tri_cnt;k++ , top_start+=direction)
+ {
+ glEvalCoord2f((GLfloat)bottom_start/bottom_domain,
+ (GLfloat)bottom_z/bottom_domain);
+ glEvalPoint2(top_start,top_z);
+ }
+ if(bottom_cnt)
+ {
+ glEvalCoord2f((GLfloat)bottom_start/bottom_domain,
+ (GLfloat)bottom_z/bottom_domain);
+ bottom_start+=direction;
+ top_start-=direction;
+ glEvalCoord2f((GLfloat)bottom_start/bottom_domain,
+ (GLfloat)bottom_z/bottom_domain);
+ glEvalPoint2(top_start,top_z);
+ glEvalCoord2f((GLfloat)bottom_start/bottom_domain,
+ (GLfloat)bottom_z/bottom_domain);
+ }
+ top_cnt-=direction*tri_cnt;
+ bottom_cnt-=direction;
+ }
+ glEnd();
+}
+
+void
+tesselate_strip_s(GLenum display_mode, GLint top_start, GLint top_end,
+ GLint top_z, GLint bottom_start, GLint bottom_end, GLint bottom_z,
+ GLfloat bottom_domain)
+{
+ if(display_mode==GL_FILL)
+ tesselate_strip_s_fill(top_start,top_end,top_z,bottom_start,
+ bottom_end,bottom_z,bottom_domain);
+ else
+ tesselate_strip_s_line(top_start,top_end,top_z,bottom_start,
+ bottom_end,bottom_z,bottom_domain);
+}
+
+void
+tesselate_bottom_left_corner(GLenum display_mode, GLfloat s_1, GLfloat t_1)
+{
+ if(display_mode==GL_FILL)
+ {
+ glBegin(GL_TRIANGLE_FAN);
+ glEvalPoint2(1,1);
+ glEvalCoord2f(s_1,0.0);
+ glEvalCoord2f(0.0,0.0);
+ glEvalCoord2f(0.0,t_1);
+ }
+ else
+ {
+ glBegin(GL_LINES);
+ glEvalCoord2f(0.0,0.0);
+ glEvalCoord2f(0.0,t_1);
+ glEvalCoord2f(0.0,0.0);
+ glEvalPoint2(1,1);
+ glEvalCoord2f(0.0,0.0);
+ glEvalCoord2f(s_1,0.0);
+ }
+ glEnd();
+}
+
+void
+tesselate_bottom_right_corner(GLenum display_mode, GLint v_top,GLint v_bottom,
+ GLfloat s_1, GLfloat t_1)
+{
+ if(display_mode==GL_FILL)
+ {
+ glBegin(GL_TRIANGLE_FAN);
+ glEvalPoint2(1,v_top);
+ glEvalCoord2f(0.0,v_bottom*t_1);
+ glEvalCoord2f(0.0,(v_bottom+1)*t_1);
+ glEvalCoord2f(s_1,(v_bottom+1)*t_1);
+ }
+ else
+ {
+ glBegin(GL_LINES);
+ glEvalCoord2f(0.0,(v_bottom+1)*t_1);
+ glEvalPoint2(1,v_top);
+ glEvalCoord2f(0.0,(v_bottom+1)*t_1);
+ glEvalCoord2f(0.0,v_bottom*t_1);
+ glEvalCoord2f(0.0,(v_bottom+1)*t_1);
+ glEvalCoord2f(s_1,(v_bottom+1)*t_1);
+ }
+ glEnd();
+}
+
+void
+tesselate_top_left_corner(GLenum display_mode, GLint u_right, GLint u_left,
+ GLfloat s_1, GLfloat t_1)
+{
+ if(display_mode==GL_FILL)
+ {
+ glBegin(GL_TRIANGLE_FAN);
+ glEvalPoint2(u_right,1);
+ glEvalCoord2f((u_left+1)*s_1,t_1);
+ glEvalCoord2f((u_left+1)*s_1,0.0);
+ glEvalCoord2f(u_left*s_1,0.0);
+ }
+ else
+ {
+ glBegin(GL_LINES);
+ glEvalCoord2f((u_left+1)*s_1,0.0);
+ glEvalPoint2(u_right,1);
+ glEvalCoord2f((u_left+1)*s_1,0.0);
+ glEvalCoord2f(u_left*s_1,0.0);
+ glEvalCoord2f((u_left+1)*s_1,0.0);
+ glEvalCoord2f((u_left+1)*s_1,t_1);
+ }
+ glEnd();
+}
+
+void
+tesselate_top_right_corner(GLenum display_mode, GLint u_left, GLint v_bottom,
+ GLint u_right, GLint v_top, GLfloat s_1, GLfloat t_1)
+{
+ if(display_mode==GL_FILL)
+ {
+ glBegin(GL_TRIANGLE_FAN);
+ glEvalPoint2(u_left,v_bottom);
+ glEvalCoord2f((u_right-1)*s_1,v_top*t_1);
+ glEvalCoord2f(u_right*s_1,v_top*t_1);
+ glEvalCoord2f(u_right*s_1,(v_top-1)*t_1);
+ }
+ else
+ {
+ glBegin(GL_LINES);
+ glEvalCoord2f(u_right*s_1,v_top*t_1);
+ glEvalPoint2(u_left,v_bottom);
+ glEvalCoord2f(u_right*s_1,v_top*t_1);
+ glEvalCoord2f(u_right*s_1,(v_top-1)*t_1);
+ glEvalCoord2f(u_right*s_1,v_top*t_1);
+ glEvalCoord2f((u_right-1)*s_1,v_top*t_1);
+ }
+ glEnd();
+}
+
+/* do mesh mapping of Bezier */
+static void
+nurbs_map_bezier(GLenum display_mode,GLint *sfactors,GLint *tfactors,
+ GLint s_bezier_cnt, GLint t_bezier_cnt, GLint s, GLint t)
+{
+ GLint top,bottom,right,left;
+
+
+ if(s==0)
+ {
+ top=*(tfactors+t*3);
+ bottom=*(tfactors+t*3+1);
+ }
+ else
+ if(s==s_bezier_cnt-1)
+ {
+ top=*(tfactors+t*3+2);
+ bottom=*(tfactors+t*3);
+ }
+ else
+ {
+ top=bottom=*(tfactors+t*3);
+ }
+ if(t==0)
+ {
+ left=*(sfactors+s*3+1);
+ right=*(sfactors+s*3);
+ }
+ else
+ if(t==t_bezier_cnt-1)
+ {
+ left=*(sfactors+s*3);
+ right=*(sfactors+s*3+2);
+ }
+ else
+ {
+ left=right=*(sfactors+s*3);
+ }
+
+ if(top>bottom)
+ {
+ if(left<right)
+ {
+ glMapGrid2f(right, 0.0, 1.0, top, 0.0, 1.0);
+ glEvalMesh2(display_mode,1,right, 1, top);
+ tesselate_strip_s(display_mode,1,right,1,1,left,0,(GLfloat)left);
+ tesselate_bottom_left_corner(display_mode,(GLfloat)(1.0/left),
+ (GLfloat)(1.0/bottom));
+/* tesselate_strip_t(display_mode,1,top,1,1,bottom,0,(GLfloat)bottom);*/
+ tesselate_strip_t(display_mode,top,1,1,bottom,1,0,(GLfloat)bottom);
+ }
+ else
+ if(left==right)
+ {
+ glMapGrid2f(right, 0.0, 1.0, top, 0.0, 1.0);
+ glEvalMesh2(display_mode,1,right, 0, top);
+/* tesselate_strip_t(display_mode,0,top,1,0,bottom,0,(GLfloat)bottom);*/
+ tesselate_strip_t(display_mode,top,0,1,bottom,0,0,(GLfloat)bottom);
+ }
+ else
+ {
+ glMapGrid2f(left, 0.0, 1.0, top, 0.0, 1.0);
+ glEvalMesh2(display_mode,1,left, 0, top-1);
+/* tesselate_strip_t(display_mode,0,top-1,1,0,bottom-1,0,
+ (GLfloat)bottom);*/
+ tesselate_strip_t(display_mode,top-1,0,1,bottom-1,0,0,
+ (GLfloat)bottom);
+ tesselate_bottom_right_corner(display_mode,top-1,bottom-1,
+ (GLfloat)(1.0/right),(GLfloat)(1.0/bottom));
+/* tesselate_strip_s(display_mode,1,left,top-1,1,right,right,
+ (GLfloat)right);*/
+ tesselate_strip_s(display_mode,left,1,top-1,right,1,right,
+ (GLfloat)right);
+ }
+ }
+ else
+ if(top==bottom)
+ {
+ if(left<right)
+ {
+ glMapGrid2f(right, 0.0, 1.0, top, 0.0, 1.0);
+ glEvalMesh2(display_mode,0,right, 1, top);
+ tesselate_strip_s(display_mode,0,right,1,0,left,0,(GLfloat)left);
+ }
+ else
+ if(left==right)
+ {
+ glMapGrid2f(right, 0.0, 1.0, top, 0.0, 1.0);
+ glEvalMesh2(display_mode,0,right, 0, top);
+ }
+ else
+ {
+ glMapGrid2f(left, 0.0, 1.0, top, 0.0, 1.0);
+ glEvalMesh2(display_mode,0,left, 0, top-1);
+/* tesselate_strip_s(display_mode,0,left,top-1,0,right,right,
+ (GLfloat)right);*/
+ tesselate_strip_s(display_mode,left,0,top-1,right,0,right,
+ (GLfloat)right);
+ }
+ }
+ else
+ {
+ if(left<right)
+ {
+ glMapGrid2f(right, 0.0, 1.0, bottom, 0.0, 1.0);
+ glEvalMesh2(display_mode,0,right-1, 1, bottom);
+ tesselate_strip_s(display_mode,0,right-1,1,0,left-1,0,
+ (GLfloat)left);
+ tesselate_top_left_corner(display_mode,right-1,left-1,
+ (GLfloat)(1.0/left),(GLfloat)(1.0/top));
+ tesselate_strip_t(display_mode,1,bottom,right-1,1,top,top,
+ (GLfloat)top);
+ }
+ else
+ if(left==right)
+ {
+ glMapGrid2f(right, 0.0, 1.0, bottom, 0.0, 1.0);
+ glEvalMesh2(display_mode,0,right-1, 0, bottom);
+ tesselate_strip_t(display_mode,0,bottom,right-1,0,top,top,
+ (GLfloat)top);
+ }
+ else
+ {
+ glMapGrid2f(left, 0.0, 1.0, bottom, 0.0, 1.0);
+ glEvalMesh2(display_mode,0,left-1, 0, bottom-1);
+ tesselate_strip_t(display_mode,0,bottom-1,left-1,0,top-1,top,
+ (GLfloat)top);
+ tesselate_top_right_corner(display_mode,left-1,bottom-1,right,top,
+ (GLfloat)(1.0/right),(GLfloat)(1.0/top));
+/* tesselate_strip_s(display_mode,0,left-1,bottom-1,0,right-1,right,
+ (GLfloat)right);*/
+ tesselate_strip_s(display_mode,left-1,0,bottom-1,right-1,0,right,
+ (GLfloat)right);
+ }
+ }
+}
+
+/* draw NURBS surface in OUTLINE POLYGON mode */
+static void
+draw_polygon_mode( GLenum display_mode, GLUnurbsObj *nobj,
+ new_ctrl_type *new_ctrl, GLint *sfactors, GLint *tfactors )
+{
+ GLsizei offset;
+ GLint t_bezier_cnt,s_bezier_cnt;
+ GLboolean do_color,do_normal,do_texture;
+ GLint i,j;
+
+ t_bezier_cnt=new_ctrl->t_bezier_cnt;
+ s_bezier_cnt=new_ctrl->s_bezier_cnt;
+ glEnable(nobj->surface.geom.type);
+ if(new_ctrl->color_ctrl)
+ {
+ glEnable(nobj->surface.color.type);
+ do_color=GL_TRUE;
+ }
+ else
+ do_color=GL_FALSE;
+ if(new_ctrl->normal_ctrl)
+ {
+ glEnable(nobj->surface.normal.type);
+ do_normal=GL_TRUE;
+ }
+ else
+ do_normal=GL_FALSE;
+ if(new_ctrl->texture_ctrl)
+ {
+ glEnable(nobj->surface.texture.type);
+ do_texture=GL_TRUE;
+ }
+ else
+ do_texture=GL_FALSE;
+ for(j=0; j<s_bezier_cnt; j++)
+ {
+ for(i=0; i<t_bezier_cnt; i++)
+ {
+ offset=j*t_bezier_cnt + i;
+ if(fine_culling_test_3D(nobj,*(new_ctrl->geom_offsets + offset),
+ nobj->surface.geom.sorder,nobj->surface.geom.torder,
+ new_ctrl->geom_s_stride,new_ctrl->geom_t_stride,
+ nobj->surface.geom.dim))
+ continue;
+ glMap2f(nobj->surface.geom.type,0.0,1.0,new_ctrl->geom_s_stride,
+ nobj->surface.geom.sorder,0.0,1.0,new_ctrl->geom_t_stride,
+ nobj->surface.geom.torder,*(new_ctrl->geom_offsets + offset));
+ if(do_color)
+ {
+ glMap2f(nobj->surface.color.type,0.0,1.0,
+ new_ctrl->color_s_stride,nobj->surface.color.sorder,
+ 0.0,1.0,new_ctrl->color_t_stride,nobj->surface.color.torder,
+ *(new_ctrl->color_offsets + offset));
+ }
+ if(do_normal)
+ {
+ glMap2f(nobj->surface.normal.type,0.0,1.0,
+ new_ctrl->normal_s_stride,nobj->surface.normal.sorder,
+ 0.0,1.0,new_ctrl->normal_t_stride,
+ nobj->surface.normal.torder,
+ *(new_ctrl->normal_offsets+offset));
+ }
+ if(do_texture)
+ {
+ glMap2f(nobj->surface.texture.type,0.0,1.0,
+ new_ctrl->texture_s_stride,nobj->surface.texture.sorder,
+ 0.0,1.0,new_ctrl->texture_t_stride,
+ nobj->surface.texture.torder,
+ *(new_ctrl->texture_offsets+offset));
+ }
+/* glMapGrid2f(sfactors[j*3+0],0.0,1.0,tfactors[i*3+0],0.0,1.0);
+ glEvalMesh2(display_mode,0,sfactors[j*3+0],0,tfactors[i*3+0]);*/
+ nurbs_map_bezier(display_mode,sfactors,tfactors,s_bezier_cnt,
+ t_bezier_cnt,j,i);
+ }
+ }
+}
+
+
+
+/* draw NURBS surface in OUTLINE POLYGON mode */
+#if 0
+static void
+draw_patch_mode( GLenum display_mode, GLUnurbsObj *nobj,
+ new_ctrl_type *new_ctrl, GLint *sfactors, GLint *tfactors )
+{
+ GLsizei offset;
+ GLint t_bezier_cnt,s_bezier_cnt;
+ GLboolean do_color,do_normal,do_texture;
+ GLint i,j;
+
+ t_bezier_cnt=new_ctrl->t_bezier_cnt;
+ s_bezier_cnt=new_ctrl->s_bezier_cnt;
+ glEnable(nobj->surface.geom.type);
+ if(new_ctrl->color_ctrl)
+ {
+ glEnable(nobj->surface.color.type);
+ do_color=GL_TRUE;
+ }
+ else
+ do_color=GL_FALSE;
+ if(new_ctrl->normal_ctrl)
+ {
+ glEnable(nobj->surface.normal.type);
+ do_normal=GL_TRUE;
+ }
+ else
+ do_normal=GL_FALSE;
+ if(new_ctrl->texture_ctrl)
+ {
+ glEnable(nobj->surface.texture.type);
+ do_texture=GL_TRUE;
+ }
+ else
+ do_texture=GL_FALSE;
+ for(j=0; j<s_bezier_cnt; j++)
+ {
+ for(i=0; i<t_bezier_cnt; i++)
+ {
+ offset=j*t_bezier_cnt + i;
+ if(fine_culling_test_3D(nobj,*(new_ctrl->geom_offsets + offset),
+ nobj->surface.geom.sorder,nobj->surface.geom.torder,
+ new_ctrl->geom_s_stride,new_ctrl->geom_t_stride,
+ nobj->surface.geom.dim))
+ continue;
+ glMap2f(nobj->surface.geom.type,0.0,1.0,new_ctrl->geom_s_stride,
+ nobj->surface.geom.sorder,0.0,1.0,new_ctrl->geom_t_stride,
+ nobj->surface.geom.torder,*(new_ctrl->geom_offsets + offset));
+ if(do_color)
+ {
+ glMap2f(nobj->surface.color.type,0.0,1.0,
+ new_ctrl->color_s_stride,nobj->surface.color.sorder,
+ 0.0,1.0,new_ctrl->color_t_stride,nobj->surface.color.torder,
+ *(new_ctrl->color_offsets + offset));
+ }
+ if(do_normal)
+ {
+ glMap2f(nobj->surface.normal.type,0.0,1.0,
+ new_ctrl->normal_s_stride,nobj->surface.normal.sorder,
+ 0.0,1.0,new_ctrl->normal_t_stride,
+ nobj->surface.normal.torder,
+ *(new_ctrl->normal_offsets+offset));
+ }
+ if(do_texture)
+ {
+ glMap2f(nobj->surface.texture.type,0.0,1.0,
+ new_ctrl->texture_s_stride,nobj->surface.texture.sorder,
+ 0.0,1.0,new_ctrl->texture_t_stride,
+ nobj->surface.texture.torder,
+ *(new_ctrl->texture_offsets+offset));
+ }
+ nurbs_map_bezier(display_mode,sfactors,tfactors,s_bezier_cnt,
+ t_bezier_cnt,i,j);
+/* glMapGrid2f(sfactors[j],0.0,1.0,tfactors[i],0.0,1.0);
+ glEvalMesh2(display_mode,0,sfactors[j],0,tfactors[i]);*/
+ }
+ }
+}
+#endif
+
+
+
+void
+init_new_ctrl(new_ctrl_type *p)
+{
+ p->geom_ctrl=p->color_ctrl=p->normal_ctrl=p->texture_ctrl=NULL;
+ p->geom_offsets=p->color_offsets=p->normal_offsets=p->texture_offsets=NULL;
+ p->s_bezier_cnt=p->t_bezier_cnt=0;
+}
+
+GLenum
+augment_new_ctrl(GLUnurbsObj *nobj, new_ctrl_type *p)
+{
+ GLsizei offset_size;
+ GLint i,j;
+
+ p->s_bezier_cnt=(p->geom_s_pt_cnt)/(nobj->surface.geom.sorder);
+ p->t_bezier_cnt=(p->geom_t_pt_cnt)/(nobj->surface.geom.torder);
+ offset_size=(p->s_bezier_cnt)*(p->t_bezier_cnt);
+ p->geom_t_stride=nobj->surface.geom.dim;
+ p->geom_s_stride=(p->geom_t_pt_cnt)*(nobj->surface.geom.dim);
+ p->color_t_stride=nobj->surface.color.dim;
+ p->color_s_stride=(p->color_t_pt_cnt)*(nobj->surface.color.dim);
+ p->normal_t_stride=nobj->surface.normal.dim;
+ p->normal_s_stride=(p->normal_t_pt_cnt)*(nobj->surface.normal.dim);
+ p->texture_t_stride=nobj->surface.texture.dim;
+ p->texture_s_stride=(p->texture_t_pt_cnt)*(nobj->surface.texture.dim);
+ if((p->geom_offsets=(GLfloat **)malloc(sizeof(GLfloat *)*offset_size))==NULL)
+ {
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ if(p->color_ctrl)
+ if((p->color_offsets=(GLfloat **)malloc(sizeof(GLfloat *)*offset_size))==NULL)
+ {
+ free_new_ctrl(p);
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ if(p->normal_ctrl)
+ if((p->normal_offsets=(GLfloat **)malloc(sizeof(GLfloat *)*offset_size))==NULL)
+ {
+ free_new_ctrl(p);
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ if(p->texture_ctrl)
+ if((p->texture_offsets=(GLfloat **)malloc(sizeof(GLfloat *)*offset_size))==NULL)
+ {
+ free_new_ctrl(p);
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ for(i=0;i<p->s_bezier_cnt;i++)
+ for(j=0;j<p->t_bezier_cnt;j++)
+ *(p->geom_offsets + i*(p->t_bezier_cnt) + j) =
+ p->geom_ctrl + i*(nobj->surface.geom.sorder)*
+ (nobj->surface.geom.dim)*(p->geom_t_pt_cnt) +
+ j*(nobj->surface.geom.dim)*(nobj->surface.geom.torder);
+ if(p->color_ctrl)
+ for(i=0;i<p->s_bezier_cnt;i++)
+ for(j=0;j<p->t_bezier_cnt;j++)
+ *(p->color_offsets + i*(p->t_bezier_cnt) + j) =
+ p->color_ctrl + i*(nobj->surface.color.sorder)*
+ (nobj->surface.color.dim)*(p->color_t_pt_cnt) +
+ j*(nobj->surface.color.dim)*(nobj->surface.color.torder);
+ if(p->normal_ctrl)
+ for(i=0;i<p->s_bezier_cnt;i++)
+ for(j=0;j<p->t_bezier_cnt;j++)
+ *(p->normal_offsets + i*(p->t_bezier_cnt) + j) =
+ p->normal_ctrl + i*(nobj->surface.normal.sorder)*
+ (nobj->surface.normal.dim)*(p->normal_t_pt_cnt) +
+ j*(nobj->surface.normal.dim)*(nobj->surface.normal.torder);
+ if(p->texture_ctrl)
+ for(i=0;i<p->s_bezier_cnt;i++)
+ for(j=0;j<p->t_bezier_cnt;j++)
+ *(p->texture_offsets + i*(p->t_bezier_cnt) + j) =
+ p->texture_ctrl + i*(nobj->surface.texture.sorder)*
+ (nobj->surface.texture.dim)*(p->texture_t_pt_cnt) +
+ j*(nobj->surface.texture.dim)*(nobj->surface.texture.torder);
+ return GLU_NO_ERROR;
+}
+
+/* main NURBS surface procedure */
+void
+do_nurbs_surface( GLUnurbsObj *nobj )
+{
+ GLint *sfactors,*tfactors;
+ new_ctrl_type new_ctrl;
+
+ /* test user supplied data */
+ if(test_nurbs_surfaces(nobj)!=GLU_NO_ERROR)
+ return;
+
+ init_new_ctrl(&new_ctrl);
+
+ if(convert_surfs(nobj,&new_ctrl)!=GLU_NO_ERROR)
+ return;
+ if(augment_new_ctrl(nobj,&new_ctrl)!=GLU_NO_ERROR)
+ return;
+ switch(nobj->sampling_method)
+ {
+ case GLU_PATH_LENGTH:
+ if(glu_do_sampling_3D(nobj,&new_ctrl,&sfactors,&tfactors)!=
+ GLU_NO_ERROR)
+ {
+ free_new_ctrl(&new_ctrl);
+ return;
+ }
+ break;
+ case GLU_DOMAIN_DISTANCE:
+ if(glu_do_sampling_uv(nobj,&new_ctrl,&sfactors,&tfactors)!=
+ GLU_NO_ERROR)
+ {
+ free_new_ctrl(&new_ctrl);
+ return;
+ }
+ break;
+ case GLU_PARAMETRIC_ERROR:
+ if(glu_do_sampling_param_3D(nobj,&new_ctrl,&sfactors,&tfactors)!=
+ GLU_NO_ERROR)
+ {
+ free_new_ctrl(&new_ctrl);
+ return;
+ }
+ break;
+ default:
+ abort();
+ }
+ glFrontFace(GL_CW);
+ switch(nobj->display_mode)
+ {
+ case GLU_FILL:
+/* if(polygon_trimming(nobj,&new_ctrl,sfactors,tfactors)==GLU_NO_ERROR)*/
+ draw_polygon_mode(GL_FILL,nobj,&new_ctrl,sfactors,tfactors);
+ break;
+ case GLU_OUTLINE_POLYGON:
+ /* TODO - missing trimming handeling */
+/* just for now - no OUTLINE_PATCH mode
+ draw_patch_mode(GL_LINE,nobj,&new_ctrl,sfactors,tfactors);
+ break; */
+ case GLU_OUTLINE_PATCH:
+/* if(polygon_trimming(nobj,&new_ctrl,sfactors,tfactors)==GLU_NO_ERROR)*/
+ draw_polygon_mode(GL_LINE,nobj,&new_ctrl,sfactors,tfactors);
+ break;
+ default:
+ abort(); /* TODO: is this OK? */
+ }
+ free(sfactors);
+ free(tfactors);
+ free_new_ctrl(&new_ctrl);
+}
+
diff --git a/src/glu/mesa/nurbsutl.c b/src/glu/mesa/nurbsutl.c
new file mode 100644
index 00000000000..f0f166cb647
--- /dev/null
+++ b/src/glu/mesa/nurbsutl.c
@@ -0,0 +1,1403 @@
+/* $Id: nurbsutl.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: nurbsutl.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.8 1999/06/08 00:44:51 brianp
+ * OpenStep updates ([email protected])
+ *
+ * Revision 1.7 1998/07/26 02:07:59 brianp
+ * updated for Windows compilation per Ted Jump
+ *
+ * Revision 1.6 1997/10/29 02:02:20 brianp
+ * various MS Windows compiler changes (David Bucciarelli, v20 3dfx driver)
+ *
+ * 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/05/27 03:19:54 brianp
+ * minor clean-up
+ *
+ * Revision 1.2 1997/05/27 03:00:16 brianp
+ * incorporated Bogdan's new NURBS code
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+/*
+ * NURBS implementation written by Bogdan Sikorski ([email protected])
+ * See README2 for more info.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdlib.h>
+#include "gluP.h"
+#include "nurbs.h"
+#endif
+
+
+GLenum
+test_knot(GLint nknots, GLfloat *knot, GLint order)
+{
+ GLsizei i;
+ GLint knot_mult;
+ GLfloat tmp_knot;
+
+ tmp_knot=knot[0];
+ knot_mult=1;
+ for(i=1;i<nknots;i++)
+ {
+ if(knot[i] < tmp_knot)
+ return GLU_NURBS_ERROR4;
+ if(fabs(tmp_knot-knot[i]) > EPSILON)
+ {
+ if(knot_mult>order)
+ return GLU_NURBS_ERROR5;
+ knot_mult=1;
+ tmp_knot=knot[i];
+ }
+ else
+ ++knot_mult;
+ }
+ return GLU_NO_ERROR;
+}
+
+static int
+/* qsort function */
+#if defined(WIN32) && !defined(OPENSTEP)
+__cdecl
+#endif
+knot_sort(const void *a, const void *b)
+{
+ GLfloat x,y;
+
+ x=*((GLfloat *)a);
+ y=*((GLfloat *)b);
+ if(fabs(x-y) < EPSILON)
+ return 0;
+ if(x > y)
+ return 1;
+ return -1;
+}
+
+/* insert into dest knot all values within the valid range from src knot */
+/* that do not appear in dest */
+void
+collect_unified_knot(knot_str_type *dest, knot_str_type *src,
+ GLfloat maximal_min_knot, GLfloat minimal_max_knot)
+{
+ GLfloat *src_knot,*dest_knot;
+ GLint src_t_min,src_t_max,dest_t_min,dest_t_max;
+ GLint src_nknots,dest_nknots;
+ GLint i,j,k,new_cnt;
+ GLboolean not_found_flag;
+
+ src_knot=src->unified_knot;
+ dest_knot=dest->unified_knot;
+ src_t_min=src->t_min;
+ src_t_max=src->t_max;
+ dest_t_min=dest->t_min;
+ dest_t_max=dest->t_max;
+ src_nknots=src->unified_nknots;
+ dest_nknots=dest->unified_nknots;
+
+ k=new_cnt=dest_nknots;
+ for(i=src_t_min;i<=src_t_max;i++)
+ if(src_knot[i] - maximal_min_knot > -EPSILON &&
+ src_knot[i] - minimal_max_knot < EPSILON)
+ {
+ not_found_flag=GL_TRUE;
+ for(j=dest_t_min;j<=dest_t_max;j++)
+ if(fabs(dest_knot[j]-src_knot[i]) < EPSILON)
+ {
+ not_found_flag=GL_FALSE;
+ break;
+ }
+ if(not_found_flag)
+ {
+ /* knot from src is not in dest - add this knot to dest */
+ dest_knot[k++]=src_knot[i];
+ ++new_cnt;
+ ++(dest->t_max); /* the valid range widens */
+ ++(dest->delta_nknots); /* increment the extra knot value counter */
+ }
+ }
+ dest->unified_nknots=new_cnt;
+ qsort((void *)dest_knot,(size_t)new_cnt,(size_t)sizeof(GLfloat),
+ &knot_sort);
+}
+
+/* basing on the new common knot range for all attributes set */
+/* t_min and t_max values for each knot - they will be used later on */
+/* by explode_knot() and calc_new_ctrl_pts */
+static void
+set_new_t_min_t_max(knot_str_type *geom_knot, knot_str_type *color_knot,
+ knot_str_type *normal_knot, knot_str_type *texture_knot,
+ GLfloat maximal_min_knot, GLfloat minimal_max_knot)
+{
+ GLuint t_min,t_max,cnt;
+
+ if(minimal_max_knot-maximal_min_knot < EPSILON)
+ {
+ /* knot common range empty */
+ geom_knot->t_min=geom_knot->t_max=0;
+ color_knot->t_min=color_knot->t_max=0;
+ normal_knot->t_min=normal_knot->t_max=0;
+ texture_knot->t_min=texture_knot->t_max=0;
+ }
+ else
+ {
+ if(geom_knot->unified_knot!=NULL)
+ {
+ cnt=geom_knot->unified_nknots;
+ for(t_min=0;t_min<cnt;t_min++)
+ if(fabs((geom_knot->unified_knot)[t_min] - maximal_min_knot) <
+ EPSILON)
+ break;
+ for(t_max=cnt-1;t_max;t_max--)
+ if(fabs((geom_knot->unified_knot)[t_max] - minimal_max_knot) <
+ EPSILON)
+ break;
+ }
+ else
+ if(geom_knot->nknots)
+ {
+ cnt=geom_knot->nknots;
+ for(t_min=0;t_min<cnt;t_min++)
+ if(fabs((geom_knot->knot)[t_min] - maximal_min_knot) < EPSILON)
+ break;
+ for(t_max=cnt-1;t_max;t_max--)
+ if(fabs((geom_knot->knot)[t_max] - minimal_max_knot) < EPSILON)
+ break;
+ }
+ geom_knot->t_min=t_min;
+ geom_knot->t_max=t_max;
+ if(color_knot->unified_knot!=NULL)
+ {
+ cnt=color_knot->unified_nknots;
+ for(t_min=0;t_min<cnt;t_min++)
+ if(fabs((color_knot->unified_knot)[t_min] - maximal_min_knot) <
+ EPSILON)
+ break;
+ for(t_max=cnt-1;t_max;t_max--)
+ if(fabs((color_knot->unified_knot)[t_max] - minimal_max_knot) <
+ EPSILON)
+ break;
+ color_knot->t_min=t_min;
+ color_knot->t_max=t_max;
+ }
+ if(normal_knot->unified_knot!=NULL)
+ {
+ cnt=normal_knot->unified_nknots;
+ for(t_min=0;t_min<cnt;t_min++)
+ if(fabs((normal_knot->unified_knot)[t_min] - maximal_min_knot) <
+ EPSILON)
+ break;
+ for(t_max=cnt-1;t_max;t_max--)
+ if(fabs((normal_knot->unified_knot)[t_max] - minimal_max_knot) <
+ EPSILON)
+ break;
+ normal_knot->t_min=t_min;
+ normal_knot->t_max=t_max;
+ }
+ if(texture_knot->unified_knot!=NULL)
+ {
+ cnt=texture_knot->unified_nknots;
+ for(t_min=0;t_min<cnt;t_min++)
+ if(fabs((texture_knot->unified_knot)[t_min] - maximal_min_knot)
+ < EPSILON)
+ break;
+ for(t_max=cnt-1;t_max;t_max--)
+ if(fabs((texture_knot->unified_knot)[t_max] - minimal_max_knot)
+ < EPSILON)
+ break;
+ texture_knot->t_min=t_min;
+ texture_knot->t_max=t_max;
+ }
+ }
+}
+
+/* modify all knot valid ranges in such a way that all have the same */
+/* range, common to all knots */
+/* do this by knot insertion */
+GLenum
+select_knot_working_range(GLUnurbsObj *nobj,knot_str_type *geom_knot,
+ knot_str_type *color_knot, knot_str_type *normal_knot,
+ knot_str_type *texture_knot)
+{
+ GLint max_nknots;
+ GLfloat maximal_min_knot,minimal_max_knot;
+ GLint i;
+
+ /* find the maximum modified knot length */
+ max_nknots=geom_knot->nknots;
+ if(color_knot->unified_knot)
+ max_nknots+=color_knot->nknots;
+ if(normal_knot->unified_knot)
+ max_nknots+=normal_knot->nknots;
+ if(texture_knot->unified_knot)
+ max_nknots+=texture_knot->nknots;
+ maximal_min_knot=(geom_knot->knot)[geom_knot->t_min];
+ minimal_max_knot=(geom_knot->knot)[geom_knot->t_max];
+ /* any attirb data ? */
+ if(max_nknots!=geom_knot->nknots)
+ {
+ /* allocate space for the unified knots */
+ if((geom_knot->unified_knot=
+ (GLfloat *)malloc(sizeof(GLfloat)*max_nknots))==NULL)
+ {
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ /* copy the original knot to the unified one */
+ geom_knot->unified_nknots=geom_knot->nknots;
+ for(i=0;i<geom_knot->nknots;i++)
+ (geom_knot->unified_knot)[i]=(geom_knot->knot)[i];
+ if(color_knot->unified_knot)
+ {
+ if((color_knot->knot)[color_knot->t_min] - maximal_min_knot >
+ EPSILON)
+ maximal_min_knot=(color_knot->knot)[color_knot->t_min];
+ if(minimal_max_knot - (color_knot->knot)[color_knot->t_max] >
+ EPSILON)
+ minimal_max_knot=(color_knot->knot)[color_knot->t_max];
+ if((color_knot->unified_knot=
+ (GLfloat *)malloc(sizeof(GLfloat)*max_nknots))==NULL)
+ {
+ free(geom_knot->unified_knot);
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ /* copy the original knot to the unified one */
+ color_knot->unified_nknots=color_knot->nknots;
+ for(i=0;i<color_knot->nknots;i++)
+ (color_knot->unified_knot)[i]=(color_knot->knot)[i];
+ }
+ if(normal_knot->unified_knot)
+ {
+ if((normal_knot->knot)[normal_knot->t_min] - maximal_min_knot >
+ EPSILON)
+ maximal_min_knot=(normal_knot->knot)[normal_knot->t_min];
+ if(minimal_max_knot - (normal_knot->knot)[normal_knot->t_max] >
+ EPSILON)
+ minimal_max_knot=(normal_knot->knot)[normal_knot->t_max];
+ if((normal_knot->unified_knot=
+ (GLfloat *)malloc(sizeof(GLfloat)*max_nknots))==NULL)
+ {
+ free(geom_knot->unified_knot);
+ free(color_knot->unified_knot);
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ /* copy the original knot to the unified one */
+ normal_knot->unified_nknots=normal_knot->nknots;
+ for(i=0;i<normal_knot->nknots;i++)
+ (normal_knot->unified_knot)[i]=(normal_knot->knot)[i];
+ }
+ if(texture_knot->unified_knot)
+ {
+ if((texture_knot->knot)[texture_knot->t_min] - maximal_min_knot >
+ EPSILON)
+ maximal_min_knot=(texture_knot->knot)[texture_knot->t_min];
+ if(minimal_max_knot - (texture_knot->knot)[texture_knot->t_max] >
+ EPSILON)
+ minimal_max_knot=(texture_knot->knot)[texture_knot->t_max];
+ if((texture_knot->unified_knot=
+ (GLfloat *)malloc(sizeof(GLfloat)*max_nknots))==NULL)
+ {
+ free(geom_knot->unified_knot);
+ free(color_knot->unified_knot);
+ free(normal_knot->unified_knot);
+ call_user_error(nobj,GLU_OUT_OF_MEMORY);
+ return GLU_ERROR;
+ }
+ /* copy the original knot to the unified one */
+ texture_knot->unified_nknots=texture_knot->nknots;
+ for(i=0;i<texture_knot->nknots;i++)
+ (texture_knot->unified_knot)[i]=(texture_knot->knot)[i];
+ }
+ /* work on the geometry knot with all additional knot values */
+ /* appearing in attirbutive knots */
+ if(minimal_max_knot-maximal_min_knot < EPSILON)
+ {
+ /* empty working range */
+ geom_knot->unified_nknots=0;
+ color_knot->unified_nknots=0;
+ normal_knot->unified_nknots=0;
+ texture_knot->unified_nknots=0;
+ }
+ else
+ {
+ if(color_knot->unified_knot)
+ collect_unified_knot(geom_knot,color_knot,maximal_min_knot,
+ minimal_max_knot);
+ if(normal_knot->unified_knot)
+ collect_unified_knot(geom_knot,normal_knot,maximal_min_knot,
+ minimal_max_knot);
+ if(texture_knot->unified_knot)
+ collect_unified_knot(geom_knot,texture_knot,maximal_min_knot,
+ minimal_max_knot);
+ /* since we have now built the "unified" geometry knot */
+ /* add same knot values to all attributive knots */
+ if(color_knot->unified_knot)
+ collect_unified_knot(color_knot,geom_knot,maximal_min_knot,
+ minimal_max_knot);
+ if(normal_knot->unified_knot)
+ collect_unified_knot(normal_knot,geom_knot,maximal_min_knot,
+ minimal_max_knot);
+ if(texture_knot->unified_knot)
+ collect_unified_knot(texture_knot,geom_knot,maximal_min_knot,
+ minimal_max_knot);
+ }
+ }
+ set_new_t_min_t_max(geom_knot,color_knot,normal_knot,texture_knot,
+ maximal_min_knot,minimal_max_knot);
+ return GLU_NO_ERROR;
+}
+
+void
+free_unified_knots(knot_str_type *geom_knot, knot_str_type *color_knot,
+ knot_str_type *normal_knot, knot_str_type *texture_knot)
+{
+ if(geom_knot->unified_knot)
+ free(geom_knot->unified_knot);
+ if(color_knot->unified_knot)
+ free(color_knot->unified_knot);
+ if(normal_knot->unified_knot)
+ free(normal_knot->unified_knot);
+ if(texture_knot->unified_knot)
+ free(texture_knot->unified_knot);
+}
+
+GLenum
+explode_knot(knot_str_type *the_knot)
+{
+ GLfloat *knot,*new_knot;
+ GLint nknots,n_new_knots=0;
+ GLint t_min,t_max;
+ GLint ord;
+ GLsizei i,j,k;
+ GLfloat tmp_float;
+
+ if(the_knot->unified_knot)
+ {
+ knot=the_knot->unified_knot;
+ nknots=the_knot->unified_nknots;
+ }
+ else
+ {
+ knot=the_knot->knot;
+ nknots=the_knot->nknots;
+ }
+ ord=the_knot->order;
+ t_min=the_knot->t_min;
+ t_max=the_knot->t_max;
+
+ for(i=t_min;i<=t_max;)
+ {
+ tmp_float=knot[i];
+ for(j=0;j<ord && (i+j)<=t_max;j++)
+ if(fabs(tmp_float-knot[i+j])>EPSILON)
+ break;
+ n_new_knots+=ord-j;
+ i+=j;
+ }
+ /* alloc space for new_knot */
+ if((new_knot=(GLfloat *)malloc(sizeof(GLfloat)*(nknots+n_new_knots)))==NULL)
+ {
+ return GLU_OUT_OF_MEMORY;
+ }
+ /* fill in new knot */
+ for(j=0;j<t_min;j++)
+ new_knot[j]=knot[j];
+ for(i=j;i<=t_max;i++)
+ {
+ tmp_float=knot[i];
+ for(k=0;k<ord;k++)
+ {
+ new_knot[j++]=knot[i];
+ if(tmp_float==knot[i+1])
+ i++;
+ }
+ }
+ for(i=t_max+1;i<(int)nknots;i++)
+ new_knot[j++]=knot[i];
+ /* fill in the knot structure */
+ the_knot->new_knot=new_knot;
+ the_knot->delta_nknots+=n_new_knots;
+ the_knot->t_max+=n_new_knots;
+ return GLU_NO_ERROR;
+}
+
+GLenum
+calc_alphas(knot_str_type *the_knot)
+{
+ GLfloat tmp_float;
+ int i,j,k,m,n;
+ int order;
+ GLfloat *alpha,*alpha_new,*tmp_alpha;
+ GLfloat denom;
+ GLfloat *knot,*new_knot;
+
+
+ knot=the_knot->knot;
+ order=the_knot->order;
+ new_knot=the_knot->new_knot;
+ n=the_knot->nknots-the_knot->order;
+ m=n+the_knot->delta_nknots;
+ if((alpha=(GLfloat *)malloc(sizeof(GLfloat)*n*m))==NULL)
+ {
+ return GLU_OUT_OF_MEMORY;
+ }
+ if((alpha_new=(GLfloat *)malloc(sizeof(GLfloat)*n*m))==NULL)
+ {
+ free(alpha);
+ return GLU_OUT_OF_MEMORY;
+ }
+ for(j=0;j<m;j++)
+ {
+ for(i=0;i<n;i++)
+ {
+ if((knot[i] <= new_knot[j]) && (new_knot[j] < knot[i+1]))
+ tmp_float=1.0;
+ else
+ tmp_float=0.0;
+ alpha[i+j*n]=tmp_float;
+ }
+ }
+ for(k=1;k<order;k++)
+ {
+ for(j=0;j<m;j++)
+ for(i=0;i<n;i++)
+ {
+ denom=knot[i+k]-knot[i];
+ if(fabs(denom)<EPSILON)
+ tmp_float=0.0;
+ else
+ tmp_float=(new_knot[j+k]-knot[i])/denom*
+ alpha[i+j*n];
+ denom=knot[i+k+1]-knot[i+1];
+ if(fabs(denom)>EPSILON)
+ tmp_float+=(knot[i+k+1]-new_knot[j+k])/denom*
+ alpha[(i+1)+j*n];
+ alpha_new[i+j*n]=tmp_float;
+ }
+ tmp_alpha=alpha_new;
+ alpha_new=alpha;
+ alpha=tmp_alpha;
+ }
+ the_knot->alpha=alpha;
+ free(alpha_new);
+ return GLU_NO_ERROR;
+}
+
+GLenum
+calc_new_ctrl_pts(GLfloat *ctrl,GLint stride,knot_str_type *the_knot,
+ GLint dim,GLfloat **new_ctrl,GLint *ncontrol)
+{
+ GLsizei i,j,k,l,m,n;
+ GLsizei index1,index2;
+ GLfloat *alpha;
+ GLfloat *new_knot;
+
+ new_knot=the_knot->new_knot;
+ n=the_knot->nknots-the_knot->order;
+ alpha=the_knot->alpha;
+
+ m=the_knot->t_max+1-the_knot->t_min-the_knot->order;
+ k=the_knot->t_min;
+ /* allocate space for new control points */
+ if((*new_ctrl=(GLfloat *)malloc(sizeof(GLfloat)*dim*m))==NULL)
+ {
+ return GLU_OUT_OF_MEMORY;
+ }
+ for(j=0;j<m;j++)
+ {
+ for(l=0;l<dim;l++)
+ (*new_ctrl)[j*dim+l]=0.0;
+ for(i=0;i<n;i++)
+ {
+ index1=i+(j+k)*n;
+ index2=i*stride;
+ for(l=0;l<dim;l++)
+ (*new_ctrl)[j*dim+l]+=alpha[index1]*ctrl[index2+l];
+ }
+ }
+ *ncontrol=(GLint)m;
+ return GLU_NO_ERROR;
+}
+
+static GLint
+calc_factor(GLfloat *pts,GLint order,GLint indx,GLint stride,GLfloat tolerance,
+ GLint dim)
+{
+ GLdouble model[16],proj[16];
+ GLint viewport[4];
+ GLdouble x,y,z,w,winx1,winy1,winz,winx2,winy2;
+ GLint i;
+ GLdouble len,dx,dy;
+
+ glGetDoublev(GL_MODELVIEW_MATRIX,model);
+ glGetDoublev(GL_PROJECTION_MATRIX,proj);
+ glGetIntegerv(GL_VIEWPORT,viewport);
+ if(dim==4)
+ {
+ w=(GLdouble)pts[indx+3];
+ x=(GLdouble)pts[indx]/w;
+ y=(GLdouble)pts[indx+1]/w;
+ z=(GLdouble)pts[indx+2]/w;
+ gluProject(x,y,z,model,proj,viewport,&winx1,&winy1,&winz);
+ len=0.0;
+ for(i=1;i<order;i++)
+ {
+ w=(GLdouble)pts[indx+i*stride+3];
+ x=(GLdouble)pts[indx+i*stride]/w;
+ y=(GLdouble)pts[indx+i*stride+1]/w;
+ z=(GLdouble)pts[indx+i*stride+2]/w;
+ if(gluProject(x,y,z,model,proj,viewport,&winx2,&winy2,&winz))
+ {
+ dx=winx2-winx1;
+ dy=winy2-winy1;
+ len+=sqrt(dx*dx+dy*dy);
+ }
+ winx1=winx2; winy1=winy2;
+ }
+ }
+ else
+ {
+ x=(GLdouble)pts[indx];
+ y=(GLdouble)pts[indx+1];
+ if(dim==2)
+ z=0.0;
+ else
+ z=(GLdouble)pts[indx+2];
+ gluProject(x,y,z,model,proj,viewport,&winx1,&winy1,&winz);
+ len=0.0;
+ for(i=1;i<order;i++)
+ {
+ x=(GLdouble)pts[indx+i*stride];
+ y=(GLdouble)pts[indx+i*stride+1];
+ if(dim==2)
+ z=0.0;
+ else
+ z=(GLdouble)pts[indx+i*stride+2];
+ if(gluProject(x,y,z,model,proj,viewport,&winx2,&winy2,&winz))
+ {
+ dx=winx2-winx1;
+ dy=winy2-winy1;
+ len+=sqrt(dx*dx+dy*dy);
+ }
+ winx1=winx2; winy1=winy2;
+ }
+ }
+ len /= tolerance;
+ return ((GLint)len+1);
+}
+
+/* we can't use the Mesa evaluators - no way to get the point coords */
+/* so we use our own Bezier point calculus routines */
+/* because I'm lazy, I reuse the ones from eval.c */
+
+static void
+bezier_curve(GLfloat *cp, GLfloat *out, GLfloat t,
+ GLuint dim, GLuint order, GLint offset)
+{
+ GLfloat s, powert;
+ GLuint i, k, bincoeff;
+
+ if(order >= 2)
+ {
+ bincoeff = order-1;
+ s = 1.0-t;
+
+ for(k=0; k<dim; k++)
+ out[k] = s*cp[k] + bincoeff*t*cp[offset+k];
+
+ for(i=2, cp+=2*offset, powert=t*t; i<order; i++, powert*=t, cp +=offset)
+ {
+ bincoeff *= order-i;
+ bincoeff /= i;
+
+ for(k=0; k<dim; k++)
+ out[k] = s*out[k] + bincoeff*powert*cp[k];
+ }
+ }
+ else /* order=1 -> constant curve */
+ {
+ for(k=0; k<dim; k++)
+ out[k] = cp[k];
+ }
+}
+
+static GLint
+calc_parametric_factor(GLfloat *pts,GLint order,GLint indx,GLint stride,
+ GLfloat tolerance,GLint dim)
+{
+ GLdouble model[16],proj[16];
+ GLint viewport[4];
+ GLdouble x,y,z,w,x1,y1,z1,x2,y2,z2,x3,y3,z3;
+ GLint i;
+ GLint P;
+ GLfloat bez_pt[4];
+ GLdouble len=0.0,tmp,z_med;
+
+ P = 2*(order+2);
+ glGetDoublev(GL_MODELVIEW_MATRIX,model);
+ glGetDoublev(GL_PROJECTION_MATRIX,proj);
+ glGetIntegerv(GL_VIEWPORT,viewport);
+ z_med = (viewport[2] + viewport[3]) * 0.5;
+ switch(dim)
+ {
+ case 4:
+ for(i=1;i<P;i++)
+ {
+ bezier_curve(pts+indx, bez_pt, (GLfloat)i/(GLfloat)P, 4,
+ order,stride);
+ w = (GLdouble)bez_pt[3];
+ x = (GLdouble)bez_pt[0] / w;
+ y = (GLdouble)bez_pt[1] / w;
+ z = (GLdouble)bez_pt[2] / w;
+ gluProject(x,y,z,model,proj,viewport,&x3,&y3,&z3);
+ z3 *= z_med;
+ bezier_curve(pts+indx, bez_pt, (GLfloat)(i-1)/(GLfloat)P, 4,
+ order,stride);
+ w = (GLdouble)bez_pt[3];
+ x = (GLdouble)bez_pt[0] / w;
+ y = (GLdouble)bez_pt[1] / w;
+ z = (GLdouble)bez_pt[2] / w;
+ gluProject(x,y,z,model,proj,viewport,&x1,&y1,&z1);
+ z1 *= z_med;
+ bezier_curve(pts+indx, bez_pt, (GLfloat)(i+1)/(GLfloat)P, 4,
+ order,stride);
+ w = (GLdouble)bez_pt[3];
+ x = (GLdouble)bez_pt[0] / w;
+ y = (GLdouble)bez_pt[1] / w;
+ z = (GLdouble)bez_pt[2] / w;
+ gluProject(x,y,z,model,proj,viewport,&x2,&y2,&z2);
+ z2 *= z_med;
+ /* calc distance between point (x3,y3,z3) and line segment */
+ /* <x1,y1,z1><x2,y2,z2> */
+ x = x2-x1;
+ y = y2-y1;
+ z = z2-z1;
+ tmp = sqrt(x*x+y*y+z*z);
+ x /= tmp;
+ y /= tmp;
+ z /= tmp;
+ tmp = x3*x+y3*y+z3*z-x1*x-y1*y-z1*z;
+ x = x1+x*tmp-x3;
+ y = y1+y*tmp-y3;
+ z = z1+z*tmp-z3;
+ tmp = sqrt(x*x+y*y+z*z);
+ if(tmp > len)
+ len = tmp;
+ }
+ break;
+ case 3:
+ for(i=1;i<P;i++)
+ {
+ bezier_curve(pts+indx, bez_pt, (GLfloat)i/(GLfloat)P, 3,
+ order,stride);
+ x = (GLdouble)bez_pt[0];
+ y = (GLdouble)bez_pt[1];
+ z = (GLdouble)bez_pt[2];
+ gluProject(x,y,z,model,proj,viewport,&x3,&y3,&z3);
+ z3 *= z_med;
+ bezier_curve(pts+indx, bez_pt, (GLfloat)(i-1)/(GLfloat)P, 3,
+ order,stride);
+ x = (GLdouble)bez_pt[0];
+ y = (GLdouble)bez_pt[1];
+ z = (GLdouble)bez_pt[2];
+ gluProject(x,y,z,model,proj,viewport,&x1,&y1,&z1);
+ z1 *= z_med;
+ bezier_curve(pts+indx, bez_pt, (GLfloat)(i+1)/(GLfloat)P, 3,
+ order,stride);
+ x = (GLdouble)bez_pt[0];
+ y = (GLdouble)bez_pt[1];
+ z = (GLdouble)bez_pt[2];
+ gluProject(x,y,z,model,proj,viewport,&x2,&y2,&z2);
+ z2 *= z_med;
+ /* calc distance between point (x3,y3,z3) and line segment */
+ /* <x1,y1,z1><x2,y2,z2> */
+ x = x2-x1;
+ y = y2-y1;
+ z = z2-z1;
+ tmp = sqrt(x*x+y*y+z*z);
+ x /= tmp;
+ y /= tmp;
+ z /= tmp;
+ tmp = x3*x+y3*y+z3*z-x1*x-y1*y-z1*z;
+ x = x1+x*tmp-x3;
+ y = y1+y*tmp-y3;
+ z = z1+z*tmp-z3;
+ tmp = sqrt(x*x+y*y+z*z);
+ if(tmp > len)
+ len = tmp;
+ }
+ break;
+ case 2:
+ for(i=1;i<P;i++)
+ {
+ bezier_curve(pts+indx, bez_pt, (GLfloat)i/(GLfloat)P, 2,
+ order,stride);
+ x = (GLdouble)bez_pt[0];
+ y = (GLdouble)bez_pt[1];
+ z = 0.0;
+ gluProject(x,y,z,model,proj,viewport,&x3,&y3,&z3);
+ z3 *= z_med;
+ bezier_curve(pts+indx, bez_pt, (GLfloat)(i-1)/(GLfloat)P, 2,
+ order,stride);
+ x = (GLdouble)bez_pt[0];
+ y = (GLdouble)bez_pt[1];
+ z = 0.0;
+ gluProject(x,y,z,model,proj,viewport,&x1,&y1,&z1);
+ z1 *= z_med;
+ bezier_curve(pts+indx, bez_pt, (GLfloat)(i+1)/(GLfloat)P, 2,
+ order,stride);
+ x = (GLdouble)bez_pt[0];
+ y = (GLdouble)bez_pt[1];
+ z = 0.0;
+ gluProject(x,y,z,model,proj,viewport,&x2,&y2,&z2);
+ z2 *= z_med;
+ /* calc distance between point (x3,y3,z3) and line segment */
+ /* <x1,y1,z1><x2,y2,z2> */
+ x = x2-x1;
+ y = y2-y1;
+ z = z2-z1;
+ tmp = sqrt(x*x+y*y+z*z);
+ x /= tmp;
+ y /= tmp;
+ z /= tmp;
+ tmp = x3*x+y3*y+z3*z-x1*x-y1*y-z1*z;
+ x = x1+x*tmp-x3;
+ y = y1+y*tmp-y3;
+ z = z1+z*tmp-z3;
+ tmp = sqrt(x*x+y*y+z*z);
+ if(tmp > len)
+ len = tmp;
+ }
+ break;
+
+ }
+ if(len < tolerance)
+ return (order);
+ else
+ return (GLint)(sqrt(len/tolerance)*(order+2)+1);
+}
+
+static GLenum
+calc_sampling_3D(new_ctrl_type *new_ctrl, GLfloat tolerance, GLint dim,
+ GLint uorder, GLint vorder, GLint **ufactors, GLint **vfactors)
+{
+ GLfloat *ctrl;
+ GLint tmp_factor1,tmp_factor2;
+ GLint ufactor_cnt,vfactor_cnt;
+ GLint offset1,offset2,offset3;
+ GLint i,j;
+
+ ufactor_cnt=new_ctrl->s_bezier_cnt;
+ vfactor_cnt=new_ctrl->t_bezier_cnt;
+ if((*ufactors=(GLint *)malloc(sizeof(GLint)*ufactor_cnt*3))
+ ==NULL)
+ {
+ return GLU_OUT_OF_MEMORY;
+ }
+ if((*vfactors=(GLint *)malloc(sizeof(GLint)*vfactor_cnt*3))
+ ==NULL)
+ {
+ free(*ufactors);
+ return GLU_OUT_OF_MEMORY;
+ }
+ ctrl=new_ctrl->geom_ctrl;
+ offset1=new_ctrl->geom_t_stride*vorder;
+ offset2=new_ctrl->geom_s_stride*uorder;
+ for(j=0;j<vfactor_cnt;j++)
+ {
+ *(*vfactors+j*3+1)=tmp_factor1=calc_factor(ctrl,vorder,
+ j*offset1,dim,tolerance,dim);
+ /* loop ufactor_cnt-1 times */
+ for(i=1;i<ufactor_cnt;i++)
+ {
+ tmp_factor2=calc_factor(ctrl,vorder,
+ j*offset1+i*offset2,dim,tolerance,dim);
+ if(tmp_factor2>tmp_factor1)
+ tmp_factor1=tmp_factor2;
+ }
+ /* last time for the opposite edge */
+ *(*vfactors+j*3+2)=tmp_factor2=calc_factor(ctrl,vorder,
+ j*offset1+i*offset2-new_ctrl->geom_s_stride,
+ dim,tolerance,dim);
+ if(tmp_factor2>tmp_factor1)
+ *(*vfactors+j*3)=tmp_factor2;
+ else
+ *(*vfactors+j*3)=tmp_factor1;
+ }
+ offset3=new_ctrl->geom_s_stride;
+ offset2=new_ctrl->geom_s_stride*uorder;
+ for(j=0;j<ufactor_cnt;j++)
+ {
+ *(*ufactors+j*3+1)=tmp_factor1=calc_factor(ctrl,uorder,
+ j*offset2,offset3,tolerance,dim);
+ /* loop vfactor_cnt-1 times */
+ for(i=1;i<vfactor_cnt;i++)
+ {
+ tmp_factor2=calc_factor(ctrl,uorder,
+ j*offset2+i*offset1,offset3,tolerance,dim);
+ if(tmp_factor2>tmp_factor1)
+ tmp_factor1=tmp_factor2;
+ }
+ /* last time for the opposite edge */
+ *(*ufactors+j*3+2)=tmp_factor2=calc_factor(ctrl,uorder,
+ j*offset2+i*offset1-new_ctrl->geom_t_stride,
+ offset3,tolerance,dim);
+ if(tmp_factor2>tmp_factor1)
+ *(*ufactors+j*3)=tmp_factor2;
+ else
+ *(*ufactors+j*3)=tmp_factor1;
+ }
+ return GL_NO_ERROR;
+}
+
+static GLenum
+calc_sampling_param_3D(new_ctrl_type *new_ctrl, GLfloat tolerance, GLint dim,
+ GLint uorder, GLint vorder, GLint **ufactors, GLint **vfactors)
+{
+ GLfloat *ctrl;
+ GLint tmp_factor1,tmp_factor2;
+ GLint ufactor_cnt,vfactor_cnt;
+ GLint offset1,offset2,offset3;
+ GLint i,j;
+
+ ufactor_cnt=new_ctrl->s_bezier_cnt;
+ vfactor_cnt=new_ctrl->t_bezier_cnt;
+ if((*ufactors=(GLint *)malloc(sizeof(GLint)*ufactor_cnt*3))
+ ==NULL)
+ {
+ return GLU_OUT_OF_MEMORY;
+ }
+ if((*vfactors=(GLint *)malloc(sizeof(GLint)*vfactor_cnt*3))
+ ==NULL)
+ {
+ free(*ufactors);
+ return GLU_OUT_OF_MEMORY;
+ }
+ ctrl=new_ctrl->geom_ctrl;
+ offset1=new_ctrl->geom_t_stride*vorder;
+ offset2=new_ctrl->geom_s_stride*uorder;
+ for(j=0;j<vfactor_cnt;j++)
+ {
+ *(*vfactors+j*3+1)=tmp_factor1=calc_parametric_factor(ctrl,vorder,
+ j*offset1,dim,tolerance,dim);
+ /* loop ufactor_cnt-1 times */
+ for(i=1;i<ufactor_cnt;i++)
+ {
+ tmp_factor2=calc_parametric_factor(ctrl,vorder,
+ j*offset1+i*offset2,dim,tolerance,dim);
+ if(tmp_factor2>tmp_factor1)
+ tmp_factor1=tmp_factor2;
+ }
+ /* last time for the opposite edge */
+ *(*vfactors+j*3+2)=tmp_factor2=calc_parametric_factor(ctrl,vorder,
+ j*offset1+i*offset2-new_ctrl->geom_s_stride,
+ dim,tolerance,dim);
+ if(tmp_factor2>tmp_factor1)
+ *(*vfactors+j*3)=tmp_factor2;
+ else
+ *(*vfactors+j*3)=tmp_factor1;
+ }
+ offset3=new_ctrl->geom_s_stride;
+ offset2=new_ctrl->geom_s_stride*uorder;
+ for(j=0;j<ufactor_cnt;j++)
+ {
+ *(*ufactors+j*3+1)=tmp_factor1=calc_parametric_factor(ctrl,uorder,
+ j*offset2,offset3,tolerance,dim);
+ /* loop vfactor_cnt-1 times */
+ for(i=1;i<vfactor_cnt;i++)
+ {
+ tmp_factor2=calc_parametric_factor(ctrl,uorder,
+ j*offset2+i*offset1,offset3,tolerance,dim);
+ if(tmp_factor2>tmp_factor1)
+ tmp_factor1=tmp_factor2;
+ }
+ /* last time for the opposite edge */
+ *(*ufactors+j*3+2)=tmp_factor2=calc_parametric_factor(ctrl,uorder,
+ j*offset2+i*offset1-new_ctrl->geom_t_stride,
+ offset3,tolerance,dim);
+ if(tmp_factor2>tmp_factor1)
+ *(*ufactors+j*3)=tmp_factor2;
+ else
+ *(*ufactors+j*3)=tmp_factor1;
+ }
+ return GL_NO_ERROR;
+}
+
+static GLenum
+calc_sampling_2D(GLfloat *ctrl, GLint cnt, GLint order,
+ GLfloat tolerance, GLint dim, GLint **factors)
+{
+ GLint factor_cnt;
+ GLint tmp_factor;
+ GLint offset;
+ GLint i;
+
+ factor_cnt=cnt/order;
+ if((*factors=(GLint *)malloc(sizeof(GLint)*factor_cnt))==NULL)
+ {
+ return GLU_OUT_OF_MEMORY;
+ }
+ offset=order*dim;
+ for(i=0;i<factor_cnt;i++)
+ {
+ tmp_factor=calc_factor(ctrl,order,i*offset,dim,tolerance,dim);
+ if(tmp_factor == 0)
+ (*factors)[i]=1;
+ else
+ (*factors)[i]=tmp_factor;
+ }
+ return GL_NO_ERROR;
+}
+
+static void
+set_sampling_and_culling( GLUnurbsObj *nobj )
+{
+ if(nobj->auto_load_matrix==GL_FALSE)
+ {
+ GLint i;
+ GLfloat m[4];
+
+ glPushAttrib( (GLbitfield) (GL_VIEWPORT_BIT | GL_TRANSFORM_BIT));
+ for(i=0;i<4;i++)
+ m[i]=nobj->sampling_matrices.viewport[i];
+ glViewport(m[0],m[1],m[2],m[3]);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(nobj->sampling_matrices.proj);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf(nobj->sampling_matrices.model);
+ }
+}
+
+static void
+revert_sampling_and_culling( GLUnurbsObj *nobj )
+{
+ if(nobj->auto_load_matrix==GL_FALSE)
+ {
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+ }
+}
+
+GLenum
+glu_do_sampling_3D( GLUnurbsObj *nobj, new_ctrl_type *new_ctrl,
+ GLint **sfactors, GLint **tfactors)
+{
+ GLint dim;
+ GLenum err;
+
+ *sfactors=NULL;
+ *tfactors=NULL;
+ dim=nobj->surface.geom.dim;
+ set_sampling_and_culling(nobj);
+ if((err=calc_sampling_3D(new_ctrl,nobj->sampling_tolerance,dim,
+ nobj->surface.geom.sorder,nobj->surface.geom.torder,
+ sfactors,tfactors))==GLU_ERROR)
+ {
+ revert_sampling_and_culling(nobj);
+ call_user_error(nobj,err);
+ return GLU_ERROR;
+ }
+ revert_sampling_and_culling(nobj);
+ return GLU_NO_ERROR;
+}
+
+GLenum
+glu_do_sampling_uv( GLUnurbsObj *nobj, new_ctrl_type *new_ctrl,
+ GLint **sfactors, GLint **tfactors)
+{
+ GLint s_cnt, t_cnt, i;
+ GLint u_steps, v_steps;
+
+ s_cnt = new_ctrl->s_bezier_cnt;
+ t_cnt = new_ctrl->t_bezier_cnt;
+ *sfactors=NULL;
+ *tfactors=NULL;
+ if((*sfactors=(GLint *)malloc(sizeof(GLint)*s_cnt*3))
+ ==NULL)
+ {
+ return GLU_OUT_OF_MEMORY;
+ }
+ if((*tfactors=(GLint *)malloc(sizeof(GLint)*t_cnt*3))
+ ==NULL)
+ {
+ free(*sfactors);
+ return GLU_OUT_OF_MEMORY;
+ }
+ u_steps = nobj->u_step;
+ v_steps = nobj->v_step;
+ for(i=0; i<s_cnt; i++)
+ {
+ *(*sfactors+i*3) = u_steps;
+ *(*sfactors+i*3+1) = u_steps;
+ *(*sfactors+i*3+2) = u_steps;
+ }
+ for(i=0; i<t_cnt; i++)
+ {
+ *(*tfactors+i*3) = v_steps;
+ *(*tfactors+i*3+1) = v_steps;
+ *(*tfactors+i*3+2) = v_steps;
+ }
+ return GLU_NO_ERROR;
+}
+
+GLenum
+glu_do_sampling_param_3D( GLUnurbsObj *nobj, new_ctrl_type *new_ctrl,
+ GLint **sfactors, GLint **tfactors)
+{
+ GLint dim;
+ GLenum err;
+
+ *sfactors=NULL;
+ *tfactors=NULL;
+ dim=nobj->surface.geom.dim;
+ set_sampling_and_culling(nobj);
+ if((err=calc_sampling_param_3D(new_ctrl,nobj->parametric_tolerance,dim,
+ nobj->surface.geom.sorder,nobj->surface.geom.torder,
+ sfactors,tfactors))==GLU_ERROR)
+ {
+ revert_sampling_and_culling(nobj);
+ call_user_error(nobj,err);
+ return GLU_ERROR;
+ }
+ revert_sampling_and_culling(nobj);
+ return GLU_NO_ERROR;
+}
+
+GLenum
+glu_do_sampling_2D( GLUnurbsObj *nobj, GLfloat *ctrl, GLint cnt, GLint order,
+ GLint dim, GLint **factors)
+{
+ GLenum err;
+
+ set_sampling_and_culling(nobj);
+ err=calc_sampling_2D(ctrl,cnt,order,nobj->sampling_tolerance,dim,
+ factors);
+ revert_sampling_and_culling(nobj);
+ return err;
+}
+
+
+GLenum
+glu_do_sampling_u( GLUnurbsObj *nobj, GLfloat *ctrl, GLint cnt, GLint order,
+ GLint dim, GLint **factors)
+{
+ GLint i;
+ GLint u_steps;
+
+ cnt /= order;
+ if((*factors=(GLint *)malloc(sizeof(GLint)*cnt))
+ ==NULL)
+ {
+ return GLU_OUT_OF_MEMORY;
+ }
+ u_steps = nobj->u_step;
+ for(i=0; i<cnt; i++)
+ (*factors)[i] = u_steps;
+ return GLU_NO_ERROR;
+}
+
+GLenum
+glu_do_sampling_param_2D( GLUnurbsObj *nobj, GLfloat *ctrl, GLint cnt,
+ GLint order, GLint dim, GLint **factors)
+{
+ GLint i;
+ GLint u_steps;
+ GLfloat tolerance;
+
+ set_sampling_and_culling(nobj);
+ tolerance = nobj->parametric_tolerance;
+ cnt /= order;
+ if((*factors=(GLint *)malloc(sizeof(GLint)*cnt))
+ ==NULL)
+ {
+ revert_sampling_and_culling(nobj);
+ return GLU_OUT_OF_MEMORY;
+ }
+ u_steps = nobj->u_step;
+ for(i=0; i<cnt; i++)
+ {
+ (*factors)[i] = calc_parametric_factor(ctrl,order,0,
+ dim,tolerance,dim);
+
+ }
+ revert_sampling_and_culling(nobj);
+ return GLU_NO_ERROR;
+}
+
+GLenum
+glu_do_sampling_crv( GLUnurbsObj *nobj, GLfloat *ctrl, GLint cnt, GLint order,
+ GLint dim, GLint **factors)
+{
+ GLenum err;
+
+ *factors=NULL;
+ switch(nobj->sampling_method)
+ {
+ case GLU_PATH_LENGTH:
+ if((err=glu_do_sampling_2D(nobj,ctrl,cnt,order,dim,factors))!=
+ GLU_NO_ERROR)
+ {
+ call_user_error(nobj,err);
+ return GLU_ERROR;
+ }
+ break;
+ case GLU_DOMAIN_DISTANCE:
+ if((err=glu_do_sampling_u(nobj,ctrl,cnt,order,dim,factors))!=
+ GLU_NO_ERROR)
+ {
+ call_user_error(nobj,err);
+ return GLU_ERROR;
+ }
+ break;
+ case GLU_PARAMETRIC_ERROR:
+ if((err=glu_do_sampling_param_2D(nobj,ctrl,cnt,order,dim,factors))!=
+ GLU_NO_ERROR)
+ {
+ call_user_error(nobj,err);
+ return GLU_ERROR;
+ }
+ break;
+ default:
+ abort();
+ }
+
+ return GLU_NO_ERROR;
+}
+
+/* TODO - i don't like this culling - this one just tests if at least one */
+/* ctrl point lies within the viewport . Also the point_in_viewport() */
+/* should be included in the fnctions for efficiency reasons */
+
+static GLboolean
+point_in_viewport(GLfloat *pt, GLint dim)
+{
+ GLdouble model[16],proj[16];
+ GLint viewport[4];
+ GLdouble x,y,z,w,winx,winy,winz;
+
+ glGetDoublev(GL_MODELVIEW_MATRIX,model);
+ glGetDoublev(GL_PROJECTION_MATRIX,proj);
+ glGetIntegerv(GL_VIEWPORT,viewport);
+ if(dim==3)
+ {
+ x=(GLdouble)pt[0];
+ y=(GLdouble)pt[1];
+ z=(GLdouble)pt[2];
+ gluProject(x,y,z,model,proj,viewport,&winx,&winy,&winz);
+ }
+ else
+ {
+ w=(GLdouble)pt[3];
+ x=(GLdouble)pt[0]/w;
+ y=(GLdouble)pt[1]/w;
+ z=(GLdouble)pt[2]/w;
+ gluProject(x,y,z,model,proj,viewport,&winx,&winy,&winz);
+ }
+ if((GLint)winx >= viewport[0] && (GLint)winx < viewport[2] &&
+ (GLint)winy >= viewport[1] && (GLint)winy < viewport[3])
+ return GL_TRUE;
+ return GL_FALSE;
+}
+
+GLboolean
+fine_culling_test_3D(GLUnurbsObj *nobj,GLfloat *pts,GLint s_cnt,GLint t_cnt,
+ GLint s_stride,GLint t_stride, GLint dim)
+{
+ GLint i,j;
+
+ if(nobj->culling==GL_FALSE)
+ return GL_FALSE;
+ set_sampling_and_culling(nobj);
+
+ if(dim==3)
+ {
+ for(i=0;i<s_cnt;i++)
+ for(j=0;j<t_cnt;j++)
+ if(point_in_viewport(pts+i*s_stride+j*t_stride,dim))
+ {
+ revert_sampling_and_culling(nobj);
+ return GL_FALSE;
+ }
+ }
+ else
+ {
+ for(i=0;i<s_cnt;i++)
+ for(j=0;j<t_cnt;j++)
+ if(point_in_viewport(pts+i*s_stride+j*t_stride,dim))
+ {
+ revert_sampling_and_culling(nobj);
+ return GL_FALSE;
+ }
+ }
+ revert_sampling_and_culling(nobj);
+ return GL_TRUE;
+}
+
+/*GLboolean
+fine_culling_test_3D(GLUnurbsObj *nobj,GLfloat *pts,GLint s_cnt,GLint t_cnt,
+ GLint s_stride,GLint t_stride, GLint dim)
+{
+ GLint visible_cnt;
+ GLfloat feedback_buffer[5];
+ GLsizei buffer_size;
+ GLint i,j;
+
+ if(nobj->culling==GL_FALSE)
+ return GL_FALSE;
+ buffer_size=5;
+ set_sampling_and_culling(nobj);
+
+ glFeedbackBuffer(buffer_size,GL_2D,feedback_buffer);
+ glRenderMode(GL_FEEDBACK);
+ if(dim==3)
+ {
+ for(i=0;i<s_cnt;i++)
+ {
+ glBegin(GL_LINE_LOOP);
+ for(j=0;j<t_cnt;j++)
+ glVertex3fv(pts+i*s_stride+j*t_stride);
+ glEnd();
+ }
+ for(j=0;j<t_cnt;j++)
+ {
+ glBegin(GL_LINE_LOOP);
+ for(i=0;i<s_cnt;i++)
+ glVertex3fv(pts+i*s_stride+j*t_stride);
+ glEnd();
+ }
+ }
+ else
+ {
+ for(i=0;i<s_cnt;i++)
+ {
+ glBegin(GL_LINE_LOOP);
+ for(j=0;j<t_cnt;j++)
+ glVertex4fv(pts+i*s_stride+j*t_stride);
+ glEnd();
+ }
+ for(j=0;j<t_cnt;j++)
+ {
+ glBegin(GL_LINE_LOOP);
+ for(i=0;i<s_cnt;i++)
+ glVertex4fv(pts+i*s_stride+j*t_stride);
+ glEnd();
+ }
+ }
+ visible_cnt=glRenderMode(GL_RENDER);
+
+ revert_sampling_and_culling(nobj);
+ return (GLboolean)(visible_cnt==0);
+}*/
+
+GLboolean
+fine_culling_test_2D(GLUnurbsObj *nobj,GLfloat *pts,GLint cnt,
+ GLint stride, GLint dim)
+{
+ GLint i;
+
+ if(nobj->culling==GL_FALSE)
+ return GL_FALSE;
+ set_sampling_and_culling(nobj);
+
+ if(dim==3)
+ {
+ for(i=0;i<cnt;i++)
+ if(point_in_viewport(pts+i*stride,dim))
+ {
+ revert_sampling_and_culling(nobj);
+ return GL_FALSE;
+ }
+ }
+ else
+ {
+ for(i=0;i<cnt;i++)
+ if(point_in_viewport(pts+i*stride,dim))
+ {
+ revert_sampling_and_culling(nobj);
+ return GL_FALSE;
+ }
+ }
+ revert_sampling_and_culling(nobj);
+ return GL_TRUE;
+}
+
+/*GLboolean
+fine_culling_test_2D(GLUnurbsObj *nobj,GLfloat *pts,GLint cnt,
+ GLint stride, GLint dim)
+{
+ GLint visible_cnt;
+ GLfloat feedback_buffer[5];
+ GLsizei buffer_size;
+ GLint i;
+
+ if(nobj->culling==GL_FALSE)
+ return GL_FALSE;
+ buffer_size=5;
+ set_sampling_and_culling(nobj);
+
+ glFeedbackBuffer(buffer_size,GL_2D,feedback_buffer);
+ glRenderMode(GL_FEEDBACK);
+ glBegin(GL_LINE_LOOP);
+ if(dim==3)
+ {
+ for(i=0;i<cnt;i++)
+ glVertex3fv(pts+i*stride);
+ }
+ else
+ {
+ for(i=0;i<cnt;i++)
+ glVertex4fv(pts+i*stride);
+ }
+ glEnd();
+ visible_cnt=glRenderMode(GL_RENDER);
+
+ revert_sampling_and_culling(nobj);
+ return (GLboolean)(visible_cnt==0);
+}*/
+
diff --git a/src/glu/mesa/polytest.c b/src/glu/mesa/polytest.c
new file mode 100644
index 00000000000..9b42c63477e
--- /dev/null
+++ b/src/glu/mesa/polytest.c
@@ -0,0 +1,1049 @@
+/* $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 ([email protected])
+ *
+ * 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;
+}
diff --git a/src/glu/mesa/project.c b/src/glu/mesa/project.c
new file mode 100644
index 00000000000..32142c959e9
--- /dev/null
+++ b/src/glu/mesa/project.c
@@ -0,0 +1,318 @@
+/* $Id: project.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ * Copyright (C) 1995-1999 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: project.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.7 1999/01/03 03:23:15 brianp
+ * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
+ *
+ * Revision 1.6 1998/07/08 01:43:43 brianp
+ * new version of invert_matrix() (also in src/matrix.c)
+ *
+ * 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/04/11 23:22:42 brianp
+ * added divide by zero checks to gluProject() and gluUnproject()
+ *
+ * Revision 1.2 1997/01/29 19:05:29 brianp
+ * faster invert_matrix() function from Stephane Rehel
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "gluP.h"
+#endif
+
+
+/*
+ * This code was contributed by Marc Buffat ([email protected]).
+ * Thanks Marc!!!
+ */
+
+
+
+/* implementation de gluProject et gluUnproject */
+/* M. Buffat 17/2/95 */
+
+
+
+/*
+ * Transform a point (column vector) by a 4x4 matrix. I.e. out = m * in
+ * Input: m - the 4x4 matrix
+ * in - the 4x1 vector
+ * Output: out - the resulting 4x1 vector.
+ */
+static void transform_point( GLdouble out[4], const GLdouble m[16],
+ const GLdouble in[4] )
+{
+#define M(row,col) m[col*4+row]
+ out[0] = M(0,0) * in[0] + M(0,1) * in[1] + M(0,2) * in[2] + M(0,3) * in[3];
+ out[1] = M(1,0) * in[0] + M(1,1) * in[1] + M(1,2) * in[2] + M(1,3) * in[3];
+ out[2] = M(2,0) * in[0] + M(2,1) * in[1] + M(2,2) * in[2] + M(2,3) * in[3];
+ out[3] = M(3,0) * in[0] + M(3,1) * in[1] + M(3,2) * in[2] + M(3,3) * in[3];
+#undef M
+}
+
+
+
+
+/*
+ * Perform a 4x4 matrix multiplication (product = a x b).
+ * Input: a, b - matrices to multiply
+ * Output: product - product of a and b
+ */
+static void matmul( GLdouble *product, const GLdouble *a, const GLdouble *b )
+{
+ /* This matmul was contributed by Thomas Malik */
+ GLdouble temp[16];
+ GLint i;
+
+#define A(row,col) a[(col<<2)+row]
+#define B(row,col) b[(col<<2)+row]
+#define T(row,col) temp[(col<<2)+row]
+
+ /* i-te Zeile */
+ for (i = 0; i < 4; i++)
+ {
+ T(i, 0) = A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i, 3) * B(3, 0);
+ T(i, 1) = A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i, 3) * B(3, 1);
+ T(i, 2) = A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i, 3) * B(3, 2);
+ T(i, 3) = A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i, 3) * B(3, 3);
+ }
+
+#undef A
+#undef B
+#undef T
+ MEMCPY( product, temp, 16*sizeof(GLdouble) );
+}
+
+
+static GLdouble Identity[16] = {
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0
+};
+
+
+
+/*
+ * Compute inverse of 4x4 transformation matrix.
+ * Code contributed by Jacques Leroy [email protected]
+ * Return GL_TRUE for success, GL_FALSE for failure (singular matrix)
+ */
+static GLboolean invert_matrix( const GLdouble *m, GLdouble *out )
+{
+/* NB. OpenGL Matrices are COLUMN major. */
+#define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; }
+#define MAT(m,r,c) (m)[(c)*4+(r)]
+
+ GLdouble wtmp[4][8];
+ GLdouble m0, m1, m2, m3, s;
+ GLdouble *r0, *r1, *r2, *r3;
+
+ r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
+
+ r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1),
+ r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3),
+ r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
+
+ r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1),
+ r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3),
+ r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
+
+ r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1),
+ r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3),
+ r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
+
+ r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1),
+ r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3),
+ r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
+
+ /* choose pivot - or die */
+ if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2);
+ if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1);
+ if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0);
+ if (0.0 == r0[0]) return GL_FALSE;
+
+ /* eliminate first variable */
+ m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
+ s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
+ s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
+ s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
+ s = r0[4];
+ if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
+ s = r0[5];
+ if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
+ s = r0[6];
+ if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
+ s = r0[7];
+ if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
+
+ /* choose pivot - or die */
+ if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2);
+ if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1);
+ if (0.0 == r1[1]) return GL_FALSE;
+
+ /* eliminate second variable */
+ m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
+ r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
+ r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
+ s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
+ s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
+ s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
+ s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
+
+ /* choose pivot - or die */
+ if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2);
+ if (0.0 == r2[2]) return GL_FALSE;
+
+ /* eliminate third variable */
+ m3 = r3[2]/r2[2];
+ r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
+ r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
+ r3[7] -= m3 * r2[7];
+
+ /* last check */
+ if (0.0 == r3[3]) return GL_FALSE;
+
+ s = 1.0/r3[3]; /* now back substitute row 3 */
+ r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
+
+ m2 = r2[3]; /* now back substitute row 2 */
+ s = 1.0/r2[2];
+ r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
+ r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
+ m1 = r1[3];
+ r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
+ r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
+ m0 = r0[3];
+ r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
+ r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
+
+ m1 = r1[2]; /* now back substitute row 1 */
+ s = 1.0/r1[1];
+ r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
+ r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
+ m0 = r0[2];
+ r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
+ r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
+
+ m0 = r0[1]; /* now back substitute row 0 */
+ s = 1.0/r0[0];
+ r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
+ r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
+
+ MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5],
+ MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7],
+ MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5],
+ MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7],
+ MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5],
+ MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7],
+ MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5],
+ MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7];
+
+ return GL_TRUE;
+
+#undef MAT
+#undef SWAP_ROWS
+}
+
+
+
+/* projection du point (objx,objy,obz) sur l'ecran (winx,winy,winz) */
+GLint GLAPIENTRY gluProject(GLdouble objx,GLdouble objy,GLdouble objz,
+ const GLdouble model[16],const GLdouble proj[16],
+ const GLint viewport[4],
+ GLdouble *winx,GLdouble *winy,GLdouble *winz)
+{
+ /* matrice de transformation */
+ GLdouble in[4],out[4];
+
+ /* initilise la matrice et le vecteur a transformer */
+ in[0]=objx; in[1]=objy; in[2]=objz; in[3]=1.0;
+ transform_point(out,model,in);
+ transform_point(in,proj,out);
+
+ /* d'ou le resultat normalise entre -1 et 1*/
+ if (in[3]==0.0)
+ return GL_FALSE;
+
+ in[0]/=in[3]; in[1]/=in[3]; in[2]/=in[3];
+
+ /* en coordonnees ecran */
+ *winx = viewport[0]+(1+in[0])*viewport[2]/2;
+ *winy = viewport[1]+(1+in[1])*viewport[3]/2;
+ /* entre 0 et 1 suivant z */
+ *winz = (1+in[2])/2;
+ return GL_TRUE;
+}
+
+
+
+/* transformation du point ecran (winx,winy,winz) en point objet */
+GLint GLAPIENTRY gluUnProject(GLdouble winx,GLdouble winy,GLdouble winz,
+ const GLdouble model[16],const GLdouble proj[16],
+ const GLint viewport[4],
+ GLdouble *objx,GLdouble *objy,GLdouble *objz)
+{
+ /* matrice de transformation */
+ GLdouble m[16], A[16];
+ GLdouble in[4],out[4];
+
+ /* transformation coordonnees normalisees entre -1 et 1 */
+ in[0]=(winx-viewport[0])*2/viewport[2] - 1.0;
+ in[1]=(winy-viewport[1])*2/viewport[3] - 1.0;
+ in[2]=2*winz - 1.0;
+ in[3]=1.0;
+
+ /* calcul transformation inverse */
+ matmul(A,proj,model);
+ invert_matrix(A,m);
+
+ /* d'ou les coordonnees objets */
+ transform_point(out,m,in);
+ if (out[3]==0.0)
+ return GL_FALSE;
+ *objx=out[0]/out[3];
+ *objy=out[1]/out[3];
+ *objz=out[2]/out[3];
+ return GL_TRUE;
+}
+
diff --git a/src/glu/mesa/quadric.c b/src/glu/mesa/quadric.c
new file mode 100644
index 00000000000..4698e795b15
--- /dev/null
+++ b/src/glu/mesa/quadric.c
@@ -0,0 +1,858 @@
+/* $Id: quadric.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ * Copyright (C) 1995-1999 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: quadric.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.19 1999/02/27 13:55:31 brianp
+ * fixed BeOS-related GLU typedef problems
+ *
+ * Revision 1.18 1999/01/03 03:23:15 brianp
+ * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
+ *
+ * Revision 1.17 1999/01/03 03:19:15 brianp
+ * rewrote some of gluCylinder
+ *
+ * Revision 1.16 1998/06/01 01:08:36 brianp
+ * small update for Next/OpenStep from Alexander Mai
+ *
+ * Revision 1.15 1998/03/15 18:28:54 brianp
+ * reimplemented gluDisk() point and line mode
+ *
+ * Revision 1.14 1998/03/15 18:14:17 brianp
+ * fixed a compiler cast warning
+ *
+ * Revision 1.13 1998/02/07 14:28:34 brianp
+ * another change to gluQuadricCallback(), this time for StormC compiler
+ *
+ * Revision 1.12 1998/02/05 00:43:19 brianp
+ * Yes, still another change to gluQuadricCallback()!
+ *
+ * Revision 1.11 1998/02/04 00:27:43 brianp
+ * yet another change to gluQuadricCallback()!
+ *
+ * Revision 1.10 1998/02/04 00:23:23 brianp
+ * fixed CALLBACK problem in gluQuadricCallback() (Stephane Rehel)
+ *
+ * Revision 1.9 1998/02/04 00:20:09 brianp
+ * added missing (int) in ErrorFunc cast
+ *
+ * Revision 1.8 1998/01/16 03:37:51 brianp
+ * fixed another assignment warning in gluQuadricCallback()
+ *
+ * Revision 1.7 1998/01/16 03:35:26 brianp
+ * fixed Windows compilation warnings (Theodore Jump)
+ *
+ * Revision 1.6 1997/10/29 02:02:20 brianp
+ * various MS Windows compiler changes (David Bucciarelli, v20 3dfx driver)
+ *
+ * Revision 1.5 1997/09/17 01:51:48 brianp
+ * changed glu*Callback() functions to match prototype in glu.h
+ *
+ * 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/03/12 02:15:38 brianp
+ * fixed problem in gluPartialDisk() reported by Kenneth H. Carpenter
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+/* TODO:
+ * texture coordinate support
+ * flip normals according to orientation
+ * there's still some inside/outside orientation bugs in possibly all
+ * but the sphere function
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "gluP.h"
+#endif
+
+
+
+#ifndef M_PI
+# define M_PI (3.1415926)
+#endif
+
+
+/*
+ * Convert degrees to radians:
+ */
+#define DEG_TO_RAD(A) ((A)*(M_PI/180.0))
+
+
+/*
+ * Sin and Cos for degree angles:
+ */
+#define SIND( A ) sin( (A)*(M_PI/180.0) )
+#define COSD( A) cos( (A)*(M_PI/180.0) )
+
+
+/*
+ * Texture coordinates if texture flag is set
+ */
+#define TXTR_COORD(x,y) if (qobj->TextureFlag) glTexCoord2f(x,y);
+
+
+
+struct GLUquadric {
+ GLenum DrawStyle; /* GLU_FILL, LINE, SILHOUETTE, or POINT */
+ GLenum Orientation; /* GLU_INSIDE or GLU_OUTSIDE */
+ GLboolean TextureFlag; /* Generate texture coords? */
+ GLenum Normals; /* GLU_NONE, GLU_FLAT, or GLU_SMOOTH */
+ void (GLCALLBACK *ErrorFunc)(GLenum err); /* Error handler callback function */
+};
+
+
+
+/*
+ * Process a GLU error.
+ */
+static void quadric_error( GLUquadricObj *qobj, GLenum error, const char *msg )
+{
+ /* Call the error call back function if any */
+ if (qobj->ErrorFunc) {
+ (*qobj->ErrorFunc)( error );
+ }
+ /* Print a message to stdout if MESA_DEBUG variable is defined */
+ if (getenv("MESA_DEBUG")) {
+ fprintf(stderr,"GLUError: %s: %s\n", (char*) gluErrorString(error), msg);
+ }
+}
+
+
+
+
+GLUquadricObj * GLAPIENTRY gluNewQuadric( void )
+{
+ GLUquadricObj *q;
+
+ q = (GLUquadricObj *) malloc( sizeof(struct GLUquadric) );
+ if (q) {
+ q->DrawStyle = GLU_FILL;
+ q->Orientation = GLU_OUTSIDE;
+ q->TextureFlag = GL_FALSE;
+ q->Normals = GLU_SMOOTH;
+ q->ErrorFunc = NULL;
+ }
+ return q;
+}
+
+
+
+void GLAPIENTRY gluDeleteQuadric( GLUquadricObj *state )
+{
+ if (state) {
+ free( (void *) state );
+ }
+}
+
+
+
+/*
+ * Set the drawing style to be GLU_FILL, GLU_LINE, GLU_SILHOUETTE,
+ * or GLU_POINT.
+ */
+void GLAPIENTRY gluQuadricDrawStyle( GLUquadricObj *quadObject, GLenum drawStyle )
+{
+ if (quadObject && (drawStyle==GLU_FILL || drawStyle==GLU_LINE
+ || drawStyle==GLU_SILHOUETTE || drawStyle==GLU_POINT)) {
+ quadObject->DrawStyle = drawStyle;
+ }
+ else {
+ quadric_error( quadObject, GLU_INVALID_ENUM, "qluQuadricDrawStyle" );
+ }
+}
+
+
+
+/*
+ * Set the orientation to GLU_INSIDE or GLU_OUTSIDE.
+ */
+void GLAPIENTRY gluQuadricOrientation( GLUquadricObj *quadObject,
+ GLenum orientation )
+{
+ if (quadObject && (orientation==GLU_INSIDE || orientation==GLU_OUTSIDE)) {
+ quadObject->Orientation = orientation;
+ }
+ else {
+ quadric_error( quadObject, GLU_INVALID_ENUM, "qluQuadricOrientation" );
+ }
+}
+
+
+
+/*
+ * Set the error handler callback function.
+ */
+void GLAPIENTRY gluQuadricCallback( GLUquadricObj *qobj,
+ GLenum which, void (GLCALLBACK *fn)() )
+{
+ /*
+ * UGH, this is a mess! I thought ANSI was a standard.
+ */
+ if (qobj && which==GLU_ERROR) {
+#ifdef __CYGWIN32__
+ qobj->ErrorFunc = (void(*)(int))fn;
+#elif defined(OPENSTEP)
+ qobj->ErrorFunc = (void(*)(GLenum))fn;
+#elif defined(_WIN32)
+ qobj->ErrorFunc = (void(GLCALLBACK*)(int))fn;
+#elif defined(__STORM__)
+ qobj->ErrorFunc = (void(GLCALLBACK*)(GLenum))fn;
+#elif defined(__BEOS__)
+ qobj->ErrorFunc = (void(*)(GLenum))fn;
+#else
+ qobj->ErrorFunc = (void(GLCALLBACK*)())fn;
+#endif
+ }
+}
+
+
+void GLAPIENTRY gluQuadricNormals( GLUquadricObj *quadObject, GLenum normals )
+{
+ if (quadObject
+ && (normals==GLU_NONE || normals==GLU_FLAT || normals==GLU_SMOOTH)) {
+ quadObject->Normals = normals;
+ }
+}
+
+
+void GLAPIENTRY gluQuadricTexture( GLUquadricObj *quadObject,
+ GLboolean textureCoords )
+{
+ if (quadObject) {
+ quadObject->TextureFlag = textureCoords;
+ }
+}
+
+
+
+
+/*
+ * Call glNormal3f after scaling normal to unit length.
+ */
+static void normal3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ GLdouble mag;
+
+ mag = sqrt( x*x + y*y + z*z );
+ if (mag>0.00001F) {
+ x /= mag;
+ y /= mag;
+ z /= mag;
+ }
+ glNormal3f( x, y, z );
+}
+
+
+
+void GLAPIENTRY gluCylinder( GLUquadricObj *qobj,
+ GLdouble baseRadius, GLdouble topRadius,
+ GLdouble height, GLint slices, GLint stacks )
+{
+ GLdouble da, r, dr, dz;
+ GLfloat x, y, z, nz, nsign;
+ GLint i, j;
+
+ if (qobj->Orientation==GLU_INSIDE) {
+ nsign = -1.0;
+ }
+ else {
+ nsign = 1.0;
+ }
+
+ da = 2.0*M_PI / slices;
+ dr = (topRadius-baseRadius) / stacks;
+ dz = height / stacks;
+ nz = (baseRadius-topRadius) / height; /* Z component of normal vectors */
+
+ if (qobj->DrawStyle==GLU_POINT) {
+ glBegin( GL_POINTS );
+ for (i=0;i<slices;i++) {
+ x = cos(i*da);
+ y = sin(i*da);
+ normal3f( x*nsign, y*nsign, nz*nsign );
+
+ z = 0.0;
+ r = baseRadius;
+ for (j=0;j<=stacks;j++) {
+ glVertex3f( x*r, y*r, z );
+ z += dz;
+ r += dr;
+ }
+ }
+ glEnd();
+ }
+ else if (qobj->DrawStyle==GLU_LINE || qobj->DrawStyle==GLU_SILHOUETTE) {
+ /* Draw rings */
+ if (qobj->DrawStyle==GLU_LINE) {
+ z = 0.0;
+ r = baseRadius;
+ for (j=0;j<=stacks;j++) {
+ glBegin( GL_LINE_LOOP );
+ for (i=0;i<slices;i++) {
+ x = cos(i*da);
+ y = sin(i*da);
+ normal3f( x*nsign, y*nsign, nz*nsign );
+ glVertex3f( x*r, y*r, z );
+ }
+ glEnd();
+ z += dz;
+ r += dr;
+ }
+ }
+ else {
+ /* draw one ring at each end */
+ if (baseRadius!=0.0) {
+ glBegin( GL_LINE_LOOP );
+ for (i=0;i<slices;i++) {
+ x = cos(i*da);
+ y = sin(i*da);
+ normal3f( x*nsign, y*nsign, nz*nsign );
+ glVertex3f( x*baseRadius, y*baseRadius, 0.0 );
+ }
+ glEnd();
+ glBegin( GL_LINE_LOOP );
+ for (i=0;i<slices;i++) {
+ x = cos(i*da);
+ y = sin(i*da);
+ normal3f( x*nsign, y*nsign, nz*nsign );
+ glVertex3f( x*topRadius, y*topRadius, height );
+ }
+ glEnd();
+ }
+ }
+ /* draw length lines */
+ glBegin( GL_LINES );
+ for (i=0;i<slices;i++) {
+ x = cos(i*da);
+ y = sin(i*da);
+ normal3f( x*nsign, y*nsign, nz*nsign );
+ glVertex3f( x*baseRadius, y*baseRadius, 0.0 );
+ glVertex3f( x*topRadius, y*topRadius, height );
+ }
+ glEnd();
+ }
+ else if (qobj->DrawStyle==GLU_FILL) {
+ GLfloat ds = 1.0 / slices;
+ GLfloat dt = 1.0 / stacks;
+ GLfloat t = 0.0;
+ z = 0.0;
+ r = baseRadius;
+ for (j=0;j<stacks;j++) {
+ GLfloat s = 0.0;
+ glBegin( GL_QUAD_STRIP );
+ for (i=0;i<=slices;i++) {
+ GLfloat x, y;
+ if (i == slices) {
+ x = sin(0);
+ y = cos(0);
+ }
+ else {
+ x = sin(i * da);
+ y = cos(i * da);
+ }
+ if (nsign==1.0) {
+ normal3f( x*nsign, y*nsign, nz*nsign );
+ TXTR_COORD(s, t);
+ glVertex3f( x * r, y * r, z );
+ normal3f( x*nsign, y*nsign, nz*nsign );
+ TXTR_COORD(s, t + dt);
+ glVertex3f( x * (r + dr), y * (r + dr), z + dz);
+ }
+ else {
+ normal3f( x*nsign, y*nsign, nz*nsign );
+ TXTR_COORD(s, t);
+ glVertex3f( x * r, y * r, z );
+ normal3f( x*nsign, y*nsign, nz*nsign );
+ TXTR_COORD(s, t + dt);
+ glVertex3f( x * (r + dr), y * (r + dr), z + dz);
+ }
+ s += ds;
+ } /* for slices */
+ glEnd();
+ r += dr;
+ t += dt;
+ z += dz;
+ } /* for stacks */
+ }
+}
+
+
+
+
+
+void GLAPIENTRY gluSphere( GLUquadricObj *qobj,
+ GLdouble radius, GLint slices, GLint stacks )
+{
+ GLfloat rho, drho, theta, dtheta;
+ GLfloat x, y, z;
+ GLfloat s, t, ds, dt;
+ GLint i, j, imin, imax;
+ GLboolean normals;
+ GLfloat nsign;
+
+ if (qobj->Normals==GLU_NONE) {
+ normals = GL_FALSE;
+ }
+ else {
+ normals = GL_TRUE;
+ }
+ if (qobj->Orientation==GLU_INSIDE) {
+ nsign = -1.0;
+ }
+ else {
+ nsign = 1.0;
+ }
+
+ drho = M_PI / (GLfloat) stacks;
+ dtheta = 2.0 * M_PI / (GLfloat) slices;
+
+ /* texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis */
+ /* t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) */
+ /* cannot use triangle fan on texturing (s coord. at top/bottom tip varies) */
+
+ if (qobj->DrawStyle==GLU_FILL) {
+ if (!qobj->TextureFlag) {
+ /* draw +Z end as a triangle fan */
+ glBegin( GL_TRIANGLE_FAN );
+ glNormal3f( 0.0, 0.0, 1.0 );
+ TXTR_COORD(0.5,1.0);
+ glVertex3f( 0.0, 0.0, nsign * radius );
+ for (j=0;j<=slices;j++) {
+ theta = (j==slices) ? 0.0 : j * dtheta;
+ x = -sin(theta) * sin(drho);
+ y = cos(theta) * sin(drho);
+ z = nsign * cos(drho);
+ if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
+ glVertex3f( x*radius, y*radius, z*radius );
+ }
+ glEnd();
+ }
+
+ ds = 1.0 / slices;
+ dt = 1.0 / stacks;
+ t = 1.0; /* because loop now runs from 0 */
+ if (qobj->TextureFlag) {
+ imin = 0;
+ imax = stacks;
+ }
+ else {
+ imin = 1;
+ imax = stacks-1;
+ }
+
+ /* draw intermediate stacks as quad strips */
+ for (i=imin;i<imax;i++) {
+ rho = i * drho;
+ glBegin( GL_QUAD_STRIP );
+ s = 0.0;
+ for (j=0;j<=slices;j++) {
+ theta = (j==slices) ? 0.0 : j * dtheta;
+ x = -sin(theta) * sin(rho);
+ y = cos(theta) * sin(rho);
+ z = nsign * cos(rho);
+ if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
+ TXTR_COORD(s,t);
+ glVertex3f( x*radius, y*radius, z*radius );
+ x = -sin(theta) * sin(rho+drho);
+ y = cos(theta) * sin(rho+drho);
+ z = nsign * cos(rho+drho);
+ if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
+ TXTR_COORD(s,t-dt);
+ s += ds;
+ glVertex3f( x*radius, y*radius, z*radius );
+ }
+ glEnd();
+ t -= dt;
+ }
+
+ if (!qobj->TextureFlag) {
+ /* draw -Z end as a triangle fan */
+ glBegin( GL_TRIANGLE_FAN );
+ glNormal3f( 0.0, 0.0, -1.0 );
+ TXTR_COORD(0.5,0.0);
+ glVertex3f( 0.0, 0.0, -radius*nsign );
+ rho = M_PI - drho;
+ s = 1.0;
+ t = dt;
+ for (j=slices;j>=0;j--) {
+ theta = (j==slices) ? 0.0 : j * dtheta;
+ x = -sin(theta) * sin(rho);
+ y = cos(theta) * sin(rho);
+ z = nsign * cos(rho);
+ if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
+ TXTR_COORD(s,t);
+ s -= ds;
+ glVertex3f( x*radius, y*radius, z*radius );
+ }
+ glEnd();
+ }
+ }
+ else if (qobj->DrawStyle==GLU_LINE || qobj->DrawStyle==GLU_SILHOUETTE) {
+ /* draw stack lines */
+ for (i=1;i<stacks;i++) { /* stack line at i==stacks-1 was missing here */
+ rho = i * drho;
+ glBegin( GL_LINE_LOOP );
+ for (j=0;j<slices;j++) {
+ theta = j * dtheta;
+ x = cos(theta) * sin(rho);
+ y = sin(theta) * sin(rho);
+ z = cos(rho);
+ if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
+ glVertex3f( x*radius, y*radius, z*radius );
+ }
+ glEnd();
+ }
+ /* draw slice lines */
+ for (j=0;j<slices;j++) {
+ theta = j * dtheta;
+ glBegin( GL_LINE_STRIP );
+ for (i=0;i<=stacks;i++) {
+ rho = i * drho;
+ x = cos(theta) * sin(rho);
+ y = sin(theta) * sin(rho);
+ z = cos(rho);
+ if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
+ glVertex3f( x*radius, y*radius, z*radius );
+ }
+ glEnd();
+ }
+ }
+ else if (qobj->DrawStyle==GLU_POINT) {
+ /* top and bottom-most points */
+ glBegin( GL_POINTS );
+ if (normals) glNormal3f( 0.0, 0.0, nsign );
+ glVertex3d( 0.0, 0.0, radius );
+ if (normals) glNormal3f( 0.0, 0.0, -nsign );
+ glVertex3d( 0.0, 0.0, -radius );
+
+ /* loop over stacks */
+ for (i=1;i<stacks-1;i++) {
+ rho = i * drho;
+ for (j=0;j<slices;j++) {
+ theta = j * dtheta;
+ x = cos(theta) * sin(rho);
+ y = sin(theta) * sin(rho);
+ z = cos(rho);
+ if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
+ glVertex3f( x*radius, y*radius, z*radius );
+ }
+ }
+ glEnd();
+ }
+
+}
+
+
+
+void GLAPIENTRY gluDisk( GLUquadricObj *qobj,
+ GLdouble innerRadius, GLdouble outerRadius,
+ GLint slices, GLint loops )
+{
+ GLfloat da, dr;
+#if 0
+ GLdouble a, da;
+ GLfloat r, dr;
+ GLfloat x, y;
+ GLfloat r1, r2, dtc;
+ GLint s, l;
+#endif
+
+ /* Normal vectors */
+ if (qobj->Normals!=GLU_NONE) {
+ if (qobj->Orientation==GLU_OUTSIDE) {
+ glNormal3f( 0.0, 0.0, +1.0 );
+ }
+ else {
+ glNormal3f( 0.0, 0.0, -1.0 );
+ }
+ }
+
+ da = 2.0*M_PI / slices;
+ dr = (outerRadius-innerRadius) / (GLfloat) loops;
+
+ switch (qobj->DrawStyle) {
+ case GLU_FILL:
+ {
+ /* texture of a gluDisk is a cut out of the texture unit square
+ * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1]
+ * (linear mapping)
+ */
+ GLfloat dtc = 2.0f * outerRadius;
+ GLfloat sa,ca;
+ GLfloat r1 = innerRadius;
+ GLint l;
+ for (l=0; l<loops; l++) {
+ GLfloat r2 = r1 + dr;
+ if (qobj->Orientation==GLU_OUTSIDE) {
+ GLint s;
+ glBegin( GL_QUAD_STRIP );
+ for (s=0;s<=slices;s++) {
+ GLfloat a;
+ if (s==slices) a = 0.0;
+ else a = s * da;
+ sa = sin(a); ca = cos(a);
+ TXTR_COORD(0.5+sa*r2/dtc,0.5+ca*r2/dtc);
+ glVertex2f( r2*sa, r2*ca );
+ TXTR_COORD(0.5+sa*r1/dtc,0.5+ca*r1/dtc);
+ glVertex2f( r1*sa, r1*ca );
+ }
+ glEnd();
+ }
+ else {
+ GLint s;
+ glBegin( GL_QUAD_STRIP );
+ for (s=slices;s>=0;s--) {
+ GLfloat a;
+ if (s==slices) a = 0.0;
+ else a = s * da;
+ sa = sin(a); ca = cos(a);
+ TXTR_COORD(0.5-sa*r2/dtc,0.5+ca*r2/dtc);
+ glVertex2f( r2*sa, r2*ca );
+ TXTR_COORD(0.5-sa*r1/dtc,0.5+ca*r1/dtc);
+ glVertex2f( r1*sa, r1*ca );
+ }
+ glEnd();
+ }
+ r1 = r2;
+ }
+ break;
+ }
+ case GLU_LINE:
+ {
+ GLint l, s;
+ /* draw loops */
+ for (l=0; l<=loops; l++) {
+ GLfloat r = innerRadius + l * dr;
+ glBegin( GL_LINE_LOOP );
+ for (s=0; s<slices; s++) {
+ GLfloat a = s * da;
+ glVertex2f( r*sin(a), r*cos(a) );
+ }
+ glEnd();
+ }
+ /* draw spokes */
+ for (s=0; s<slices; s++) {
+ GLfloat a = s * da;
+ GLfloat x = sin(a);
+ GLfloat y = cos(a);
+ glBegin( GL_LINE_STRIP );
+ for (l=0; l<=loops; l++) {
+ GLfloat r = innerRadius + l * dr;
+ glVertex2f( r*x, r*y );
+ }
+ glEnd();
+ }
+ break;
+ }
+ case GLU_POINT:
+ {
+ GLint s;
+ glBegin( GL_POINTS );
+ for (s=0; s<slices; s++) {
+ GLfloat a = s * da;
+ GLfloat x = sin(a);
+ GLfloat y = cos(a);
+ GLint l;
+ for (l=0; l<=loops; l++) {
+ GLfloat r = innerRadius * l * dr;
+ glVertex2f( r*x, r*y );
+ }
+ }
+ glEnd();
+ break;
+ }
+ case GLU_SILHOUETTE:
+ {
+ if (innerRadius!=0.0) {
+ GLfloat a;
+ glBegin( GL_LINE_LOOP );
+ for (a=0.0; a<2.0*M_PI; a+=da) {
+ GLfloat x = innerRadius * sin(a);
+ GLfloat y = innerRadius * cos(a);
+ glVertex2f( x, y );
+ }
+ glEnd();
+ }
+ {
+ GLfloat a;
+ glBegin( GL_LINE_LOOP );
+ for (a=0; a<2.0*M_PI; a+=da) {
+ GLfloat x = outerRadius * sin(a);
+ GLfloat y = outerRadius * cos(a);
+ glVertex2f( x, y );
+ }
+ glEnd();
+ }
+ break;
+ }
+ default:
+ abort();
+ }
+}
+
+
+
+void GLAPIENTRY gluPartialDisk( GLUquadricObj *qobj, GLdouble innerRadius,
+ GLdouble outerRadius, GLint slices, GLint loops,
+ GLdouble startAngle, GLdouble sweepAngle )
+{
+ if (qobj->Normals!=GLU_NONE) {
+ if (qobj->Orientation==GLU_OUTSIDE) {
+ glNormal3f( 0.0, 0.0, +1.0 );
+ }
+ else {
+ glNormal3f( 0.0, 0.0, -1.0 );
+ }
+ }
+
+ if (qobj->DrawStyle==GLU_POINT) {
+ GLint loop, slice;
+ GLdouble radius, delta_radius;
+ GLdouble angle, delta_angle;
+ delta_radius = (outerRadius - innerRadius) / (loops-1);
+ delta_angle = DEG_TO_RAD((sweepAngle) / (slices-1));
+ glBegin( GL_POINTS );
+ radius = innerRadius;
+ for (loop=0; loop<loops; loop++) {
+ angle = DEG_TO_RAD(startAngle);
+ for (slice=0; slice<slices; slice++) {
+ glVertex2d( radius * sin(angle), radius * cos(angle) );
+ angle += delta_angle;
+ }
+ radius += delta_radius;
+ }
+ glEnd();
+ }
+ else if (qobj->DrawStyle==GLU_LINE) {
+ GLint loop, slice;
+ GLdouble radius, delta_radius;
+ GLdouble angle, delta_angle;
+ delta_radius = (outerRadius - innerRadius) / loops;
+ delta_angle = DEG_TO_RAD(sweepAngle / slices);
+ /* draw rings */
+ radius = innerRadius;
+ for (loop=0; loop<loops; loop++) {
+ angle = DEG_TO_RAD(startAngle);
+ glBegin( GL_LINE_STRIP );
+ for (slice=0; slice<slices; slice++) {
+ glVertex2d( radius * sin(angle), radius * cos(angle) );
+ angle += delta_angle;
+ }
+ glEnd();
+ radius += delta_radius;
+ }
+ /* draw spokes */
+ angle = DEG_TO_RAD(startAngle);
+ for (slice=0; slice<slices; slice++) {
+ radius = innerRadius;
+ glBegin( GL_LINE_STRIP );
+ for (loop=0; loop<loops; loop++) {
+ glVertex2d( radius * sin(angle), radius * cos(angle) );
+ radius += delta_radius;
+ }
+ glEnd();
+ angle += delta_angle;
+ }
+ }
+ else if (qobj->DrawStyle==GLU_SILHOUETTE) {
+ GLint slice;
+ GLdouble angle, delta_angle;
+ delta_angle = DEG_TO_RAD(sweepAngle / slices);
+ /* draw outer ring */
+ glBegin( GL_LINE_STRIP );
+ angle = DEG_TO_RAD(startAngle);
+ for (slice=0; slice<=slices; slice++) {
+ glVertex2d( outerRadius * sin(angle), outerRadius * cos(angle) );
+ angle += delta_angle;
+ }
+ glEnd();
+ /* draw inner ring */
+ if (innerRadius>0.0) {
+ glBegin( GL_LINE_STRIP );
+ angle = DEG_TO_RAD(startAngle);
+ for (slice=0; slice<slices; slice++) {
+ glVertex2d( innerRadius * sin(angle), innerRadius * cos(angle) );
+ angle += delta_angle;
+ }
+ glEnd();
+ }
+ /* draw spokes */
+ if (sweepAngle<360.0) {
+ GLdouble stopAngle = startAngle + sweepAngle;
+ glBegin( GL_LINES );
+ glVertex2d( innerRadius*SIND(startAngle), innerRadius*COSD(startAngle) );
+ glVertex2d( outerRadius*SIND(startAngle), outerRadius*COSD(startAngle) );
+ glVertex2d( innerRadius*SIND(stopAngle), innerRadius*COSD(stopAngle) );
+ glVertex2d( outerRadius*SIND(stopAngle), outerRadius*COSD(stopAngle) );
+ glEnd();
+ }
+ }
+ else if (qobj->DrawStyle==GLU_FILL) {
+ GLint loop, slice;
+ GLdouble radius, delta_radius;
+ GLdouble angle, delta_angle;
+ delta_radius = (outerRadius - innerRadius) / loops;
+ delta_angle = DEG_TO_RAD(sweepAngle / slices);
+ radius = innerRadius;
+ for (loop=0; loop<loops; loop++) {
+ glBegin( GL_QUAD_STRIP );
+ angle = DEG_TO_RAD(startAngle);
+ for (slice=0; slice<slices; slice++) {
+ if (qobj->Orientation==GLU_OUTSIDE) {
+ glVertex2d( (radius+delta_radius)*sin(angle),
+ (radius+delta_radius)*cos(angle) );
+ glVertex2d( radius * sin(angle), radius * cos(angle) );
+ }
+ else {
+ glVertex2d( radius * sin(angle), radius * cos(angle) );
+ glVertex2d( (radius+delta_radius)*sin(angle),
+ (radius+delta_radius)*cos(angle) );
+ }
+ angle += delta_angle;
+ }
+ glEnd();
+ radius += delta_radius;
+ }
+ }
+}
+
+
+
diff --git a/src/glu/mesa/tess.c b/src/glu/mesa/tess.c
new file mode 100644
index 00000000000..c773fbaae4b
--- /dev/null
+++ b/src/glu/mesa/tess.c
@@ -0,0 +1,369 @@
+/* $Id: tess.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ * Copyright (C) 1995-1999 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * $Log: tess.c,v $
+ * Revision 1.1 1999/08/19 00:55:42 jtg
+ * Initial revision
+ *
+ * Revision 1.11 1999/02/27 13:55:31 brianp
+ * fixed BeOS-related GLU typedef problems
+ *
+ * Revision 1.10 1999/01/03 03:23:15 brianp
+ * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
+ *
+ * Revision 1.9 1998/06/01 01:10:29 brianp
+ * small update for Next/OpenStep from Alexander Mai
+ *
+ * Revision 1.8 1998/02/04 00:27:58 brianp
+ * cygnus changes from Stephane Rehel
+ *
+ * Revision 1.7 1998/01/16 03:35:26 brianp
+ * fixed Windows compilation warnings (Theodore Jump)
+ *
+ * Revision 1.6 1997/09/17 01:51:48 brianp
+ * changed glu*Callback() functions to match prototype in glu.h
+ *
+ * Revision 1.5 1997/07/24 01:28:44 brianp
+ * changed precompiled header symbol from PCH to PC_HEADER
+ *
+ * Revision 1.4 1997/05/28 02:29:38 brianp
+ * added support for precompiled headers (PCH), inserted APIENTRY keyword
+ *
+ * Revision 1.3 1996/11/12 01:23:02 brianp
+ * added test to prevent free(vertex) when vertex==NULL in delete_contours()
+ *
+ * Revision 1.2 1996/10/22 22:57:19 brianp
+ * better error handling in gluBegin/EndPolygon() from Erich Eder
+ *
+ * Revision 1.1 1996/09/27 01:19:39 brianp
+ * Initial revision
+ *
+ */
+
+
+/*
+ * This file is part of the polygon tesselation code contributed by
+ * Bogdan Sikorski
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <math.h>
+#include <stdlib.h>
+#include "tess.h"
+#endif
+
+
+/*
+ * This is ugly, but seems the easiest way to do things to make the
+ * code work under YellowBox for Windows
+ */
+#if defined(OPENSTEP) && defined(GLCALLBACK)
+#undef GLCALLBACK
+#define GLCALLBACK
+#endif
+
+
+extern void tess_test_polygon(GLUtriangulatorObj *);
+extern void tess_find_contour_hierarchies(GLUtriangulatorObj *);
+extern void tess_handle_holes(GLUtriangulatorObj *);
+extern void tess_tesselate(GLUtriangulatorObj *);
+extern void tess_tesselate_with_edge_flag(GLUtriangulatorObj *);
+static void delete_contours(GLUtriangulatorObj *);
+
+#ifdef __CYGWIN32__
+#define _CALLBACK
+#else
+#define _CALLBACK GLCALLBACK
+#endif
+
+void init_callbacks(tess_callbacks *callbacks)
+{
+ callbacks->begin = ( void (_CALLBACK*)(GLenum) ) 0;
+ callbacks->edgeFlag = ( void (_CALLBACK*)(GLboolean) ) 0;
+ callbacks->vertex = ( void (_CALLBACK*)(void*) ) 0;
+ callbacks->end = ( void (_CALLBACK*)(void) ) 0;
+ callbacks->error = ( void (_CALLBACK*)(GLenum) ) 0;
+}
+
+void tess_call_user_error(GLUtriangulatorObj *tobj, GLenum gluerr)
+{
+ if(tobj->error==GLU_NO_ERROR)
+ tobj->error=gluerr;
+ if(tobj->callbacks.error!=NULL)
+ (tobj->callbacks.error)(gluerr);
+}
+
+GLUtriangulatorObj* GLAPIENTRY gluNewTess( void )
+{
+ GLUtriangulatorObj *tobj;
+ tobj = (GLUtriangulatorObj *) malloc(sizeof(struct GLUtesselator));
+ if (!tobj)
+ return NULL;
+ tobj->contours=tobj->last_contour=NULL;
+ init_callbacks(&tobj->callbacks);
+ tobj->error=GLU_NO_ERROR;
+ tobj->current_polygon=NULL;
+ tobj->contour_cnt=0;
+ return tobj;
+}
+
+
+void GLAPIENTRY gluTessCallback( GLUtriangulatorObj *tobj, GLenum which,
+ void (GLCALLBACK *fn)() )
+{
+ switch(which)
+ {
+ case GLU_BEGIN:
+ tobj->callbacks.begin = (void (_CALLBACK*)(GLenum)) fn;
+ break;
+ case GLU_EDGE_FLAG:
+ tobj->callbacks.edgeFlag = (void (_CALLBACK*)(GLboolean)) fn;
+ break;
+ case GLU_VERTEX:
+ tobj->callbacks.vertex = (void (_CALLBACK*)(void *)) fn;
+ break;
+ case GLU_END:
+ tobj->callbacks.end = (void (_CALLBACK*)(void)) fn;
+ break;
+ case GLU_ERROR:
+ tobj->callbacks.error = (void (_CALLBACK*)(GLenum)) fn;
+ break;
+ default:
+ tobj->error=GLU_INVALID_ENUM;
+ break;
+ }
+}
+
+
+
+void GLAPIENTRY gluDeleteTess( GLUtriangulatorObj *tobj )
+{
+ if(tobj->error==GLU_NO_ERROR && tobj->contour_cnt)
+ /* was gluEndPolygon called? */
+ tess_call_user_error(tobj,GLU_TESS_ERROR1);
+ /* delete all internal structures */
+ delete_contours(tobj);
+ free(tobj);
+}
+
+
+void GLAPIENTRY gluBeginPolygon( GLUtriangulatorObj *tobj )
+{
+/*
+ if(tobj->error!=GLU_NO_ERROR)
+ return;
+*/
+ tobj->error = GLU_NO_ERROR;
+ if(tobj->current_polygon!=NULL)
+ {
+ /* gluEndPolygon was not called */
+ tess_call_user_error(tobj,GLU_TESS_ERROR1);
+ /* delete all internal structures */
+ delete_contours(tobj);
+ }
+ else
+ {
+ if((tobj->current_polygon=
+ (tess_polygon *)malloc(sizeof(tess_polygon)))==NULL)
+ {
+ tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ tobj->current_polygon->vertex_cnt=0;
+ tobj->current_polygon->vertices=
+ tobj->current_polygon->last_vertex=NULL;
+ }
+}
+
+
+void GLAPIENTRY gluEndPolygon( GLUtriangulatorObj *tobj )
+{
+ /*tess_contour *contour_ptr;*/
+
+ /* there was an error */
+ if(tobj->error!=GLU_NO_ERROR) goto end;
+
+ /* check if gluBeginPolygon was called */
+ if(tobj->current_polygon==NULL)
+ {
+ tess_call_user_error(tobj,GLU_TESS_ERROR2);
+ return;
+ }
+ tess_test_polygon(tobj);
+ /* there was an error */
+ if(tobj->error!=GLU_NO_ERROR) goto end;
+
+ /* any real contours? */
+ if(tobj->contour_cnt==0)
+ {
+ /* delete all internal structures */
+ delete_contours(tobj);
+ return;
+ }
+ tess_find_contour_hierarchies(tobj);
+ /* there was an error */
+ if(tobj->error!=GLU_NO_ERROR) goto end;
+
+ tess_handle_holes(tobj);
+ /* there was an error */
+ if(tobj->error!=GLU_NO_ERROR) goto end;
+
+ /* if no callbacks, nothing to do */
+ if(tobj->callbacks.begin!=NULL && tobj->callbacks.vertex!=NULL &&
+ tobj->callbacks.end!=NULL)
+ {
+ if(tobj->callbacks.edgeFlag==NULL)
+ tess_tesselate(tobj);
+ else
+ tess_tesselate_with_edge_flag(tobj);
+ }
+
+end:
+ /* delete all internal structures */
+ delete_contours(tobj);
+}
+
+
+void GLAPIENTRY gluNextContour( GLUtriangulatorObj *tobj, GLenum type )
+{
+ if(tobj->error!=GLU_NO_ERROR)
+ return;
+ if(tobj->current_polygon==NULL)
+ {
+ tess_call_user_error(tobj,GLU_TESS_ERROR2);
+ return;
+ }
+ /* first contour? */
+ if(tobj->current_polygon->vertex_cnt)
+ tess_test_polygon(tobj);
+}
+
+
+void GLAPIENTRY gluTessVertex( GLUtriangulatorObj *tobj, GLdouble v[3], void *data )
+{
+ tess_polygon *polygon=tobj->current_polygon;
+ tess_vertex *last_vertex_ptr;
+
+ if(tobj->error!=GLU_NO_ERROR)
+ return;
+ if(polygon==NULL)
+ {
+ tess_call_user_error(tobj,GLU_TESS_ERROR2);
+ return;
+ }
+ last_vertex_ptr=polygon->last_vertex;
+ if(last_vertex_ptr==NULL)
+ {
+ if((last_vertex_ptr=(tess_vertex *)
+ malloc(sizeof(tess_vertex)))==NULL)
+ {
+ tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ polygon->vertices=last_vertex_ptr;
+ polygon->last_vertex=last_vertex_ptr;
+ last_vertex_ptr->data=data;
+ last_vertex_ptr->location[0]=v[0];
+ last_vertex_ptr->location[1]=v[1];
+ last_vertex_ptr->location[2]=v[2];
+ last_vertex_ptr->next=NULL;
+ last_vertex_ptr->previous=NULL;
+ ++(polygon->vertex_cnt);
+ }
+ else
+ {
+ tess_vertex *vertex_ptr;
+
+ /* same point twice? */
+ if(fabs(last_vertex_ptr->location[0]-v[0]) < EPSILON &&
+ fabs(last_vertex_ptr->location[1]-v[1]) < EPSILON &&
+ fabs(last_vertex_ptr->location[2]-v[2]) < EPSILON)
+ {
+ tess_call_user_error(tobj,GLU_TESS_ERROR6);
+ return;
+ }
+ if((vertex_ptr=(tess_vertex *)
+ malloc(sizeof(tess_vertex)))==NULL)
+ {
+ tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
+ return;
+ }
+ vertex_ptr->data=data;
+ vertex_ptr->location[0]=v[0];
+ vertex_ptr->location[1]=v[1];
+ vertex_ptr->location[2]=v[2];
+ vertex_ptr->next=NULL;
+ vertex_ptr->previous=last_vertex_ptr;
+ ++(polygon->vertex_cnt);
+ last_vertex_ptr->next=vertex_ptr;
+ polygon->last_vertex=vertex_ptr;
+ }
+}
+
+
+static void delete_contours(GLUtriangulatorObj *tobj)
+{
+ tess_polygon *polygon=tobj->current_polygon;
+ tess_contour *contour,*contour_tmp;
+ tess_vertex *vertex,*vertex_tmp;
+
+ /* remove current_polygon list - if exists due to detected error */
+ if(polygon!=NULL)
+ {
+ if (polygon->vertices)
+ {
+ for(vertex=polygon->vertices;vertex!=polygon->last_vertex;)
+ {
+ vertex_tmp=vertex->next;
+ free(vertex);
+ vertex=vertex_tmp;
+ }
+ free(vertex);
+ }
+ free(polygon);
+ tobj->current_polygon=NULL;
+ }
+ /* remove all contour data */
+ for(contour=tobj->contours;contour!=NULL;)
+ {
+ for(vertex=contour->vertices;vertex!=contour->last_vertex;)
+ {
+ vertex_tmp=vertex->next;
+ free(vertex);
+ vertex=vertex_tmp;
+ }
+ free(vertex);
+ contour_tmp=contour->next;
+ free(contour);
+ contour=contour_tmp;
+ }
+ tobj->contours=tobj->last_contour=NULL;
+ tobj->contour_cnt=0;
+}
+
+
+
diff --git a/src/glu/mesa/tess.h b/src/glu/mesa/tess.h
new file mode 100644
index 00000000000..53d673ccbea
--- /dev/null
+++ b/src/glu/mesa/tess.h
@@ -0,0 +1,121 @@
+/* $Id: tess.h,v 1.1 1999/08/19 00:55:42 jtg 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.
+ */
+
+
+/*
+ * $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
+ *
+ * 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
+
+
+#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;
+
+typedef struct polygon_str
+{
+ GLuint vertex_cnt;
+ GLdouble A,B,C,D;
+ GLdouble area;
+ GLenum orientation;
+ struct vertex_str *vertices,*last_vertex;
+} tess_polygon;
+
+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;
+};
+
+
+extern void tess_call_user_error(GLUtriangulatorObj *,GLenum);
+
+
+#endif
diff --git a/src/glu/mesa/tesselat.c b/src/glu/mesa/tesselat.c
new file mode 100644
index 00000000000..1e424c17ca7
--- /dev/null
+++ b/src/glu/mesa/tesselat.c
@@ -0,0 +1,456 @@
+/* $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)();
+}