summaryrefslogtreecommitdiffstats
path: root/src/glu
diff options
context:
space:
mode:
Diffstat (limited to 'src/glu')
-rw-r--r--src/glu/Makefile6
-rw-r--r--src/glu/mesa/Makefile56
-rw-r--r--src/glu/mesa/Makefile.DJ100
-rw-r--r--src/glu/mesa/Makefile.m3263
-rw-r--r--src/glu/mesa/Makefile.ugl96
-rw-r--r--src/glu/mesa/MesaGLU.def62
-rw-r--r--src/glu/mesa/README1195
-rw-r--r--src/glu/mesa/README243
-rw-r--r--src/glu/mesa/all.h54
-rw-r--r--src/glu/mesa/descrip.mms61
-rw-r--r--src/glu/mesa/glu.c416
-rw-r--r--src/glu/mesa/gluP.h97
-rw-r--r--src/glu/mesa/mipmap.c824
-rw-r--r--src/glu/mesa/mms_depend15
-rw-r--r--src/glu/mesa/nurbs.c628
-rw-r--r--src/glu/mesa/nurbs.h252
-rw-r--r--src/glu/mesa/nurbscrv.c444
-rw-r--r--src/glu/mesa/nurbssrf.c1317
-rw-r--r--src/glu/mesa/nurbsutl.c1309
-rw-r--r--src/glu/mesa/polytest.c937
-rw-r--r--src/glu/mesa/project.c403
-rw-r--r--src/glu/mesa/quadric.c819
-rw-r--r--src/glu/mesa/tess.c327
-rw-r--r--src/glu/mesa/tess.h107
-rw-r--r--src/glu/mesa/tesselat.c406
-rw-r--r--src/glu/mini/all.h55
-rw-r--r--src/glu/mini/glu.c417
-rw-r--r--src/glu/mini/gluP.h142
-rw-r--r--src/glu/mini/mipmap.c764
-rw-r--r--src/glu/mini/nurbs.c158
-rw-r--r--src/glu/mini/nurbs.h253
-rw-r--r--src/glu/mini/nurbscrv.c133
-rw-r--r--src/glu/mini/polytest.c938
-rw-r--r--src/glu/mini/project.c404
-rw-r--r--src/glu/mini/quadric.c774
-rw-r--r--src/glu/mini/tess.c328
-rw-r--r--src/glu/mini/tess.h108
-rw-r--r--src/glu/mini/tesselat.c407
-rw-r--r--src/glu/sgi/Makefile2
39 files changed, 13916 insertions, 4 deletions
diff --git a/src/glu/Makefile b/src/glu/Makefile
index 836baa684cb..23161b50156 100644
--- a/src/glu/Makefile
+++ b/src/glu/Makefile
@@ -10,7 +10,7 @@ SUBDIRS = $(GLU_DIRS)
default: $(TOP)/configs/current
@for dir in $(SUBDIRS) ; do \
- (cd $$dir ; $(MAKE)) ; \
+ (cd $$dir && $(MAKE)) || exit 1 ; \
done
# GLU pkg-config file
@@ -28,6 +28,6 @@ install: glu.pc
$(INSTALL) -m 644 glu.pc $(DESTDIR)$(INSTALL_DIR)/$(LIB_DIR)/pkgconfig
clean:
- @for dir in $(SUBDIRS) ; do \
- (cd $$dir ; $(MAKE) clean) ; \
+ -@for dir in $(SUBDIRS) ; do \
+ (cd $$dir && $(MAKE) clean) ; \
done
diff --git a/src/glu/mesa/Makefile b/src/glu/mesa/Makefile
new file mode 100644
index 00000000000..1064bbd2d4f
--- /dev/null
+++ b/src/glu/mesa/Makefile
@@ -0,0 +1,56 @@
+# src/glu/mesa/Makefile
+
+TOP = ../../..
+
+include $(TOP)/configs/current
+
+GLU_MAJOR = 1
+GLU_MINOR = 1
+GLU_TINY = 0$(MESA_MAJOR)0$(MESA_MINOR)0$(MESA_TINY)
+
+C_SOURCES = \
+ glu.c \
+ mipmap.c \
+ nurbs.c \
+ nurbscrv.c \
+ nurbssrf.c \
+ nurbsutl.c \
+ polytest.c \
+ project.c \
+ quadric.c \
+ tess.c \
+ tesselat.c
+
+OBJECTS = $(C_SOURCES:.c=.o)
+
+INCLUDES = -I. -I$(TOP)/include
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@
+
+##### TARGETS #####
+
+default:
+ @if [ "${CONFIG_NAME}" = "beos" ] ; then \
+ echo "$(GLU_LIB_NAME) not build under BeOS, but integrated into ${GL_LIB_NAME}." ; \
+ exit 0 ; \
+ else \
+ $(MAKE) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) || exit 1 ; \
+ fi
+
+$(TOP)/$(LIB_DIR):
+ -mkdir $(TOP)/$(LIB_DIR)
+
+# Make the library:
+$(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME): $(OBJECTS)
+ @ $(TOP)/bin/mklib -o $(GLU_LIB) -linker '$(CC)' -ldflags '$(LDFLAGS)' \
+ -major $(GLU_MAJOR) -minor $(GLU_MINOR) -patch $(GLU_TINY) \
+ $(MKLIB_OPTIONS) -install $(TOP)/$(LIB_DIR) \
+ $(GLU_LIB_DEPS) $(OBJECTS)
+
+clean:
+ -rm -f *.o */*.o */*/*.o
+ -rm -f *.lo */*.lo */*/*.lo
+ -rm -f *.la */*.la */*/*.la
diff --git a/src/glu/mesa/Makefile.DJ b/src/glu/mesa/Makefile.DJ
new file mode 100644
index 00000000000..92bcdaae945
--- /dev/null
+++ b/src/glu/mesa/Makefile.DJ
@@ -0,0 +1,100 @@
+# Mesa 3-D graphics library
+# Version: 4.0
+#
+# Copyright (C) 1999 Brian Paul All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# DOS/DJGPP glu makefile v1.5 for Mesa
+#
+# Copyright (C) 2002 - Daniel Borca
+# Web : http://www.geocities.com/dborca
+
+
+#
+# Available options:
+#
+# Environment variables:
+# CFLAGS
+#
+# Targets:
+# all: build GLU
+# clean: remove object files
+#
+
+
+
+.PHONY: all clean
+
+TOP = ../../..
+LIBDIR = $(TOP)/lib
+GLU_LIB = libglu.a
+GLU_DXE = glu.dxe
+GLU_IMP = libiglu.a
+
+export LD_LIBRARY_PATH := $(LD_LIBRARY_PATH);$(LIBDIR);$(GLIDE)/lib
+
+CC = gcc
+CFLAGS += -I$(TOP)/include
+
+AR = ar
+ARFLAGS = crus
+
+HAVEDXE3 = $(wildcard $(DJDIR)/bin/dxe3gen.exe)
+
+ifeq ($(wildcard $(addsuffix /rm.exe,$(subst ;, ,$(PATH)))),)
+UNLINK = del $(subst /,\,$(1))
+else
+UNLINK = $(RM) $(1)
+endif
+
+CORE_SOURCES = \
+ glu.c \
+ mipmap.c \
+ nurbs.c \
+ nurbscrv.c \
+ nurbssrf.c \
+ nurbsutl.c \
+ polytest.c \
+ project.c \
+ quadric.c \
+ tess.c \
+ tesselat.c
+
+SOURCES = $(CORE_SOURCES)
+
+OBJECTS = $(SOURCES:.c=.o)
+
+.c.o:
+ $(CC) -o $@ $(CFLAGS) -c $<
+
+all: $(LIBDIR)/$(GLU_LIB) $(LIBDIR)/$(GLU_DXE) $(LIBDIR)/$(GLU_IMP)
+
+$(LIBDIR)/$(GLU_LIB): $(OBJECTS)
+ $(AR) $(ARFLAGS) $@ $^
+
+$(LIBDIR)/$(GLU_DXE) $(LIBDIR)/$(GLU_IMP): $(OBJECTS)
+ifeq ($(HAVEDXE3),)
+ $(warning Missing DXE3 package... Skipping $(GLU_DXE))
+else
+ -dxe3gen -o $(LIBDIR)/$(GLU_DXE) -Y $(LIBDIR)/$(GLU_IMP) -D "MesaGLU DJGPP" -E _glu -P gl.dxe -U $^
+endif
+
+clean:
+ -$(call UNLINK,*.o)
diff --git a/src/glu/mesa/Makefile.m32 b/src/glu/mesa/Makefile.m32
new file mode 100644
index 00000000000..e2cf9dd5279
--- /dev/null
+++ b/src/glu/mesa/Makefile.m32
@@ -0,0 +1,63 @@
+# Makefile for GLU for GCC-2.95.2/Mingw32 contributed by
+# Paul Garceau <[email protected]>
+
+# Mesa 3-D graphics library
+# Version: 3.3
+# 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.
+
+
+MESA_MAJOR=3
+MESA_MINOR=3
+MESA_TINY=0
+VERSION=$(MESA_MAJOR).$(MESA_MINOR)
+
+CFLAGS = -I. -DWIN32 -D__WIN32__ -D_WINDOWS \
+ -O2 -funroll-loops \
+ -fexpensive-optimizations -fomit-frame-pointer -ffast-math \
+ -malign-loops=2 -malign-jumps=2 -malign-functions=2 \
+ -mwindows
+CC = gcc
+MAKELIB = ar ru
+GLU_LIB = libGLU.a
+
+
+##### MACROS #####
+
+VPATH = RCS
+
+INCDIR = ../include
+LIBDIR = ../lib
+
+SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \
+ polytest.c project.c quadric.c tess.c tesselat.c
+
+OBJECTS = $(SOURCES:.c=.o)
+
+
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c -I$(INCDIR) $(CFLAGS) $<
+
+
+
+##### TARGETS #####
+
+# Make the library:
+$(LIBDIR)/$(GLU_LIB): $(OBJECTS)
+ $(MAKELIB) $(GLU_LIB) $(MAJOR) $(MINOR) $(TINY) $(OBJECTS) \ No newline at end of file
diff --git a/src/glu/mesa/Makefile.ugl b/src/glu/mesa/Makefile.ugl
new file mode 100644
index 00000000000..fc189bd8047
--- /dev/null
+++ b/src/glu/mesa/Makefile.ugl
@@ -0,0 +1,96 @@
+# Mesa 3-D graphics library
+# Version: 3.5
+#
+# Copyright (C) 2001 Wind River Systems, Inc
+
+# The MIT License
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+# Makefile for GLU library
+
+##### MACROS #####
+GLU_MAJOR = 1
+GLU_MINOR = 3
+GLU_TINY = 0$(MESA_MAJOR)0$(MESA_MINOR)0$(MESA_TINY)
+
+##### RULES #####
+
+include ../rules.windml
+
+GLU_SOURCES = \
+ glu.c \
+ mipmap.c \
+ nurbs.c \
+ nurbscrv.c \
+ nurbssrf.c \
+ nurbsutl.c \
+ polytest.c \
+ project.c \
+ quadric.c \
+ tess.c \
+ tesselat.c \
+ ../src/windml/tornado/torMesaGLUInit.c
+
+GLU_OBJECTS = $(GLU_SOURCES:.c=.o)
+GLU_OBJNAME = $(MESA_LIBDIR)/objMesaGLU.o
+
+SOURCES = $(GLU_SOURCES)
+
+##### TARGETS #####
+
+all: depend.$(CPU)$(TOOL) $(GLU_OBJNAME)
+
+# Make the GLU library
+$(GLU_OBJNAME): $(GLU_OBJECTS)
+# $(LD) -r $(GLU_OBJECTS) -o $(MESA_OBJNAME)
+ $(LD) -r $(GLU_OBJECTS) -o $(GLU_OBJNAME)
+# $(AR) rus $(MESA_LIBNAME) $(GLU_OBJNAME)
+# $(AR) rus $(VX_LIBNAME) $(GLU_OBJNAME)
+
+depend.$(CPU)$(TOOL):
+ifeq ($(WIND_HOST_TYPE),x86-win32)
+ @ $(RM) $@
+ @ $(ECHO) Creating depend.$(CPU)$(TOOL)
+ifneq ($(SOURCES),)
+ @ for %f in ($(SOURCES)) do \
+ $(CC) -MM $(CFLAGS) %f >>$@
+endif
+else
+Makefile
+ @ $(RM) $@
+ @ $(ECHO) "Creating depend.$(CPU)$(TOOL)"
+ifneq ($(SOURCES),)
+ @ for FILE in $(filter-out $(NODEPENDOBJS), $(SOURCES)); \
+ do \
+ $(CC) -MM $(CFLAGS) $$FILE \
+ | $(TCL) $(BIN_DIR)/depend.tcl $(TGT_DIR) >>$@; \
+ done
+endif
+endif
+
+.PHONY = clean
+
+clean:
+# $(AR) d $(MESA_LIBNAME) $(GLU_OBJNAME)
+# $(AR) d $(VX_LIBNAME) $(GLU_OBJNAME)
+ $(RM) $(GLU_OBJNAME)
+ $(RM) $(GLU_OBJECTS)
+ $(RM) depend.$(CPU)$(TOOL)
+
+include depend.$(CPU)$(TOOL)
diff --git a/src/glu/mesa/MesaGLU.def b/src/glu/mesa/MesaGLU.def
new file mode 100644
index 00000000000..0cdd7bb7875
--- /dev/null
+++ b/src/glu/mesa/MesaGLU.def
@@ -0,0 +1,62 @@
+LIBRARY GLU32
+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
+ gluDeleteTess
+; gluTessBeginPolygon
+; gluTessBeginContour
+ gluTessVertex
+; gluTessEndContour
+; gluTessEndPolygon
+; gluTessProperty
+; gluTessNormal
+ gluTessCallback
+; gluGetTessProperty
+ gluBeginPolygon
+ gluNextContour
+ gluEndPolygon
+ 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..874c9359254
--- /dev/null
+++ b/src/glu/mesa/all.h
@@ -0,0 +1,54 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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..2b3f64d8bcc
--- /dev/null
+++ b/src/glu/mesa/descrip.mms
@@ -0,0 +1,61 @@
+# 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)/name=(as_is,short)/float=ieee/ieee=denorm
+
+SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \
+ polytest.c project.c quadric.c tess.c tesselat.c
+
+OBJECTS =glu.obj,mipmap.obj,nurbs.obj,nurbscrv.obj,nurbssrf.obj,nurbsutl.obj,\
+ polytest.obj,project.obj,quadric.obj,tess.obj,tesselat.obj
+
+
+##### RULES #####
+
+VERSION=MesaGlu V3.2
+
+##### 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,2
+ @ 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..f9e33980a4e
--- /dev/null
+++ b/src/glu/mesa/glu.c
@@ -0,0 +1,416 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ * Copyright (C) 1995-2001 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.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gluP.h"
+#endif
+
+
+/*
+ * Miscellaneous utility functions
+ */
+
+
+#ifndef M_PI
+#define M_PI 3.1415926536
+#endif
+#define EPS 0.00001
+
+#ifndef GLU_INCOMPATIBLE_GL_VERSION
+#define GLU_INCOMPATIBLE_GL_VERSION 100903
+#endif
+
+
+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);
+}
+
+
+
+static void
+frustum(GLdouble left, GLdouble right,
+ GLdouble bottom, GLdouble top,
+ GLdouble nearval, GLdouble farval)
+{
+ GLdouble x, y, a, b, c, d;
+ GLdouble m[16];
+
+ x = (2.0 * nearval) / (right - left);
+ y = (2.0 * nearval) / (top - bottom);
+ a = (right + left) / (right - left);
+ b = (top + bottom) / (top - bottom);
+ c = -(farval + nearval) / ( farval - nearval);
+ d = -(2.0 * farval * nearval) / (farval - nearval);
+
+#define M(row,col) m[col*4+row]
+ M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
+ M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
+ M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
+ M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
+#undef M
+
+ glMultMatrixd(m);
+}
+
+
+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;
+
+ /* don't call glFrustum() because of error semantics (covglu) */
+ frustum(xmin, xmax, ymin, ymax, zNear, zFar);
+}
+
+
+
+void GLAPIENTRY
+gluPickMatrix(GLdouble x, GLdouble y,
+ GLdouble width, GLdouble height, 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 gluBeginPolygon",
+ "missing gluBeginContour",
+ "missing gluEndPolygon",
+ "missing gluEndContour",
+ "misoriented or self-intersecting loops",
+ "coincident vertices",
+ "colinear vertices",
+ "FIST recovery process fatal error"
+ };
+ 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 encountered",
+ "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_ERROR8) {
+ 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.5";
+
+ switch (name) {
+ case GLU_EXTENSIONS:
+ return (GLubyte *) extensions;
+ case GLU_VERSION:
+ return (GLubyte *) version;
+ default:
+ return NULL;
+ }
+}
+
+
+
+#if 0 /* gluGetProcAddressEXT not finalized yet! */
+
+#ifdef __cplusplus
+ /* for BeOS R4.5 */
+void GLAPIENTRY(*gluGetProcAddressEXT(const GLubyte * procName)) (...)
+#else
+void (GLAPIENTRY * gluGetProcAddressEXT(const GLubyte * procName)) ()
+#endif
+{
+ struct proc
+ {
+ const char *name;
+ void *address;
+ };
+ static struct proc procTable[] = {
+ {"gluGetProcAddressEXT", (void *) gluGetProcAddressEXT}, /* me! */
+
+ /* new 1.1 functions */
+ {"gluGetString", (void *) gluGetString},
+
+ /* new 1.2 functions */
+ {"gluTessBeginPolygon", (void *) gluTessBeginPolygon},
+ {"gluTessBeginContour", (void *) gluTessBeginContour},
+ {"gluTessEndContour", (void *) gluTessEndContour},
+ {"gluTessEndPolygon", (void *) gluTessEndPolygon},
+ {"gluGetTessProperty", (void *) gluGetTessProperty},
+
+ /* new 1.3 functions */
+
+ {NULL, NULL}
+ };
+ GLuint i;
+
+ for (i = 0; procTable[i].address; i++) {
+ if (strcmp((const char *) procName, procTable[i].name) == 0)
+ return (void (GLAPIENTRY *) ()) procTable[i].address;
+ }
+
+ return NULL;
+}
+
+#endif
+
+
+
+/*
+ * New in GLU 1.3
+ */
+#ifdef GLU_VERSION_1_3
+GLboolean GLAPIENTRY
+gluCheckExtension(const GLubyte *extName, const GLubyte * extString)
+{
+ assert(extName);
+ assert(extString);
+ {
+ const int len = strlen((const char *) extName);
+ const char *start = (const char *) extString;
+
+ while (1) {
+ const char *c = strstr(start, (const char *) extName);
+ if (!c)
+ return GL_FALSE;
+
+ if ((c == start || c[-1] == ' ') && (c[len] == ' ' || c[len] == 0))
+ return GL_TRUE;
+
+ start = c + len;
+ }
+ }
+}
+#endif
diff --git a/src/glu/mesa/gluP.h b/src/glu/mesa/gluP.h
new file mode 100644
index 00000000000..dc1b05b6a1b
--- /dev/null
+++ b/src/glu/mesa/gluP.h
@@ -0,0 +1,97 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.3
+ * Copyright (C) 1995-2004 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.
+ */
+
+
+/*
+ * 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>
+#include <string.h>
+
+
+#if defined(_WIN32) && !defined(__WIN32__)
+# define __WIN32__
+#endif
+
+#if !defined(OPENSTEP) && (defined(__WIN32__) || defined(__CYGWIN__))
+# pragma warning( disable : 4068 ) /* unknown pragma */
+# pragma warning( disable : 4710 ) /* function 'foo' not inlined */
+# pragma warning( disable : 4711 ) /* function 'foo' selected for automatic inline expansion */
+# pragma warning( disable : 4127 ) /* conditional expression is constant */
+# if defined(MESA_MINWARN)
+# pragma warning( disable : 4244 ) /* '=' : conversion from 'const double ' to 'float ', possible loss of data */
+# pragma warning( disable : 4018 ) /* '<' : signed/unsigned mismatch */
+# pragma warning( disable : 4305 ) /* '=' : truncation from 'const double ' to 'float ' */
+# pragma warning( disable : 4550 ) /* 'function' undefined; assuming extern returning int */
+# pragma warning( disable : 4761 ) /* integral size mismatch in argument; conversion supplied */
+# endif
+# define GLCALLBACK __stdcall
+# if defined(__CYGWIN__)
+# define GLCALLBACKPCAST *
+# else
+# define GLCALLBACKPCAST __stdcall *
+# endif
+#else
+/* non-Windows compilation */
+# define GLCALLBACK
+# define GLCALLBACKPCAST *
+#endif /* WIN32 / CYGWIN bracket */
+
+/* compatability guard so we don't need to change client code */
+
+#if defined(_WIN32) && !defined(_WINDEF_) && !defined(_GNU_H_WINDOWS32_BASE) && !defined(OPENSTEP)
+# define CALLBACK GLCALLBACK
+#endif
+
+
+
+#ifndef GLU_TESS_ERROR9
+ /* 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..d85ce9b9b0a
--- /dev/null
+++ b/src/glu/mesa/mipmap.c
@@ -0,0 +1,824 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+#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,
+ GLsizei widthin, GLsizei heightin,
+ GLenum typein, const void *datain,
+ GLsizei widthout, GLsizei 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:
+ case GL_BGR:
+ components = 3;
+ break;
+ case GL_RGBA:
+ case GL_BGRA:
+#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:
+ case GL_BGR:
+ n = 3;
+ break;
+ case GL_RGBA:
+ case GL_BGRA:
+#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,
+ GLsizei 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);
+
+ return 0;
+}
+
+
+
+GLint GLAPIENTRY
+gluBuild2DMipmaps(GLenum target, GLint components,
+ GLsizei width, GLsizei height, GLenum format,
+ GLenum type, const void *data)
+{
+ GLint w, h, maxsize;
+ void *image, *newimage;
+ GLint neww, newh, level, bpp;
+ int error;
+ GLboolean done;
+ GLint retval = 0;
+ GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
+ GLint packrowlength, packalignment, packskiprows, packskippixels;
+
+ 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;
+ }
+
+ /* Get current glPixelStore values */
+ 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);
+
+ /* set pixel packing */
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+
+ done = GL_FALSE;
+
+ 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) {
+ retval = error;
+ done = GL_TRUE;
+ }
+ }
+ else {
+ image = (void *) data;
+ }
+
+ level = 0;
+ while (!done) {
+ if (image != data) {
+ /* set pixel unpacking */
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ }
+
+ 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) {
+ retval = error;
+ done = GL_TRUE;
+ }
+
+ if (image != data) {
+ free(image);
+ }
+ image = newimage;
+
+ w = neww;
+ h = newh;
+ level++;
+ }
+
+ if (image != data) {
+ free(image);
+ }
+
+ /* Restore original glPixelStore state */
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, unpackrowlength);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpackalignment);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, unpackskiprows);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpackskippixels);
+ glPixelStorei(GL_PACK_ROW_LENGTH, packrowlength);
+ glPixelStorei(GL_PACK_ALIGNMENT, packalignment);
+ glPixelStorei(GL_PACK_SKIP_ROWS, packskiprows);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, packskippixels);
+
+ return retval;
+}
diff --git a/src/glu/mesa/mms_depend b/src/glu/mesa/mms_depend
new file mode 100644
index 00000000000..ed59ca9de89
--- /dev/null
+++ b/src/glu/mesa/mms_depend
@@ -0,0 +1,15 @@
+# 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
+tess_fist.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h
+tess_hash.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h
+tess_heap.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h
+tess_clip.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..3f102b4e455
--- /dev/null
+++ b/src/glu/mesa/nurbs.c
@@ -0,0 +1,628 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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) ())
+{
+ nobj->error_callback = (void (GLCALLBACKPCAST) (GLenum)) fn;
+
+ 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..3642e213a8c
--- /dev/null
+++ b/src/glu/mesa/nurbs.h
@@ -0,0 +1,252 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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..4483e1f7761
--- /dev/null
+++ b/src/glu/mesa/nurbscrv.c
@@ -0,0 +1,444 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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 = 0, *color_ctrl = 0, *normal_ctrl = 0, *texture_ctrl = 0;
+ 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..d39fa47d18a
--- /dev/null
+++ b/src/glu/mesa/nurbssrf.c
@@ -0,0 +1,1317 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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;
+}
+
+
+static 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 */
+static 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();
+}
+
+
+static 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;
+ }
+}
+
+
+static 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);
+}
+
+
+static 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;
+ }
+}
+
+
+static 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();
+}
+
+
+static 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);
+}
+
+static 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();
+}
+
+static 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();
+}
+
+static 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();
+}
+
+static 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
+
+
+
+static 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;
+}
+
+
+static 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..b46348a50b2
--- /dev/null
+++ b/src/glu/mesa/nurbsutl.c
@@ -0,0 +1,1309 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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 = 0, t_max = 0, cnt = 0;
+
+ 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 + 1))) == 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;
+}
+
+
+static 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;
+}
+
+
+static 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;
+}
+
+
+static 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..1ff966f61ce
--- /dev/null
+++ b/src/glu/mesa/polytest.c
@@ -0,0 +1,937 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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
+#ifdef WIN32
+ __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 = 0;
+
+ /* 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..2e79cdf0840
--- /dev/null
+++ b/src/glu/mesa/project.c
@@ -0,0 +1,403 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+#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));
+}
+
+
+
+/*
+ * 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);
+ if (!invert_matrix(A, m))
+ return GL_FALSE;
+
+ /* 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;
+}
+
+
+/*
+ * New in GLU 1.3
+ * This is like gluUnProject but also takes near and far DepthRange values.
+ */
+#ifdef GLU_VERSION_1_3
+GLint GLAPIENTRY
+gluUnProject4(GLdouble winx, GLdouble winy, GLdouble winz, GLdouble clipw,
+ const GLdouble modelMatrix[16],
+ const GLdouble projMatrix[16],
+ const GLint viewport[4],
+ GLclampd nearZ, GLclampd farZ,
+ GLdouble * objx, GLdouble * objy, GLdouble * objz,
+ GLdouble * objw)
+{
+ /* matrice de transformation */
+ GLdouble m[16], A[16];
+ GLdouble in[4], out[4];
+ GLdouble z = nearZ + winz * (farZ - nearZ);
+
+ /* 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.0 * z - 1.0;
+ in[3] = clipw;
+
+ /* calcul transformation inverse */
+ matmul(A, projMatrix, modelMatrix);
+ if (!invert_matrix(A, m))
+ return GL_FALSE;
+
+ /* 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];
+ *objw = out[3];
+ return GL_TRUE;
+}
+#endif
diff --git a/src/glu/mesa/quadric.c b/src/glu/mesa/quadric.c
new file mode 100644
index 00000000000..0f6889b284f
--- /dev/null
+++ b/src/glu/mesa/quadric.c
@@ -0,0 +1,819 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1999-2000 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.
+ */
+
+
+/* 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 (GLCALLBACKPCAST) (GLenum)) 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.0);
+ y = cos(0.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);
+ 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);
+ 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);
+ 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..341d29bae3a
--- /dev/null
+++ b/src/glu/mesa/tess.c
@@ -0,0 +1,327 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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(CALLBACK)
+#undef CALLBACK
+#define CALLBACK
+#endif
+
+
+static void delete_contours(GLUtriangulatorObj *);
+
+#ifdef __CYGWIN32__
+#define _CALLBACK
+#else
+#define _CALLBACK GLCALLBACK
+#endif
+
+
+static 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;
+
+ if ((tobj = (GLUtriangulatorObj *)
+ malloc(sizeof(struct GLUtesselator))) == NULL)
+ 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;
+}
+
+
+void GLAPIENTRY
+gluTessNormal(GLUtesselator *tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ)
+{
+ /* dummy function */
+ (void) tess;
+ (void) valueX;
+ (void) valueY;
+ (void) valueZ;
+}
diff --git a/src/glu/mesa/tess.h b/src/glu/mesa/tess.h
new file mode 100644
index 00000000000..4e51dddd37d
--- /dev/null
+++ b/src/glu/mesa/tess.h
@@ -0,0 +1,107 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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);
+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 *);
+
+
+#endif
diff --git a/src/glu/mesa/tesselat.c b/src/glu/mesa/tesselat.c
new file mode 100644
index 00000000000..47d230073fd
--- /dev/null
+++ b/src/glu/mesa/tesselat.c
@@ -0,0 +1,406 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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) ();
+}
diff --git a/src/glu/mini/all.h b/src/glu/mini/all.h
new file mode 100644
index 00000000000..d626bee937f
--- /dev/null
+++ b/src/glu/mini/all.h
@@ -0,0 +1,55 @@
+/* $Id: all.h,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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/mini/glu.c b/src/glu/mini/glu.c
new file mode 100644
index 00000000000..5c7722c5f0b
--- /dev/null
+++ b/src/glu/mini/glu.c
@@ -0,0 +1,417 @@
+/* $Id: glu.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ * Copyright (C) 1995-2001 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.
+ */
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gluP.h"
+#endif
+
+
+/*
+ * Miscellaneous utility functions
+ */
+
+
+#ifndef M_PI
+#define M_PI 3.1415926536
+#endif
+#define EPS 0.00001
+
+#ifndef GLU_INCOMPATIBLE_GL_VERSION
+#define GLU_INCOMPATIBLE_GL_VERSION 100903
+#endif
+
+
+void GLAPIENTRY
+gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,
+ GLdouble centerx, GLdouble centery, GLdouble centerz,
+ GLdouble upx, GLdouble upy, GLdouble upz)
+{
+ GLfloat m[16];
+ GLfloat x[3], y[3], z[3];
+ GLfloat 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
+ glMultMatrixf(m);
+
+ /* Translate Eye to Origin */
+ glTranslatef(-eyex, -eyey, -eyez);
+
+}
+
+
+
+void GLAPIENTRY
+gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)
+{
+ glOrtho(left, right, bottom, top, -1.0, 1.0);
+}
+
+
+
+static void
+frustum(GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat nearval, GLfloat farval)
+{
+ GLfloat x, y, a, b, c, d;
+ GLfloat m[16];
+
+ x = (2.0 * nearval) / (right - left);
+ y = (2.0 * nearval) / (top - bottom);
+ a = (right + left) / (right - left);
+ b = (top + bottom) / (top - bottom);
+ c = -(farval + nearval) / ( farval - nearval);
+ d = -(2.0 * farval * nearval) / (farval - nearval);
+
+#define M(row,col) m[col*4+row]
+ M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
+ M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
+ M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
+ M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
+#undef M
+
+ glMultMatrixf(m);
+}
+
+
+void GLAPIENTRY
+gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
+{
+ GLfloat xmin, xmax, ymin, ymax;
+
+ ymax = zNear * tan(fovy * M_PI / 360.0);
+ ymin = -ymax;
+ xmin = ymin * aspect;
+ xmax = ymax * aspect;
+
+ /* don't call glFrustum() because of error semantics (covglu) */
+ frustum(xmin, xmax, ymin, ymax, zNear, zFar);
+}
+
+
+
+void GLAPIENTRY
+gluPickMatrix(GLdouble x, GLdouble y,
+ GLdouble width, GLdouble height, 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 gluBeginPolygon",
+ "missing gluBeginContour",
+ "missing gluEndPolygon",
+ "missing gluEndContour",
+ "misoriented or self-intersecting loops",
+ "coincident vertices",
+ "colinear vertices",
+ "FIST recovery process fatal error"
+ };
+ 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 encountered",
+ "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_ERROR8) {
+ 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.5";
+
+ switch (name) {
+ case GLU_EXTENSIONS:
+ return (GLubyte *) extensions;
+ case GLU_VERSION:
+ return (GLubyte *) version;
+ default:
+ return NULL;
+ }
+}
+
+
+
+#if 0 /* gluGetProcAddressEXT not finalized yet! */
+
+#ifdef __cplusplus
+ /* for BeOS R4.5 */
+void GLAPIENTRY(*gluGetProcAddressEXT(const GLubyte * procName)) (...)
+#else
+void (GLAPIENTRY * gluGetProcAddressEXT(const GLubyte * procName)) ()
+#endif
+{
+ struct proc
+ {
+ const char *name;
+ void *address;
+ };
+ static struct proc procTable[] = {
+ {"gluGetProcAddressEXT", (void *) gluGetProcAddressEXT}, /* me! */
+
+ /* new 1.1 functions */
+ {"gluGetString", (void *) gluGetString},
+
+ /* new 1.2 functions */
+ {"gluTessBeginPolygon", (void *) gluTessBeginPolygon},
+ {"gluTessBeginContour", (void *) gluTessBeginContour},
+ {"gluTessEndContour", (void *) gluTessEndContour},
+ {"gluTessEndPolygon", (void *) gluTessEndPolygon},
+ {"gluGetTessProperty", (void *) gluGetTessProperty},
+
+ /* new 1.3 functions */
+
+ {NULL, NULL}
+ };
+ GLuint i;
+
+ for (i = 0; procTable[i].address; i++) {
+ if (strcmp((const char *) procName, procTable[i].name) == 0)
+ return (void (GLAPIENTRY *) ()) procTable[i].address;
+ }
+
+ return NULL;
+}
+
+#endif
+
+
+
+/*
+ * New in GLU 1.3
+ */
+#ifdef GLU_VERSION_1_3
+GLboolean GLAPIENTRY
+gluCheckExtension(const GLubyte *extName, const GLubyte * extString)
+{
+ assert(extName);
+ assert(extString);
+ {
+ const int len = strlen((const char *) extName);
+ const char *start = (const char *) extString;
+
+ while (1) {
+ const char *c = strstr(start, (const char *) extName);
+ if (!c)
+ return GL_FALSE;
+
+ if ((c == start || c[-1] == ' ') && (c[len] == ' ' || c[len] == 0))
+ return GL_TRUE;
+
+ start = c + len;
+ }
+ }
+}
+#endif
diff --git a/src/glu/mini/gluP.h b/src/glu/mini/gluP.h
new file mode 100644
index 00000000000..85fbc33c625
--- /dev/null
+++ b/src/glu/mini/gluP.h
@@ -0,0 +1,142 @@
+/* $Id: gluP.h,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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>
+#include <string.h>
+
+
+#if defined(_WIN32) && !defined(__WIN32__)
+# define __WIN32__
+#endif
+
+#if !defined(OPENSTEP) && (defined(__WIN32__) || defined(__CYGWIN__))
+# pragma warning( disable : 4068 ) /* unknown pragma */
+# pragma warning( disable : 4710 ) /* function 'foo' not inlined */
+# pragma warning( disable : 4711 ) /* function 'foo' selected for automatic inline expansion */
+# pragma warning( disable : 4127 ) /* conditional expression is constant */
+# if defined(MESA_MINWARN)
+# pragma warning( disable : 4244 ) /* '=' : conversion from 'const double ' to 'float ', possible loss of data */
+# pragma warning( disable : 4018 ) /* '<' : signed/unsigned mismatch */
+# pragma warning( disable : 4305 ) /* '=' : truncation from 'const double ' to 'float ' */
+# pragma warning( disable : 4550 ) /* 'function' undefined; assuming extern returning int */
+# pragma warning( disable : 4761 ) /* integral size mismatch in argument; conversion supplied */
+# endif
+# if defined(_MSC_VER) && defined(BUILD_GL32) /* tag specify we're building mesa as a DLL */
+# define GLAPI __declspec(dllexport)
+# define WGLAPI __declspec(dllexport)
+# elif defined(_MSC_VER) && defined(_DLL) /* tag specifying we're building for DLL runtime support */
+# define GLAPI __declspec(dllimport)
+# define WGLAPI __declspec(dllimport)
+# else /* for use with static link lib build of Win32 edition only */
+# define GLAPI extern
+# define WGLAPI __declspec(dllimport)
+# endif /* _STATIC_MESA support */
+# define GLAPIENTRY __stdcall
+# define GLAPIENTRYP __stdcall *
+# define GLCALLBACK __stdcall
+# define GLCALLBACKP __stdcall *
+# if defined(__CYGWIN__)
+# define GLCALLBACKPCAST *
+# else
+# define GLCALLBACKPCAST __stdcall *
+# endif
+# define GLWINAPI __stdcall
+# define GLWINAPIV __cdecl
+#else
+/* non-Windows compilation */
+# define GLAPI extern
+# define GLAPIENTRY
+# define GLAPIENTRYP *
+# define GLCALLBACK
+# define GLCALLBACKP *
+# define GLCALLBACKPCAST *
+# define GLWINAPI
+# define GLWINAPIV
+#endif /* WIN32 / CYGWIN bracket */
+
+/* compatibility guard so we don't need to change client code */
+
+#if defined(_WIN32) && !defined(_WINDEF_) && !defined(_GNU_H_WINDOWS32_BASE) && !defined(OPENSTEP)
+# define CALLBACK GLCALLBACK
+typedef int (GLAPIENTRY *PROC)();
+typedef void *HGLRC;
+typedef void *HDC;
+typedef unsigned long COLORREF;
+#endif
+
+#if defined(_WIN32) && !defined(_WINGDI_) && !defined(_GNU_H_WINDOWS32_DEFINES) && !defined(OPENSTEP)
+# define WGL_FONT_LINES 0
+# define WGL_FONT_POLYGONS 1
+#ifndef _GNU_H_WINDOWS32_FUNCTIONS
+# ifdef UNICODE
+# define wglUseFontBitmaps wglUseFontBitmapsW
+# define wglUseFontOutlines wglUseFontOutlinesW
+# else
+# define wglUseFontBitmaps wglUseFontBitmapsA
+# define wglUseFontOutlines wglUseFontOutlinesA
+# endif /* !UNICODE */
+#endif /* _GNU_H_WINDOWS32_FUNCTIONS */
+typedef struct tagLAYERPLANEDESCRIPTOR LAYERPLANEDESCRIPTOR, *PLAYERPLANEDESCRIPTOR, *LPLAYERPLANEDESCRIPTOR;
+typedef struct _GLYPHMETRICSFLOAT GLYPHMETRICSFLOAT, *PGLYPHMETRICSFLOAT, *LPGLYPHMETRICSFLOAT;
+typedef struct tagPIXELFORMATDESCRIPTOR PIXELFORMATDESCRIPTOR, *PPIXELFORMATDESCRIPTOR, *LPPIXELFORMATDESCRIPTOR;
+#include <gl/mesa_wgl.h>
+#endif
+
+
+
+#ifndef GLU_TESS_ERROR9
+ /* 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/mini/mipmap.c b/src/glu/mini/mipmap.c
new file mode 100644
index 00000000000..97297729e78
--- /dev/null
+++ b/src/glu/mini/mipmap.c
@@ -0,0 +1,764 @@
+/* $Id: mipmap.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+#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,
+ GLsizei widthin, GLsizei heightin,
+ GLenum typein, const void *datain,
+ GLsizei widthout, GLsizei heightout,
+ GLenum typeout, void *dataout)
+{
+ GLint components, i, j, k;
+ GLfloat *tempin, *tempout, f;
+ 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:
+ case GL_BGR:
+ components = 3;
+ break;
+ case GL_RGBA:
+ case GL_BGRA:
+#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 */
+ glGetFloatv(GL_UNPACK_ROW_LENGTH, &f); unpackrowlength = (int)f;
+ glGetFloatv(GL_UNPACK_ALIGNMENT, &f); unpackalignment = (int)f;
+ glGetFloatv(GL_UNPACK_SKIP_ROWS, &f); unpackskiprows = (int)f;
+ glGetFloatv(GL_UNPACK_SKIP_PIXELS, &f); unpackskippixels = (int)f;
+ glGetFloatv(GL_PACK_ROW_LENGTH, &f); packrowlength = (int)f;
+ glGetFloatv(GL_PACK_ALIGNMENT, &f); packalignment = (int)f;
+ glGetFloatv(GL_PACK_SKIP_ROWS, &f); packskiprows = (int)f;
+ glGetFloatv(GL_PACK_SKIP_PIXELS, &f); packskippixels = (int)f;
+
+ /* 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 data type, 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:
+ case GL_BGR:
+ n = 3;
+ break;
+ case GL_RGBA:
+ case GL_BGRA:
+#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,
+ GLsizei width, GLenum format, GLenum type, const void *data)
+{
+ return 0;
+}
+
+
+
+GLint GLAPIENTRY
+gluBuild2DMipmaps(GLenum target, GLint components,
+ GLsizei width, GLsizei height, GLenum format,
+ GLenum type, const void *data)
+{
+ GLint w, h;
+ GLint maxsize;
+ void *image, *newimage;
+ GLint neww, newh, level, bpp;
+ int error;
+ GLboolean done;
+ GLint retval = 0;
+ GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
+ GLint packrowlength, packalignment, packskiprows, packskippixels;
+ GLfloat f;
+
+ if (width < 1 || height < 1)
+ return GLU_INVALID_VALUE;
+
+ glGetFloatv(GL_MAX_TEXTURE_SIZE, &f); maxsize = (int)f;
+
+ 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;
+ }
+
+ /* Get current glPixelStore values */
+ glGetFloatv(GL_UNPACK_ROW_LENGTH, &f); unpackrowlength = (int)f;
+ glGetFloatv(GL_UNPACK_ALIGNMENT, &f); unpackalignment = (int)f;
+ glGetFloatv(GL_UNPACK_SKIP_ROWS, &f); unpackskiprows = (int)f;
+ glGetFloatv(GL_UNPACK_SKIP_PIXELS, &f); unpackskippixels = (int)f;
+ glGetFloatv(GL_PACK_ROW_LENGTH, &f); packrowlength = (int)f;
+ glGetFloatv(GL_PACK_ALIGNMENT, &f); packalignment = (int)f;
+ glGetFloatv(GL_PACK_SKIP_ROWS, &f); packskiprows = (int)f;
+ glGetFloatv(GL_PACK_SKIP_PIXELS, &f); packskippixels = (int)f;
+
+ /* set pixel packing */
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+
+ done = GL_FALSE;
+
+ 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) {
+ retval = error;
+ done = GL_TRUE;
+ }
+ }
+ else {
+ image = (void *) data;
+ }
+
+ level = 0;
+ while (!done) {
+ if (image != data) {
+ /* set pixel unpacking */
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ }
+
+ 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) {
+ retval = error;
+ done = GL_TRUE;
+ }
+
+ if (image != data) {
+ free(image);
+ }
+ image = newimage;
+
+ w = neww;
+ h = newh;
+ level++;
+ }
+
+ if (image != data) {
+ free(image);
+ }
+
+ /* Restore original glPixelStore state */
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, unpackrowlength);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpackalignment);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, unpackskiprows);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpackskippixels);
+ glPixelStorei(GL_PACK_ROW_LENGTH, packrowlength);
+ glPixelStorei(GL_PACK_ALIGNMENT, packalignment);
+ glPixelStorei(GL_PACK_SKIP_ROWS, packskiprows);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, packskippixels);
+
+ return retval;
+}
diff --git a/src/glu/mini/nurbs.c b/src/glu/mini/nurbs.c
new file mode 100644
index 00000000000..93c0dd3ce23
--- /dev/null
+++ b/src/glu/mini/nurbs.c
@@ -0,0 +1,158 @@
+/* $Id: nurbs.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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));
+ 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])
+{
+}
+
+
+void GLAPIENTRY
+gluNurbsProperty(GLUnurbsObj * nobj, GLenum property, GLfloat value)
+{
+}
+
+
+void GLAPIENTRY
+gluGetNurbsProperty(GLUnurbsObj * nobj, GLenum property, GLfloat * value)
+{
+}
+
+
+
+void GLAPIENTRY
+gluBeginCurve(GLUnurbsObj * nobj)
+{
+}
+
+
+void GLAPIENTRY
+gluEndCurve(GLUnurbsObj * nobj)
+{
+}
+
+
+void GLAPIENTRY
+gluNurbsCurve(GLUnurbsObj * nobj, GLint nknots, GLfloat * knot,
+ GLint stride, GLfloat * ctlarray, GLint order, GLenum type)
+{
+}
+
+
+void GLAPIENTRY
+gluBeginSurface(GLUnurbsObj * nobj)
+{
+}
+
+
+void GLAPIENTRY
+gluEndSurface(GLUnurbsObj * nobj)
+{
+}
+
+
+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)
+{
+}
+
+
+void GLAPIENTRY
+gluNurbsCallback(GLUnurbsObj * nobj, GLenum which, void (GLCALLBACK * fn) ())
+{
+}
+
+void GLAPIENTRY
+gluBeginTrim(GLUnurbsObj * nobj)
+{
+}
+
+void GLAPIENTRY
+gluPwlCurve(GLUnurbsObj * nobj, GLint count, GLfloat * array, GLint stride,
+ GLenum type)
+{
+}
+
+void GLAPIENTRY
+gluEndTrim(GLUnurbsObj * nobj)
+{
+}
diff --git a/src/glu/mini/nurbs.h b/src/glu/mini/nurbs.h
new file mode 100644
index 00000000000..c9c9c094f1a
--- /dev/null
+++ b/src/glu/mini/nurbs.h
@@ -0,0 +1,253 @@
+/* $Id: nurbs.h,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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/mini/nurbscrv.c b/src/glu/mini/nurbscrv.c
new file mode 100644
index 00000000000..62d91b46d3f
--- /dev/null
+++ b/src/glu/mini/nurbscrv.c
@@ -0,0 +1,133 @@
+/* $Id: nurbscrv.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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
+
+
+
+/* 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 = 0, *color_ctrl = 0, *normal_ctrl = 0, *texture_ctrl = 0;
+ 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/mini/polytest.c b/src/glu/mini/polytest.c
new file mode 100644
index 00000000000..52f272a3cb4
--- /dev/null
+++ b/src/glu/mini/polytest.c
@@ -0,0 +1,938 @@
+/* $Id: polytest.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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
+#ifdef WIN32
+ __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 = 0;
+
+ /* 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/mini/project.c b/src/glu/mini/project.c
new file mode 100644
index 00000000000..71279947cf9
--- /dev/null
+++ b/src/glu/mini/project.c
@@ -0,0 +1,404 @@
+/* $Id: project.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+#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));
+}
+
+
+
+/*
+ * 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);
+ if (!invert_matrix(A, m))
+ return GL_FALSE;
+
+ /* 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;
+}
+
+
+/*
+ * New in GLU 1.3
+ * This is like gluUnProject but also takes near and far DepthRange values.
+ */
+#ifdef GLU_VERSION_1_3
+GLint GLAPIENTRY
+gluUnProject4(GLdouble winx, GLdouble winy, GLdouble winz, GLdouble clipw,
+ const GLdouble modelMatrix[16],
+ const GLdouble projMatrix[16],
+ const GLint viewport[4],
+ GLclampd nearZ, GLclampd farZ,
+ GLdouble * objx, GLdouble * objy, GLdouble * objz,
+ GLdouble * objw)
+{
+ /* matrice de transformation */
+ GLdouble m[16], A[16];
+ GLdouble in[4], out[4];
+ GLdouble z = nearZ + winz * (farZ - nearZ);
+
+ /* 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.0 * z - 1.0;
+ in[3] = clipw;
+
+ /* calcul transformation inverse */
+ matmul(A, projMatrix, modelMatrix);
+ if (!invert_matrix(A, m))
+ return GL_FALSE;
+
+ /* 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];
+ *objw = out[3];
+ return GL_TRUE;
+}
+#endif
diff --git a/src/glu/mini/quadric.c b/src/glu/mini/quadric.c
new file mode 100644
index 00000000000..015552e1237
--- /dev/null
+++ b/src/glu/mini/quadric.c
@@ -0,0 +1,774 @@
+/* $Id: quadric.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1999-2000 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.
+ */
+
+
+/* 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 (GLCALLBACKPCAST) (GLenum)) 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)
+{
+}
+
+
+
+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.0);
+ y = cos(0.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); */
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ glVertex3f(x * radius, y * radius, z * radius);
+ }
+ glEnd();
+ }
+ }
+ else if (qobj->DrawStyle == GLU_POINT) {
+ /* top and bottom-most points */
+ glBegin(GL_POINTS);
+ glVertex3f(0.0, 0.0, radius);
+ glVertex3f(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);
+ 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
+
+
+ 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->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++) {
+ glVertex2f(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++) {
+ glVertex2f(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++) {
+ glVertex2f(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++) {
+ glVertex2f(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++) {
+ glVertex2f(innerRadius * sin(angle), innerRadius * cos(angle));
+ angle += delta_angle;
+ }
+ glEnd();
+ }
+ /* draw spokes */
+ if (sweepAngle < 360.0) {
+ GLdouble stopAngle = startAngle + sweepAngle;
+ glBegin(GL_LINES);
+ glVertex2f(innerRadius * SIND(startAngle),
+ innerRadius * COSD(startAngle));
+ glVertex2f(outerRadius * SIND(startAngle),
+ outerRadius * COSD(startAngle));
+ glVertex2f(innerRadius * SIND(stopAngle),
+ innerRadius * COSD(stopAngle));
+ glVertex2f(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) {
+ glVertex2f((radius + delta_radius) * sin(angle),
+ (radius + delta_radius) * cos(angle));
+ glVertex2f(radius * sin(angle), radius * cos(angle));
+ }
+ else {
+ glVertex2f(radius * sin(angle), radius * cos(angle));
+ glVertex2f((radius + delta_radius) * sin(angle),
+ (radius + delta_radius) * cos(angle));
+ }
+ angle += delta_angle;
+ }
+ glEnd();
+ radius += delta_radius;
+ }
+ }
+}
diff --git a/src/glu/mini/tess.c b/src/glu/mini/tess.c
new file mode 100644
index 00000000000..1a384239be0
--- /dev/null
+++ b/src/glu/mini/tess.c
@@ -0,0 +1,328 @@
+/* $Id: tess.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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(CALLBACK)
+#undef CALLBACK
+#define CALLBACK
+#endif
+
+
+static void delete_contours(GLUtriangulatorObj *);
+
+#ifdef __CYGWIN32__
+#define _CALLBACK
+#else
+#define _CALLBACK GLCALLBACK
+#endif
+
+
+static 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;
+
+ if ((tobj = (GLUtriangulatorObj *)
+ malloc(sizeof(struct GLUtesselator))) == NULL)
+ 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;
+}
+
+
+void GLAPIENTRY
+gluTessNormal(GLUtesselator *tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ)
+{
+ /* dummy function */
+ (void) tess;
+ (void) valueX;
+ (void) valueY;
+ (void) valueZ;
+}
diff --git a/src/glu/mini/tess.h b/src/glu/mini/tess.h
new file mode 100644
index 00000000000..908e20972cf
--- /dev/null
+++ b/src/glu/mini/tess.h
@@ -0,0 +1,108 @@
+/* $Id: tess.h,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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);
+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 *);
+
+
+#endif
diff --git a/src/glu/mini/tesselat.c b/src/glu/mini/tesselat.c
new file mode 100644
index 00000000000..a1102e6e5a6
--- /dev/null
+++ b/src/glu/mini/tesselat.c
@@ -0,0 +1,407 @@
+/* $Id: tesselat.c,v 1.2 2003/08/22 20:11:43 brianp Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ * Copyright (C) 1995-2000 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.
+ */
+
+
+/*
+ * 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) ();
+}
diff --git a/src/glu/sgi/Makefile b/src/glu/sgi/Makefile
index bb1c0a8aba5..207247ad87a 100644
--- a/src/glu/sgi/Makefile
+++ b/src/glu/sgi/Makefile
@@ -128,7 +128,7 @@ default:
echo "$(GLU_LIB_NAME) not build under BeOS, but integrated into ${GL_LIB_NAME}." ; \
exit 0 ; \
else \
- $(MAKE) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) ; \
+ $(MAKE) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) || exit 1 ; \
fi
$(TOP)/$(LIB_DIR):